From 3f563629b4b433d200dae8c9723d2c07d404494d Mon Sep 17 00:00:00 2001 From: "Documenter.jl" Date: Tue, 29 Aug 2023 23:16:41 +0000 Subject: [PATCH] build based on fa8e7f2 --- dev/assets/notebooks/fei2_classical.ipynb | 941 ++++++++++++++++++ dev/assets/notebooks/fei2_tutorial.ipynb | 766 ++++++++++++++ dev/assets/notebooks/ising2d.ipynb | 179 ++++ dev/assets/notebooks/one_dim_chain.ipynb | 602 +++++++++++ dev/assets/notebooks/out_of_equilibrium.ipynb | 279 ++++++ dev/assets/notebooks/powder_averaging.ipynb | 225 +++++ dev/examples/fei2_classical/index.html | 12 +- dev/examples/fei2_tutorial/index.html | 4 +- dev/examples/ising2d/index.html | 66 +- dev/examples/one_dim_chain/index.html | 18 +- dev/examples/out_of_equilibrium/index.html | 4 +- dev/examples/powder_averaging/index.html | 4 +- dev/index.html | 2 +- dev/library/index.html | 46 +- dev/search/index.html | 2 +- dev/search_index.js | 2 +- dev/structure-factor/index.html | 2 +- dev/versions/index.html | 2 +- dev/writevtk/index.html | 2 +- 19 files changed, 3075 insertions(+), 83 deletions(-) create mode 100644 dev/assets/notebooks/fei2_classical.ipynb create mode 100644 dev/assets/notebooks/fei2_tutorial.ipynb create mode 100644 dev/assets/notebooks/ising2d.ipynb create mode 100644 dev/assets/notebooks/one_dim_chain.ipynb create mode 100644 dev/assets/notebooks/out_of_equilibrium.ipynb create mode 100644 dev/assets/notebooks/powder_averaging.ipynb diff --git a/dev/assets/notebooks/fei2_classical.ipynb b/dev/assets/notebooks/fei2_classical.ipynb new file mode 100644 index 000000000..bc8497198 --- /dev/null +++ b/dev/assets/notebooks/fei2_classical.ipynb @@ -0,0 +1,941 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Structure Factors with Classical Dynamics" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Sunny, LinearAlgebra, WGLMakie" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "In our previous Case Study: FeI$_{2}$, we used linear spin wave theory\n", + "(LSWT) to calculate the dynamical structure factor. Here, we perform a similar\n", + "calculation using classical spin dynamics. Because we are interested in the\n", + "coupled dynamics of spin dipoles and quadrupoles, we employ a [classical\n", + "dynamics of SU(3) coherent states](https://arxiv.org/abs/2209.01265) that\n", + "generalizes the Landau-Lifshitz equation.\n", + "\n", + "Compared to LSWT, simulations using classical dynamics are much slower, and\n", + "are limited in $k$-space resolution. However, they make it is possible to\n", + "capture nonlinear effects associated with finite temperature fluctuations.\n", + "Classical dynamics are also appealing for studying out-of-equilibrium systems\n", + "(e.g., relaxation of spin glasses), or systems with quenched inhomogeneities\n", + "that require large simulation volumes.\n", + "\n", + "In this tutorial, we show how to study the finite temperature dynamics of\n", + "FeI$_2$ using the classical approach. It is important to stress that the\n", + "estimation of $S(𝐪,ω)$ with classical dynamics is fundamentally a Monte\n", + "Carlo calculation: sample spin configurations are drawn from thermal\n", + "equilibrium and used as initial conditions for generating dissipationless\n", + "trajectories. The correlations of these trajectories are then averaged and\n", + "used to calculate scattering intensities. It is therefore important to ensure\n", + "that the initial spin configurations are sampled appropriately and that\n", + "sufficient statistics are collected. We will demonstrate one approach here.\n", + "\n", + "As an overview, we will:\n", + "\n", + "1. Identify the ground state\n", + "2. Measure correlation data describing the excitations around that ground state\n", + "3. Use the correlation data to compute scattering intensities\n", + "\n", + "As the implementation of the FeI$_2$ model is already covered in detail in the\n", + "LSWT tutorial, we will not repeat it below. Instead, we will assume that you\n", + "already have defined a `sys` in the same way with lattice dimensions $4×4×4$." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "a = b = 4.05012#hide\n", + "c = 6.75214#hide\n", + "latvecs = lattice_vectors(a, b, c, 90, 90, 120)#hide\n", + "positions = [[0,0,0], [1/3, 2/3, 1/4], [2/3, 1/3, 3/4]]#hide\n", + "types = [\"Fe\", \"I\", \"I\"]#hide\n", + "FeI2 = Crystal(latvecs, positions; types)#hide\n", + "cryst = subcrystal(FeI2, \"Fe\")#hide\n", + "sys = System(cryst, (4,4,4), [SpinInfo(1,S=1,g=2)], :SUN, seed=2)#hide\n", + "J1pm = -0.236#hide\n", + "J1pmpm = -0.161#hide\n", + "J1zpm = -0.261#hide\n", + "J2pm = 0.026#hide\n", + "J3pm = 0.166#hide\n", + "J′0pm = 0.037#hide\n", + "J′1pm = 0.013#hide\n", + "J′2apm = 0.068#hide\n", + "J1zz = -0.236#hide\n", + "J2zz = 0.113#hide\n", + "J3zz = 0.211#hide\n", + "J′0zz = -0.036#hide\n", + "J′1zz = 0.051#hide\n", + "J′2azz = 0.073#hide\n", + "J1xx = J1pm + J1pmpm#hide\n", + "J1yy = J1pm - J1pmpm#hide\n", + "J1yz = J1zpm#hide\n", + "set_exchange!(sys, [J1xx 0.0 0.0; 0.0 J1yy J1yz; 0.0 J1yz J1zz], Bond(1,1,[1,0,0]))#hide\n", + "set_exchange!(sys, [J2pm 0.0 0.0; 0.0 J2pm 0.0; 0.0 0.0 J2zz], Bond(1,1,[1,2,0]))#hide\n", + "set_exchange!(sys, [J3pm 0.0 0.0; 0.0 J3pm 0.0; 0.0 0.0 J3zz], Bond(1,1,[2,0,0]))#hide\n", + "set_exchange!(sys, [J′0pm 0.0 0.0; 0.0 J′0pm 0.0; 0.0 0.0 J′0zz], Bond(1,1,[0,0,1]))#hide\n", + "set_exchange!(sys, [J′1pm 0.0 0.0; 0.0 J′1pm 0.0; 0.0 0.0 J′1zz], Bond(1,1,[1,0,1]))#hide\n", + "set_exchange!(sys, [J′2apm 0.0 0.0; 0.0 J′2apm 0.0; 0.0 0.0 J′2azz], Bond(1,1,[1,2,1]))#hide\n", + "D = 2.165#hide\n", + "S = spin_operators(sys, 1)#hide\n", + "set_onsite_coupling!(sys, -D*S[3]^2, 1)#hide" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "## Finding a ground state" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Sunny uses the [Langevin dynamics of SU(_N_) coherent\n", + "states](https://arxiv.org/abs/2209.01265) to sample spin configurations\n", + "from the thermal equlibrium. One first constructs a\n", + "`Langevin` integrator. This requires a time step, temperature, and a\n", + "phenomenological damping parameter $λ$ that sets the coupling to the thermal\n", + "bath." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "Δt = 0.05/D # Should be inversely proportional to the largest energy scale\n", + " # in the system. For FeI2, this is the easy-axis anisotropy,\n", + " # `D = 2.165` (meV). The prefactor 0.05 is relatively small,\n", + " # and achieves high accuracy.\n", + "kT = 0.2 # Temperature of the thermal bath (meV).\n", + "λ = 0.1 # This value is typically good for Monte Carlo sampling,\n", + " # independent of system details.\n", + "\n", + "langevin = Langevin(Δt; kT, λ);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Sampling with a large number of Langevin time-steps should hopefully\n", + "thermalize the system to a target temperature. For demonstration purposes, we\n", + "will here run for a relatively short period of 1,000 timesteps." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "randomize_spins!(sys)\n", + "for _ in 1:1_000\n", + " step!(sys, langevin)\n", + "end" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "To inspect the structure of the spin configuration, we use the function\n", + "`minimize_energy!` to find a nearby _local_ minimum. Then\n", + "`print_wrapped_intensities` provides information about the Fourier\n", + "modes in reciprocal lattice units (RLU)." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "minimize_energy!(sys)\n", + "print_wrapped_intensities(sys)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The wide distribution of intensities indicates an imperfect magnetic order.\n", + "The defects are immediately apparent in the real-space spin configuration." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "plot_spins(sys)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "In this case, we can find the correct ground state simply by running the\n", + "Langevin dynamics for longer." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "for _ in 1:10_000\n", + " step!(sys, langevin)\n", + "end\n", + "minimize_energy!(sys)\n", + "print_wrapped_intensities(sys)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "This is the perfect single-$𝐐$ ground state. This worked because the\n", + "temperature `kT = 0.2` was carefully selected. It is below the magnetic\n", + "ordering temperature, but still large enough that the Langevin dynamics could\n", + "quickly overcome local energy barriers. More complicated magnetic orderings\n", + "will frequently require more sophisticated sampling schemes. One possibility\n", + "is simulated annealing, where `kT` is slowly lowered over the course of the\n", + "sampling procedure." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Calculating Thermal-Averaged Correlations $\\langle S^{\\alpha\\beta}(𝐪,ω)\\rangle$\n", + "\n", + "Now that we have identified an appropriate ground state, we will adjust\n", + "the temperature so that the system still remains near the ground state, but still\n", + "has thermal fluctuations." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "kT = 3.5 * meV_per_K # 3.5K ≈ 0.30 meV\n", + "langevin.kT = kT;" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Additionally, since these classical simulations are conducted on a finite-sized lattice,\n", + "obtaining acceptable resolution in momentum space requires the use of a larger\n", + "system size. We resize the magnetic supercell to a much larger\n", + "simulation volume, provided as multiples of the original unit cell." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "sys_large = resize_supercell(sys, (16,16,4)) # 16x16x4 copies of the original unit cell\n", + "plot_spins(sys_large)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "As stressed above, we need to sample multiple spin configurations\n", + "from the thermal equilibrium distribution.\n", + "We therefore begin by using Langevin dynamics to\n", + "bring the system into thermal equilibrium at the new temperature." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "# At the new temperature\n", + "for _ in 1:10_000\n", + " step!(sys_large, langevin)\n", + "end" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Now that we are in a state drawn from thermal equilibrium, we are ready to begin\n", + "collecting correlation data $S^{\\alpha\\beta}$.\n", + "\n", + "To collect one sample of spin-spin correlation data, we integrate the\n", + "[Hamiltonian dynamics of SU(_N_) coherent states](https://arxiv.org/abs/2204.07563).\n", + "This generates trajectories $S^\\alpha(\\vec r,t)$.\n", + "However, note that the spins are only defined at the finitely-many lattice\n", + "sites, so $\\vec r$ is discrete.\n", + "From the trajectories, Sunny computes fourier-transformed correlations $S^{\\alpha\\beta}(q,\\omega)$,\n", + "where $q$ is discrete for the same reason.\n", + "\n", + "The correlation data from this sample is now ready to be averaged together with data\n", + "from other samples to form the thermal average.\n", + "Samples of correlation data are accumulated and averaged into a\n", + "`SampledCorrelations`, which is initialized by calling\n", + "`dynamical_correlations`:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "sc = dynamical_correlations(sys_large; Δt=2Δt, nω=120, ωmax=7.5)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "`dynamical_correlations` takes a `System`\n", + "and three keyword parameters that determine the ω information that will be\n", + "available: an integration step size, the number of ωs to resolve, and the\n", + "maximum ω to resolve. For the time step, twice the value used for the Langevin\n", + "integrator is usually a good choice." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "`sc` currently contains no data. The first sample can be accumulated into it by\n", + "calling `add_sample!`." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "add_sample!(sc, sys_large)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Additional samples can be added after re-sampling new\n", + "spin configurations from the thermal distribution.\n", + "The new samples are generated in the same way as the first sample, by running\n", + "the Langevin dynamics.\n", + "The dynamics should be run long enough that consecutive samples are uncorrelated, or\n", + "else the thermal average will converge only very slowly." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "for _ in 1:2\n", + " for _ in 1:1000 # Enough steps to decorrelate spins\n", + " step!(sys_large, langevin)\n", + " end\n", + " add_sample!(sc, sys_large) # Accumulate the sample into `sc`\n", + "end" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Now, `sc` has more samples included:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "sc" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "## Computing Scattering Intensities" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "With the thermally-averaged correlation data $\\langle S^{\\alpha\\beta}(q,\\omega)\\rangle$\n", + "in hand, we now need to specify how to extract a scattering intensity from this information.\n", + "This is done by constructing an `intensity_formula`.\n", + "By way of example, we will use a formula which computes the trace of the structure\n", + "factor and applies a classical-to-quantum temperature-dependent rescaling `kT`." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "formula = intensity_formula(sc, :trace; kT = kT)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Recall that $\\langle S^{\\alpha\\beta}(q,\\omega)\\rangle$ is only available at certain discrete\n", + "$q$ values, due to the finite lattice size.\n", + "There are two basic approaches to handling this discreteness.\n", + "The first approach is to interpolate between the available\n", + "data using `intensities_interpolated`. For example, we can plot single-$q$ slices\n", + "at (0,0,0) and (π,π,π) using this method:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "qs = [[0, 0, 0], [0.5, 0.5, 0.5]]\n", + "is = intensities_interpolated(sc, qs, formula; interpolation = :round)\n", + "\n", + "ωs = available_energies(sc)\n", + "fig = lines(ωs, is[1,:]; axis=(xlabel=\"meV\", ylabel=\"Intensity\"), label=\"(0,0,0)\")\n", + "lines!(ωs, is[2,:]; label=\"(π,π,π)\")\n", + "axislegend()\n", + "fig" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The resolution in energy can be improved by increasing `nω` (and decreasing `Δt`),\n", + "and the general accuracy can be improved by collecting additional samples from the thermal\n", + "equilibrium.\n", + "\n", + "For real calculations, one often wants to apply further corrections and more\n", + "accurate formulas. Here, we apply `FormFactor` corrections appropriate\n", + "for `Fe2` magnetic ions, and a dipole polarization correction `:perp`." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "formfactors = [FormFactor(\"Fe2\"; g_lande=3/2)]\n", + "new_formula = intensity_formula(sc, :perp; kT = kT, formfactors = formfactors)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Frequently, one wants to extract energy intensities along lines that connect\n", + "special wave vectors--a so-called \"spaghetti plot\". The function\n", + "`reciprocal_space_path` creates an appropriate horizontal axis for this plot\n", + "by linearly sampling between provided $q$-points, with a given sample density." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "points = [[0, 0, 0], # List of wave vectors that define a path\n", + " [1, 0, 0],\n", + " [0, 1, 0],\n", + " [1/2, 0, 0],\n", + " [0, 1, 0],\n", + " [0, 0, 0]]\n", + "density = 40\n", + "path, xticks = reciprocal_space_path(cryst, points, density);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Again using `intensities_interpolated`, we can evaluate the (interpolated) intensity\n", + "at each point on the `path`.\n", + "Since scattering intensities are only available at a certain discrete $(Q,\\omega)$\n", + "points, the intensity on the path can be calculated by interpolating between these\n", + "discrete points:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "is_interpolated = intensities_interpolated(sc, path, new_formula;\n", + " interpolation = :linear, # Interpolate between available wave vectors\n", + ");\n", + "# Add artificial broadening\n", + "is_interpolated_broadened = broaden_energy(sc, is, (ω, ω₀)->lorentzian(ω-ω₀, 0.05));" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The second approach to handle the discreteness of the data is to bin the intensity\n", + "at the discrete points into the bins of a histogram.\n", + "First, the five sub-histograms are set up using `reciprocal_space_path_bins` in\n", + "analogy to `reciprocal_space_path`." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "cut_width = 0.3\n", + "density = 15\n", + "paramsList, markers, ranges = reciprocal_space_path_bins(sc,points,density,cut_width);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Then, the intensity data is computed using `intensities_binned` for each sub-histogram:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "total_bins = ranges[end][end]\n", + "energy_bins = paramsList[1].numbins[4]\n", + "is_binned = zeros(Float64,total_bins,energy_bins)\n", + "integrated_kernel = integrated_lorentzian(0.05) # Lorentzian broadening\n", + "for k in eachindex(paramsList)\n", + " bin_data, counts = intensities_binned(sc,paramsList[k], new_formula;\n", + " integrated_kernel = integrated_kernel\n", + " )\n", + " is_binned[ranges[k],:] = bin_data[:,1,1,:] ./ counts[:,1,1,:]\n", + "end" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The graph produced by interpolating (top) is similar to the one produced by binning (bottom):" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "fig = Figure()\n", + "ax_top = Axis(fig[1,1],ylabel = \"meV\",xticklabelrotation=π/8,xticklabelsize=12;xticks)\n", + "ax_bottom = Axis(fig[2,1],ylabel = \"meV\",xticks = (markers, string.(points)),xticklabelrotation=π/8,xticklabelsize=12)\n", + "\n", + "heatmap!(ax_top,1:size(is_interpolated,1), ωs, is_interpolated;\n", + " colorrange=(0.0,0.07),\n", + ")\n", + "\n", + "heatmap!(ax_bottom,1:size(is_binned,1), ωs, is_binned;\n", + " colorrange=(0.0,0.05),\n", + ")\n", + "\n", + "fig" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Note that we have clipped the colors in order to make the higher-energy\n", + "excitations more visible." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "# Unconventional R.L.U. Systems and Constant Energy Cuts" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Often it is useful to plot cuts across multiple wave vectors but at a single\n", + "energy. We'll pick an energy," + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "ωidx = 60\n", + "target_ω = ωs[ωidx]\n", + "println(\"target_ω = $(target_ω)\")#hide" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "and take a constant-energy cut at that energy.\n", + "The most straightforward way is to make a plot whose axes are aligned with\n", + "the conventional reciprocal lattice of the crystal.\n", + "This is accomplished using `unit_resolution_binning_parameters`:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "params = unit_resolution_binning_parameters(sc)\n", + "params.binstart[1:2] .= -1 # Expand plot range slightly\n", + "\n", + "# Set energy integration range\n", + "omega_width = 0.3\n", + "params.binstart[4] = target_ω - (omega_width/2)\n", + "params.binend[4] = target_ω # `binend` should be inside (e.g. at the center) of the range\n", + "params.binwidth[4] = omega_width\n", + "\n", + "integrate_axes!(params, axes = 3) # Integrate out z direction entirely\n", + "params#hide" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "In each of the following plots, black dashed lines represent (direct) lattice vectors.\n", + "Since these plots are in reciprocal space, direct lattice vectors are represented\n", + "as covectors (i.e. coordinate grids) instead of as arrows." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "is, counts = intensities_binned(sc,params,new_formula)\n", + "\n", + "fig = Figure()\n", + "ax = Axis(fig[1,1];\n", + " title=\"Δω=0.3 meV (Binned)\", aspect=true,\n", + " xlabel = \"[H, 0, 0]\",\n", + " ylabel = \"[0, K, 0]\"\n", + ")\n", + "bcs = axes_bincenters(params)\n", + "hm = heatmap!(ax,bcs[1],bcs[2],is[:,:,1,1] ./ counts[:,:,1,1])\n", + "function add_lines!(ax,params)#hide\n", + " bes = Sunny.axes_binedges(params)#hide\n", + " hrange = range(-2,2,length=17)#hide\n", + " linesegments!(ax,[(Point2f(params.covectors[1,1:3] ⋅ [h,-10,0],params.covectors[2,1:3] ⋅ [h,-10,0]),Point2f(params.covectors[1,1:3] ⋅ [h,10,0],params.covectors[2,1:3] ⋅ [h,10,0])) for h = hrange],linestyle=:dash,color=:black)#hide\n", + " krange = range(-2,2,length=17)#hide\n", + " linesegments!(ax,[(Point2f(params.covectors[1,1:3] ⋅ [-10,k,0],params.covectors[2,1:3] ⋅ [-10,k,0]),Point2f(params.covectors[1,1:3] ⋅ [10,k,0],params.covectors[2,1:3] ⋅ [10,k,0])) for k = krange],linestyle=:dash,color=:black)#hide\n", + " xlims!(ax,bes[1][1],bes[1][end])#hide\n", + " ylims!(ax,bes[2][1],bes[2][end])#hide\n", + "end#hide\n", + "add_lines!(ax,params)\n", + "Colorbar(fig[1,2], hm);\n", + "fig" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "In the above plot, the dashed-line (direct) lattice vectors are clearly orthogonal.\n", + "However, we know that in real space, the lattice vectors $a$ and $b$ are *not* orthogonal, but rather\n", + "point along the edges of a hexagon (see lower left corner):\n", + "\n", + "\n", + "

\n", + "\n", + "\n", + "Thus, plotting the direct lattice vectors as orthogonal (even in reciprocal space) is somewhat misleading.\n", + "Worse yet, the `[H,0,0]` by `[0,K,0]` plot apparently loses the 6-fold symmetry of the crystal!\n", + "Lastly, if one works out the components of the real-space metric with respect to the axes of the plot,\n", + "one finds that there are non-zero off-diagonal entries," + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "latvecs = sys.crystal.latvecs\n", + "metric = latvecs' * I(3) * latvecs" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "so real-space rotations and angles map into reciprocal space rotations angles in a complicated way.\n", + "\n", + "To resolve these important issues, we want to use axes which are orthogonal (i.e. they diagonalize\n", + "the metric and solve all of the problems just mentioned). The canonical choice is to use\n", + "the combination $\\frac{1}{2}a + b$ of lattice vectors (equiv. $a^* - \\frac{1}{2}b^*$), which is orthogonal to $a$:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "(latvecs * [1/2,1,0]) ⋅ (latvecs * [1,0,0]) == 0" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "This new vector $\\frac{1}{2}a+b$ is visibly orthogonal to $a$ in real space:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "f = Figure()#hide\n", + "ax = Axis(f[1,1])#hide\n", + "arrows!(ax,[Point2f(0,0),Point2f(latvecs[1:2,1] ./ 2)],[Vec2f(latvecs[1:2,1] ./ 2), Vec2f(latvecs[1:2,2])],arrowcolor = :blue,arrowsize = 30.,linewidth = 5.,linecolor = :blue)#hide\n", + "arrows!(ax,[Point2f(0,0)],[Vec2f(latvecs[1:2,:] * [1/2,1,0])],arrowcolor = :red,arrowsize = 30.,linewidth = 5.,linecolor = :red, linestyle = :dash)#hide\n", + "scatter!(ax,[Point2f(latvecs[1:2,:] * [a,b,0]) for a in -1:1, b in -1:1][:],color = :black)#hide\n", + "annotations!(ax,[\"0\",\"0+b\",\"0+a\", \"a/2\", \"b\"],[Point2f(0,-0.3),Point2f(latvecs[1:2,2]) .- Vec2f(0,0.3),Point2f(latvecs[1:2,1]) .- Vec2f(0,0.3),Point2f(latvecs[1:2,1] ./ 4) .- Vec2f(0,0.3),Point2f(latvecs[1:2,1] ./ 2) .+ Vec2f(latvecs[1:2,2] ./ 2) .+ Vec2f(0.3,0.3)],color=[:black,:black,:black,:blue,:blue])#hide\n", + "f#hide" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "To use \"projection onto the new vector\" as a histogram axis, only a single change is needed to the binning parameters.\n", + "The second covector (previously $b$) must be swapped out for $\\frac{1}{2}a + b$ (recall that reciprocal space covectors, such\n", + "as those used in `BinningParameters` correspond to direct space vectors)." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "params.covectors[2,1:3] = [1/2,1,0] # [1/2,1,0] times [a;b;c] is (a/2 + b)\n", + "params#hide" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The second axis of the histogram now agrees with what is conventionally labelled as `[H,-H/2,0]`." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "!!! warning \"Length of the new vector\"\n", + "\n", + " Note that, although $\\frac{1}{2}a+b$ is orthogonal to $a$, it is not the same length as $a$.\n", + " Instead, it is `sqrt(3/4)` times as long. Note the unsymmetrical axes labels in the plots that\n", + " follow as a direct result of this!" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "# Zoom out horizontal axis\n", + "params.binstart[1], params.binend[1] = -2, 2\n", + "\n", + "# Adjust vertical axis bounds to account for\n", + "# length of a/2 + b\n", + "params.binstart[2], params.binend[2] = -2 * sqrt(3/4), 2 * sqrt(3/4)\n", + "\n", + "# Re-compute in the new coordinate system\n", + "is, counts = intensities_binned(sc,params,new_formula)\n", + "\n", + "fig = Figure(; resolution=(1200,500))#hide\n", + "ax_right = Axis(fig[1,3];#hide\n", + " title=\"ω≈$(round(target_ω, digits=2)) meV with Δω=0.3 meV (Binned)\", aspect=true,#hide\n", + " xlabel = \"[H, -1/2H, 0]\"#hide\n", + ")#hide\n", + "bcs = axes_bincenters(params)#hide\n", + "hm_right = heatmap!(ax_right,bcs[1],bcs[2],is[:,:,1,1] ./ counts[:,:,1,1])#hide\n", + "add_lines!(ax_right,params)\n", + "Colorbar(fig[1,4], hm_right);#hide" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "For comparison purposes, we will make the same plot using\n", + "`intensities_interpolated` to emulate zero-width bins.\n", + "This time, it's more convenient to think in terms of reciprocal vectors $a^*$ and $b^*$.\n", + "Now, our coordinate transformation consists of\n", + "establishing a new, orthogonal basis\n", + "to specify our wave vectors: $a^* - \\frac{1}{2}b^*$, $b^*$ and $c^*$.\n", + "Writing this in matrix form allows us to sample a rectilinear grid of wave vectors in this frame.\n", + "Finally, we'll convert these back into the original RLU system for input into Sunny." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "# New basis matrix\n", + "A = [1 0 0\n", + " -1/2 1 0\n", + " 0 0 1]\n", + "\n", + "# Define our grid of wave vectors\n", + "npoints = 60\n", + "as = range(-2, 2, npoints)\n", + "bs = range(-3/√3, 3/√3, npoints)\n", + "qs_ortho = [[a, b, 0] for a in as, b in bs]\n", + "\n", + "# Convert to original RLU system for input to Sunny\n", + "qs = [A * q for q in qs_ortho]\n", + "\n", + "# Use interpolation to get intensities\n", + "is = intensities_interpolated(sc, qs, new_formula; interpolation=:linear)\n", + "\n", + "ax_left = Axis(fig[1,2];#hide\n", + " title=\"ω≈$(round(ωs[ωidx], digits=2)) meV (Interpolated)\", aspect=true,#hide\n", + " xlabel = \"[H, -1/2H, 0]\", ylabel = \"[0, K, 0]\"#hide\n", + ")#hide\n", + "hm_left = heatmap!(ax_left, as, bs, is[:,:,ωidx])#hide\n", + "add_lines!(ax_left,params)\n", + "Colorbar(fig[1,1], hm_left);#hide\n", + "fig" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Now, not only are the dashed-line lattice vectors no longer misleadingly orthogonal,\n", + "but the six-fold symmetry has been restored as well!\n", + "Further, the metric has been diagonalized:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "metric = (latvecs * inv(A'))' * I(3) * (latvecs * inv(A'))" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Finally, we note that instantaneous structure factor data, $𝒮(𝐪)$, can be\n", + "obtained from a dynamic structure factor with\n", + "`instant_intensities_interpolated`. Here we'll reuse the grid of wave\n", + "vectors we generated above." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "is_static = instant_intensities_interpolated(sc, qs, new_formula; interpolation = :linear)\n", + "\n", + "hm = heatmap(as, bs, is_static;\n", + " axis=(\n", + " title=\"Instantaneous Structure Factor\",\n", + " xlabel = \"[H, -1/2H, 0]\",\n", + " ylabel = \"[0, K, 0]\",\n", + " aspect=true\n", + " )\n", + ")\n", + "Colorbar(hm.figure[1,2], hm.plot)\n", + "hm" + ], + "metadata": {}, + "execution_count": null + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.9.3" + }, + "kernelspec": { + "name": "julia-1.9", + "display_name": "Julia 1.9.3", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/dev/assets/notebooks/fei2_tutorial.ipynb b/dev/assets/notebooks/fei2_tutorial.ipynb new file mode 100644 index 000000000..8b4b08ee4 --- /dev/null +++ b/dev/assets/notebooks/fei2_tutorial.ipynb @@ -0,0 +1,766 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Case Study: FeI$_{2}$\n", + "\n", + "FeI$_2$ is an effective spin-1 material with strong single-ion anisotropy.\n", + "Quadrupolar fluctuations give rise to a single-ion bound state that cannot be\n", + "described by a dipole-only model. This tutorial illustrates how to use the\n", + "linear spin wave theory of SU(3) coherent states (i.e. 2-flavor bosons) to\n", + "model the magnetic behavior in FeI$_2$. The original study was performed in\n", + "[Bai et al., Nature Physics 17, 467–472\n", + "(2021)](https://doi.org/10.1038/s41567-020-01110-1).\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "The Fe atoms are arranged in stacked triangular layers. The effective spin\n", + "interactions include various anisotropic exchange interactions, and a strong\n", + "single-ion anisotropy:\n", + "\n", + "$$\n", + "\\mathcal{H}=\\sum_{(i,j)} J^{\\alpha\\beta}_{ij} S^{\\alpha}_i S^{\\beta}_j - D\\sum_i \\left(S^z\\right)^2\n", + "$$\n", + "\n", + "We will formulate this Hamiltonian in Sunny and then calculate its dynamic\n", + "structure factor." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Get Julia and Sunny\n", + "\n", + "Sunny is implemented in Julia. This is a relatively new programming language\n", + "that allows for interactive development (like Python or Matlab) while also\n", + "providing high numerical efficiency (like C++ or Fortran). New Julia users may\n", + "wish to take a look at our [Getting Started with\n", + "Julia](https://github.com/SunnySuite/Sunny.jl/wiki/Getting-started-with-Julia)\n", + "guide. Sunny requires Julia 1.9 or later.\n", + "\n", + "From the Julia prompt, load `Sunny`. For plotting, one can choose either\n", + "`GLMakie` (a pop-up window) or `WGLMakie` (inline plots for a Jupyter notebook\n", + "or VSCode)." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Sunny, WGLMakie" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "If these packages are not yet installed, Julia should offer to install them\n", + "using its built-in package management system. If old versions are installed,\n", + "you may need to update them to run this tutorial." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Crystals\n", + "\n", + "A `Crystal` describes the crystallographic unit cell and will usually\n", + "be loaded from a `.cif` file. Here, we instead build a crystal by listing all\n", + "atoms and their types." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "a = b = 4.05012 # Lattice constants for triangular lattice\n", + "c = 6.75214 # Spacing in the z-direction\n", + "\n", + "latvecs = lattice_vectors(a, b, c, 90, 90, 120) # A 3x3 matrix of lattice vectors that\n", + " # define the conventional unit cell\n", + "positions = [[0, 0, 0], [1/3, 2/3, 1/4], [2/3, 1/3, 3/4]] # Positions of atoms in fractions\n", + " # of lattice vectors\n", + "types = [\"Fe\", \"I\", \"I\"]\n", + "FeI2 = Crystal(latvecs, positions; types)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Observe that Sunny inferred the space group, 'P -3 m 1' (164) and labeled the\n", + "atoms according to their point group symmetries." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "An interactive viewer of the crystal and its bonds is available for Jupyter notebooks." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "view_crystal(FeI2, 8.0)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Only the Fe atoms are magnetic, so we discard the I ions using\n", + "`subcrystal`." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "cryst = subcrystal(FeI2, \"Fe\")" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Importantly, `cryst` retains the spacegroup symmetry of the full FeI$_2$\n", + "crystal. This information will be used, for example, to propagate exchange\n", + "interactions between symmetry-equivalent bonds." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Symmetry analysis\n", + "\n", + "The command `print_symmetry_table` provides a list of all the\n", + "symmetry-allowed interactions up to a cutoff distance." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "print_symmetry_table(cryst, 8.0)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The allowed $g$-tensor is expressed as a 3×3 matrix in the free coefficients\n", + "`A`, `B`, ... The allowed single-ion anisotropy is expressed as a linear\n", + "combination of Stevens operators. The latter correspond to polynomials of the\n", + "spin operators, as we will describe below.\n", + "\n", + "The allowed exchange interactions are given as a 3×3 matrix for representative\n", + "bonds. The notation `Bond(i, j, n)` indicates a bond between atom indices `i`\n", + "and `j`, with cell offset `n`. In the general case, it will be necessary to\n", + "associate atom indices with their positions in the unit cell; these can be\n", + "viewed with `display(cryst)`. Note that the order of the pair $(i, j)$ is\n", + "significant if the exchange tensor contains antisymmetric\n", + "Dzyaloshinskii–Moriya (DM) interactions.\n", + "\n", + "In the case of FeI$_2$, `Bond(1, 1, [1,0,0])` is one of the 6 nearest-neighbor\n", + "Fe-Fe bonds on a triangular lattice layer, and `Bond(1, 1, [0,0,1])` is an\n", + "Fe-Fe bond between layers." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Building a spin System" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "In constructing a spin `System`, we must provide several additional\n", + "details about the spins." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "sys = System(cryst, (4,4,4), [SpinInfo(1, S=1, g=2)], :SUN, seed=2)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "This system includes $4×4×4$ unit cells, i.e. 64 Fe atoms, each with spin $S=1$\n", + "and a $g$-factor of 2. Quantum mechanically, spin $S=1$ involves a\n", + "superposition of $2S+1=3$ distinct angular momentum states. In `:SUN` mode,\n", + "this superposition will be modeled explicitly using the formalism of SU(3)\n", + "coherent states, which captures both dipolar and quadrupolar fluctuations. For\n", + "the more traditional dipole dynamics, use `:dipole` mode instead." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Next we will use `set_exchange!` to assign interaction to bonds. Sunny\n", + "will automatically propagate each interaction to all symmetry-equivalent bonds\n", + "in the unit cell. The FeI$_2$ interactions below follow [Bai et\n", + "al](https://doi.org/10.1038/s41567-020-01110-1)." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "J1pm = -0.236\n", + "J1pmpm = -0.161\n", + "J1zpm = -0.261\n", + "J2pm = 0.026\n", + "J3pm = 0.166\n", + "J′0pm = 0.037\n", + "J′1pm = 0.013\n", + "J′2apm = 0.068\n", + "\n", + "J1zz = -0.236\n", + "J2zz = 0.113\n", + "J3zz = 0.211\n", + "J′0zz = -0.036\n", + "J′1zz = 0.051\n", + "J′2azz = 0.073\n", + "\n", + "J1xx = J1pm + J1pmpm\n", + "J1yy = J1pm - J1pmpm\n", + "J1yz = J1zpm\n", + "\n", + "set_exchange!(sys, [J1xx 0.0 0.0;\n", + " 0.0 J1yy J1yz;\n", + " 0.0 J1yz J1zz], Bond(1,1,[1,0,0]))\n", + "set_exchange!(sys, [J2pm 0.0 0.0;\n", + " 0.0 J2pm 0.0;\n", + " 0.0 0.0 J2zz], Bond(1,1,[1,2,0]))\n", + "set_exchange!(sys, [J3pm 0.0 0.0;\n", + " 0.0 J3pm 0.0;\n", + " 0.0 0.0 J3zz], Bond(1,1,[2,0,0]))\n", + "set_exchange!(sys, [J′0pm 0.0 0.0;\n", + " 0.0 J′0pm 0.0;\n", + " 0.0 0.0 J′0zz], Bond(1,1,[0,0,1]))\n", + "set_exchange!(sys, [J′1pm 0.0 0.0;\n", + " 0.0 J′1pm 0.0;\n", + " 0.0 0.0 J′1zz], Bond(1,1,[1,0,1]))\n", + "set_exchange!(sys, [J′2apm 0.0 0.0;\n", + " 0.0 J′2apm 0.0;\n", + " 0.0 0.0 J′2azz], Bond(1,1,[1,2,1]))" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The function `set_onsite_coupling!` assigns a single-ion anisotropy\n", + "operator. It can be constructed, e.g., from the matrices given by\n", + "`spin_operators` or `stevens_operators`. Here we construct an\n", + "easy-axis anisotropy along the direction $\\hat{z}$." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "D = 2.165\n", + "S = spin_operators(sys, 1)\n", + "set_onsite_coupling!(sys, -D*S[3]^2, 1)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Any anisotropy operator can be converted to a linear combination of Stevens\n", + "operators with `print_stevens_expansion`." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "# Calculating structure factor intensities" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "In the remainder of this tutorial, we will examine Sunny's tools for\n", + "calculating the dynamical structure factor using a [multi-boson\n", + "generalization](https://arxiv.org/abs/1307.7731) of linear spin wave theory\n", + "(LSWT). This theory describes non-interacting quasi-particle excitations that\n", + "hybridize dipolar and quadrupolar modes." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Finding the ground state" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Begin with a random configuration and use `minimize_energy!` to find a\n", + "configuration of the SU(3) coherent states (i.e. spin dipoles and quadrupoles)\n", + "that locally minimizes energy." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "randomize_spins!(sys)\n", + "minimize_energy!(sys);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The expected ground state for FeI$_2$ is an antiferrogmanetic striped phase\n", + "with a period of four spins (two up, two down). Visualizing the result of\n", + "optimization, however, may indicate the system got stuck in a local minimum\n", + "with defects." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "plot_spins(sys)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "A better understanding of the magnetic ordering can often be obtained by\n", + "moving to Fourier space. The 'instant' structure factor $𝒮(𝐪)$ is an\n", + "experimental observable. To investigate $𝒮(𝐪)$ as true 3D data, Sunny\n", + "provides `instant_correlations` and related functions. Here, however,\n", + "we will use the lighter weight function `print_wrapped_intensities` to\n", + "get a quick understanding of the periodicities present in the spin\n", + "configuration." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "print_wrapped_intensities(sys)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The precise output may vary with Sunny version due to, e.g., different\n", + "floating point roundoff effects. Very likely, however, the result will be\n", + "approximately consistent with the known zero-field energy-minimizing magnetic\n", + "structure of FeI$_2$, which is single-$Q$. Mathematically, spontaneous\n", + "symmetry breaking should select one of $±Q = [0, -1/4, 1/4]$, $[1/4, 0, 1/4]$,\n", + "or $[-1/4,1/4,1/4]$, associated with the three-fold rotational symmetry of the\n", + "crystal spacegroup. In practice, however, one will frequently encounter\n", + "competing \"domains\" associated with the three possible orientations of the\n", + "ground state." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "If the desired ground state is already known, as with FeI$_2$, it could be\n", + "entered by hand using `set_dipole!`. Alternatively, in the case of\n", + "FeI$_2$, we could repeatedly employ the above randomization and minimization\n", + "procedure until a defect-free configuration is found. Some systems will have\n", + "more complicated ground states, which can be much more challenging to find.\n", + "For this, Sunny provides experimental support for powerful simulated annealing\n", + "via [parallel tempering](https://en.wikipedia.org/wiki/Parallel_tempering),\n", + "but that is outside the scope of this tutorial." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Here, let's break the three-fold symmetry of FeI$_2$ by hand. Given one or\n", + "more desired $Q$ modes, Sunny can suggest a magnetic supercell with\n", + "appropriate periodicity. Let's arbitrarily select one of the three possible\n", + "ordering wavevectors, $Q = [0, -1/4, 1/4]$. Sunny suggest a corresponding\n", + "magnetic supercell in units of the crystal lattice vectors." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "suggest_magnetic_supercell([[0, -1/4, 1/4]], sys.latsize)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The function `reshape_supercell` allows an arbitrary reshaping of the\n", + "system's supercell. We select the supercell appropriate to the broken-symmetry\n", + "ground-state, which makes optimization much easier." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "sys_min = reshape_supercell(sys, [1 0 0; 0 1 -2; 0 1 2])\n", + "randomize_spins!(sys_min)\n", + "minimize_energy!(sys_min)\n", + "plot_spins(sys_min; ghost_radius=3)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "## Linear spin wave theory\n", + "\n", + "Now that we have found the ground state for a magnetic supercell, we can\n", + "immediately proceed to perform zero-temperature calculations using linear spin\n", + "wave theory. We begin by instantiating a `SpinWaveTheory` type using the\n", + "supercell." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "swt = SpinWaveTheory(sys_min)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Select a sequence of wavevectors that will define a piecewise linear\n", + "interpolation in reciprocal lattice units (RLU)." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "q_points = [[0,0,0], [1,0,0], [0,1,0], [1/2,0,0], [0,1,0], [0,0,0]];" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The function `reciprocal_space_path` will linearly sample a `path`\n", + "between the provided $q$-points with a given `density`. The `xticks` return\n", + "value provides labels for use in plotting." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "density = 50\n", + "path, xticks = reciprocal_space_path(cryst, q_points, density);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The `dispersion` function defines the quasiparticle excitation\n", + "energies $ω_i(𝐪)$ for each point $𝐪$ along the reciprocal space path." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "disp = dispersion(swt, path);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "In addition to the band energies $ω_i(𝐪)$, Sunny can calculate the inelastic\n", + "neutron scattering intensity $I_i(𝐪)$ for each band $i$ according to an\n", + "`intensity_formula`. We choose to apply a polarization correction\n", + "$(1 - 𝐪⊗𝐪)$ by setting the mode argument to `:perp`. Selecting\n", + "`delta_function_kernel` specifies that we want the energy and intensity of\n", + "each band individually." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "formula = intensity_formula(swt, :perp; kernel=delta_function_kernel)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The function `intensities_bands` uses linear spin wave theory to\n", + "calculate both the dispersion and intensity data for the provided path." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "disp, intensity = intensities_bands(swt, path, formula);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "These can be plotted in GLMakie." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "fig = Figure()\n", + "ax = Axis(fig[1,1]; xlabel=\"𝐪\", ylabel=\"Energy (meV)\", xticks, xticklabelrotation=π/6)\n", + "ylims!(ax, 0.0, 7.5)\n", + "xlims!(ax, 1, size(disp, 1))\n", + "colorrange = extrema(intensity)\n", + "for i in axes(disp)[2]\n", + " lines!(ax, 1:length(disp[:,i]), disp[:,i]; color=intensity[:,i], colorrange)\n", + "end\n", + "fig" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "To make comparisons with inelastic neutron scattering (INS) data, it is\n", + "helpful to employ an empirical broadening kernel, e.g., a\n", + "`lorentzian`." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "γ = 0.15 # width in meV\n", + "broadened_formula = intensity_formula(swt, :perp; kernel=lorentzian(γ))" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The `intensities_broadened` function requires an energy range in\n", + "addition to the $𝐪$-space path." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "energies = collect(0:0.01:10) # 0 < ω < 10 (meV).\n", + "is1 = intensities_broadened(swt, path, energies, broadened_formula);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "A real FeI$_2$ sample will exhibit competing magnetic domains associated with\n", + "spontaneous symmetry breaking of the 6-fold rotational symmetry of the\n", + "triangular lattice. Note that the wavevectors $𝐪$ and $-𝐪$ are equivalent in\n", + "the structure factor, which leaves three distinct domain orientations, which\n", + "are related by 120° rotations about the $ẑ$-axis. Rather than rotating the\n", + "spin configuration directly, on can rotate the $𝐪$-space path. Below, we use\n", + "`rotation_in_rlu` to average the intensities over all three possible\n", + "orientations." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "R = rotation_in_rlu(cryst, [0, 0, 1], 2π/3)\n", + "is2 = intensities_broadened(swt, [R*q for q in path], energies, broadened_formula)\n", + "is3 = intensities_broadened(swt, [R*R*q for q in path], energies, broadened_formula)\n", + "is_averaged = (is1 + is2 + is3) / 3\n", + "\n", + "fig = Figure()\n", + "ax = Axis(fig[1,1]; xlabel=\"(H,0,0)\", ylabel=\"Energy (meV)\", xticks, xticklabelrotation=π/6)\n", + "heatmap!(ax, 1:size(is_averaged, 1), energies, is_averaged)\n", + "fig" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "This result can be directly compared to experimental neutron scattering data\n", + "from [Bai et al.](https://doi.org/10.1038/s41567-020-01110-1)\n", + "\n", + "\n", + "\n", + "\n", + "(The publication figure accidentally used a non-standard coordinate system to\n", + "label the wave vectors.)\n", + "\n", + "To get this agreement, the use of SU(3) coherent states is essential. In other\n", + "words, we needed a theory of multi-flavored bosons. The lower band has large\n", + "quadrupolar character, and arises from the strong easy-axis anisotropy of\n", + "FeI$_2$. By setting `mode = :SUN`, the calculation captures this coupled\n", + "dipole-quadrupole dynamics.\n", + "\n", + "An interesting exercise is to repeat the same study, but using `mode =\n", + ":dipole` instead of `:SUN`. That alternative choice would constrain the\n", + "coherent state dynamics to the space of dipoles only." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "The full dynamical spin structure factor (DSSF) can be retrieved as a $3×3$\n", + "matrix with the `dssf` function, for a given path of $𝐪$-vectors." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "disp, is = dssf(swt, path);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The first output `disp` is identical to that obtained from `dispersion`. The\n", + "second output `is` contains a list of $3×3$ matrix of intensities. For\n", + "example, `is[q,n][2,3]` yields the $(ŷ,ẑ)$ component of the structure factor\n", + "intensity for `nth` mode at the `q`th wavevector in the `path`." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## What's next?\n", + "\n", + "The multi-boson linear spin wave theory, applied above, can be understood as\n", + "the quantization of a certain generalization of the Landau-Lifshitz spin\n", + "dynamics. Rather than dipoles, this dynamics takes places on the space of\n", + "[SU(_N_) coherent states](https://arxiv.org/abs/2106.14125).\n", + "\n", + "The full SU(_N_) coherent state dynamics, with appropriate quantum correction\n", + "factors, can be useful to model finite temperature scattering data. In\n", + "particular, it captures certain anharmonic effects due to thermal\n", + "fluctuations. This is the subject of our [Structure Factors with Classical\n", + "Dynamics](@ref) tutorial.\n", + "\n", + "The classical dynamics is also a good starting point to study non-equilibrium\n", + "phenomena. Empirical noise and damping terms can be used to model [coupling to\n", + "a thermal bath](https://arxiv.org/abs/2209.01265). This yields a Langevin\n", + "dynamics of SU(_N_) coherent states. Our CP$^2$ Skyrmion Quench\n", + "tutorial shows how this dynamics gives rise to the formation of novel\n", + "topological defects in a temperature quench.\n", + "\n", + "Relative to LSWT calculations, it can take much more time to estimate\n", + "$\\mathcal{S}(𝐪,ω)$ intensities using classical dynamics simulation. See the\n", + "[SunnyTutorials\n", + "notebooks](https://nbviewer.org/github/SunnySuite/SunnyTutorials/tree/main/Tutorials/)\n", + "for examples of \"production-scale\" simulations." + ], + "metadata": {} + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.9.3" + }, + "kernelspec": { + "name": "julia-1.9", + "display_name": "Julia 1.9.3", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/dev/assets/notebooks/ising2d.ipynb b/dev/assets/notebooks/ising2d.ipynb new file mode 100644 index 000000000..c3ba5f30f --- /dev/null +++ b/dev/assets/notebooks/ising2d.ipynb @@ -0,0 +1,179 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Classical Ising model\n", + "\n", + "This tutorial illustrates simulation of the classical 2D Ising model." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Sunny, Plots" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Sunny expects a 3D `Crystal` unit cell. To model a square lattice, we\n", + "create an orthogonal unit cell where the $z$-spacing is distinct from the $x$\n", + "and $y$ spacing." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "a = 1\n", + "latvecs = lattice_vectors(a,a,10a,90,90,90)\n", + "crystal = Crystal(latvecs, [[0,0,0]])" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Create a `System` of spins with linear size `L` in the $x$ and $y$\n", + "directions, and only one layer in the $z$ direction. The option `:dipole`\n", + "means that the system will store Heisenberg spins, as opposed to SU($N$)\n", + "coherent states. Polarize the initial spin configuration using\n", + "`polarize_spins!`. Following the Ising convention, we will restrict\n", + "these spins to the $z$-axis and give them magnitude $S=1$.\n", + "\n", + "By default, Sunny uses physical units, e.g. magnetic field in tesla. Here we\n", + "specify an alternative `Units` system, so that the Zeeman coupling\n", + "between the spin dipole $𝐬$ and an external field $𝐁$ has the dimensionless\n", + "form $-𝐁⋅𝐬$." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "L = 128\n", + "sys = System(crystal, (L,L,1), [SpinInfo(1, S=1, g=1)], :dipole, units=Units.theory, seed=0)\n", + "polarize_spins!(sys, (0,0,1))" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Use `set_exchange!` to include a ferromagnetic Heisenberg interaction\n", + "along nearest-neighbor bonds. The `Bond` below connects two spins\n", + "displaced by one lattice constant in the $x$-direction. This interaction will\n", + "be propagated to all nearest-neighbors bonds in the system, consistent with\n", + "the symmetries of the square lattice." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "set_exchange!(sys, -1.0, Bond(1,1,(1,0,0)))" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "If an external field is desired, it can be set using\n", + "`set_external_field!`." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "B = 0\n", + "set_external_field!(sys, (0,0,B))" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The critical temperature for the Ising model is known analytically." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "Tc = 2/log(1+√2)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Use a `LocalSampler` to perform `nsweeps` Monte Carlo sweeps. A sweep\n", + "consists of, on average, one trial update per spin in the system. Each\n", + "proposed update is accepted or rejected according to the Metropolis acceptance\n", + "probability. As its name suggests, the `propose_flip` function will\n", + "only propose pure spin flips, $𝐬 \\rightarrow -𝐬$." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "nsweeps = 4000\n", + "sampler = LocalSampler(kT=Tc, propose=propose_flip)\n", + "for i in 1:nsweeps\n", + " step!(sys, sampler)\n", + "end" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Plot the Ising spins by extracting the $z$-component of the dipoles" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "heatmap(reshape([s.z for s in sys.dipoles], (L,L)))" + ], + "metadata": {}, + "execution_count": null + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.9.3" + }, + "kernelspec": { + "name": "julia-1.9", + "display_name": "Julia 1.9.3", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/dev/assets/notebooks/one_dim_chain.ipynb b/dev/assets/notebooks/one_dim_chain.ipynb new file mode 100644 index 000000000..c1b94024a --- /dev/null +++ b/dev/assets/notebooks/one_dim_chain.ipynb @@ -0,0 +1,602 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Fitting model parameters in a 1D spin-1 ferromagnetic chain" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Sunny, LinearAlgebra, WGLMakie, Optim" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "In this Example, we consider a 1D chain of spin-1 sites.\n", + "The sites along the chain interact via a ferromagnetic nearest-neighbor\n", + "interaction $J\\sum_{\\langle i,j\\rangle} \\mathbf{S}_i \\cdot \\mathbf{S}_j$, with $J < 0$.\n", + "By default, the ground state would be ferromagnetic and highly degenerate, since the spins\n", + "can align in any direction.\n", + "An on-site interaction, $D\\sum_i (S^z_i)^2$ breaks this isotropy by making it easier for\n", + "the spins to align in the $\\pm z$ direction than in any other orientation.\n", + "Thus, the entire Hamiltonian is:\n", + "\n", + "$\\mathcal{H} = \\overbrace{J\\sum_{\\langle i,j\\rangle} \\mathbf{S}_i \\cdot \\mathbf{S}_j}^{\\text{Ferromagnetic}}\\;\\;\\;\\;\\;\\; \\overbrace{-D\\sum_i (S^z_i)^2}^{\\text{Easy-axis single-ion anisotropy}}$\n", + "\n", + "The goal of this Example is to illustrate how to determine the parameters $J$ and $D$\n", + "from \"experiment\" data by fitting using Sunny's implementation of Linear Spin Wave Theory.\n", + "In our case, the \"experiment\" data will actually be simulation data produced\n", + "using Landau-Lifschitz dynamics." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Creating simulated \"experiment\" data using Landau-Lifschitz dynamics" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "Our simulated data will use ground truth values $J_0 = -1\\,\\text{meV}$ and $D_0 = 10\\,\\text{meV}$ with a lattice spacing $a = 10$ angstrom." + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "We begin with a 1D chain of spin-1 sites along the $x$ direction." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "# Establish geometry of the unit cell.\n", + "# \"P1\" is required due to the rotational symmetry about the\n", + "# x-axis being broken.\n", + "chain_spacing = 10. # Angstrom\n", + "latvecs = chain_spacing * I(3)\n", + "one_dimensional_chain = Crystal(latvecs,[[0,0,0]],\"P1\")\n", + "\n", + "# Establish geometry of the whole chain.\n", + "chain_length = 16 # Number of atoms\n", + "latsize = (chain_length,1,1) # 1D chain is Nx1x1 lattice\n", + "spin_one_chain = System(one_dimensional_chain, latsize, [SpinInfo(1,S=1,g=2)], :SUN)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Configure the nearest-neighbor interaction:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "# Scalar J indicates J*(Sᵢ⋅Sⱼ)\n", + "J_groundtruth = -1.\n", + "\n", + "# Interaction is with the left and right next neighbor along the chain (x-direction)\n", + "nearest_neighbor_right = Bond(1,1,(1,0,0))\n", + "nearest_neighbor_left = Bond(1,1,(-1,0,0))\n", + "\n", + "set_exchange!(spin_one_chain,J_groundtruth,nearest_neighbor_right)\n", + "set_exchange!(spin_one_chain,J_groundtruth,nearest_neighbor_left)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Configure the symmetry-breaking easy-axis term:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "D_groundtruth = 10.\n", + "Sz = spin_operators(spin_one_chain, 1)[3]\n", + "set_onsite_coupling!(spin_one_chain, -D_groundtruth*Sz^2, 1)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "With the ground-truth hamiltonian in place, we use Sunny's classical dynamics\n", + "to generate ficticious experiment data at temperature `kT = 0.1`." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "Δt = 0.05/D_groundtruth\n", + "λ = 0.1\n", + "kT = 0.1\n", + "langevin = Langevin(Δt; kT, λ);\n", + "\n", + "function viz_chain(sys;kwargs...)#hide\n", + " ##ups = map(x -> abs2(x[1]), sys.coherents)[:];#hide\n", + " ##zs = map(x -> abs2(x[2]), sys.coherents)[:];#hide\n", + " ##downs = map(x -> abs2(x[3]), sys.coherents)[:];#hide\n", + "###hide\n", + " ##f = Figure()#hide\n", + " ##ax = LScene(f[1,1];show_axis = false)#hide\n", + " ##_ = Makie.cam3d!(ax.scene, projectiontype=Makie.Orthographic)#hide\n", + "###hide\n", + " ##linewidth = 5.#hide\n", + " ##arrowsize = 10.#hide\n", + " ##lengthscale = 15.#hide\n", + " ##pts = [Point3f(Sunny.global_position(sys,site)) for site in eachsite(sys)][:]#hide\n", + "###hide\n", + " #### Ups#hide\n", + " ##vecs = [Vec3f([0,0,1]) for site in eachsite(sys)][:]#hide\n", + " ##cols = map(x -> (:blue,x), ups)#hide\n", + " ##Makie.arrows!(ax, pts .+ 0.5 .* vecs, vecs;#hide\n", + " ##linecolor = cols, arrowcolor = cols,#hide\n", + " ##lengthscale, arrowsize, linewidth, kwargs...)#hide\n", + "###hide\n", + " #### Downs#hide\n", + " ##vecs = [Vec3f([0,0,-1]) for site in eachsite(sys)][:]#hide\n", + " ##cols = map(x -> (:red,x), downs)#hide\n", + " ##Makie.arrows!(ax, pts .+ 0.5 .* vecs, vecs;#hide\n", + " ##linecolor = cols, arrowcolor = cols,#hide\n", + " ##lengthscale, arrowsize, linewidth, kwargs...)#hide\n", + "###hide\n", + " ##cols = map(x -> (:green,x), zs)#hide\n", + " ##meshscatter!(ax,pts, markersize = 7., color = cols)#hide\n", + " ##f#hide\n", + " Sunny.Plotting.plot_coherents(sys;quantization_axis = [0,0,1],kwargs...)\n", + "end#hide\n", + "randomize_spins!(spin_one_chain)\n", + "viz_chain(spin_one_chain)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "In this plot, the z-axis has been used as the quantization axis for each site,\n", + "with the up/down arrows and circle representing the $\\pm \\hbar$ and $0\\hbar$ spin projections\n", + "onto the z-axis respectively. The opacity of each object represents the probability (absolute value\n", + "squared), and the color represents the phase.\n", + "Since we are using classical dynamics to simulate the data, the phase will be mostly random.\n", + "\n", + "First, we thermalize the chain, and then take several samples\n", + "in order get reasonably good \"experiment\" data." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "nStep = 50_000#hide\n", + "for _ in 1:nStep#hide\n", + " step!(spin_one_chain, langevin)#hide\n", + "end#hide\n", + "# ... thermalize ...\n", + "viz_chain(spin_one_chain)" + ], + "metadata": {}, + "execution_count": null + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "sc = dynamical_correlations(spin_one_chain; Δt, nω = 80, ωmax = 20.);#hide\n", + "\n", + "for _ in 1:10_000#hide\n", + " step!(spin_one_chain, langevin)#hide\n", + "end#hide\n", + "add_sample!(sc, spin_one_chain)#hide\n", + "# ... some time later ...\n", + "viz_chain(spin_one_chain)" + ], + "metadata": {}, + "execution_count": null + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "for _ in 1:10_000#hide\n", + " step!(spin_one_chain, langevin)#hide\n", + "end#hide\n", + "add_sample!(sc, spin_one_chain)#hide\n", + "# ... some time later ...\n", + "viz_chain(spin_one_chain)" + ], + "metadata": {}, + "execution_count": null + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "for _ in 1:20#hide\n", + " for _ in 1:10_000#hide\n", + " step!(spin_one_chain, langevin)#hide\n", + " end#hide\n", + " add_sample!(sc, spin_one_chain)#hide\n", + "end#hide\n", + "# ... some time later ...\n", + "viz_chain(spin_one_chain)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Now that we have collected several samples," + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "sc" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "we are ready to generate the intensity data.\n", + "Since this is supposed to represent an experiment, the intensity data will go in a histogram:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS = unit_resolution_binning_parameters(sc)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Here's what the experiment data looks like:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "formula = intensity_formula(sc,:perp;kT)\n", + "is, counts = intensities_binned(sc,SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS,formula)\n", + "\n", + "SIMULATED_EXPERIMENT_DATA = (is ./ counts)[:,1,1,:]\n", + "\n", + "bcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)\n", + "f = Figure()#hide\n", + "ax = Axis(f[1,1])#hide\n", + "heatmap!(ax,bcs[1],bcs[4],log10.(SIMULATED_EXPERIMENT_DATA))\n", + "f#hide" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "## Fitting to the experiment data" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "To fit this data, we first model the known aspects of the system in Sunny.\n", + "The first steps are the same whether we are simulating a known system or modelling an\n", + "unknown system:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "# Same as before\n", + "chain_spacing = 10. # Angstrom\n", + "latvecs = chain_spacing * I(3)\n", + "one_dimensional_chain = Crystal(latvecs,[[0,0,0]],\"P1\")\n", + "chain_length = 16 # Number of atoms\n", + "latsize = (chain_length,1,1) # 1D chain is Nx1x1 lattice\n", + "spin_one_chain = System(one_dimensional_chain, latsize, [SpinInfo(1,S=1,g=2)], :SUN)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Originally, the next step would have been to configure the hamiltonian by\n", + "specifying the $J$ and $D$ values. However, since these are unknowns,\n", + "we will avoid using them as long as possible, and instead proceed to set up the\n", + "bonds, spin operators, and `Langevin` integrator--none of which require the values:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "Δt = 0.05\n", + "λ = 0.1\n", + "kT = 0. # LSWT uses zero temperature\n", + "langevin = Langevin(Δt; kT, λ);\n", + "\n", + "nearest_neighbor_right = Bond(1,1,(1,0,0))\n", + "nearest_neighbor_left = Bond(1,1,(-1,0,0))\n", + "\n", + "Sz = spin_operators(spin_one_chain, 1)[3]" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "After this setup work is done *once*, we create a function `forward_problem(J_trial,D_trial)`\n", + "which will compute the Linear Spin Wave Theoretic spectrum at the trial values of the\n", + "$J$ and $D$ fitting parameters.\n", + "In other words, the part of the original calculation which depends on the fitting\n", + "parameters gets wrapped into a function:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "function forward_problem(J_trial, D_trial)\n", + "\n", + " # Ensure there is no phase transition (or else LSWT will throw errors)\n", + " J_trial = min(J_trial,0)\n", + " D_trial = max(D_trial,0)\n", + "\n", + " # Uses J_trial\n", + " set_exchange!(spin_one_chain,J_trial,nearest_neighbor_right)\n", + " set_exchange!(spin_one_chain,J_trial,nearest_neighbor_left)\n", + "\n", + " # Uses D_trial\n", + " set_onsite_coupling!(spin_one_chain, -D_trial*Sz^2, 1)\n", + "\n", + " # Perform spin wave calculation, continued below...\n", + "# Note that `forward_problem` refers to variables defined outside\n", + "# of the scope of the function. This allows us to reuse those variables in each call to\n", + "# `forward_problem`, without reconstructing them each time. In general, the more that is known\n", + "# about the system you are modelling, the later in the code `function forward_problem(...)` can be\n", + "# inserted, and the more setup work can be re-used.\n", + "#\n", + "# !!! tip \"`forward_problem` is a closure\"\n", + "# In computer progrogramming parlance, `forward_problem` is said to 'capture' variables such\n", + "# as `spin_one_chain` from the enviroment. Since the result of calling `forward_problem` depends\n", + "# not only on `J_trial` and `D_trial`, but also on `spin_one_chain`, it's no longer a function\n", + "# of only its arguments.\n", + "#\n", + "# Since `forward_problem` is not a closed system, but\n", + "# `forward_problem + (captured variables)` _is_ a closed system, the latter is called\n", + "# the 'closure' of the former.\n", + "# ## Spin wave calculation\n", + "# We can leverage our knowledge that the ground state should be ferromagnetic\n", + "# to simplify the spin wave calculation. Since the ferrommagnetic unit cell is just one site,\n", + "# the simplified system is extremely simple:\n", + " # ... perform spin wave calculation, continued from above.\n", + " one_site_system = reshape_supercell(spin_one_chain,[1 0 0; 0 1 0; 0 0 1])\n", + "# After restricting to a single site, it's best to re-thermalize the system\n", + "# at zero temperature to ensure a good classical ground state for LSWT:\n", + " langevin.kT = 0.\n", + " nStep = 1_000\n", + " for _ in 1:nStep\n", + " step!(one_site_system, langevin)\n", + " end\n", + "# The spin wave intensity data must be placed in a histogram with the same parameters\n", + "# as the experiment data, in order to ensure a good comparision.\n", + "#\n", + "# The kernel and `intensities_bin_centers` used here are temporary, until a better\n", + "# binning method is written.\n", + " swt = SpinWaveTheory(one_site_system)\n", + " formula = intensity_formula(swt,:perp; kernel = lorentzian(0.5))\n", + " params = SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS\n", + " is_swt = Sunny.intensities_bin_centers(swt, params, formula)\n", + "\n", + " return is_swt[:,1,1,:]\n", + "end # end of forward_problem" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "We can see the different possible results from LSWT by plotting the dispersion:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "function plot_forward(J,D)\n", + " is_swt = forward_problem(J,D)\n", + " bcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)\n", + " heatmap(bcs[1],bcs[4],log10.(is_swt))\n", + "end\n", + "\n", + "plot_forward(-1,10)" + ], + "metadata": {}, + "execution_count": null + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "plot_forward(-6,2)" + ], + "metadata": {}, + "execution_count": null + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "plot_forward(-0.01,15)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Now, we can easily define a least-squares loss function comparing the \"experiment\" data to the LSWT result:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "function get_loss(parameters)\n", + " J,D = parameters\n", + " is_swt = forward_problem(J,D)\n", + " sqrt(sum(abs2.(SIMULATED_EXPERIMENT_DATA .- is_swt)))\n", + "end" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Sweeping the parameters over a range containing the true value reveals\n", + "that the loss is minimized near the true parameters (dot).\n", + "The minimum loss is not exactly at the ground truth parameters in this case.\n", + "Gradient descent (finite-differenced) can be used to find the actual minimizer:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "nJ = 30\n", + "nD = 35\n", + "loss_landscape = zeros(Float64,nJ,nD)\n", + "Js = range(-2,0,length=nJ)\n", + "Ds = range(8,12,length=nD)\n", + "for (ij,J) in enumerate(Js)\n", + " for (id,D) in enumerate(Ds)\n", + " loss_landscape[ij,id] = get_loss([J,D])\n", + " end\n", + "end\n", + "\n", + "fig = Figure()\n", + "ax = Axis(fig[1,1],xlabel = \"J [meV]\", ylabel = \"D [meV]\")\n", + "contourf!(ax,Js,Ds,loss_landscape)\n", + "\n", + "x0 = [-2,9.5]\n", + "opt_result = optimize(get_loss,x0,method=GradientDescent(alphaguess=1e-3),store_trace=true,extended_trace = true,time_limit=10.)\n", + "lines!(ax,Point2f.(Optim.x_trace(opt_result)))\n", + "scatter!(ax,-1,10)\n", + "fig" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The fit can be verified by plotting the LSWT band structure over top of the experiment data:" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "bcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)\n", + "f = Figure()#hide\n", + "ax = Axis(f[1,1]; xlabel=\"Q [R.L.U.]\", ylabel=\"Energy (meV)\")#hide\n", + "heatmap!(ax,bcs[1],bcs[4],log10.(SIMULATED_EXPERIMENT_DATA), colormap = :deepsea)\n", + "f#hide\n", + "\n", + "\n", + "J_trial, D_trial = opt_result.minimizer\n", + "set_exchange!(spin_one_chain,J_trial,nearest_neighbor_right)#hide\n", + "set_exchange!(spin_one_chain,J_trial,nearest_neighbor_left)#hide\n", + "\n", + "set_onsite_coupling!(spin_one_chain, -D_trial*Sz^2, 1)#hide\n", + "one_site_system = reshape_supercell(spin_one_chain,[1 0 0; 0 1 0; 0 0 1])#hide\n", + "\n", + "langevin.kT = 0.#hide\n", + "nStep = 1_000#hide\n", + "for _ in 1:nStep#hide\n", + " step!(one_site_system, langevin)#hide\n", + "end#hide\n", + "\n", + "swt = SpinWaveTheory(one_site_system)#hide\n", + "params = SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS\n", + "\n", + "path = [[q,0,0] for q in bcs[1]]\n", + "disp, intensity = intensities_bands(swt, path, intensity_formula(swt,:perp, kernel = delta_function_kernel))\n", + "\n", + "for i in axes(disp)[2]\n", + " lines!(ax, bcs[1], disp[:,i]; color=intensity[:,i], colormap = :turbo,linewidth = 5,colorrange = (0.,1.))\n", + "end\n", + "Colorbar(f[1,2],colormap = :turbo, limits = (0.,1.))\n", + "Colorbar(f[1,3],colormap = :deepsea, limits = (0.,1.))\n", + "f" + ], + "metadata": {}, + "execution_count": null + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.9.3" + }, + "kernelspec": { + "name": "julia-1.9", + "display_name": "Julia 1.9.3", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/dev/assets/notebooks/out_of_equilibrium.ipynb b/dev/assets/notebooks/out_of_equilibrium.ipynb new file mode 100644 index 000000000..e9dde4343 --- /dev/null +++ b/dev/assets/notebooks/out_of_equilibrium.ipynb @@ -0,0 +1,279 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# CP$^2$ Skyrmion Quench\n", + "\n", + "This example demonstrates Sunny's ability to simulate the out-of-equilibrium\n", + "dynamics of generalized spin systems. We will implement the model Hamiltonian\n", + "of [Zhang et al., Nature Communications **14**, 3626\n", + "(2023)](https://www.nature.com/articles/s41467-023-39232-8), which supports a\n", + "novel type of topological defect, a CP² skyrmion, that involves both the\n", + "dipolar and quadrupolar parts of a quantum spin.\n", + "\n", + "Beginning from an initial high-temperature state, a disordered gas of CP²\n", + "skyrmions can be formed by rapidly quenching to low temperature. To model the\n", + "coupled dynamics of dipoles and quadrupoles, Sunny uses a recently developed\n", + "generalization of the Landau-Lifshitz spin dynamics, [Dahlbom et al., Phys.\n", + "Rev. B **106**, 235154 (2022)](https://doi.org/10.1103/PhysRevB.106.235154)." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Sunny, WGLMakie" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The Hamiltonian we will implement,\n", + "$$\n", + "\\mathcal{H} = \\sum_{\\langle i,j \\rangle} J_{ij}( \\hat{S}_i^x \\hat{S}_j^x + \\hat{S}_i^y \\hat{S}_j^y + \\Delta\\hat{S}_i^z \\hat{S}_j^z) - h\\sum_{i}\\hat{S}_i^z + D\\sum_{i}(\\hat{S}_i^z)^2\n", + "$$\n", + "contains competing ferromagnetic nearest-neightbor and antiferromagnetic\n", + "next-nearest-neighbor exchange terms on a triangular lattice. Both exchanges\n", + "exhibit anisotropy on the z-term. Additionally, there is an external magnetic\n", + "field, $h$, and easy-plane single-ion anisotropy, $D$. We begin by implementing\n", + "the `Crystal`." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "lat_vecs = Sunny.lattice_vectors(1.0, 1.0, 2.0, 90, 90, 120)\n", + "basis_vecs = [[0,0,0]]\n", + "cryst = Crystal(lat_vecs, basis_vecs)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The crystal is then used to create a spin `System`. All parameters in\n", + "this model system are dimensionless, so we select \"theory\" units and set the\n", + "g-factor to one." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "L = 40\n", + "dims = (L, L, 1)\n", + "sys = System(cryst, dims, [SpinInfo(1, S=1, g=1)], :SUN; seed=101, units=Units.theory)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "We proceed to implement each term of the Hamiltonian, selecting our parameters\n", + "so that the system occupies a region of the phase diagram that supports\n", + "skyrmions. The exchange interactions are set as follows." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "J1 = -1 # Nearest-neighbor ferromagnetic\n", + "J2 = (2.0/(1+√5)) # Tune competing exchange to set skyrmion scale length\n", + "Δ = 2.6 # Exchange anisotropy\n", + "\n", + "ex1 = J1 * [1.0 0.0 0.0;\n", + " 0.0 1.0 0.0;\n", + " 0.0 0.0 Δ]\n", + "ex2 = J2 * [1.0 0.0 0.0;\n", + " 0.0 1.0 0.0;\n", + " 0.0 0.0 Δ]\n", + "set_exchange!(sys, ex1, Bond(1, 1, [1, 0, 0]))\n", + "set_exchange!(sys, ex2, Bond(1, 1, [1, 2, 0]));" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Next we add the external field," + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "h = 15.5\n", + "field = set_external_field!(sys, [0.0 0.0 h]);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "and finally the single-ion anisotropy," + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "D = 19.0\n", + "Sz = Sunny.spin_operators(sys, 1)[3]\n", + "set_onsite_coupling!(sys, D*Sz^2, 1);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Initialize system to an infinite temperature (fully randomized) initial\n", + "condition." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "randomize_spins!(sys)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "We are now ready to simulate the quenching process using a generalized\n", + "`Langevin` spin dynamics. If we were working with spin dipoles only,\n", + "then `Langevin` dynamics would be the usual Landau-Lifshitz spin dynamics,\n", + "augmented with damping and noise terms. In the present study, we are instead\n", + "working with quantum spin-1 (an ($N=3$)-level system that includes both\n", + "dipoles and quadrupoles). Here, `Langevin` captures the coupled\n", + "dipole-quadrupole dynamics using the formalism of SU($N$) coherent states.\n", + "\n", + "Selecting `kT = 0` in the Langevin dynamics will effective disable the noise\n", + "term. Then the parameter `λ` effectively determines the damping time-scale." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "Δt = 0.2/D # Integration time step (inverse meV). Typically this will be\n", + " # inversely proportional to the largest energy scale in the\n", + " # system. We can use a fairly large time-step here because\n", + " # accuracy isn't critical.\n", + "kT = 0 # Target equilibrium temperature (meV)\n", + "λ = 0.1 # Magnitude of coupling to thermal bath (dimensionless)\n", + "integrator = Langevin(Δt; kT, λ);" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Finally we run the dynamics. We will record the state of the system at three\n", + "different times during the quenching process by copying the `coherents` field\n", + "of the `System`." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "τs = [4., 16, 256] # Times to record snapshots\n", + "frames = [] # Empty array to store snapshots\n", + "for i in eachindex(τs)\n", + " dur = i == 1 ? τs[1] : τs[i] - τs[i-1] # Determine the length of time to simulate\n", + " numsteps = round(Int, dur/Δt)\n", + " for _ in 1:numsteps # Perform the integration\n", + " step!(sys, integrator)\n", + " end\n", + " push!(frames, copy(sys.coherents)) # Save a snapshot spin configuration\n", + "end" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "To visualize the state of the system contained in each snapshot, we will\n", + "calculate and plot the skyrmion density on each plaquette of our lattice. The\n", + "function `plot_triangular_plaquettes` is not part of the core Sunny package,\n", + "but rather something you could define yourself. We are using the definition in\n", + "`plotting2d.jl` from the Sunny [`examples/extra`\n", + "directory](https://github.com/SunnySuite/Sunny.jl/tree/main/examples/extra)." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "include(joinpath(pkgdir(Sunny), \"examples\", \"extra\", \"plotting2d.jl\"))\n", + "\n", + "function sun_berry_curvature(z₁, z₂, z₃)\n", + " z₁, z₂, z₃ = normalize.((z₁, z₂, z₃))\n", + " n₁ = z₁ ⋅ z₂\n", + " n₂ = z₂ ⋅ z₃\n", + " n₃ = z₃ ⋅ z₁\n", + " return angle(n₁ * n₂ * n₃)\n", + "end\n", + "\n", + "plot_triangular_plaquettes(sun_berry_curvature, frames; resolution=(1800,600),\n", + " offset_spacing=10, texts = [\"\\tt = \"*string(τ) for τ in τs], text_offset = (0.0, 6.0)\n", + ")" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The times are given in $\\hbar/|J_1|$. The white\n", + "background corresponds to a quantum paramagnetic state, where the local spin\n", + "exhibits a strong quadrupole moment and little or no dipole moment. Observe\n", + "that the process has generated a number of well-formed skyrmions of both\n", + "positive (red) and negative (blue) charge in addition to a number of other\n", + "metastable spin configurations. A full-sized version of this figure is\n", + "available in [Dahlbom et al.](https://doi.org/10.1103/PhysRevB.106.235154)." + ], + "metadata": {} + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.9.3" + }, + "kernelspec": { + "name": "julia-1.9", + "display_name": "Julia 1.9.3", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/dev/assets/notebooks/powder_averaging.ipynb b/dev/assets/notebooks/powder_averaging.ipynb new file mode 100644 index 000000000..b4cfcb309 --- /dev/null +++ b/dev/assets/notebooks/powder_averaging.ipynb @@ -0,0 +1,225 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Powder averaged CoRh$_2$O$_4$\n", + "\n", + "This tutorial illustrates the calculation of the powder-averaged structure\n", + "factor by performing an orientational average. We consider a simple model of\n", + "the diamond-cubic crystal CoRh$_2$O$_4$, with parameters extracted from [Ge et\n", + "al., Phys. Rev. B 96, 064413](https://doi.org/10.1103/PhysRevB.96.064413)." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "using Sunny, WGLMakie" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Construct a diamond `Crystal` in the conventional (non-primitive)\n", + "cubic unit cell. Sunny will populate all eight symmetry-equivalent sites when\n", + "given the international spacegroup number 227 (\"Fd-3m\") and the appropriate\n", + "setting. For this spacegroup, there are two conventional translations of the\n", + "unit cell, and it is necessary to disambiguate through the `setting` keyword\n", + "argument. (On your own: what happens if `setting` is omitted?)" + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "a = 8.5031 # (Å)\n", + "latvecs = lattice_vectors(a, a, a, 90, 90, 90)\n", + "crystal = Crystal(latvecs, [[0,0,0]], 227, setting=\"1\")" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Construct a `System` with an antiferromagnetic nearest neighbor\n", + "interaction `J`. Because the diamond crystal is bipartite, the ground state\n", + "will have unfrustrated Néel order. Selecting `latsize=(1,1,1)` is sufficient\n", + "because the ground state is periodic over each cubic unit cell. By passing an\n", + "explicit `seed`, the system's random number generator will give repeatable\n", + "results." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "latsize = (1,1,1)\n", + "seed = 0\n", + "S = 3/2\n", + "J = 7.5413*meV_per_K # (~ 0.65 meV)\n", + "sys = System(crystal, latsize, [SpinInfo(1; S, g=2)], :dipole; seed=0)\n", + "set_exchange!(sys, J, Bond(1, 3, [0,0,0]))" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "The ground state is non-frustrated. Each spin should be exactly anti-aligned\n", + "with its 4 nearest-neighbors, such that every bond contributes an energy of\n", + "$-JS^2$. This gives an energy per site of $-2JS^2$. In this calculation, a\n", + "factor of 1/2 is necessary to avoid double-counting the bonds. Given the small\n", + "magnetic supercell (which includes only one unit cell), direct energy\n", + "minimization is successful in finding the ground state." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "randomize_spins!(sys)\n", + "minimize_energy!(sys)\n", + "\n", + "energy_per_site = energy(sys) / length(eachsite(sys))\n", + "@assert energy_per_site ≈ -2J*S^2" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "Plotting the spins confirms the expected Néel order. Note that the overall,\n", + "global rotation of dipoles is arbitrary." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "plot_spins(sys; ghost_radius=2.0)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "We can now estimate $𝒮(𝐪,ω)$ with `SpinWaveTheory` and\n", + "`intensity_formula`. The mode `:perp` contracts with a dipole factor\n", + "to return the unpolarized intensity. We will also apply broadening with the\n", + "`lorentzian` kernel, and will dampen intensities using the\n", + "`FormFactor` for Cobalt(2+)." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "swt = SpinWaveTheory(sys)\n", + "η = 0.4 # (meV)\n", + "kernel = lorentzian(η)\n", + "formfactors = [FormFactor(\"Co2\")]\n", + "formula = intensity_formula(swt, :perp; kernel, formfactors)" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "First, we consider the \"single crystal\" results. Use\n", + "`reciprocal_space_path` to construct a path that connects\n", + "high-symmetry points in reciprocal space. The `intensities_broadened`\n", + "function collects intensities along this path for the given set of energy\n", + "values." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "qpoints = [[0.0, 0.0, 0.0], [0.5, 0.0, 0.0], [0.5, 0.5, 0.0], [0.0, 0.0, 0.0]]\n", + "path, xticks = reciprocal_space_path(crystal, qpoints, 50)\n", + "energies = collect(0:0.01:6)\n", + "is = intensities_broadened(swt, path, energies, formula)\n", + "\n", + "fig = Figure()\n", + "ax = Axis(fig[1,1]; aspect=1.4, ylabel=\"ω (meV)\", xlabel=\"𝐪 (RLU)\",\n", + " xticks, xticklabelrotation=π/10)\n", + "heatmap!(ax, 1:size(is, 1), energies, is, colormap=:gnuplot2)\n", + "fig" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "A powder measurement effectively involves an average over all possible crystal\n", + "orientations. We use the function `reciprocal_space_shell` to sample\n", + "`n` wavevectors on a sphere of a given radius (inverse angstroms), and then\n", + "calculate the spherically-averaged intensity." + ], + "metadata": {} + }, + { + "outputs": [], + "cell_type": "code", + "source": [ + "radii = 0.01:0.02:3 # (1/Å)\n", + "output = zeros(Float64, length(radii), length(energies))\n", + "for (i, radius) in enumerate(radii)\n", + " n = 300\n", + " qs = reciprocal_space_shell(crystal, radius, n)\n", + " is = intensities_broadened(swt, qs, energies, formula)\n", + " output[i, :] = sum(is, dims=1) / size(is, 1)\n", + "end\n", + "\n", + "fig = Figure()\n", + "ax = Axis(fig[1,1]; xlabel=\"|Q| (Å⁻¹)\", ylabel=\"ω (meV)\")\n", + "heatmap!(ax, radii, energies, output, colormap=:gnuplot2)\n", + "fig" + ], + "metadata": {}, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "This result can be compared to experimental neutron scattering data\n", + "from Fig. 5 of [Ge et al.](https://doi.org/10.1103/PhysRevB.96.064413)\n", + "\n", + "" + ], + "metadata": {} + } + ], + "nbformat_minor": 3, + "metadata": { + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.9.3" + }, + "kernelspec": { + "name": "julia-1.9", + "display_name": "Julia 1.9.3", + "language": "julia" + } + }, + "nbformat": 4 +} diff --git a/dev/examples/fei2_classical/index.html b/dev/examples/fei2_classical/index.html index 59598ea5b..75396c677 100644 --- a/dev/examples/fei2_classical/index.html +++ b/dev/examples/fei2_classical/index.html @@ -1,5 +1,5 @@ -Structure Factors with Classical Dynamics · Sunny documentation
Download as a Jupyter notebook

Structure Factors with Classical Dynamics

using Sunny, LinearAlgebra, GLMakie

In our previous Case Study: FeI$_{2}$, we used linear spin wave theory (LSWT) to calculate the dynamical structure factor. Here, we perform a similar calculation using classical spin dynamics. Because we are interested in the coupled dynamics of spin dipoles and quadrupoles, we employ a classical dynamics of SU(3) coherent states that generalizes the Landau-Lifshitz equation.

Compared to LSWT, simulations using classical dynamics are much slower, and are limited in $k$-space resolution. However, they make it is possible to capture nonlinear effects associated with finite temperature fluctuations. Classical dynamics are also appealing for studying out-of-equilibrium systems (e.g., relaxation of spin glasses), or systems with quenched inhomogeneities that require large simulation volumes.

In this tutorial, we show how to study the finite temperature dynamics of FeI$_2$ using the classical approach. It is important to stress that the estimation of $S(𝐪,ω)$ with classical dynamics is fundamentally a Monte Carlo calculation: sample spin configurations are drawn from thermal equilibrium and used as initial conditions for generating dissipationless trajectories. The correlations of these trajectories are then averaged and used to calculate scattering intensities. It is therefore important to ensure that the initial spin configurations are sampled appropriately and that sufficient statistics are collected. We will demonstrate one approach here.

As an overview, we will:

  1. Identify the ground state
  2. Measure correlation data describing the excitations around that ground state
  3. Use the correlation data to compute scattering intensities

As the implementation of the FeI$_2$ model is already covered in detail in the LSWT tutorial, we will not repeat it below. Instead, we will assume that you already have defined a sys in the same way with lattice dimensions $4×4×4$.

Finding a ground state

Sunny uses the Langevin dynamics of SU(N) coherent states to sample spin configurations from the thermal equlibrium. One first constructs a Langevin integrator. This requires a time step, temperature, and a phenomenological damping parameter $λ$ that sets the coupling to the thermal bath.

Δt = 0.05/D    # Should be inversely proportional to the largest energy scale
+Structure Factors with Classical Dynamics · Sunny documentation
Download as a Jupyter notebook

Structure Factors with Classical Dynamics

using Sunny, LinearAlgebra, GLMakie

In our previous Case Study: FeI$_{2}$, we used linear spin wave theory (LSWT) to calculate the dynamical structure factor. Here, we perform a similar calculation using classical spin dynamics. Because we are interested in the coupled dynamics of spin dipoles and quadrupoles, we employ a classical dynamics of SU(3) coherent states that generalizes the Landau-Lifshitz equation.

Compared to LSWT, simulations using classical dynamics are much slower, and are limited in $k$-space resolution. However, they make it is possible to capture nonlinear effects associated with finite temperature fluctuations. Classical dynamics are also appealing for studying out-of-equilibrium systems (e.g., relaxation of spin glasses), or systems with quenched inhomogeneities that require large simulation volumes.

In this tutorial, we show how to study the finite temperature dynamics of FeI$_2$ using the classical approach. It is important to stress that the estimation of $S(𝐪,ω)$ with classical dynamics is fundamentally a Monte Carlo calculation: sample spin configurations are drawn from thermal equilibrium and used as initial conditions for generating dissipationless trajectories. The correlations of these trajectories are then averaged and used to calculate scattering intensities. It is therefore important to ensure that the initial spin configurations are sampled appropriately and that sufficient statistics are collected. We will demonstrate one approach here.

As an overview, we will:

  1. Identify the ground state
  2. Measure correlation data describing the excitations around that ground state
  3. Use the correlation data to compute scattering intensities

As the implementation of the FeI$_2$ model is already covered in detail in the LSWT tutorial, we will not repeat it below. Instead, we will assume that you already have defined a sys in the same way with lattice dimensions $4×4×4$.

Finding a ground state

Sunny uses the Langevin dynamics of SU(N) coherent states to sample spin configurations from the thermal equlibrium. One first constructs a Langevin integrator. This requires a time step, temperature, and a phenomenological damping parameter $λ$ that sets the coupling to the thermal bath.

Δt = 0.05/D    # Should be inversely proportional to the largest energy scale
                # in the system. For FeI2, this is the easy-axis anisotropy,
                # `D = 2.165` (meV). The prefactor 0.05 is relatively small,
                # and achieves high accuracy.
@@ -69,7 +69,7 @@
 fig = lines(ωs, is[1,:]; axis=(xlabel="meV", ylabel="Intensity"), label="(0,0,0)")
 lines!(ωs, is[2,:]; label="(π,π,π)")
 axislegend()
-fig

The resolution in energy can be improved by increasing (and decreasing Δt), and the general accuracy can be improved by collecting additional samples from the thermal equilibrium.

For real calculations, one often wants to apply further corrections and more accurate formulas. Here, we apply FormFactor corrections appropriate for Fe2 magnetic ions, and a dipole polarization correction :perp.

formfactors = [FormFactor("Fe2"; g_lande=3/2)]
+fig

The resolution in energy can be improved by increasing (and decreasing Δt), and the general accuracy can be improved by collecting additional samples from the thermal equilibrium.

For real calculations, one often wants to apply further corrections and more accurate formulas. Here, we apply FormFactor corrections appropriate for Fe2 magnetic ions, and a dipole polarization correction :perp.

formfactors = [FormFactor("Fe2"; g_lande=3/2)]
 new_formula = intensity_formula(sc, :perp; kT = kT, formfactors = formfactors)
Classical Scattering Intensity Formula
 At discrete scattering modes S = S[ix_q,ix_ω], use:
 
@@ -113,7 +113,7 @@
     colorrange=(0.0,0.05),
 )
 
-fig

Note that we have clipped the colors in order to make the higher-energy excitations more visible.

Unconventional R.L.U. Systems and Constant Energy Cuts

Often it is useful to plot cuts across multiple wave vectors but at a single energy. We'll pick an energy,

ωidx = 60
+fig

Note that we have clipped the colors in order to make the higher-energy excitations more visible.

Unconventional R.L.U. Systems and Constant Energy Cuts

Often it is useful to plot cuts across multiple wave vectors but at a single energy. We'll pick an energy,

ωidx = 60
 target_ω = ωs[ωidx]
target_ω = 3.7312072301840273

and take a constant-energy cut at that energy. The most straightforward way is to make a plot whose axes are aligned with the conventional reciprocal lattice of the crystal. This is accomplished using unit_resolution_binning_parameters:

params = unit_resolution_binning_parameters(sc)
 params.binstart[1:2] .= -1 # Expand plot range slightly
 
@@ -140,7 +140,7 @@
 hm = heatmap!(ax,bcs[1],bcs[2],is[:,:,1,1] ./ counts[:,:,1,1])
 add_lines!(ax,params)
 Colorbar(fig[1,2], hm);
-fig

In the above plot, the dashed-line (direct) lattice vectors are clearly orthogonal. However, we know that in real space, the lattice vectors $a$ and $b$ are not orthogonal, but rather point along the edges of a hexagon (see lower left corner):



Thus, plotting the direct lattice vectors as orthogonal (even in reciprocal space) is somewhat misleading. Worse yet, the [H,0,0] by [0,K,0] plot apparently loses the 6-fold symmetry of the crystal! Lastly, if one works out the components of the real-space metric with respect to the axes of the plot, one finds that there are non-zero off-diagonal entries,

latvecs = sys.crystal.latvecs
+fig

In the above plot, the dashed-line (direct) lattice vectors are clearly orthogonal. However, we know that in real space, the lattice vectors $a$ and $b$ are not orthogonal, but rather point along the edges of a hexagon (see lower left corner):



Thus, plotting the direct lattice vectors as orthogonal (even in reciprocal space) is somewhat misleading. Worse yet, the [H,0,0] by [0,K,0] plot apparently loses the 6-fold symmetry of the crystal! Lastly, if one works out the components of the real-space metric with respect to the axes of the plot, one finds that there are non-zero off-diagonal entries,

latvecs = sys.crystal.latvecs
 metric = latvecs' * I(3) * latvecs
3×3 Matrix{Float64}:
  16.4035   -8.20174   0.0
  -8.20174  16.4035    0.0
@@ -177,7 +177,7 @@
 is = intensities_interpolated(sc, qs, new_formula; interpolation=:linear)
 
 add_lines!(ax_left,params)
-fig

Now, not only are the dashed-line lattice vectors no longer misleadingly orthogonal, but the six-fold symmetry has been restored as well! Further, the metric has been diagonalized:

metric = (latvecs * inv(A'))' * I(3) * (latvecs * inv(A'))
3×3 Matrix{Float64}:
+fig

Now, not only are the dashed-line lattice vectors no longer misleadingly orthogonal, but the six-fold symmetry has been restored as well! Further, the metric has been diagonalized:

metric = (latvecs * inv(A'))' * I(3) * (latvecs * inv(A'))
3×3 Matrix{Float64}:
  16.4035   0.0      0.0
   0.0     12.3026   0.0
   0.0      0.0     45.5914

Finally, we note that instantaneous structure factor data, $𝒮(𝐪)$, can be obtained from a dynamic structure factor with instant_intensities_interpolated. Here we'll reuse the grid of wave vectors we generated above.

is_static = instant_intensities_interpolated(sc, qs, new_formula; interpolation = :linear)
@@ -191,4 +191,4 @@
     )
 )
 Colorbar(hm.figure[1,2], hm.plot)
-hm
+hm
diff --git a/dev/examples/fei2_tutorial/index.html b/dev/examples/fei2_tutorial/index.html index 6c0d6881d..383c40768 100644 --- a/dev/examples/fei2_tutorial/index.html +++ b/dev/examples/fei2_tutorial/index.html @@ -1,5 +1,5 @@ -Case Study: FeI_2 · Sunny documentation
Download as a Jupyter notebook

Case Study: FeI$_{2}$

FeI$_2$ is an effective spin-1 material with strong single-ion anisotropy. Quadrupolar fluctuations give rise to a single-ion bound state that cannot be described by a dipole-only model. This tutorial illustrates how to use the linear spin wave theory of SU(3) coherent states (i.e. 2-flavor bosons) to model the magnetic behavior in FeI$_2$. The original study was performed in Bai et al., Nature Physics 17, 467–472 (2021).

The Fe atoms are arranged in stacked triangular layers. The effective spin interactions include various anisotropic exchange interactions, and a strong single-ion anisotropy:

\[\mathcal{H}=\sum_{(i,j)} J^{\alpha\beta}_{ij} S^{\alpha}_i S^{\beta}_j - D\sum_i \left(S^z\right)^2\]

We will formulate this Hamiltonian in Sunny and then calculate its dynamic structure factor.

Get Julia and Sunny

Sunny is implemented in Julia. This is a relatively new programming language that allows for interactive development (like Python or Matlab) while also providing high numerical efficiency (like C++ or Fortran). New Julia users may wish to take a look at our Getting Started with Julia guide. Sunny requires Julia 1.9 or later.

From the Julia prompt, load Sunny. For plotting, one can choose either GLMakie (a pop-up window) or WGLMakie (inline plots for a Jupyter notebook or VSCode).

using Sunny, GLMakie

If these packages are not yet installed, Julia should offer to install them using its built-in package management system. If old versions are installed, you may need to update them to run this tutorial.

Crystals

A Crystal describes the crystallographic unit cell and will usually be loaded from a .cif file. Here, we instead build a crystal by listing all atoms and their types.

a = b = 4.05012  # Lattice constants for triangular lattice
+Case Study: FeI_2 · Sunny documentation
Download as a Jupyter notebook

Case Study: FeI$_{2}$

FeI$_2$ is an effective spin-1 material with strong single-ion anisotropy. Quadrupolar fluctuations give rise to a single-ion bound state that cannot be described by a dipole-only model. This tutorial illustrates how to use the linear spin wave theory of SU(3) coherent states (i.e. 2-flavor bosons) to model the magnetic behavior in FeI$_2$. The original study was performed in Bai et al., Nature Physics 17, 467–472 (2021).

The Fe atoms are arranged in stacked triangular layers. The effective spin interactions include various anisotropic exchange interactions, and a strong single-ion anisotropy:

\[\mathcal{H}=\sum_{(i,j)} J^{\alpha\beta}_{ij} S^{\alpha}_i S^{\beta}_j - D\sum_i \left(S^z\right)^2\]

We will formulate this Hamiltonian in Sunny and then calculate its dynamic structure factor.

Get Julia and Sunny

Sunny is implemented in Julia. This is a relatively new programming language that allows for interactive development (like Python or Matlab) while also providing high numerical efficiency (like C++ or Fortran). New Julia users may wish to take a look at our Getting Started with Julia guide. Sunny requires Julia 1.9 or later.

From the Julia prompt, load Sunny. For plotting, one can choose either GLMakie (a pop-up window) or WGLMakie (inline plots for a Jupyter notebook or VSCode).

using Sunny, GLMakie

If these packages are not yet installed, Julia should offer to install them using its built-in package management system. If old versions are installed, you may need to update them to run this tutorial.

Crystals

A Crystal describes the crystallographic unit cell and will usually be loaded from a .cif file. Here, we instead build a crystal by listing all atoms and their types.

a = b = 4.05012  # Lattice constants for triangular lattice
 c = 6.75214      # Spacing in the z-direction
 
 latvecs = lattice_vectors(a, b, c, 90, 90, 120) # A 3x3 matrix of lattice vectors that
@@ -157,4 +157,4 @@
 fig = Figure()
 ax = Axis(fig[1,1]; xlabel="(H,0,0)", ylabel="Energy (meV)", xticks, xticklabelrotation=π/6)
 heatmap!(ax, 1:size(is_averaged, 1), energies, is_averaged)
-fig

This result can be directly compared to experimental neutron scattering data from Bai et al.

(The publication figure accidentally used a non-standard coordinate system to label the wave vectors.)

To get this agreement, the use of SU(3) coherent states is essential. In other words, we needed a theory of multi-flavored bosons. The lower band has large quadrupolar character, and arises from the strong easy-axis anisotropy of FeI$_2$. By setting mode = :SUN, the calculation captures this coupled dipole-quadrupole dynamics.

An interesting exercise is to repeat the same study, but using mode = :dipole instead of :SUN. That alternative choice would constrain the coherent state dynamics to the space of dipoles only.

The full dynamical spin structure factor (DSSF) can be retrieved as a $3×3$ matrix with the dssf function, for a given path of $𝐪$-vectors.

disp, is = dssf(swt, path);

The first output disp is identical to that obtained from dispersion. The second output is contains a list of $3×3$ matrix of intensities. For example, is[q,n][2,3] yields the $(ŷ,ẑ)$ component of the structure factor intensity for nth mode at the qth wavevector in the path.

What's next?

The multi-boson linear spin wave theory, applied above, can be understood as the quantization of a certain generalization of the Landau-Lifshitz spin dynamics. Rather than dipoles, this dynamics takes places on the space of SU(N) coherent states.

The full SU(N) coherent state dynamics, with appropriate quantum correction factors, can be useful to model finite temperature scattering data. In particular, it captures certain anharmonic effects due to thermal fluctuations. This is the subject of our Structure Factors with Classical Dynamics tutorial.

The classical dynamics is also a good starting point to study non-equilibrium phenomena. Empirical noise and damping terms can be used to model coupling to a thermal bath. This yields a Langevin dynamics of SU(N) coherent states. Our CP$^2$ Skyrmion Quench tutorial shows how this dynamics gives rise to the formation of novel topological defects in a temperature quench.

Relative to LSWT calculations, it can take much more time to estimate $\mathcal{S}(𝐪,ω)$ intensities using classical dynamics simulation. See the SunnyTutorials notebooks for examples of "production-scale" simulations.

+fig

This result can be directly compared to experimental neutron scattering data from Bai et al.

(The publication figure accidentally used a non-standard coordinate system to label the wave vectors.)

To get this agreement, the use of SU(3) coherent states is essential. In other words, we needed a theory of multi-flavored bosons. The lower band has large quadrupolar character, and arises from the strong easy-axis anisotropy of FeI$_2$. By setting mode = :SUN, the calculation captures this coupled dipole-quadrupole dynamics.

An interesting exercise is to repeat the same study, but using mode = :dipole instead of :SUN. That alternative choice would constrain the coherent state dynamics to the space of dipoles only.

The full dynamical spin structure factor (DSSF) can be retrieved as a $3×3$ matrix with the dssf function, for a given path of $𝐪$-vectors.

disp, is = dssf(swt, path);

The first output disp is identical to that obtained from dispersion. The second output is contains a list of $3×3$ matrix of intensities. For example, is[q,n][2,3] yields the $(ŷ,ẑ)$ component of the structure factor intensity for nth mode at the qth wavevector in the path.

What's next?

The multi-boson linear spin wave theory, applied above, can be understood as the quantization of a certain generalization of the Landau-Lifshitz spin dynamics. Rather than dipoles, this dynamics takes places on the space of SU(N) coherent states.

The full SU(N) coherent state dynamics, with appropriate quantum correction factors, can be useful to model finite temperature scattering data. In particular, it captures certain anharmonic effects due to thermal fluctuations. This is the subject of our Structure Factors with Classical Dynamics tutorial.

The classical dynamics is also a good starting point to study non-equilibrium phenomena. Empirical noise and damping terms can be used to model coupling to a thermal bath. This yields a Langevin dynamics of SU(N) coherent states. Our CP$^2$ Skyrmion Quench tutorial shows how this dynamics gives rise to the formation of novel topological defects in a temperature quench.

Relative to LSWT calculations, it can take much more time to estimate $\mathcal{S}(𝐪,ω)$ intensities using classical dynamics simulation. See the SunnyTutorials notebooks for examples of "production-scale" simulations.

diff --git a/dev/examples/ising2d/index.html b/dev/examples/ising2d/index.html index ab9578006..4c525c039 100644 --- a/dev/examples/ising2d/index.html +++ b/dev/examples/ising2d/index.html @@ -1,5 +1,5 @@ -Classical Ising model · Sunny documentation
Download as a Jupyter notebook

Classical Ising model

This tutorial illustrates simulation of the classical 2D Ising model.

using Sunny, Plots

Sunny expects a 3D Crystal unit cell. To model a square lattice, we create an orthogonal unit cell where the $z$-spacing is distinct from the $x$ and $y$ spacing.

a = 1
+Classical Ising model · Sunny documentation
Download as a Jupyter notebook

Classical Ising model

This tutorial illustrates simulation of the classical 2D Ising model.

using Sunny, Plots

Sunny expects a 3D Crystal unit cell. To model a square lattice, we create an orthogonal unit cell where the $z$-spacing is distinct from the $x$ and $y$ spacing.

a = 1
 latvecs = lattice_vectors(a,a,10a,90,90,90)
 crystal = Crystal(latvecs, [[0,0,0]])
Crystal
 HM symbol 'P 4/m m m' (123)
@@ -17,45 +17,45 @@
 end

Plot the Ising spins by extracting the $z$-component of the dipoles

heatmap(reshape([s.z for s in sys.dipoles], (L,L)))
- + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + -
+
diff --git a/dev/examples/one_dim_chain/index.html b/dev/examples/one_dim_chain/index.html index b38a4ba39..04b09d9dc 100644 --- a/dev/examples/one_dim_chain/index.html +++ b/dev/examples/one_dim_chain/index.html @@ -1,5 +1,5 @@ -Fitting model parameters in a 1D spin-1 ferromagnetic chain · Sunny documentation
Download as a Jupyter notebook

Fitting model parameters in a 1D spin-1 ferromagnetic chain

using Sunny, LinearAlgebra, GLMakie, Optim

In this Example, we consider a 1D chain of spin-1 sites. The sites along the chain interact via a ferromagnetic nearest-neighbor interaction $J\sum_{\langle i,j\rangle} \mathbf{S}_i \cdot \mathbf{S}_j$, with $J < 0$. By default, the ground state would be ferromagnetic and highly degenerate, since the spins can align in any direction. An on-site interaction, $D\sum_i (S^z_i)^2$ breaks this isotropy by making it easier for the spins to align in the $\pm z$ direction than in any other orientation. Thus, the entire Hamiltonian is:

$\mathcal{H} = \overbrace{J\sum_{\langle i,j\rangle} \mathbf{S}_i \cdot \mathbf{S}_j}^{\text{Ferromagnetic}}\;\;\;\;\;\; \overbrace{-D\sum_i (S^z_i)^2}^{\text{Easy-axis single-ion anisotropy}}$

The goal of this Example is to illustrate how to determine the parameters $J$ and $D$ from "experiment" data by fitting using Sunny's implementation of Linear Spin Wave Theory. In our case, the "experiment" data will actually be simulation data produced using Landau-Lifschitz dynamics.

Creating simulated "experiment" data using Landau-Lifschitz dynamics

Our simulated data will use ground truth values $J_0 = -1\,\text{meV}$ and $D_0 = 10\,\text{meV}$ with a lattice spacing $a = 10$ angstrom.

We begin with a 1D chain of spin-1 sites along the $x$ direction.

# Establish geometry of the unit cell.
+Fitting model parameters in a 1D spin-1 ferromagnetic chain · Sunny documentation
Download as a Jupyter notebook

Fitting model parameters in a 1D spin-1 ferromagnetic chain

using Sunny, LinearAlgebra, GLMakie, Optim

In this Example, we consider a 1D chain of spin-1 sites. The sites along the chain interact via a ferromagnetic nearest-neighbor interaction $J\sum_{\langle i,j\rangle} \mathbf{S}_i \cdot \mathbf{S}_j$, with $J < 0$. By default, the ground state would be ferromagnetic and highly degenerate, since the spins can align in any direction. An on-site interaction, $D\sum_i (S^z_i)^2$ breaks this isotropy by making it easier for the spins to align in the $\pm z$ direction than in any other orientation. Thus, the entire Hamiltonian is:

$\mathcal{H} = \overbrace{J\sum_{\langle i,j\rangle} \mathbf{S}_i \cdot \mathbf{S}_j}^{\text{Ferromagnetic}}\;\;\;\;\;\; \overbrace{-D\sum_i (S^z_i)^2}^{\text{Easy-axis single-ion anisotropy}}$

The goal of this Example is to illustrate how to determine the parameters $J$ and $D$ from "experiment" data by fitting using Sunny's implementation of Linear Spin Wave Theory. In our case, the "experiment" data will actually be simulation data produced using Landau-Lifschitz dynamics.

Creating simulated "experiment" data using Landau-Lifschitz dynamics

Our simulated data will use ground truth values $J_0 = -1\,\text{meV}$ and $D_0 = 10\,\text{meV}$ with a lattice spacing $a = 10$ angstrom.

We begin with a 1D chain of spin-1 sites along the $x$ direction.

# Establish geometry of the unit cell.
 # "P1" is required due to the rotational symmetry about the
 # x-axis being broken.
 chain_spacing = 10. # Angstrom
@@ -28,11 +28,11 @@
 
   Sunny.Plotting.plot_coherents(sys;quantization_axis = [0,0,1],kwargs...)
 randomize_spins!(spin_one_chain)
-viz_chain(spin_one_chain)

In this plot, the z-axis has been used as the quantization axis for each site, with the up/down arrows and circle representing the $\pm \hbar$ and $0\hbar$ spin projections onto the z-axis respectively. The opacity of each object represents the probability (absolute value squared), and the color represents the phase. Since we are using classical dynamics to simulate the data, the phase will be mostly random.

First, we thermalize the chain, and then take several samples in order get reasonably good "experiment" data.

# ... thermalize ...
-viz_chain(spin_one_chain)
# ... some time later ...
-viz_chain(spin_one_chain)
# ... some time later ...
-viz_chain(spin_one_chain)
# ... some time later ...
-viz_chain(spin_one_chain)

Now that we have collected several samples,

sc
SampledCorrelations (401.206 KiB)
+viz_chain(spin_one_chain)

In this plot, the z-axis has been used as the quantization axis for each site, with the up/down arrows and circle representing the $\pm \hbar$ and $0\hbar$ spin projections onto the z-axis respectively. The opacity of each object represents the probability (absolute value squared), and the color represents the phase. Since we are using classical dynamics to simulate the data, the phase will be mostly random.

First, we thermalize the chain, and then take several samples in order get reasonably good "experiment" data.

# ... thermalize ...
+viz_chain(spin_one_chain)
# ... some time later ...
+viz_chain(spin_one_chain)
# ... some time later ...
+viz_chain(spin_one_chain)
# ... some time later ...
+viz_chain(spin_one_chain)

Now that we have collected several samples,

sc
SampledCorrelations (401.206 KiB)
 [S(q,ω) | nω = 80, Δω = 0.2549 | 22 samples]
 Lattice: (16, 1, 1)×1
 6 correlations in SU(3) mode:
@@ -50,7 +50,7 @@
 SIMULATED_EXPERIMENT_DATA = (is ./ counts)[:,1,1,:]
 
 bcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)
-heatmap!(ax,bcs[1],bcs[4],log10.(SIMULATED_EXPERIMENT_DATA))

Fitting to the experiment data

To fit this data, we first model the known aspects of the system in Sunny. The first steps are the same whether we are simulating a known system or modelling an unknown system:

# Same as before
+heatmap!(ax,bcs[1],bcs[4],log10.(SIMULATED_EXPERIMENT_DATA))

Fitting to the experiment data

To fit this data, we first model the known aspects of the system in Sunny. The first steps are the same whether we are simulating a known system or modelling an unknown system:

# Same as before
 chain_spacing = 10. # Angstrom
 latvecs = chain_spacing * I(3)
 one_dimensional_chain = Crystal(latvecs,[[0,0,0]],"P1")
@@ -122,7 +122,7 @@
 opt_result = optimize(get_loss,x0,method=GradientDescent(alphaguess=1e-3),store_trace=true,extended_trace = true,time_limit=10.)
 lines!(ax,Point2f.(Optim.x_trace(opt_result)))
 scatter!(ax,-1,10)
-fig

The fit can be verified by plotting the LSWT band structure over top of the experiment data:

bcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)
+fig

The fit can be verified by plotting the LSWT band structure over top of the experiment data:

bcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)
 heatmap!(ax,bcs[1],bcs[4],log10.(SIMULATED_EXPERIMENT_DATA), colormap = :deepsea)
 
 
@@ -140,4 +140,4 @@
 end
 Colorbar(f[1,2],colormap = :turbo, limits = (0.,1.))
 Colorbar(f[1,3],colormap = :deepsea, limits = (0.,1.))
-f
+f
diff --git a/dev/examples/out_of_equilibrium/index.html b/dev/examples/out_of_equilibrium/index.html index 2fe3394ed..8eabde5d5 100644 --- a/dev/examples/out_of_equilibrium/index.html +++ b/dev/examples/out_of_equilibrium/index.html @@ -1,5 +1,5 @@ -CP^2 Skyrmion Quench · Sunny documentation
Download as a Jupyter notebook

CP$^2$ Skyrmion Quench

This example demonstrates Sunny's ability to simulate the out-of-equilibrium dynamics of generalized spin systems. We will implement the model Hamiltonian of Zhang et al., Nature Communications 14, 3626 (2023), which supports a novel type of topological defect, a CP² skyrmion, that involves both the dipolar and quadrupolar parts of a quantum spin.

Beginning from an initial high-temperature state, a disordered gas of CP² skyrmions can be formed by rapidly quenching to low temperature. To model the coupled dynamics of dipoles and quadrupoles, Sunny uses a recently developed generalization of the Landau-Lifshitz spin dynamics, Dahlbom et al., Phys. Rev. B 106, 235154 (2022).

using Sunny, GLMakie

The Hamiltonian we will implement,

\[\mathcal{H} = \sum_{\langle i,j \rangle} J_{ij}( \hat{S}_i^x \hat{S}_j^x + \hat{S}_i^y \hat{S}_j^y + \Delta\hat{S}_i^z \hat{S}_j^z) - h\sum_{i}\hat{S}_i^z + D\sum_{i}(\hat{S}_i^z)^2\]

contains competing ferromagnetic nearest-neightbor and antiferromagnetic next-nearest-neighbor exchange terms on a triangular lattice. Both exchanges exhibit anisotropy on the z-term. Additionally, there is an external magnetic field, $h$, and easy-plane single-ion anisotropy, $D$. We begin by implementing the Crystal.

lat_vecs = Sunny.lattice_vectors(1.0, 1.0, 2.0, 90, 90, 120)
+CP^2 Skyrmion Quench · Sunny documentation
Download as a Jupyter notebook

CP$^2$ Skyrmion Quench

This example demonstrates Sunny's ability to simulate the out-of-equilibrium dynamics of generalized spin systems. We will implement the model Hamiltonian of Zhang et al., Nature Communications 14, 3626 (2023), which supports a novel type of topological defect, a CP² skyrmion, that involves both the dipolar and quadrupolar parts of a quantum spin.

Beginning from an initial high-temperature state, a disordered gas of CP² skyrmions can be formed by rapidly quenching to low temperature. To model the coupled dynamics of dipoles and quadrupoles, Sunny uses a recently developed generalization of the Landau-Lifshitz spin dynamics, Dahlbom et al., Phys. Rev. B 106, 235154 (2022).

using Sunny, GLMakie

The Hamiltonian we will implement,

\[\mathcal{H} = \sum_{\langle i,j \rangle} J_{ij}( \hat{S}_i^x \hat{S}_j^x + \hat{S}_i^y \hat{S}_j^y + \Delta\hat{S}_i^z \hat{S}_j^z) - h\sum_{i}\hat{S}_i^z + D\sum_{i}(\hat{S}_i^z)^2\]

contains competing ferromagnetic nearest-neightbor and antiferromagnetic next-nearest-neighbor exchange terms on a triangular lattice. Both exchanges exhibit anisotropy on the z-term. Additionally, there is an external magnetic field, $h$, and easy-plane single-ion anisotropy, $D$. We begin by implementing the Crystal.

lat_vecs = Sunny.lattice_vectors(1.0, 1.0, 2.0, 90, 90, 120)
 basis_vecs = [[0,0,0]]
 cryst = Crystal(lat_vecs, basis_vecs)
Crystal
 HM symbol 'P 6/m m m' (191)
@@ -52,4 +52,4 @@
 
 plot_triangular_plaquettes(sun_berry_curvature, frames; resolution=(1800,600),
     offset_spacing=10, texts = ["\tt = "*string(τ) for τ in τs], text_offset = (0.0, 6.0)
-)

The times are given in $\hbar/|J_1|$. The white background corresponds to a quantum paramagnetic state, where the local spin exhibits a strong quadrupole moment and little or no dipole moment. Observe that the process has generated a number of well-formed skyrmions of both positive (red) and negative (blue) charge in addition to a number of other metastable spin configurations. A full-sized version of this figure is available in Dahlbom et al..

+)

The times are given in $\hbar/|J_1|$. The white background corresponds to a quantum paramagnetic state, where the local spin exhibits a strong quadrupole moment and little or no dipole moment. Observe that the process has generated a number of well-formed skyrmions of both positive (red) and negative (blue) charge in addition to a number of other metastable spin configurations. A full-sized version of this figure is available in Dahlbom et al..

diff --git a/dev/examples/powder_averaging/index.html b/dev/examples/powder_averaging/index.html index 6dacc0620..110a9fa88 100644 --- a/dev/examples/powder_averaging/index.html +++ b/dev/examples/powder_averaging/index.html @@ -1,5 +1,5 @@ -Powder averaged CoRh_2O_4 · Sunny documentation
Download as a Jupyter notebook

Powder averaged CoRh$_2$O$_4$

This tutorial illustrates the calculation of the powder-averaged structure factor by performing an orientational average. We consider a simple model of the diamond-cubic crystal CoRh$_2$O$_4$, with parameters extracted from Ge et al., Phys. Rev. B 96, 064413.

using Sunny, GLMakie

Construct a diamond Crystal in the conventional (non-primitive) cubic unit cell. Sunny will populate all eight symmetry-equivalent sites when given the international spacegroup number 227 ("Fd-3m") and the appropriate setting. For this spacegroup, there are two conventional translations of the unit cell, and it is necessary to disambiguate through the setting keyword argument. (On your own: what happens if setting is omitted?)

a = 8.5031 # (Å)
+Powder averaged CoRh_2O_4 · Sunny documentation
Download as a Jupyter notebook

Powder averaged CoRh$_2$O$_4$

This tutorial illustrates the calculation of the powder-averaged structure factor by performing an orientational average. We consider a simple model of the diamond-cubic crystal CoRh$_2$O$_4$, with parameters extracted from Ge et al., Phys. Rev. B 96, 064413.

using Sunny, GLMakie

Construct a diamond Crystal in the conventional (non-primitive) cubic unit cell. Sunny will populate all eight symmetry-equivalent sites when given the international spacegroup number 227 ("Fd-3m") and the appropriate setting. For this spacegroup, there are two conventional translations of the unit cell, and it is necessary to disambiguate through the setting keyword argument. (On your own: what happens if setting is omitted?)

a = 8.5031 # (Å)
 latvecs = lattice_vectors(a, a, a, 90, 90, 90)
 crystal = Crystal(latvecs, [[0,0,0]], 227, setting="1")
Crystal
 HM symbol 'F d -3 m' (227)
@@ -56,4 +56,4 @@
 fig = Figure()
 ax = Axis(fig[1,1]; xlabel="|Q| (Å⁻¹)", ylabel="ω (meV)")
 heatmap!(ax, radii, energies, output, colormap=:gnuplot2)
-fig

This result can be compared to experimental neutron scattering data from Fig. 5 of Ge et al.

+fig

This result can be compared to experimental neutron scattering data from Fig. 5 of Ge et al.

diff --git a/dev/index.html b/dev/index.html index 24e1b72eb..31cdc7355 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -Overview · Sunny documentation

Sunny Overview

Sunny is a Julia package for modeling atomic-scale magnetism. It provides powerful tools to study equilibrium and non-equilibrium magnetic phenomena. In particular, it allows estimation of dynamical structure factor intensities, $\mathcal{S}(𝐪,ω)$, to support quantitative modeling of experimental scattering data.

Features include:

  • Generalized spin dynamics using SU(N) coherent states.
  • Ability specify a crystal by a .cif file, or using its spacegroup symmetry.
  • Interactive visualizations of the 3D crystals and magnetic ordering.
  • Symmetry analysis to classify allowed interaction terms, and to propagate them by symmetry.
  • Single-ion anisotropy at arbitrary order, which can be specified using Stevens operators or as a polynomial of spin operators.
  • Monte Carlo sampling of spin configurations in thermal equilibrium, and optimization tools.
  • Measurements of dynamical correlation functions. For small supercells at low temperature, one can use linear spin wave theory and its multi-boson generalization. Alternatively, one can use the full classical dynamics to study systems with large supercells (e.g., disordered systems), or anharmonic effects with thermal fluctuations.
  • Long-range dipole-dipole interactions accelerated with the fast Fourier transform (FFT).
  • Various correction factors to facilitate comparison with experimental data (form factor, dipole factor, temperature-dependent classical-to-quantum factors, intensity binning, etc.).
+Overview · Sunny documentation

Sunny Overview

Sunny is a Julia package for modeling atomic-scale magnetism. It provides powerful tools to study equilibrium and non-equilibrium magnetic phenomena. In particular, it allows estimation of dynamical structure factor intensities, $\mathcal{S}(𝐪,ω)$, to support quantitative modeling of experimental scattering data.

Features include:

  • Generalized spin dynamics using SU(N) coherent states.
  • Ability specify a crystal by a .cif file, or using its spacegroup symmetry.
  • Interactive visualizations of the 3D crystals and magnetic ordering.
  • Symmetry analysis to classify allowed interaction terms, and to propagate them by symmetry.
  • Single-ion anisotropy at arbitrary order, which can be specified using Stevens operators or as a polynomial of spin operators.
  • Monte Carlo sampling of spin configurations in thermal equilibrium, and optimization tools.
  • Measurements of dynamical correlation functions. For small supercells at low temperature, one can use linear spin wave theory and its multi-boson generalization. Alternatively, one can use the full classical dynamics to study systems with large supercells (e.g., disordered systems), or anharmonic effects with thermal fluctuations.
  • Long-range dipole-dipole interactions accelerated with the fast Fourier transform (FFT).
  • Various correction factors to facilitate comparison with experimental data (form factor, dipole factor, temperature-dependent classical-to-quantum factors, intensity binning, etc.).
diff --git a/dev/library/index.html b/dev/library/index.html index 5e0e3f3d1..d4ae5ada3 100644 --- a/dev/library/index.html +++ b/dev/library/index.html @@ -1,8 +1,8 @@ -Library API · Sunny documentation

Library API

This page describes the public types and functions exported by Sunny. This documentation can be also be accessed using the Julia help system (enter ? at the Julia command prompt).

Sunny.SiteType
(cell1, cell2, cell3, i) :: Site

Four indices identifying a single site in a System. The first three indices select the lattice cell and the last selects the sublattice (i.e., the atom within the unit cell).

This object can be used to index dipoles and coherents fields of a System. A Site is also required to specify inhomogeneous interactions via functions such as set_external_field_at! or set_exchange_at!.

Note that the definition of a cell may change when a system is reshaped. In this case, it is convenient to construct the Site using position_to_site, which always takes a position in fractional coordinates of the original lattice vectors.

source
Sunny.UnitsConstant
Units.meV
-Units.theory

The unit system is implicitly determined by the definition of two physical constants: the vacuum permeability $μ₀$ and the Bohr magneton $μ_B$. Temperatures are effectively measured in units of energy ($k_B = 1$) and time is effectively measured in units of inverse energy ($ħ = 1$). The default unit system, Units.meV, employs (meV, Å, tesla). Select alternatively Units.theory for a units system defined so that $μ₀ = μ_B = 1$.

See also meV_per_K

source
Sunny.meV_per_KConstant
meV_per_K = 0.086173332621451774

A physical constant. Useful for converting kelvin into the default energy units, meV.

source
Sunny.BinningParametersType
BinningParameters(binstart,binend,binwidth;covectors = I(4))
+Library API · Sunny documentation

Library API

This page describes the public types and functions exported by Sunny. This documentation can be also be accessed using the Julia help system (enter ? at the Julia command prompt).

Sunny.SiteType
(cell1, cell2, cell3, i) :: Site

Four indices identifying a single site in a System. The first three indices select the lattice cell and the last selects the sublattice (i.e., the atom within the unit cell).

This object can be used to index dipoles and coherents fields of a System. A Site is also required to specify inhomogeneous interactions via functions such as set_external_field_at! or set_exchange_at!.

Note that the definition of a cell may change when a system is reshaped. In this case, it is convenient to construct the Site using position_to_site, which always takes a position in fractional coordinates of the original lattice vectors.

source
Sunny.UnitsConstant
Units.meV
+Units.theory

The unit system is implicitly determined by the definition of two physical constants: the vacuum permeability $μ₀$ and the Bohr magneton $μ_B$. Temperatures are effectively measured in units of energy ($k_B = 1$) and time is effectively measured in units of inverse energy ($ħ = 1$). The default unit system, Units.meV, employs (meV, Å, tesla). Select alternatively Units.theory for a units system defined so that $μ₀ = μ_B = 1$.

See also meV_per_K

source
Sunny.meV_per_KConstant
meV_per_K = 0.086173332621451774

A physical constant. Useful for converting kelvin into the default energy units, meV.

source
Sunny.BinningParametersType
BinningParameters(binstart,binend,binwidth;covectors = I(4))
 BinningParameters(binstart,binend;numbins,covectors = I(4))

Describes a 4D parallelepided histogram in a format compatible with experimental Inelasitic Neutron Scattering data. See generate_mantid_script_from_binning_parameters to convert BinningParameters to a format understandable by the Mantid software, or load_nxs to load BinningParameters from a Mantid .nxs file.

The coordinates of the histogram axes are specified by multiplication of (q,ω) with each row of the covectors matrix, with q given in [R.L.U.]. Since the default covectors matrix is the identity matrix, the default axes are (qx,qy,qz,ω) in absolute units.

The convention for the binning scheme is that:

  • The left edge of the first bin starts at binstart
  • The bin width is binwidth
  • The last bin contains binend
  • There are no "partial bins;" the last bin may contain values greater than binend. C.f. count_bins.

A value can be binned by computing its bin index:

coords = covectors * value
-bin_ix = 1 .+ floor.(Int64,(coords .- binstart) ./ binwidth)
source
Sunny.BondType
Bond(i, j, n)

Represents a bond between atom indices i and j. n is a vector of three integers specifying unit cell displacement in terms of lattice vectors.

source
Sunny.CrystalType

An object describing a crystallographic unit cell and its space group symmetry. Constructors are as follows:

Crystal(filename; symprec=1e-5)

Reads the crystal from a .cif file located at the path filename. The optional parameter symprec controls the precision tolerance for spacegroup symmetries.

Crystal(latvecs, positions; types=nothing, symprec=1e-5)

Constructs a crystal from the complete list of atom positions positions, with coordinates (between 0 and 1) in units of lattice vectors latvecs. Spacegroup symmetry information is automatically inferred. The optional parameter types is a list of strings, one for each atom, and can be used to break symmetry-equivalence between atoms.

Crystal(latvecs, positions, spacegroup_number; types=nothing, setting=nothing, symprec=1e-5)

Builds a crystal by applying symmetry operators for a given international spacegroup number. For certain spacegroups, there are multiple possible unit cell settings; in this case, a warning message will be printed, and a list of crystals will be returned, one for every possible setting. Alternatively, the optional setting string will disambiguate between unit cell conventions.

Currently, crystals built using only the spacegroup number will be missing some symmetry information. It is generally preferred to build a crystal from a .cif file or from the full specification of the unit cell.

Examples

# Read a Crystal from a .cif file
+bin_ix = 1 .+ floor.(Int64,(coords .- binstart) ./ binwidth)
source
Sunny.BondType
Bond(i, j, n)

Represents a bond between atom indices i and j. n is a vector of three integers specifying unit cell displacement in terms of lattice vectors.

source
Sunny.CrystalType

An object describing a crystallographic unit cell and its space group symmetry. Constructors are as follows:

Crystal(filename; symprec=1e-5)

Reads the crystal from a .cif file located at the path filename. The optional parameter symprec controls the precision tolerance for spacegroup symmetries.

Crystal(latvecs, positions; types=nothing, symprec=1e-5)

Constructs a crystal from the complete list of atom positions positions, with coordinates (between 0 and 1) in units of lattice vectors latvecs. Spacegroup symmetry information is automatically inferred. The optional parameter types is a list of strings, one for each atom, and can be used to break symmetry-equivalence between atoms.

Crystal(latvecs, positions, spacegroup_number; types=nothing, setting=nothing, symprec=1e-5)

Builds a crystal by applying symmetry operators for a given international spacegroup number. For certain spacegroups, there are multiple possible unit cell settings; in this case, a warning message will be printed, and a list of crystals will be returned, one for every possible setting. Alternatively, the optional setting string will disambiguate between unit cell conventions.

Currently, crystals built using only the spacegroup number will be missing some symmetry information. It is generally preferred to build a crystal from a .cif file or from the full specification of the unit cell.

Examples

# Read a Crystal from a .cif file
 Crystal("filename.cif")
 
 # Build an FCC crystal using the primitive unit cell. The spacegroup number
@@ -25,29 +25,29 @@
 # overall unit cell translation.
 latvecs = lattice_vectors(1, 1, 1, 90, 90, 90)
 positions = [[1, 1, 1] / 4]
-cryst = Crystal(latvecs, positions, 227; setting="1")

See also lattice_vectors.

source
Sunny.FormFactorMethod
FormFactor(ion::String; g_lande=2)

The magnetic form factor for a given magnetic ion and charge state. These can optionally be provided to intensity_formula, and will be used to scale the structure factor intensities as a function of wavevector magnitude.

The parameter ion must be one of the following allowed strings:

Sc0,Sc1,Sc2,Ti0,Ti1,Ti2,Ti3,V0,V1,V2,V3,V4,Cr0,Cr1,Cr2,Cr3,Cr4,Mn0,Mn1,Mn2,Mn3,
+cryst = Crystal(latvecs, positions, 227; setting="1")

See also lattice_vectors.

source
Sunny.FormFactorMethod
FormFactor(ion::String; g_lande=2)

The magnetic form factor for a given magnetic ion and charge state. These can optionally be provided to intensity_formula, and will be used to scale the structure factor intensities as a function of wavevector magnitude.

The parameter ion must be one of the following allowed strings:

Sc0,Sc1,Sc2,Ti0,Ti1,Ti2,Ti3,V0,V1,V2,V3,V4,Cr0,Cr1,Cr2,Cr3,Cr4,Mn0,Mn1,Mn2,Mn3,
 Mn4,Fe0,Fe1,Fe2,Fe3,Fe4,Co0,Co1,Co2,Co3,Co4,Ni0,Ni1,Ni2,Ni3,Ni4,Cu0,Cu1,Cu2,Cu3,
 Cu4,Y0,Zr0,Zr1,Nb0,Nb1,Mo0,Mo1,Tc0,Tc1,Ru0,Ru1,Rh0,Rh1,Pd0,Pd1,Ce2,Nd2,Nd3,Sm2,
 Sm3,Eu2,Eu3,Gd2,Gd3,Tb2,Tb3,Dy2,Dy3,Ho2,Ho3,Er2,Er3,Tm2,Tm3,Yb2,Yb3,Pr3,U3,U4,
-U5,Np3,Np4,Np5,Np6,Pu3,Pu4,Pu5,Pu6,Am2,Am3,Am4,Am5,Am6,Am7

A first approximation to the magnetic form factor is

$f(s) = \langle j_0(s) \rangle$,

where $\langle j_l(s) \rangle$ is a Bessel function integral of the magnetic dipole.

If Landé $g$-factor is distinct from 2, then a correction will be applied,

$F(s) = \frac{2-g}{g} \langle j_2(s) \rangle s^2 + f(s)$.

Sunny uses the semi-empirical fits for $j_0$ and $j_2$ listed from Refs. [1] and [2]. These functions are approximated as a sum of Gaussians in the scalar variable $s = |k|/4π$, where $|k|$ can be interpreted as the magnitude of momentum transfer:

$\langle j_l(s) \rangle = A e^{-as^2} + B e^{-bs^2} + Ce^{-cs^2} + D,$

where $A, B, C, D, a, b, c$ are $l$-dependent fitting parameters. For transition metals, the parameters are estimated using the Hartree-Fock method. For rare-earth metals and ions, the Dirac-Fock form is used.

References:

  1. https://www.ill.eu/sites/ccsl/ffacts/ffachtml.html
  2. J. Brown, The Neutron Data Booklet, 2nd ed., Sec. 2.5 Magnetic Form Factors (2003).
  3. Marshall W and Lovesey S W, Theory of thermal neutron scattering Chapter 6 Oxford University Press (1971)
  4. Clementi E and Roetti C, Atomic Data and Nuclear Data Tables, 14 pp 177-478 (1974)
  5. Freeman A J and Descleaux J P, J. Magn. Mag. Mater., 12 pp 11-21 (1979) Descleaux J P and Freeman A J, J. Magn. Mag. Mater., 8 pp 119-129 (1978)
source
Sunny.ImplicitMidpointType
ImplicitMidpoint(Δt::Float64; atol=1e-12) where N

Energy-conserving spin dynamics. One call to the step! function will advance a System by Δt units of time.

Uses the spherical midpoint integration scheme for dipole systems and the Schrödinger midpoint integration scheme for SU(N) spin systems. Both integration schemes are symplectic, and therefore avoid energy drift over long periods of simulation time.

source
Sunny.LangevinType
Langevin(Δt::Float64; λ::Float64, kT::Float64)

Spin dynamics with coupling to a Langevin thermostat, which includes damping and noise terms. One call to the step! function will advance a System by Δt units of time.

Assuming ergodicity, the Langevin dynamics will sample from thermal equilibrium for the target temperature kT. The empirical parameter λ determines the strength of the coupling to the thermal bath. In other words, 1/λ is the decorrelation time-scale. If $λ = 0$, then the spin dynamics coincides with ImplicitMidpoint.

An alternative approach to sampling is LocalSampler, which may be preferred when the allowed spin values become effective discrete (e.g. Ising spins).

source
Sunny.LocalSamplerType
LocalSampler(; kT, nsweeps=1.0, propose=propose_uniform)

Monte Carlo simulation involving Metropolis updates to individual spins. One call to the step! function will perform nsweeps of MCMC sampling for a provided System. The default value of 1.0 means that step! performs, on average, one trial update per spin.

Assuming ergodicity, the LocalSampler will sample from thermal equilibrium for the target temperature kT.

The trial spin updates are sampled using the propose function. Built-in options include propose_uniform, propose_flip, and propose_delta. Multiple proposals can be mixed with the macro @mix_proposals.

The returned object stores fields ΔE and Δs, which represent the cumulative change to the net energy and dipole, respectively.

An alternative approach to sampling is Langevin, which may be preferred for simulating continuous spins, especially in the presence of long-range dipole-dipole interactions (cf. enable_dipole_dipole!).

source
Sunny.SpinInfoType
SpinInfo(atom::Int; S, g=2)

Characterizes the spin at a given atom index within the crystal unit cell. S is an integer multiple of 1/2 and gives the spin angular momentum in units of ħ. g is the g-factor or tensor, such that an angular momentum dipole $s$ produces a magnetic moment $g s$ in units of the Bohr magneton.

source
Sunny.SpinWaveTheoryType
SpinWaveTheory(sys, energy_ϵ::Float64=1e-8, energy_tol=1e-6)

Constructs an object to perform linear spin wave theory. Use it with dispersion and dssf functions.

The optional parameter energy_ϵ adds a small positive shift to the diagonal of the dynamical matrix $D$ to avoid numerical issues with zero-energy quasi-particle modes. The optional parameter energy_tol relaxes the check on the imaginary part of the eigenvalues.

source
Sunny.SystemMethod
System(crystal::Crystal, latsize, infos, mode; units=Units.meV, seed::Int)

Construct a System of spins for a given Crystal symmetry. The latsize parameter determines the number of unit cells in each lattice vector direction. The infos parameter is a list of SpinInfo objects, which determine the magnitude $S$ and $g$-tensor of each spin.

The three possible options for mode are :SUN, :dipole, and :large_S. The most variationally accurate choice is :SUN, in which each spin-$S$ degree of freedom is described as an SU(N) coherent state, where $N = 2S + 1$. Note that an SU(N) coherent state fully describes any local spin state; this description includes expected dipole components $⟨Ŝᵅ⟩$, quadrupole components $⟨ŜᵅŜᵝ+ŜᵝŜᵅ⟩$, etc.

The mode :dipole projects the SU(N) dynamics onto the space of pure dipoles. In practice this means that Sunny will simulate Landau-Lifshitz dynamics, but all single-ion anisotropy and biquadratic exchange interactions will be automatically renormalized for maximum accuracy.

To disable such renormalization, e.g. to reproduce results using the historical large-$S$ classical limit, use the experimental mode :large_S. Modes :SUN or :dipole are strongly preferred for the development of new models.

The default units system of (meV, Å, tesla) can be overridden by with the units parameter; see Units.

An optional seed may be provided to achieve reproducible random number generation.

All spins are initially polarized in the $z$-direction.

source
Sunny.add_sample!Method
add_sample!(sc::SampledCorrelations, sys::System)

add_trajectory uses the spin configuration contained in the System to generate a correlation data and accumulate it into sc. For static structure factors, this involves analyzing the spin-spin correlations of the spin configuration provided. For a dynamic structure factor, a trajectory is calculated using the given spin configuration as an initial condition. The spin-spin correlations are then calculating in time and accumulated into sc.

This function will change the state of sys when calculating dynamical structure factor data. To preserve the initial state of sys, it must be saved separately prior to calling add_sample!. Alternatively, the initial spin configuration may be copied into a new System and this new System can be passed to add_sample!.

source
Sunny.available_energiesMethod
available_energies(sc::SampledCorrelations; negative_energies=false)

Return the ω values for the energy index of a SampledCorrelations. By default, only returns values for non-negative energies, which corresponds to the default output of intensities. Set negative_energies to true to retrieve all ω values.

source
Sunny.available_wave_vectorsMethod
available_wave_vectors(sc::SampledCorrelations; bzsize=(1,1,1))

Returns all wave vectors for which sc contains exact values. bsize specifies the number of Brillouin zones to be included.

source
Sunny.axes_bincentersMethod
axes_bincenters(params::BinningParameters)

Returns tick marks which label the bins of the histogram described by BinningParameters by their bin centers.

The following alternative syntax can be used to compute bin centers for a single axis:

axes_bincenters(binstart,binend,binwidth)
source
Sunny.broaden_energyMethod
broaden_energy(sc::SampledCorrelations, vals, kernel::Function; negative_energies=false)

Performs a real-space convolution along the energy axis of an array of intensities. Assumes the format of the intensities array corresponds to what would be returned by intensities_interpolated. kernel must be a function that takes two numbers: kernel(ω, ω₀), where ω is a frequency, and ω₀ is the center frequency of the kernel. Sunny provides lorentzian for the most common use case:

newvals = broaden_energy(sc, vals, (ω, ω₀) -> lorentzian(ω-ω₀, 0.2))
source
Sunny.browserMethod
browser(html_str; dir)

Launch a system browser to display the provided HTML string or SunnyViewer. If a directory dir is provided, an HTML file will be written at that location.

source
Sunny.count_binsMethod
count_bins(binstart,binend,binwidth)

Returns the number of bins in the binning scheme implied by binstart, binend, and binwidth. To count the bins in a BinningParameters, use params.numbins.

This function defines how partial bins are handled, so it should be used preferentially over computing the number of bins manually.

source
Sunny.dispersionMethod
dispersion(swt::SpinWaveTheory, qs)

Computes the spin excitation energy dispersion relations given a SpinWaveTheory and an array of wave vectors qs. Each element $q$ of qs must be a 3-vector in units of reciprocal lattice units. I.e., $qᵢ$ is given in $2π/|aᵢ|$ with $|aᵢ|$ the lattice constant of the original chemical lattice.

The first indices of the returned array correspond to those of qs. A final index, corresponding to mode, is added to these. Each entry of the array is an energy.

source
Sunny.dmvecMethod
dmvec(D)

Antisymmetric matrix representation of the Dzyaloshinskii-Moriya pseudo-vector,

  [  0    D[3] -D[2]
+U5,Np3,Np4,Np5,Np6,Pu3,Pu4,Pu5,Pu6,Am2,Am3,Am4,Am5,Am6,Am7

A first approximation to the magnetic form factor is

$f(s) = \langle j_0(s) \rangle$,

where $\langle j_l(s) \rangle$ is a Bessel function integral of the magnetic dipole.

If Landé $g$-factor is distinct from 2, then a correction will be applied,

$F(s) = \frac{2-g}{g} \langle j_2(s) \rangle s^2 + f(s)$.

Sunny uses the semi-empirical fits for $j_0$ and $j_2$ listed from Refs. [1] and [2]. These functions are approximated as a sum of Gaussians in the scalar variable $s = |k|/4π$, where $|k|$ can be interpreted as the magnitude of momentum transfer:

$\langle j_l(s) \rangle = A e^{-as^2} + B e^{-bs^2} + Ce^{-cs^2} + D,$

where $A, B, C, D, a, b, c$ are $l$-dependent fitting parameters. For transition metals, the parameters are estimated using the Hartree-Fock method. For rare-earth metals and ions, the Dirac-Fock form is used.

References:

  1. https://www.ill.eu/sites/ccsl/ffacts/ffachtml.html
  2. J. Brown, The Neutron Data Booklet, 2nd ed., Sec. 2.5 Magnetic Form Factors (2003).
  3. Marshall W and Lovesey S W, Theory of thermal neutron scattering Chapter 6 Oxford University Press (1971)
  4. Clementi E and Roetti C, Atomic Data and Nuclear Data Tables, 14 pp 177-478 (1974)
  5. Freeman A J and Descleaux J P, J. Magn. Mag. Mater., 12 pp 11-21 (1979) Descleaux J P and Freeman A J, J. Magn. Mag. Mater., 8 pp 119-129 (1978)
source
Sunny.ImplicitMidpointType
ImplicitMidpoint(Δt::Float64; atol=1e-12) where N

Energy-conserving spin dynamics. One call to the step! function will advance a System by Δt units of time.

Uses the spherical midpoint integration scheme for dipole systems and the Schrödinger midpoint integration scheme for SU(N) spin systems. Both integration schemes are symplectic, and therefore avoid energy drift over long periods of simulation time.

source
Sunny.LangevinType
Langevin(Δt::Float64; λ::Float64, kT::Float64)

Spin dynamics with coupling to a Langevin thermostat, which includes damping and noise terms. One call to the step! function will advance a System by Δt units of time.

Assuming ergodicity, the Langevin dynamics will sample from thermal equilibrium for the target temperature kT. The empirical parameter λ determines the strength of the coupling to the thermal bath. In other words, 1/λ is the decorrelation time-scale. If $λ = 0$, then the spin dynamics coincides with ImplicitMidpoint.

An alternative approach to sampling is LocalSampler, which may be preferred when the allowed spin values become effective discrete (e.g. Ising spins).

source
Sunny.LocalSamplerType
LocalSampler(; kT, nsweeps=1.0, propose=propose_uniform)

Monte Carlo simulation involving Metropolis updates to individual spins. One call to the step! function will perform nsweeps of MCMC sampling for a provided System. The default value of 1.0 means that step! performs, on average, one trial update per spin.

Assuming ergodicity, the LocalSampler will sample from thermal equilibrium for the target temperature kT.

The trial spin updates are sampled using the propose function. Built-in options include propose_uniform, propose_flip, and propose_delta. Multiple proposals can be mixed with the macro @mix_proposals.

The returned object stores fields ΔE and Δs, which represent the cumulative change to the net energy and dipole, respectively.

An alternative approach to sampling is Langevin, which may be preferred for simulating continuous spins, especially in the presence of long-range dipole-dipole interactions (cf. enable_dipole_dipole!).

source
Sunny.SpinInfoType
SpinInfo(atom::Int; S, g=2)

Characterizes the spin at a given atom index within the crystal unit cell. S is an integer multiple of 1/2 and gives the spin angular momentum in units of ħ. g is the g-factor or tensor, such that an angular momentum dipole $s$ produces a magnetic moment $g s$ in units of the Bohr magneton.

source
Sunny.SpinWaveTheoryType
SpinWaveTheory(sys, energy_ϵ::Float64=1e-8, energy_tol=1e-6)

Constructs an object to perform linear spin wave theory. Use it with dispersion and dssf functions.

The optional parameter energy_ϵ adds a small positive shift to the diagonal of the dynamical matrix $D$ to avoid numerical issues with zero-energy quasi-particle modes. The optional parameter energy_tol relaxes the check on the imaginary part of the eigenvalues.

source
Sunny.SystemMethod
System(crystal::Crystal, latsize, infos, mode; units=Units.meV, seed::Int)

Construct a System of spins for a given Crystal symmetry. The latsize parameter determines the number of unit cells in each lattice vector direction. The infos parameter is a list of SpinInfo objects, which determine the magnitude $S$ and $g$-tensor of each spin.

The three possible options for mode are :SUN, :dipole, and :large_S. The most variationally accurate choice is :SUN, in which each spin-$S$ degree of freedom is described as an SU(N) coherent state, where $N = 2S + 1$. Note that an SU(N) coherent state fully describes any local spin state; this description includes expected dipole components $⟨Ŝᵅ⟩$, quadrupole components $⟨ŜᵅŜᵝ+ŜᵝŜᵅ⟩$, etc.

The mode :dipole projects the SU(N) dynamics onto the space of pure dipoles. In practice this means that Sunny will simulate Landau-Lifshitz dynamics, but all single-ion anisotropy and biquadratic exchange interactions will be automatically renormalized for maximum accuracy.

To disable such renormalization, e.g. to reproduce results using the historical large-$S$ classical limit, use the experimental mode :large_S. Modes :SUN or :dipole are strongly preferred for the development of new models.

The default units system of (meV, Å, tesla) can be overridden by with the units parameter; see Units.

An optional seed may be provided to achieve reproducible random number generation.

All spins are initially polarized in the $z$-direction.

source
Sunny.add_sample!Method
add_sample!(sc::SampledCorrelations, sys::System)

add_trajectory uses the spin configuration contained in the System to generate a correlation data and accumulate it into sc. For static structure factors, this involves analyzing the spin-spin correlations of the spin configuration provided. For a dynamic structure factor, a trajectory is calculated using the given spin configuration as an initial condition. The spin-spin correlations are then calculating in time and accumulated into sc.

This function will change the state of sys when calculating dynamical structure factor data. To preserve the initial state of sys, it must be saved separately prior to calling add_sample!. Alternatively, the initial spin configuration may be copied into a new System and this new System can be passed to add_sample!.

source
Sunny.available_energiesMethod
available_energies(sc::SampledCorrelations; negative_energies=false)

Return the ω values for the energy index of a SampledCorrelations. By default, only returns values for non-negative energies, which corresponds to the default output of intensities. Set negative_energies to true to retrieve all ω values.

source
Sunny.available_wave_vectorsMethod
available_wave_vectors(sc::SampledCorrelations; bzsize=(1,1,1))

Returns all wave vectors for which sc contains exact values. bsize specifies the number of Brillouin zones to be included.

source
Sunny.axes_bincentersMethod
axes_bincenters(params::BinningParameters)

Returns tick marks which label the bins of the histogram described by BinningParameters by their bin centers.

The following alternative syntax can be used to compute bin centers for a single axis:

axes_bincenters(binstart,binend,binwidth)
source
Sunny.broaden_energyMethod
broaden_energy(sc::SampledCorrelations, vals, kernel::Function; negative_energies=false)

Performs a real-space convolution along the energy axis of an array of intensities. Assumes the format of the intensities array corresponds to what would be returned by intensities_interpolated. kernel must be a function that takes two numbers: kernel(ω, ω₀), where ω is a frequency, and ω₀ is the center frequency of the kernel. Sunny provides lorentzian for the most common use case:

newvals = broaden_energy(sc, vals, (ω, ω₀) -> lorentzian(ω-ω₀, 0.2))
source
Sunny.browserMethod
browser(html_str; dir)

Launch a system browser to display the provided HTML string or SunnyViewer. If a directory dir is provided, an HTML file will be written at that location.

source
Sunny.count_binsMethod
count_bins(binstart,binend,binwidth)

Returns the number of bins in the binning scheme implied by binstart, binend, and binwidth. To count the bins in a BinningParameters, use params.numbins.

This function defines how partial bins are handled, so it should be used preferentially over computing the number of bins manually.

source
Sunny.dispersionMethod
dispersion(swt::SpinWaveTheory, qs)

Computes the spin excitation energy dispersion relations given a SpinWaveTheory and an array of wave vectors qs. Each element $q$ of qs must be a 3-vector in units of reciprocal lattice units. I.e., $qᵢ$ is given in $2π/|aᵢ|$ with $|aᵢ|$ the lattice constant of the original chemical lattice.

The first indices of the returned array correspond to those of qs. A final index, corresponding to mode, is added to these. Each entry of the array is an energy.

source
Sunny.dmvecMethod
dmvec(D)

Antisymmetric matrix representation of the Dzyaloshinskii-Moriya pseudo-vector,

  [  0    D[3] -D[2]
    -D[3]   0    D[1]
-    D[2] -D[1]   0  ]

Useful in the context of set_exchange!.

source
Sunny.dssfMethod
dssf(swt::SpinWaveTheory, qs)

Given a SpinWaveTheory object, computes the dynamical spin structure factor,

\[ 𝒮^{αβ}(𝐤, ω) = 1/(2πN)∫dt ∑_𝐫 \exp[i(ωt - 𝐤⋅𝐫)] ⟨S^α(𝐫, t)S^β(0, 0)⟩,\]

using the result from linear spin-wave theory,

\[ 𝒮^{αβ}(𝐤, ω) = ∑_n |A_n^{αβ}(𝐤)|^2 δ[ω-ω_n(𝐤)].\]

qs is an array of wave vectors of arbitrary dimension. Each element $q$ of qs must be a 3-vector in reciprocal lattice units (RLU), i.e., in the basis of reciprocal lattice vectors.

The first indices of the returned array correspond to those of qs. A final index, corresponding to mode, is added to these. Each entry of this array is a tensor (3×3 matrix) corresponding to the indices $α$ and $β$.

source
Sunny.dynamical_correlationsMethod
dynamical_correlations(sys::System; Δt, nω, ωmax, 
-    process_trajectory=:none, observables=nothing, correlations=nothing)

Creates a SampledCorrelations for calculating and storing $𝒮(𝐪,ω)$ data. This information will be obtained by running dynamical spin simulations on equilibrium snapshots and measuring pair-correlations. The $𝒮(𝐪,ω)$ data can be retrieved by calling intensities_interpolated. Alternatively, instant_intensities_interpolated will integrate out $ω$ to obtain $𝒮(𝐪)$, optionally applying classical-to-quantum correction factors.

The SampleCorrelations that is returned will contain no correlation data. Samples are generated and accumulated by calling add_sample!(sc, sys) where sc is a SampleCorrelations and sys is an appropriately equilibrated System. Note that the sys should be thermalized before each call of add_sample! such that the spin configuration in the system represents a new (fully decorrelated) sample.

Three keywords are required to specify the dynamics used for the trajectory calculation.

  • Δt: The time step used for calculating the trajectory from which dynamic spin-spin correlations are calculated. The trajectories are calculated with an ImplicitMidpoint integrator.
  • ωmax: The maximum energy, $ω$, that will be resolved.
  • : The number of energy bins to calculated between 0 and ωmax.

Additional keyword options are the following:

  • process_trajectory: Specifies a function that will be applied to the sample trajectory before correlation analysis. Current options are :none and :symmetrize. The latter will symmetrize the trajectory in time, which can be useful for removing Fourier artifacts that arise when calculating the correlations.
  • observables: Allows the user to specify custom observables. The observables must be given as a list of complex N×N matrices or LinearMaps. It's recommended to name each observable, for example: observables = [:A => a_observable_matrix, :B => b_map, ...]. By default, Sunny uses the 3 components of the dipole, :Sx, :Sy and :Sz.
  • correlations: Specify which correlation functions are calculated, i.e. which matrix elements $αβ$ of $𝒮^{αβ}(q,ω)$ are calculated and stored. Specified with a vector of tuples. By default Sunny records all auto- and cross-correlations generated by all observables. To retain only the xx and xy correlations, one would set correlations=[(:Sx,:Sx), (:Sx,:Sy)] or correlations=[(1,1),(1,2)].
source
Sunny.enable_dipole_dipole!Method
enable_dipole_dipole!(sys::System)

Enables long-range dipole-dipole interactions,

\[ -(μ_0/4π) ∑_{⟨ij⟩} (3 (𝐌_j⋅𝐫̂_{ij})(𝐌_i⋅𝐫̂_{ij}) - 𝐌_i⋅𝐌_j) / |𝐫_{ij}|^3\]

where the sum is over all pairs of spins (singly counted), including periodic images, regularized using the Ewald summation convention. The magnetic moments are $𝐌_i = μ_B g 𝐒_i$ where $g$ is the g-factor or g-tensor, and $𝐒_i$ is the spin angular momentum dipole in units of ħ. The Bohr magneton $μ_B$ and vacuum permeability $μ_0$ are physical constants, with numerical values determined by the unit system.

source
Sunny.generate_mantid_script_from_binning_parametersMethod
generate_mantid_script_from_binning_parameters(params::BinningParameters)

Generate a Mantid script which bins data according to the given BinningParameters.

Units

Take care to ensure the units are correct (R.L.U. or absolute). You may want to call Sunny.bin_rlu_as_absolute_units! or Sunny.bin_absolute_units_as_rlu! first.

source
Sunny.global_positionMethod
global_position(sys::System, site::Site)

Position of a Site in global coordinates.

To precompute a full list of positions, one can use eachsite as below:

pos = [global_position(sys, site) for site in eachsite(sys)]
source
Sunny.instant_correlationsMethod
instant_correlations(sys::System; process_trajectory=:none, observables=nothing, correlations=nothing)

Creates a SampledCorrelations object for calculating and storing instantaneous structure factor intensities $𝒮(𝐪)$. This data will be calculated from the spin-spin correlations of equilibrium snapshots, absent any dynamical information. $𝒮(𝐪)$ data can be retrieved by calling instant_intensities_interpolated.

Important note: When dealing with continuous (non-Ising) spins, consider creating using dynamical_correlations instead of instant_correlations. The former will provide full $𝒮(𝐪,ω)$ data, from which $𝒮(𝐪)$ can be obtained by integrating out $ω$. During this integration step, Sunny can incorporate temperature- and $ω$-dependent classical-to-quantum correction factors to produce more accurate $𝒮(𝐪)$ estimates. See instant_intensities_interpolated for more information.

Prior to calling instant_correlations, ensure that sys represents a good equilibrium sample. Additional sample data may be accumulated by calling add_sample!(sc, sys) with newly equilibrated sys configurations.

The following optional keywords are available:

  • process_trajectory: Specifies a function that will be applied to the sample trajectory before correlation analysis. Current options are :none and :symmetrize. The latter will symmetrize the trajectory in time, which can be useful for removing Fourier artifacts that arise when calculating the correlations.
  • observables: Allows the user to specify custom observables. The observables must be given as a list of complex N×N matrices or LinearMaps. It's recommended to name each observable, for example: observables = [:A => a_observable_matrix, :B => b_map, ...]. By default, Sunny uses the 3 components of the dipole, :Sx, :Sy and :Sz.
  • correlations: Specify which correlation functions are calculated, i.e. which matrix elements $αβ$ of $𝒮^{αβ}(q,ω)$ are calculated and stored. Specified with a vector of tuples. By default Sunny records all auto- and cross-correlations generated by all observables. To retain only the xx and xy correlations, one would set correlations=[(:Sx,:Sx), (:Sx,:Sy)] or correlations=[(1,1),(1,2)].
source
Sunny.instant_intensities_interpolatedMethod
instant_intensities_interpolated(sc::SampledCorrelations, qs; kwargs...)

Return $𝒮(𝐪)$ intensities at wave vectors qs. The functionality is very similar to intensities_interpolated, except the returned array has dimensions identical to qs. If called on a SampledCorrelations with dynamical information, i.e., $𝒮(𝐪,ω)$, the $ω$ information is integrated out.

source
Sunny.integrate_axes!Method
integrate_axes!(params::BinningParameters; axes)

Integrate over one or more axes of the histogram by setting the number of bins in that axis to 1. Examples:

integrate_axes!(params; axes = [2,3])
-integrate_axes!(params; axes = 2)
source
Sunny.intensities_bandsMethod
dispersion, intensities = intensities_bands(swt::SpinWaveTheory, ks, formula::SpinWaveIntensityFormula)

Computes the scattering intensities at each energy band for each momentum transfer k in ks, according to Linear Spin Wave Theory and the given intensity formula. The formula must have a delta-function kernel, e.g.:

formula = intensity_formula(swt, :perp, formula; kernel = delta_function_kernel)

or else the bands will be broadened, and their intensity can not be computed.

The outputs will be arrays with indices identical to ks, with the last index giving the band index. dispersions reports the energy of each band, while intensities reports the scattering intensity.

source
Sunny.intensities_binnedMethod
intensity, counts = intensities_binned(sc::SampledCorrelations, params::BinningParameters, formula; integrated_kernel)

Given correlation data contained in a SampledCorrelations and BinningParameters describing the shape of a histogram, compute the intensity and normalization for each histogram bin using a given intensity_formula.

The BinningParameters are expected to accept (q,ω) in R.L.U. for the (possibly reshaped) crystal associated with sc.

This is an alternative to intensities_interpolated which bins the scattering intensities into a histogram instead of interpolating between them at specified qs values. See unit_resolution_binning_parameters for a reasonable default choice of BinningParameters which roughly emulates intensities_interpolated with interpolation = :round.

If a function integrated_kernel(Δω) is passed, it will be used as the CDF of a kernel function for energy broadening. For example, integrated_kernel = Δω -> atan(Δω/η)/pi (c.f. integrated_lorentzian implements Lorentzian broadening with parameter η. Energy-dependent energy broadening can be achieved by providing an integrated_kernel(ω,Δω) whose first argument is the energy transfer ω.

Currently, energy broadening is only supported if the BinningParameters are such that the first three axes are purely spatial and the last (energy) axis is [0,0,0,1].

source
Sunny.intensities_broadenedMethod
intensities_broadened(swt::SpinWaveTheory, ks, ωvals, formula)

Computes the scattering intensities at each (Q,ω) according to Linear Spin Wave Theory and the given intensity formula. The required formula must have a non-delta-function kernel, e.g.:

formula = intensity_formula(swt, :perp; kernel = lorentzian(0.05))

or else the intensity at ωvals which are not exactly on the dispersion curve can not be calculated.

The intensity is computed at each wave vector in ks and each energy in ωvals. The output will be an array with indices identical to ks, with the last index matching ωvals.

Note that ks is an array of wave vectors of arbitrary dimension. Each element $k$ of ks must be a 3-wavevector in absolute units.

source
Sunny.intensities_interpolatedMethod
intensities_interpolated(sc::SampledCorrelations, qs, formula:ClassicalIntensityFormula; interpolation=nothing, negative_energies=false)

The basic function for retrieving $𝒮(𝐪,ω)$ information from a SampledCorrelations. Maps an array of wave vectors qs to an array of structure factor intensities, including an additional energy index. The values of $ω$ associated with the energy index can be retrieved by calling available_energies. The three coordinates of each wave vector are measured in reciprocal lattice units, i.e., multiples of the reciprocal lattice vectors.

  • interpolation: Since $𝒮(𝐪, ω)$ is calculated on a finite lattice, data is only available at discrete wave vectors. By default, Sunny will round a requested q to the nearest available wave vector. Linear interpolation can be applied by setting interpolation=:linear.
  • negative_energies: If set to true, Sunny will return the periodic extension of the energy axis. Most users will not want this.
source
Sunny.intensity_formulaMethod
formula = intensity_formula(sc::SampledCorrelations)

Establish a formula for computing the intensity of the discrete scattering modes (q,ω) using the correlation data $𝒮^{αβ}(q,ω)$ stored in the SampledCorrelations. The formula returned from intensity_formula can be passed to intensities_interpolated or intensities_binned.

intensity_formula(sc,...; kT = Inf, formfactors = ...)

There are keyword arguments providing temperature and form factor corrections:

  • kT: If a temperature is provided, the intensities will be rescaled by a temperature- and ω-dependent classical-to-quantum factor. kT should be specified when making comparisons with spin wave calculations or experimental data. If kT is not specified, infinite temperature (no correction) is assumed.
  • formfactors: To apply form factor corrections, provide this keyword with a list of FormFactors, one for each symmetry-distinct site in the crystal. The order of FormFactors must correspond to the order of site symmetry classes, e.g., as they appear when printed in display(crystal).
source
Sunny.intensity_formulaMethod

A custom intensity formula can be specifed by providing a function intensity = f(q,ω,correlations) and specifying which correlations it requires:

intensity_formula(f,sc::SampledCorrelations, required_correlations; kwargs...)

The function is intended to be specified using do notation. For example, this custom formula sums the off-diagonal correlations:

required = [(:Sx,:Sy),(:Sy,:Sz),(:Sx,:Sz)]
+    D[2] -D[1]   0  ]

Useful in the context of set_exchange!.

source
Sunny.dssfMethod
dssf(swt::SpinWaveTheory, qs)

Given a SpinWaveTheory object, computes the dynamical spin structure factor,

\[ 𝒮^{αβ}(𝐤, ω) = 1/(2πN)∫dt ∑_𝐫 \exp[i(ωt - 𝐤⋅𝐫)] ⟨S^α(𝐫, t)S^β(0, 0)⟩,\]

using the result from linear spin-wave theory,

\[ 𝒮^{αβ}(𝐤, ω) = ∑_n |A_n^{αβ}(𝐤)|^2 δ[ω-ω_n(𝐤)].\]

qs is an array of wave vectors of arbitrary dimension. Each element $q$ of qs must be a 3-vector in reciprocal lattice units (RLU), i.e., in the basis of reciprocal lattice vectors.

The first indices of the returned array correspond to those of qs. A final index, corresponding to mode, is added to these. Each entry of this array is a tensor (3×3 matrix) corresponding to the indices $α$ and $β$.

source
Sunny.dynamical_correlationsMethod
dynamical_correlations(sys::System; Δt, nω, ωmax, 
+    process_trajectory=:none, observables=nothing, correlations=nothing)

Creates a SampledCorrelations for calculating and storing $𝒮(𝐪,ω)$ data. This information will be obtained by running dynamical spin simulations on equilibrium snapshots and measuring pair-correlations. The $𝒮(𝐪,ω)$ data can be retrieved by calling intensities_interpolated. Alternatively, instant_intensities_interpolated will integrate out $ω$ to obtain $𝒮(𝐪)$, optionally applying classical-to-quantum correction factors.

The SampleCorrelations that is returned will contain no correlation data. Samples are generated and accumulated by calling add_sample!(sc, sys) where sc is a SampleCorrelations and sys is an appropriately equilibrated System. Note that the sys should be thermalized before each call of add_sample! such that the spin configuration in the system represents a new (fully decorrelated) sample.

Three keywords are required to specify the dynamics used for the trajectory calculation.

  • Δt: The time step used for calculating the trajectory from which dynamic spin-spin correlations are calculated. The trajectories are calculated with an ImplicitMidpoint integrator.
  • ωmax: The maximum energy, $ω$, that will be resolved.
  • : The number of energy bins to calculated between 0 and ωmax.

Additional keyword options are the following:

  • process_trajectory: Specifies a function that will be applied to the sample trajectory before correlation analysis. Current options are :none and :symmetrize. The latter will symmetrize the trajectory in time, which can be useful for removing Fourier artifacts that arise when calculating the correlations.
  • observables: Allows the user to specify custom observables. The observables must be given as a list of complex N×N matrices or LinearMaps. It's recommended to name each observable, for example: observables = [:A => a_observable_matrix, :B => b_map, ...]. By default, Sunny uses the 3 components of the dipole, :Sx, :Sy and :Sz.
  • correlations: Specify which correlation functions are calculated, i.e. which matrix elements $αβ$ of $𝒮^{αβ}(q,ω)$ are calculated and stored. Specified with a vector of tuples. By default Sunny records all auto- and cross-correlations generated by all observables. To retain only the xx and xy correlations, one would set correlations=[(:Sx,:Sx), (:Sx,:Sy)] or correlations=[(1,1),(1,2)].
source
Sunny.enable_dipole_dipole!Method
enable_dipole_dipole!(sys::System)

Enables long-range dipole-dipole interactions,

\[ -(μ_0/4π) ∑_{⟨ij⟩} (3 (𝐌_j⋅𝐫̂_{ij})(𝐌_i⋅𝐫̂_{ij}) - 𝐌_i⋅𝐌_j) / |𝐫_{ij}|^3\]

where the sum is over all pairs of spins (singly counted), including periodic images, regularized using the Ewald summation convention. The magnetic moments are $𝐌_i = μ_B g 𝐒_i$ where $g$ is the g-factor or g-tensor, and $𝐒_i$ is the spin angular momentum dipole in units of ħ. The Bohr magneton $μ_B$ and vacuum permeability $μ_0$ are physical constants, with numerical values determined by the unit system.

source
Sunny.generate_mantid_script_from_binning_parametersMethod
generate_mantid_script_from_binning_parameters(params::BinningParameters)

Generate a Mantid script which bins data according to the given BinningParameters.

Units

Take care to ensure the units are correct (R.L.U. or absolute). You may want to call Sunny.bin_rlu_as_absolute_units! or Sunny.bin_absolute_units_as_rlu! first.

source
Sunny.global_positionMethod
global_position(sys::System, site::Site)

Position of a Site in global coordinates.

To precompute a full list of positions, one can use eachsite as below:

pos = [global_position(sys, site) for site in eachsite(sys)]
source
Sunny.instant_correlationsMethod
instant_correlations(sys::System; process_trajectory=:none, observables=nothing, correlations=nothing)

Creates a SampledCorrelations object for calculating and storing instantaneous structure factor intensities $𝒮(𝐪)$. This data will be calculated from the spin-spin correlations of equilibrium snapshots, absent any dynamical information. $𝒮(𝐪)$ data can be retrieved by calling instant_intensities_interpolated.

Important note: When dealing with continuous (non-Ising) spins, consider creating using dynamical_correlations instead of instant_correlations. The former will provide full $𝒮(𝐪,ω)$ data, from which $𝒮(𝐪)$ can be obtained by integrating out $ω$. During this integration step, Sunny can incorporate temperature- and $ω$-dependent classical-to-quantum correction factors to produce more accurate $𝒮(𝐪)$ estimates. See instant_intensities_interpolated for more information.

Prior to calling instant_correlations, ensure that sys represents a good equilibrium sample. Additional sample data may be accumulated by calling add_sample!(sc, sys) with newly equilibrated sys configurations.

The following optional keywords are available:

  • process_trajectory: Specifies a function that will be applied to the sample trajectory before correlation analysis. Current options are :none and :symmetrize. The latter will symmetrize the trajectory in time, which can be useful for removing Fourier artifacts that arise when calculating the correlations.
  • observables: Allows the user to specify custom observables. The observables must be given as a list of complex N×N matrices or LinearMaps. It's recommended to name each observable, for example: observables = [:A => a_observable_matrix, :B => b_map, ...]. By default, Sunny uses the 3 components of the dipole, :Sx, :Sy and :Sz.
  • correlations: Specify which correlation functions are calculated, i.e. which matrix elements $αβ$ of $𝒮^{αβ}(q,ω)$ are calculated and stored. Specified with a vector of tuples. By default Sunny records all auto- and cross-correlations generated by all observables. To retain only the xx and xy correlations, one would set correlations=[(:Sx,:Sx), (:Sx,:Sy)] or correlations=[(1,1),(1,2)].
source
Sunny.instant_intensities_interpolatedMethod
instant_intensities_interpolated(sc::SampledCorrelations, qs; kwargs...)

Return $𝒮(𝐪)$ intensities at wave vectors qs. The functionality is very similar to intensities_interpolated, except the returned array has dimensions identical to qs. If called on a SampledCorrelations with dynamical information, i.e., $𝒮(𝐪,ω)$, the $ω$ information is integrated out.

source
Sunny.integrate_axes!Method
integrate_axes!(params::BinningParameters; axes)

Integrate over one or more axes of the histogram by setting the number of bins in that axis to 1. Examples:

integrate_axes!(params; axes = [2,3])
+integrate_axes!(params; axes = 2)
source
Sunny.intensities_bandsMethod
dispersion, intensities = intensities_bands(swt::SpinWaveTheory, ks, formula::SpinWaveIntensityFormula)

Computes the scattering intensities at each energy band for each momentum transfer k in ks, according to Linear Spin Wave Theory and the given intensity formula. The formula must have a delta-function kernel, e.g.:

formula = intensity_formula(swt, :perp, formula; kernel = delta_function_kernel)

or else the bands will be broadened, and their intensity can not be computed.

The outputs will be arrays with indices identical to ks, with the last index giving the band index. dispersions reports the energy of each band, while intensities reports the scattering intensity.

source
Sunny.intensities_binnedMethod
intensity, counts = intensities_binned(sc::SampledCorrelations, params::BinningParameters, formula; integrated_kernel)

Given correlation data contained in a SampledCorrelations and BinningParameters describing the shape of a histogram, compute the intensity and normalization for each histogram bin using a given intensity_formula.

The BinningParameters are expected to accept (q,ω) in R.L.U. for the (possibly reshaped) crystal associated with sc.

This is an alternative to intensities_interpolated which bins the scattering intensities into a histogram instead of interpolating between them at specified qs values. See unit_resolution_binning_parameters for a reasonable default choice of BinningParameters which roughly emulates intensities_interpolated with interpolation = :round.

If a function integrated_kernel(Δω) is passed, it will be used as the CDF of a kernel function for energy broadening. For example, integrated_kernel = Δω -> atan(Δω/η)/pi (c.f. integrated_lorentzian implements Lorentzian broadening with parameter η. Energy-dependent energy broadening can be achieved by providing an integrated_kernel(ω,Δω) whose first argument is the energy transfer ω.

Currently, energy broadening is only supported if the BinningParameters are such that the first three axes are purely spatial and the last (energy) axis is [0,0,0,1].

source
Sunny.intensities_broadenedMethod
intensities_broadened(swt::SpinWaveTheory, ks, ωvals, formula)

Computes the scattering intensities at each (Q,ω) according to Linear Spin Wave Theory and the given intensity formula. The required formula must have a non-delta-function kernel, e.g.:

formula = intensity_formula(swt, :perp; kernel = lorentzian(0.05))

or else the intensity at ωvals which are not exactly on the dispersion curve can not be calculated.

The intensity is computed at each wave vector in ks and each energy in ωvals. The output will be an array with indices identical to ks, with the last index matching ωvals.

Note that ks is an array of wave vectors of arbitrary dimension. Each element $k$ of ks must be a 3-wavevector in absolute units.

source
Sunny.intensities_interpolatedMethod
intensities_interpolated(sc::SampledCorrelations, qs, formula:ClassicalIntensityFormula; interpolation=nothing, negative_energies=false)

The basic function for retrieving $𝒮(𝐪,ω)$ information from a SampledCorrelations. Maps an array of wave vectors qs to an array of structure factor intensities, including an additional energy index. The values of $ω$ associated with the energy index can be retrieved by calling available_energies. The three coordinates of each wave vector are measured in reciprocal lattice units, i.e., multiples of the reciprocal lattice vectors.

  • interpolation: Since $𝒮(𝐪, ω)$ is calculated on a finite lattice, data is only available at discrete wave vectors. By default, Sunny will round a requested q to the nearest available wave vector. Linear interpolation can be applied by setting interpolation=:linear.
  • negative_energies: If set to true, Sunny will return the periodic extension of the energy axis. Most users will not want this.
source
Sunny.intensity_formulaMethod
formula = intensity_formula(sc::SampledCorrelations)

Establish a formula for computing the intensity of the discrete scattering modes (q,ω) using the correlation data $𝒮^{αβ}(q,ω)$ stored in the SampledCorrelations. The formula returned from intensity_formula can be passed to intensities_interpolated or intensities_binned.

intensity_formula(sc,...; kT = Inf, formfactors = ...)

There are keyword arguments providing temperature and form factor corrections:

  • kT: If a temperature is provided, the intensities will be rescaled by a temperature- and ω-dependent classical-to-quantum factor. kT should be specified when making comparisons with spin wave calculations or experimental data. If kT is not specified, infinite temperature (no correction) is assumed.
  • formfactors: To apply form factor corrections, provide this keyword with a list of FormFactors, one for each symmetry-distinct site in the crystal. The order of FormFactors must correspond to the order of site symmetry classes, e.g., as they appear when printed in display(crystal).
source
Sunny.intensity_formulaMethod

A custom intensity formula can be specifed by providing a function intensity = f(q,ω,correlations) and specifying which correlations it requires:

intensity_formula(f,sc::SampledCorrelations, required_correlations; kwargs...)

The function is intended to be specified using do notation. For example, this custom formula sums the off-diagonal correlations:

required = [(:Sx,:Sy),(:Sy,:Sz),(:Sx,:Sz)]
 intensity_formula(sc,required,return_type = ComplexF64) do k, ω, off_diagonal_correlations
     sum(off_diagonal_correlations)
-end

If your custom formula returns a type other than Float64, use the return_type keyword argument to flag this.

source
Sunny.intensity_formulaMethod
formula = intensity_formula(swt::SpinWaveTheory; kernel = ...)

Establish a formula for computing the scattering intensity by diagonalizing the hamiltonian $H(q)$ using Linear Spin Wave Theory.

If kernel = delta_function_kernel, then the resulting formula can be used with intensities_bands.

If kernel is an energy broadening kernel function, then the resulting formula can be used with intensities_broadened. Energy broadening kernel functions can either be a function of Δω only, e.g.:

kernel = Δω -> ...

or a function of both the energy transfer ω and of Δω, e.g.:

kernel = (ω,Δω) -> ...

The integral of a properly normalized kernel function over all Δω is one.

source
Sunny.intensity_formulaMethod
intensity_formula([swt or sc], contraction_mode::Symbol)

Sunny has several built-in formulas that can be selected by setting contraction_mode to one of these values:

  • :trace (default), which yields $\operatorname{tr} 𝒮(q,ω) = ∑_α 𝒮^{αα}(q,ω)$
  • :perp, which contracts $𝒮^{αβ}(q,ω)$ with the dipole factor $δ_{αβ} - q_{α}q_{β}$, returning the unpolarized intensity.
  • :full, which will return all elements $𝒮^{αβ}(𝐪,ω)$ without contraction.
source
Sunny.lattice_paramsMethod
lattice_params(latvecs::Mat3)

Compute the lattice parameters $(a, b, c, α, β, γ)$ for the three lattice vectors provided as columns of latvecs. The inverse mapping is lattice_vectors.

source
Sunny.lattice_vectorsMethod
lattice_vectors(a, b, c, α, β, γ)

Return the lattice vectors, as columns of the $3×3$ output matrix, that correspond to the conventional unit cell defined by the lattice constants $(a, b, c)$ and the angles $(α, β, γ)$ in degrees. The inverse mapping is lattice_params.

source
Sunny.magnetic_momentMethod
magnetic_moment(sys::System, site::Site)

Get the magnetic moment for a Site. This is the spin dipole multiplied by the Bohr magneton and the local g-tensor.

source
Sunny.merge!Method
merge!(sc::SampledCorrelations, others...)

Accumulate the samples in others (one or more SampledCorrelations) into sc.

source
Sunny.minimize_energy!Method
minimize_energy!(sys::System{N}; maxiters=100, subiters=20,
-                 method=Optim.ConjugateGradient(), kwargs...) where N

Optimizes the spin configuration in sys to minimize energy. A total of maxiters iterations will be attempted, with restarts after every subiters iterations. The remaining kwargs will be forwarded to the optimize method of the Optim.jl package.

source
Sunny.position_to_siteMethod
position_to_site(sys::System, r)

Converts a position r to four indices of a Site. The coordinates of r are given in units of the lattice vectors for the original crystal. This function can be useful for working with systems that have been reshaped using reshape_supercell.

Example

# Find the `site` at the center of a unit cell which is displaced by four
+end

If your custom formula returns a type other than Float64, use the return_type keyword argument to flag this.

source
Sunny.intensity_formulaMethod
formula = intensity_formula(swt::SpinWaveTheory; kernel = ...)

Establish a formula for computing the scattering intensity by diagonalizing the hamiltonian $H(q)$ using Linear Spin Wave Theory.

If kernel = delta_function_kernel, then the resulting formula can be used with intensities_bands.

If kernel is an energy broadening kernel function, then the resulting formula can be used with intensities_broadened. Energy broadening kernel functions can either be a function of Δω only, e.g.:

kernel = Δω -> ...

or a function of both the energy transfer ω and of Δω, e.g.:

kernel = (ω,Δω) -> ...

The integral of a properly normalized kernel function over all Δω is one.

source
Sunny.intensity_formulaMethod
intensity_formula([swt or sc], contraction_mode::Symbol)

Sunny has several built-in formulas that can be selected by setting contraction_mode to one of these values:

  • :trace (default), which yields $\operatorname{tr} 𝒮(q,ω) = ∑_α 𝒮^{αα}(q,ω)$
  • :perp, which contracts $𝒮^{αβ}(q,ω)$ with the dipole factor $δ_{αβ} - q_{α}q_{β}$, returning the unpolarized intensity.
  • :full, which will return all elements $𝒮^{αβ}(𝐪,ω)$ without contraction.
source
Sunny.lattice_paramsMethod
lattice_params(latvecs::Mat3)

Compute the lattice parameters $(a, b, c, α, β, γ)$ for the three lattice vectors provided as columns of latvecs. The inverse mapping is lattice_vectors.

source
Sunny.lattice_vectorsMethod
lattice_vectors(a, b, c, α, β, γ)

Return the lattice vectors, as columns of the $3×3$ output matrix, that correspond to the conventional unit cell defined by the lattice constants $(a, b, c)$ and the angles $(α, β, γ)$ in degrees. The inverse mapping is lattice_params.

source
Sunny.magnetic_momentMethod
magnetic_moment(sys::System, site::Site)

Get the magnetic moment for a Site. This is the spin dipole multiplied by the Bohr magneton and the local g-tensor.

source
Sunny.merge!Method
merge!(sc::SampledCorrelations, others...)

Accumulate the samples in others (one or more SampledCorrelations) into sc.

source
Sunny.minimize_energy!Method
minimize_energy!(sys::System{N}; maxiters=100, subiters=20,
+                 method=Optim.ConjugateGradient(), kwargs...) where N

Optimizes the spin configuration in sys to minimize energy. A total of maxiters iterations will be attempted, with restarts after every subiters iterations. The remaining kwargs will be forwarded to the optimize method of the Optim.jl package.

source
Sunny.position_to_siteMethod
position_to_site(sys::System, r)

Converts a position r to four indices of a Site. The coordinates of r are given in units of the lattice vectors for the original crystal. This function can be useful for working with systems that have been reshaped using reshape_supercell.

Example

# Find the `site` at the center of a unit cell which is displaced by four
 # multiples of the first lattice vector
 site = position_to_site(sys, [4.5, 0.5, 0.5])
 
 # Print the dipole at this site
-println(sys.dipoles[site])
source
Sunny.powder_average_binnedMethod
powder_average_binned(sc::SampledCorrelations, radial_binning_parameters; formula
-                     ω_binning_parameters, integrated_kernel = nothing, bzsize = nothing)

This function emulates the experimental situation of "powder averaging," where only the magnitude (and not the direction) of the momentum transfer is resolvable. The intensities are binned similarly to intensities_binned, but the histogram x-axis is |k| in absolute units, which is a nonlinear function of kx,ky,kz. The y-axis is energy.

Radial binning parameters are specified as tuples (start,end,bin_width), e.g. radial_binning_parameters = (0,6π,6π/55).

Energy broadening is supported in the same way as intensities_binned, and this function accepts the same kind of intensity_formula.

source
Sunny.print_bondMethod
print_bond(cryst::Crystal, bond::Bond; b_ref::Bond)

Prints symmetry information for bond bond. A symmetry-equivalent reference bond b_ref can optionally be provided to fix the meaning of the coefficients A, B, ...

source
Sunny.print_siteMethod
print_site(cryst, i; R=I)

Print symmetry information for the site i, including allowed g-tensor and allowed anisotropy operator. An optional rotation matrix R can be provided to define the reference frame for expression of the anisotropy.

source
Sunny.print_stevens_expansionMethod
function print_stevens_expansion(op)

Prints a local Hermitian operator as a linear combination of Stevens operators. This function works on explicit matrix representations.

Examples

S = spin_matrices(N=5)
+println(sys.dipoles[site])
source
Sunny.powder_average_binnedMethod
powder_average_binned(sc::SampledCorrelations, radial_binning_parameters; formula
+                     ω_binning_parameters, integrated_kernel = nothing, bzsize = nothing)

This function emulates the experimental situation of "powder averaging," where only the magnitude (and not the direction) of the momentum transfer is resolvable. The intensities are binned similarly to intensities_binned, but the histogram x-axis is |k| in absolute units, which is a nonlinear function of kx,ky,kz. The y-axis is energy.

Radial binning parameters are specified as tuples (start,end,bin_width), e.g. radial_binning_parameters = (0,6π,6π/55).

Energy broadening is supported in the same way as intensities_binned, and this function accepts the same kind of intensity_formula.

source
Sunny.print_bondMethod
print_bond(cryst::Crystal, bond::Bond; b_ref::Bond)

Prints symmetry information for bond bond. A symmetry-equivalent reference bond b_ref can optionally be provided to fix the meaning of the coefficients A, B, ...

source
Sunny.print_siteMethod
print_site(cryst, i; R=I)

Print symmetry information for the site i, including allowed g-tensor and allowed anisotropy operator. An optional rotation matrix R can be provided to define the reference frame for expression of the anisotropy.

source
Sunny.print_stevens_expansionMethod
function print_stevens_expansion(op)

Prints a local Hermitian operator as a linear combination of Stevens operators. This function works on explicit matrix representations.

Examples

S = spin_matrices(N=5)
 print_stevens_expansion(S[1]^4 + S[2]^4 + S[3]^4)
-# Prints: (1/20)𝒪₄₀ + (1/4)𝒪₄₄ + 102/5
source
Sunny.print_suggested_frameMethod
print_suggested_frame(cryst, i; digits=4)

Print a suggested reference frame, as a rotation matrix R, that can be used as input to print_site(). This is useful to simplify the description of allowed anisotropies.

source
Sunny.print_symmetry_tableMethod
print_symmetry_table(cryst::Crystal, max_dist)

Print symmetry information for all equivalence classes of sites and bonds, up to a maximum bond distance of max_dist. Equivalent to calling print_bond(cryst, b) for every bond b in reference_bonds(cryst, max_dist), where Bond(i, i, [0,0,0]) refers to a single site i.

source
Sunny.print_wrapped_intensitiesMethod
print_wrapped_intensities(sys::System; nmax=10)

For Bravais lattices: Prints up to nmax wavevectors according to their instantaneous (static) structure factor intensities, listed in descending order. For non-Bravais lattices: Performs the same analysis for each spin sublattice independently; the output weights are naïvely averaged over sublattices, without incorporating phase shift information. Only wavevectors within the first Brillouin zone are printed. Wavevector coordinates are given in reciprocal lattice units, such that each coordinate is between $-1/2$ and $1/2$. The output from this function will typically be used as input to suggest_magnetic_supercell.

Because this function does not incorporate phase information in its averaging over sublattices, the printed weights are not directly comparable with experiment. For that purpose, use instant_correlations instead.

The weights printed by print_wrapped_intensities may be given a physical interpretation as follows: All possible $q$-vectors are periodically wrapped into the first Brillouin zone, and the average over their corresponding instantaneous structure factor intensities produce the output weights.

source
Sunny.propose_deltaMethod
propose_delta(magnitude)

Generate a proposal function that adds a Gaussian perturbation to the existing spin state. In :dipole mode, the procedure is to first introduce a random three-vector perturbation $𝐬′ = 𝐬 + |𝐬| ξ$ and then return the properly normalized spin $|𝐬| (𝐬′/|𝐬′|)$. Each component of the random vector $ξ$ is Gaussian distributed with a standard deviation of magnitude; the latter is dimensionless and typically smaller than one.

In :SUN mode, the procedure is analogous, but now involving Gaussian perturbations to each of the $N$ complex components of an SU(N) coherent state.

In the limit of very large magnitude, this function coincides with propose_uniform.

For use with LocalSampler.

source
Sunny.propose_flipMethod
propose_flip

Function to propose pure spin flip updates in the context of a LocalSampler. Dipoles are flipped as $𝐬 → -𝐬$. SU(N) coherent states are flipped using the time-reversal operator.

source
Sunny.propose_uniformFunction
propose_uniform

Function to propose a uniformly random spin update in the context of a LocalSampler. In :dipole mode, the result is a random three-vector with appropriate normalization. In :SUN mode, the result is a random SU(N) coherent state with appropriate normalization.

source
Sunny.reciprocal_lattice_vectorsMethod
reciprocal_lattice_vectors(cryst::Crystal)

Returns the $3×3$ matrix $(𝐛₁,𝐛₂,𝐛₃)$ with columns $𝐛ᵢ$ as reciprocal lattice vectors. These are defined to satisfy $𝐛ᵢ⋅𝐚ⱼ = 2πδᵢⱼ$, where $(𝐚₁,𝐚₂,𝐚₃)$ are the lattice vectors used to construct cryst.

source
Sunny.reciprocal_space_pathMethod
reciprocal_space_path(cryst::Crystal, qs, density)

Returns a pair (path, xticks). The path return value is a list of wavevectors that samples linearly between the provided wavevectors qs. The xticks return value can be used to label the special $𝐪$ values on the x-axis of a plot.

Special note about units: the wavevectors qs must be provided in reciprocal lattice units (RLU) for the given crystal, but the sampling density must be specified in units of inverse length. The path will therefore include more samples between q-points that are further apart in absolute Fourier distance (units of inverse length).

source
Sunny.reciprocal_space_path_binsMethod
reciprocal_space_path_bins(sc,qs,density,args...;kwargs...)

Takes a list of wave vectors, qs in R.L.U., and builds a series of histogram BinningParameters whose first axis traces a path through the provided points. The second and third axes are integrated over according to the args and kwargs, which are passed through to slice_2D_binning_parameters.

Also returned is a list of marker indices corresponding to the input points, and a list of ranges giving the indices of each histogram x-axis within a concatenated histogram. The density parameter is given in samples per reciprocal lattice unit (R.L.U.).

source
Sunny.reciprocal_space_shellMethod
reciprocal_space_shell(cryst::Crystal, radius, n)

Sample n points on the reciprocal space sphere with a given radius (units of inverse length).

Examples

# Sample wavevectors on the sphere at fixed density
-reciprocal_space_shell(cryst, r, 4π*r^2*density)
source
Sunny.reference_bondsMethod
reference_bonds(cryst::Crystal, max_dist)

Returns a full list of bonds, one for each symmetry equivalence class, up to distance max_dist. The reference bond b for each equivalence class is selected according to a scoring system that prioritizes simplification of the elements in basis_for_symmetry_allowed_couplings(cryst, b).

source
Sunny.remove_periodicity!Method
remove_periodicity!(sys::System, dims)

Remove periodic interactions along the dimensions where dims is true. The system must support inhomogeneous interactions via to_inhomogeneous.

Example

# Remove periodic boundaries along the 1st and 3rd dimensions
-remove_periodicity!(sys::System, (true, false, true))
source
Sunny.repeat_periodicallyMethod
repeat_periodically(sys::System{N}, counts) where N

Creates a System identical to sys but repeated a given number of times in each dimension, specified by the tuple counts.

source
Sunny.reshape_supercellMethod
reshape_supercell(sys::System, A)

Maps an existing System to a new one that has the shape and periodicity of a requested supercell. The columns of the $3×3$ integer matrix A represent the supercell lattice vectors measured in units of the original crystal lattice vectors.

The crystal unit cell may also need to be reshaped to achieve the desired periodicity of the requested supercell. If this is the case, the returned System object will be missing symmetry information. Consequently, certain operations will be unavailable for this system, e.g., setting interactions by symmetry propagation. In practice, one can set all interactions using the original system, and then reshape as a final step.

source
Sunny.resize_supercellMethod
resize_supercell(sys::System{N}, latsize) where N

Creates a System identical to sys but enlarged to a given number of unit cells in each lattice vector direction.

An error will be thrown if sys is incommensurate with latsize. Use reshape_supercell instead to reduce the volume, or to perform an incommensurate reshaping.

source
Sunny.rotate_operatorMethod
rotate_operator(A, R)

Rotates the local quantum operator A according to the $3×3$ rotation matrix R.

source
Sunny.rotation_in_rluMethod
rotation_in_rlu(cryst::Crystal, axis, angle)

Returns a $3×3$ matrix that rotates wavevectors in reciprocal lattice units (RLU). The axis vector is a real-space direction in absolute units (but arbitrary magnitude), and the angle is in radians.

source
Sunny.set_coherent!Method
set_coherent!(sys::System, Z, site::Site)

Set a coherent spin state at a Site using the $N$ complex amplitudes in Z.

For a standard SpinInfo, these amplitudes will be interpreted in the eigenbasis of $𝒮̂ᶻ$. That is, Z[1] represents the amplitude for the basis state fully polarized along the $ẑ$-direction, and subsequent components represent states with decreasing angular momentum along this axis ($m = S, S-1, …, -S$).

source
Sunny.set_exchange!Method
set_exchange!(sys::System, J, bond::Bond; biquad=0.)

Sets a 3×3 spin-exchange matrix J along bond, yielding a pairwise interaction energy $𝐒_i⋅J 𝐒_j$. This interaction will be propagated to equivalent bonds in consistency with crystal symmetry. Any previous exchange interactions on these bonds will be overwritten. The parameter bond has the form Bond(i, j, offset), where i and j are atom indices within the unit cell, and offset is a displacement in unit cells.

The parameter J may be scalar or matrix-valued. As a convenience, dmvec(D) can be used to construct the antisymmetric part of the exchange, where D is the Dzyaloshinskii-Moriya pseudo-vector. The resulting interaction will be $𝐃⋅(𝐒_i×𝐒_j)$.

The optional parameter biquad defines the strength $b$ for scalar biquadratic interactions of the form $b (𝐒_i⋅𝐒_j)²$ For systems restricted to dipoles, $b$ will be automatically renormalized for maximum consistency with the more variationally accurate SU(N) mode. This renormalization introduces also a correction to the quadratic part of the exchange.

Examples

using Sunny, LinearAlgebra
+# Prints: (1/20)𝒪₄₀ + (1/4)𝒪₄₄ + 102/5
source
Sunny.print_suggested_frameMethod
print_suggested_frame(cryst, i; digits=4)

Print a suggested reference frame, as a rotation matrix R, that can be used as input to print_site(). This is useful to simplify the description of allowed anisotropies.

source
Sunny.print_symmetry_tableMethod
print_symmetry_table(cryst::Crystal, max_dist)

Print symmetry information for all equivalence classes of sites and bonds, up to a maximum bond distance of max_dist. Equivalent to calling print_bond(cryst, b) for every bond b in reference_bonds(cryst, max_dist), where Bond(i, i, [0,0,0]) refers to a single site i.

source
Sunny.print_wrapped_intensitiesMethod
print_wrapped_intensities(sys::System; nmax=10)

For Bravais lattices: Prints up to nmax wavevectors according to their instantaneous (static) structure factor intensities, listed in descending order. For non-Bravais lattices: Performs the same analysis for each spin sublattice independently; the output weights are naïvely averaged over sublattices, without incorporating phase shift information. Only wavevectors within the first Brillouin zone are printed. Wavevector coordinates are given in reciprocal lattice units, such that each coordinate is between $-1/2$ and $1/2$. The output from this function will typically be used as input to suggest_magnetic_supercell.

Because this function does not incorporate phase information in its averaging over sublattices, the printed weights are not directly comparable with experiment. For that purpose, use instant_correlations instead.

The weights printed by print_wrapped_intensities may be given a physical interpretation as follows: All possible $q$-vectors are periodically wrapped into the first Brillouin zone, and the average over their corresponding instantaneous structure factor intensities produce the output weights.

source
Sunny.propose_deltaMethod
propose_delta(magnitude)

Generate a proposal function that adds a Gaussian perturbation to the existing spin state. In :dipole mode, the procedure is to first introduce a random three-vector perturbation $𝐬′ = 𝐬 + |𝐬| ξ$ and then return the properly normalized spin $|𝐬| (𝐬′/|𝐬′|)$. Each component of the random vector $ξ$ is Gaussian distributed with a standard deviation of magnitude; the latter is dimensionless and typically smaller than one.

In :SUN mode, the procedure is analogous, but now involving Gaussian perturbations to each of the $N$ complex components of an SU(N) coherent state.

In the limit of very large magnitude, this function coincides with propose_uniform.

For use with LocalSampler.

source
Sunny.propose_flipMethod
propose_flip

Function to propose pure spin flip updates in the context of a LocalSampler. Dipoles are flipped as $𝐬 → -𝐬$. SU(N) coherent states are flipped using the time-reversal operator.

source
Sunny.propose_uniformFunction
propose_uniform

Function to propose a uniformly random spin update in the context of a LocalSampler. In :dipole mode, the result is a random three-vector with appropriate normalization. In :SUN mode, the result is a random SU(N) coherent state with appropriate normalization.

source
Sunny.reciprocal_lattice_vectorsMethod
reciprocal_lattice_vectors(cryst::Crystal)

Returns the $3×3$ matrix $(𝐛₁,𝐛₂,𝐛₃)$ with columns $𝐛ᵢ$ as reciprocal lattice vectors. These are defined to satisfy $𝐛ᵢ⋅𝐚ⱼ = 2πδᵢⱼ$, where $(𝐚₁,𝐚₂,𝐚₃)$ are the lattice vectors used to construct cryst.

source
Sunny.reciprocal_space_pathMethod
reciprocal_space_path(cryst::Crystal, qs, density)

Returns a pair (path, xticks). The path return value is a list of wavevectors that samples linearly between the provided wavevectors qs. The xticks return value can be used to label the special $𝐪$ values on the x-axis of a plot.

Special note about units: the wavevectors qs must be provided in reciprocal lattice units (RLU) for the given crystal, but the sampling density must be specified in units of inverse length. The path will therefore include more samples between q-points that are further apart in absolute Fourier distance (units of inverse length).

source
Sunny.reciprocal_space_path_binsMethod
reciprocal_space_path_bins(sc,qs,density,args...;kwargs...)

Takes a list of wave vectors, qs in R.L.U., and builds a series of histogram BinningParameters whose first axis traces a path through the provided points. The second and third axes are integrated over according to the args and kwargs, which are passed through to slice_2D_binning_parameters.

Also returned is a list of marker indices corresponding to the input points, and a list of ranges giving the indices of each histogram x-axis within a concatenated histogram. The density parameter is given in samples per reciprocal lattice unit (R.L.U.).

source
Sunny.reciprocal_space_shellMethod
reciprocal_space_shell(cryst::Crystal, radius, n)

Sample n points on the reciprocal space sphere with a given radius (units of inverse length).

Examples

# Sample wavevectors on the sphere at fixed density
+reciprocal_space_shell(cryst, r, 4π*r^2*density)
source
Sunny.reference_bondsMethod
reference_bonds(cryst::Crystal, max_dist)

Returns a full list of bonds, one for each symmetry equivalence class, up to distance max_dist. The reference bond b for each equivalence class is selected according to a scoring system that prioritizes simplification of the elements in basis_for_symmetry_allowed_couplings(cryst, b).

source
Sunny.remove_periodicity!Method
remove_periodicity!(sys::System, dims)

Remove periodic interactions along the dimensions where dims is true. The system must support inhomogeneous interactions via to_inhomogeneous.

Example

# Remove periodic boundaries along the 1st and 3rd dimensions
+remove_periodicity!(sys::System, (true, false, true))
source
Sunny.repeat_periodicallyMethod
repeat_periodically(sys::System{N}, counts) where N

Creates a System identical to sys but repeated a given number of times in each dimension, specified by the tuple counts.

source
Sunny.reshape_supercellMethod
reshape_supercell(sys::System, A)

Maps an existing System to a new one that has the shape and periodicity of a requested supercell. The columns of the $3×3$ integer matrix A represent the supercell lattice vectors measured in units of the original crystal lattice vectors.

The crystal unit cell may also need to be reshaped to achieve the desired periodicity of the requested supercell. If this is the case, the returned System object will be missing symmetry information. Consequently, certain operations will be unavailable for this system, e.g., setting interactions by symmetry propagation. In practice, one can set all interactions using the original system, and then reshape as a final step.

source
Sunny.resize_supercellMethod
resize_supercell(sys::System{N}, latsize) where N

Creates a System identical to sys but enlarged to a given number of unit cells in each lattice vector direction.

An error will be thrown if sys is incommensurate with latsize. Use reshape_supercell instead to reduce the volume, or to perform an incommensurate reshaping.

source
Sunny.rotate_operatorMethod
rotate_operator(A, R)

Rotates the local quantum operator A according to the $3×3$ rotation matrix R.

source
Sunny.rotation_in_rluMethod
rotation_in_rlu(cryst::Crystal, axis, angle)

Returns a $3×3$ matrix that rotates wavevectors in reciprocal lattice units (RLU). The axis vector is a real-space direction in absolute units (but arbitrary magnitude), and the angle is in radians.

source
Sunny.set_coherent!Method
set_coherent!(sys::System, Z, site::Site)

Set a coherent spin state at a Site using the $N$ complex amplitudes in Z.

For a standard SpinInfo, these amplitudes will be interpreted in the eigenbasis of $𝒮̂ᶻ$. That is, Z[1] represents the amplitude for the basis state fully polarized along the $ẑ$-direction, and subsequent components represent states with decreasing angular momentum along this axis ($m = S, S-1, …, -S$).

source
Sunny.set_exchange!Method
set_exchange!(sys::System, J, bond::Bond; biquad=0.)

Sets a 3×3 spin-exchange matrix J along bond, yielding a pairwise interaction energy $𝐒_i⋅J 𝐒_j$. This interaction will be propagated to equivalent bonds in consistency with crystal symmetry. Any previous exchange interactions on these bonds will be overwritten. The parameter bond has the form Bond(i, j, offset), where i and j are atom indices within the unit cell, and offset is a displacement in unit cells.

The parameter J may be scalar or matrix-valued. As a convenience, dmvec(D) can be used to construct the antisymmetric part of the exchange, where D is the Dzyaloshinskii-Moriya pseudo-vector. The resulting interaction will be $𝐃⋅(𝐒_i×𝐒_j)$.

The optional parameter biquad defines the strength $b$ for scalar biquadratic interactions of the form $b (𝐒_i⋅𝐒_j)²$ For systems restricted to dipoles, $b$ will be automatically renormalized for maximum consistency with the more variationally accurate SU(N) mode. This renormalization introduces also a correction to the quadratic part of the exchange.

Examples

using Sunny, LinearAlgebra
 
 # An explicit exchange matrix
 J1 = [2 3 0;
@@ -57,7 +57,7 @@
 
 # An equivalent Heisenberg + DM exchange 
 J2 = 2*I + dmvec([0,0,3])
-set_exchange!(sys, J2, bond)
source
Sunny.set_exchange_at!Method
set_exchange_at!(sys::System, J, site1::Site, site2::Site; biquad=0., offset=nothing)

Sets the exchange interaction along the single bond connecting two Sites, ignoring crystal symmetry. The system must support inhomogeneous interactions via to_inhomogeneous.

If the system is relatively small, the direction of the bond can be ambiguous due to possible periodic wrapping. Resolve this ambiguity by passing an explicit offset vector, in multiples of unit cells.

See also set_exchange!.

source
Sunny.set_external_field_at!Method
set_external_field_at!(sys::System, B::Vec3, site::Site)

Sets a Zeeman coupling between a field B and a single spin. Site includes a unit cell and a sublattice index.

source
Sunny.set_onsite_coupling!Method
set_onsite_coupling!(sys::System, op::Matrix{ComplexF64}, i::Int)

Set the single-ion anisotropy for the ith atom of every unit cell, as well as all symmetry-equivalent atoms. The local operator op may be constructed using spin_operators or stevens_operators.

For systems restricted to dipoles, the anisotropy operators interactions will automatically be renormalized to achieve maximum consistency with the more variationally accurate SU(N) mode.

Examples

# An easy axis anisotropy in the z-direction
+set_exchange!(sys, J2, bond)
source
Sunny.set_exchange_at!Method
set_exchange_at!(sys::System, J, site1::Site, site2::Site; biquad=0., offset=nothing)

Sets the exchange interaction along the single bond connecting two Sites, ignoring crystal symmetry. The system must support inhomogeneous interactions via to_inhomogeneous.

If the system is relatively small, the direction of the bond can be ambiguous due to possible periodic wrapping. Resolve this ambiguity by passing an explicit offset vector, in multiples of unit cells.

See also set_exchange!.

source
Sunny.set_external_field_at!Method
set_external_field_at!(sys::System, B::Vec3, site::Site)

Sets a Zeeman coupling between a field B and a single spin. Site includes a unit cell and a sublattice index.

source
Sunny.set_onsite_coupling!Method
set_onsite_coupling!(sys::System, op::Matrix{ComplexF64}, i::Int)

Set the single-ion anisotropy for the ith atom of every unit cell, as well as all symmetry-equivalent atoms. The local operator op may be constructed using spin_operators or stevens_operators.

For systems restricted to dipoles, the anisotropy operators interactions will automatically be renormalized to achieve maximum consistency with the more variationally accurate SU(N) mode.

Examples

# An easy axis anisotropy in the z-direction
 S = spin_operators(sys, i)
 set_onsite_coupling!(sys, -D*S[3]^3, i)
 
@@ -67,15 +67,15 @@
 set_onsite_coupling!(sys, O[4,0] + 5*O[4,4], i)
 
 # An equivalent expression of this quartic anisotropy, up to a constant shift
-set_onsite_coupling!(sys, 20*(S[1]^4 + S[2]^4 + S[3]^4), i)

See also spin_operators.

source
Sunny.set_vacancy_at!Method
set_vacancy_at!(sys::System, site::Site)

Make a single site nonmagnetic. Site includes a unit cell and a sublattice index.

source
Sunny.slice_2D_binning_parametersMethod
slice_2D_binning_parameter(sc::SampledCorrelations, cut_from_q, cut_to_q, cut_bins::Int64, cut_width::Float64; plane_normal = [0,0,1],cut_height = cutwidth)

Creates BinningParameters which make a cut along one dimension of Q-space.

The x-axis of the resulting histogram consists of cut_bins-many bins ranging from cut_from_q to cut_to_q. The width of the bins in the transverse direciton is controlled by cut_width and cut_height.

The binning in the transverse directions is defined in the following way, which sets their normalization and orthogonality properties:

cut_covector = normalize(cut_to_q - cut_from_q)
+set_onsite_coupling!(sys, 20*(S[1]^4 + S[2]^4 + S[3]^4), i)

See also spin_operators.

source
Sunny.set_vacancy_at!Method
set_vacancy_at!(sys::System, site::Site)

Make a single site nonmagnetic. Site includes a unit cell and a sublattice index.

source
Sunny.slice_2D_binning_parametersMethod
slice_2D_binning_parameter(sc::SampledCorrelations, cut_from_q, cut_to_q, cut_bins::Int64, cut_width::Float64; plane_normal = [0,0,1],cut_height = cutwidth)

Creates BinningParameters which make a cut along one dimension of Q-space.

The x-axis of the resulting histogram consists of cut_bins-many bins ranging from cut_from_q to cut_to_q. The width of the bins in the transverse direciton is controlled by cut_width and cut_height.

The binning in the transverse directions is defined in the following way, which sets their normalization and orthogonality properties:

cut_covector = normalize(cut_to_q - cut_from_q)
 transverse_covector = normalize(plane_normal × cut_covector)
-cotransverse_covector = normalize(transverse_covector × cut_covector)

In other words, the axes are orthonormal with respect to the Euclidean metric.

If the cut is too narrow, there will be very few scattering vectors per bin, or the number per bin will vary substantially along the cut. If the output appears under-resolved, try increasing cut_width.

The four axes of the resulting histogram are:

  1. Along the cut
  2. Fist transverse Q direction
  3. Second transverse Q direction
  4. Energy

This function can be used without reference to a SampledCorrelations using this alternate syntax to manually specify the bin centers for the energy axis:

slice_2D_binning_parameter(ω_bincenters, cut_from, cut_to,...)

where ω_bincenters specifies the energy axis, and both cut_from and cut_to are arbitrary covectors, in any units.

source
Sunny.spin_matricesMethod
spin_matrices(; N)

Constructs the three spin operators, i.e. the generators of SU(2), in the N-dimensional irrep. See also spin_operators, which determines the appropriate value of N for a given site index.

source
Sunny.step!Function
step!(sys::System, dynamics)

Advance the spin configuration one dynamical time-step. The dynamics object may be a continuous spin dynamics, such as Langevin or ImplicitMidpoint, or it may be a discrete Monte Carlo sampling scheme such as LocalSampler.

source
Sunny.stevens_operatorsMethod
stevens_operators(sys, i::Int)
-stevens_operators(sys, site::Int)

Returns a generator of Stevens operators appropriate to an atom or Site index. The return value O can be indexed as O[k,q], where $0 ≤ k ≤ 6$ labels an irrep and $q = -k, …, k$. This will produce an $N×N$ matrix of appropriate dimension $N$.

source
Sunny.subcrystalMethod
subcrystal(cryst, types) :: Crystal

Filters sublattices of a Crystal by atom types, keeping the space group unchanged.

subcrystal(cryst, classes) :: Crystal

Filters sublattices of Crystal by equivalence classes, keeping the space group unchanged.

source
Sunny.suggest_magnetic_supercellMethod
suggest_magnetic_supercell(qs, latsize)

Suggests a magnetic supercell, in units of the crystal lattice vectors, that is consistent with periodicity of the wavevectors in qs. An upper bound for the supercell is given by latsize, which is measured in units of lattice vectors, and must be commensurate with the wavevectors.

source
Sunny.symmetry_equivalent_bondsMethod
symmetry_equivalent_bonds(sys::System, bond::Bond)

Given a Bond for the original (unreshaped) crystal, return all symmetry equivalent bonds in the System. Each returned bond is represented as a pair of Sites, which may be used as input to set_exchange_at!. Reverse bonds are not included (no double counting).

Example

for (site1, site2, offset) in symmetry_equivalent_bonds(sys, bond)
+cotransverse_covector = normalize(transverse_covector × cut_covector)

In other words, the axes are orthonormal with respect to the Euclidean metric.

If the cut is too narrow, there will be very few scattering vectors per bin, or the number per bin will vary substantially along the cut. If the output appears under-resolved, try increasing cut_width.

The four axes of the resulting histogram are:

  1. Along the cut
  2. Fist transverse Q direction
  3. Second transverse Q direction
  4. Energy

This function can be used without reference to a SampledCorrelations using this alternate syntax to manually specify the bin centers for the energy axis:

slice_2D_binning_parameter(ω_bincenters, cut_from, cut_to,...)

where ω_bincenters specifies the energy axis, and both cut_from and cut_to are arbitrary covectors, in any units.

source
Sunny.spin_matricesMethod
spin_matrices(; N)

Constructs the three spin operators, i.e. the generators of SU(2), in the N-dimensional irrep. See also spin_operators, which determines the appropriate value of N for a given site index.

source
Sunny.step!Function
step!(sys::System, dynamics)

Advance the spin configuration one dynamical time-step. The dynamics object may be a continuous spin dynamics, such as Langevin or ImplicitMidpoint, or it may be a discrete Monte Carlo sampling scheme such as LocalSampler.

source
Sunny.stevens_operatorsMethod
stevens_operators(sys, i::Int)
+stevens_operators(sys, site::Int)

Returns a generator of Stevens operators appropriate to an atom or Site index. The return value O can be indexed as O[k,q], where $0 ≤ k ≤ 6$ labels an irrep and $q = -k, …, k$. This will produce an $N×N$ matrix of appropriate dimension $N$.

source
Sunny.subcrystalMethod
subcrystal(cryst, types) :: Crystal

Filters sublattices of a Crystal by atom types, keeping the space group unchanged.

subcrystal(cryst, classes) :: Crystal

Filters sublattices of Crystal by equivalence classes, keeping the space group unchanged.

source
Sunny.suggest_magnetic_supercellMethod
suggest_magnetic_supercell(qs, latsize)

Suggests a magnetic supercell, in units of the crystal lattice vectors, that is consistent with periodicity of the wavevectors in qs. An upper bound for the supercell is given by latsize, which is measured in units of lattice vectors, and must be commensurate with the wavevectors.

source
Sunny.symmetry_equivalent_bondsMethod
symmetry_equivalent_bonds(sys::System, bond::Bond)

Given a Bond for the original (unreshaped) crystal, return all symmetry equivalent bonds in the System. Each returned bond is represented as a pair of Sites, which may be used as input to set_exchange_at!. Reverse bonds are not included (no double counting).

Example

for (site1, site2, offset) in symmetry_equivalent_bonds(sys, bond)
     @assert site1 < site2
     set_exchange_at!(sys, J, site1, site2; offset)
-end
source
Sunny.unit_resolution_binning_parametersMethod
unit_resolution_binning_parameters(sc::SampledCorrelations)

Create BinningParameters which place one histogram bin centered at each possible (q,ω) scattering vector of the crystal. This is the finest possible binning without creating bins with zero scattering vectors in them.

This function can be used without reference to a SampledCorrelations using an alternate syntax to manually specify the bin centers for the energy axis and the lattice size:

unit_resolution_binning_parameters(ω_bincenters,latsize,[reciprocal lattice vectors])

The last argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or a Crystal.

Lastly, binning parameters for a single axis may be specifed by their bin centers:

(binstart,binend,binwidth) = unit_resolution_binning_parameters(bincenters::Vector{Float64})
source
Sunny.view_crystalMethod
view_crystal(crystal::Crystal, max_dist::Real)

Create and show crystal viewer in a VSCode or Jupyter notebook environment. The result can also be displayed using browser().

source
Sunny.@mix_proposalsMacro
@mix_proposals weight1 propose1 weight2 propose2 ...

Macro to generate a proposal function that randomly selects among the provided functions according to the provided probability weights. For use with LocalSampler.

Example

# A proposal function that proposes a spin flip 40% of the time, and a
+end
source
Sunny.unit_resolution_binning_parametersMethod
unit_resolution_binning_parameters(sc::SampledCorrelations)

Create BinningParameters which place one histogram bin centered at each possible (q,ω) scattering vector of the crystal. This is the finest possible binning without creating bins with zero scattering vectors in them.

This function can be used without reference to a SampledCorrelations using an alternate syntax to manually specify the bin centers for the energy axis and the lattice size:

unit_resolution_binning_parameters(ω_bincenters,latsize,[reciprocal lattice vectors])

The last argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or a Crystal.

Lastly, binning parameters for a single axis may be specifed by their bin centers:

(binstart,binend,binwidth) = unit_resolution_binning_parameters(bincenters::Vector{Float64})
source
Sunny.view_crystalMethod
view_crystal(crystal::Crystal, max_dist::Real)

Create and show crystal viewer in a VSCode or Jupyter notebook environment. The result can also be displayed using browser().

source
Sunny.@mix_proposalsMacro
@mix_proposals weight1 propose1 weight2 propose2 ...

Macro to generate a proposal function that randomly selects among the provided functions according to the provided probability weights. For use with LocalSampler.

Example

# A proposal function that proposes a spin flip 40% of the time, and a
 # Gaussian perturbation 60% of the time.
-@mix_proposals 0.4 propose_flip 0.6 propose_delta(0.2)
source

Optional Makie extensions

The following will be enabled through a package extension if either GLMakie or WGLMakie is loaded.

Sunny.plot_spinsFunction
plot_spins(sys::System; arrowscale=1.0, linecolor=:lightgrey,
+@mix_proposals 0.4 propose_flip 0.6 propose_delta(0.2)
source

Optional Makie extensions

The following will be enabled through a package extension if either GLMakie or WGLMakie is loaded.

Sunny.plot_spinsFunction
plot_spins(sys::System; arrowscale=1.0, linecolor=:lightgrey,
            arrowcolor=:red, show_axis=false, show_cell=true,
-           orthographic=false, ghost_radius=0)

Plot the spin configuration defined by sys. Optional parameters include:

  • arrowscale: Scale all arrows by dimensionless factor.
  • show_axis: Show global Cartesian coordinates axis.
  • show_cell: Show original crystallographic unit cell.
  • orthographic: Use camera with orthographic projection.
  • ghost_radius: Show translucent periodic images up to a radius, given as a multiple of the characteristic distance between sites.
source

Optional WriteVTK extensions

The following will be enabled through a package extension if WriteVTK is loaded.

Sunny.export_vtkFunction
export_vtk(filename,params::BinningParameters,data)

Export a VTK-compatible file to filename (do not include file extension when specifying the file name) which contains the data as VTK Cell Data on a grid parameterized by params.

At least one axis of the BinningParameters must be integrated over, since VTK does not support 4D data. See integrate_axes!.

source
+ orthographic=false, ghost_radius=0)

Plot the spin configuration defined by sys. Optional parameters include:

  • arrowscale: Scale all arrows by dimensionless factor.
  • show_axis: Show global Cartesian coordinates axis.
  • show_cell: Show original crystallographic unit cell.
  • orthographic: Use camera with orthographic projection.
  • ghost_radius: Show translucent periodic images up to a radius, given as a multiple of the characteristic distance between sites.
source

Optional WriteVTK extensions

The following will be enabled through a package extension if WriteVTK is loaded.

Sunny.export_vtkFunction
export_vtk(filename,params::BinningParameters,data)

Export a VTK-compatible file to filename (do not include file extension when specifying the file name) which contains the data as VTK Cell Data on a grid parameterized by params.

At least one axis of the BinningParameters must be integrated over, since VTK does not support 4D data. See integrate_axes!.

source
diff --git a/dev/search/index.html b/dev/search/index.html index b3189a0ea..4b5b64e92 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · Sunny documentation +Search · Sunny documentation diff --git a/dev/search_index.js b/dev/search_index.js index c6c977eff..83b5e66cf 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"EditURL = \"../../../examples/fei2_tutorial.jl\"","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/fei2_tutorial/#Case-Study:-FeI_{2}","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"FeI_2 is an effective spin-1 material with strong single-ion anisotropy. Quadrupolar fluctuations give rise to a single-ion bound state that cannot be described by a dipole-only model. This tutorial illustrates how to use the linear spin wave theory of SU(3) coherent states (i.e. 2-flavor bosons) to model the magnetic behavior in FeI_2. The original study was performed in Bai et al., Nature Physics 17, 467–472 (2021).","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The Fe atoms are arranged in stacked triangular layers. The effective spin interactions include various anisotropic exchange interactions, and a strong single-ion anisotropy:","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"mathcalH=sum_(ij) J^alphabeta_ij S^alpha_i S^beta_j - Dsum_i left(S^zright)^2","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"We will formulate this Hamiltonian in Sunny and then calculate its dynamic structure factor.","category":"page"},{"location":"examples/fei2_tutorial/#Get-Julia-and-Sunny","page":"Case Study: FeI_2","title":"Get Julia and Sunny","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Sunny is implemented in Julia. This is a relatively new programming language that allows for interactive development (like Python or Matlab) while also providing high numerical efficiency (like C++ or Fortran). New Julia users may wish to take a look at our Getting Started with Julia guide. Sunny requires Julia 1.9 or later.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"From the Julia prompt, load Sunny. For plotting, one can choose either GLMakie (a pop-up window) or WGLMakie (inline plots for a Jupyter notebook or VSCode).","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"using Sunny, GLMakie","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"If these packages are not yet installed, Julia should offer to install them using its built-in package management system. If old versions are installed, you may need to update them to run this tutorial.","category":"page"},{"location":"examples/fei2_tutorial/#Crystals","page":"Case Study: FeI_2","title":"Crystals","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"A Crystal describes the crystallographic unit cell and will usually be loaded from a .cif file. Here, we instead build a crystal by listing all atoms and their types.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"a = b = 4.05012 # Lattice constants for triangular lattice\nc = 6.75214 # Spacing in the z-direction\n\nlatvecs = lattice_vectors(a, b, c, 90, 90, 120) # A 3x3 matrix of lattice vectors that\n # define the conventional unit cell\npositions = [[0, 0, 0], [1/3, 2/3, 1/4], [2/3, 1/3, 3/4]] # Positions of atoms in fractions\n # of lattice vectors\ntypes = [\"Fe\", \"I\", \"I\"]\nFeI2 = Crystal(latvecs, positions; types)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Observe that Sunny inferred the space group, 'P -3 m 1' (164) and labeled the atoms according to their point group symmetries.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Only the Fe atoms are magnetic, so we discard the I ions using subcrystal.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"cryst = subcrystal(FeI2, \"Fe\")","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Importantly, cryst retains the spacegroup symmetry of the full FeI_2 crystal. This information will be used, for example, to propagate exchange interactions between symmetry-equivalent bonds.","category":"page"},{"location":"examples/fei2_tutorial/#Symmetry-analysis","page":"Case Study: FeI_2","title":"Symmetry analysis","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The command print_symmetry_table provides a list of all the symmetry-allowed interactions up to a cutoff distance.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"print_symmetry_table(cryst, 8.0)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The allowed g-tensor is expressed as a 3×3 matrix in the free coefficients A, B, ... The allowed single-ion anisotropy is expressed as a linear combination of Stevens operators. The latter correspond to polynomials of the spin operators, as we will describe below.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The allowed exchange interactions are given as a 3×3 matrix for representative bonds. The notation Bond(i, j, n) indicates a bond between atom indices i and j, with cell offset n. In the general case, it will be necessary to associate atom indices with their positions in the unit cell; these can be viewed with display(cryst). Note that the order of the pair (i j) is significant if the exchange tensor contains antisymmetric Dzyaloshinskii–Moriya (DM) interactions.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"In the case of FeI_2, Bond(1, 1, [1,0,0]) is one of the 6 nearest-neighbor Fe-Fe bonds on a triangular lattice layer, and Bond(1, 1, [0,0,1]) is an Fe-Fe bond between layers.","category":"page"},{"location":"examples/fei2_tutorial/#Building-a-spin-System","page":"Case Study: FeI_2","title":"Building a spin System","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"In constructing a spin System, we must provide several additional details about the spins.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sys = System(cryst, (4,4,4), [SpinInfo(1, S=1, g=2)], :SUN, seed=2)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"This system includes 444 unit cells, i.e. 64 Fe atoms, each with spin S=1 and a g-factor of 2. Quantum mechanically, spin S=1 involves a superposition of 2S+1=3 distinct angular momentum states. In :SUN mode, this superposition will be modeled explicitly using the formalism of SU(3) coherent states, which captures both dipolar and quadrupolar fluctuations. For the more traditional dipole dynamics, use :dipole mode instead.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Next we will use set_exchange! to assign interaction to bonds. Sunny will automatically propagate each interaction to all symmetry-equivalent bonds in the unit cell. The FeI_2 interactions below follow Bai et al.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"J1pm = -0.236\nJ1pmpm = -0.161\nJ1zpm = -0.261\nJ2pm = 0.026\nJ3pm = 0.166\nJ′0pm = 0.037\nJ′1pm = 0.013\nJ′2apm = 0.068\n\nJ1zz = -0.236\nJ2zz = 0.113\nJ3zz = 0.211\nJ′0zz = -0.036\nJ′1zz = 0.051\nJ′2azz = 0.073\n\nJ1xx = J1pm + J1pmpm\nJ1yy = J1pm - J1pmpm\nJ1yz = J1zpm\n\nset_exchange!(sys, [J1xx 0.0 0.0;\n 0.0 J1yy J1yz;\n 0.0 J1yz J1zz], Bond(1,1,[1,0,0]))\nset_exchange!(sys, [J2pm 0.0 0.0;\n 0.0 J2pm 0.0;\n 0.0 0.0 J2zz], Bond(1,1,[1,2,0]))\nset_exchange!(sys, [J3pm 0.0 0.0;\n 0.0 J3pm 0.0;\n 0.0 0.0 J3zz], Bond(1,1,[2,0,0]))\nset_exchange!(sys, [J′0pm 0.0 0.0;\n 0.0 J′0pm 0.0;\n 0.0 0.0 J′0zz], Bond(1,1,[0,0,1]))\nset_exchange!(sys, [J′1pm 0.0 0.0;\n 0.0 J′1pm 0.0;\n 0.0 0.0 J′1zz], Bond(1,1,[1,0,1]))\nset_exchange!(sys, [J′2apm 0.0 0.0;\n 0.0 J′2apm 0.0;\n 0.0 0.0 J′2azz], Bond(1,1,[1,2,1]))","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The function set_onsite_coupling! assigns a single-ion anisotropy operator. It can be constructed, e.g., from the matrices given by spin_operators or stevens_operators. Here we construct an easy-axis anisotropy along the direction hatz.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"D = 2.165\nS = spin_operators(sys, 1)\nset_onsite_coupling!(sys, -D*S[3]^2, 1)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Any anisotropy operator can be converted to a linear combination of Stevens operators with print_stevens_expansion.","category":"page"},{"location":"examples/fei2_tutorial/#Calculating-structure-factor-intensities","page":"Case Study: FeI_2","title":"Calculating structure factor intensities","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"In the remainder of this tutorial, we will examine Sunny's tools for calculating the dynamical structure factor using a multi-boson generalization of linear spin wave theory (LSWT). This theory describes non-interacting quasi-particle excitations that hybridize dipolar and quadrupolar modes.","category":"page"},{"location":"examples/fei2_tutorial/#Finding-the-ground-state","page":"Case Study: FeI_2","title":"Finding the ground state","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Begin with a random configuration and use minimize_energy! to find a configuration of the SU(3) coherent states (i.e. spin dipoles and quadrupoles) that locally minimizes energy.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"randomize_spins!(sys)\nminimize_energy!(sys);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The expected ground state for FeI_2 is an antiferrogmanetic striped phase with a period of four spins (two up, two down). Visualizing the result of optimization, however, may indicate the system got stuck in a local minimum with defects.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"plot_spins(sys)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"A better understanding of the magnetic ordering can often be obtained by moving to Fourier space. The 'instant' structure factor 𝒮(𝐪) is an experimental observable. To investigate 𝒮(𝐪) as true 3D data, Sunny provides instant_correlations and related functions. Here, however, we will use the lighter weight function print_wrapped_intensities to get a quick understanding of the periodicities present in the spin configuration.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"print_wrapped_intensities(sys)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The precise output may vary with Sunny version due to, e.g., different floating point roundoff effects. Very likely, however, the result will be approximately consistent with the known zero-field energy-minimizing magnetic structure of FeI_2, which is single-Q. Mathematically, spontaneous symmetry breaking should select one of Q = 0 -14 14, 14 0 14, or -141414, associated with the three-fold rotational symmetry of the crystal spacegroup. In practice, however, one will frequently encounter competing \"domains\" associated with the three possible orientations of the ground state.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"If the desired ground state is already known, as with FeI_2, it could be entered by hand using set_dipole!. Alternatively, in the case of FeI_2, we could repeatedly employ the above randomization and minimization procedure until a defect-free configuration is found. Some systems will have more complicated ground states, which can be much more challenging to find. For this, Sunny provides experimental support for powerful simulated annealing via parallel tempering, but that is outside the scope of this tutorial.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Here, let's break the three-fold symmetry of FeI_2 by hand. Given one or more desired Q modes, Sunny can suggest a magnetic supercell with appropriate periodicity. Let's arbitrarily select one of the three possible ordering wavevectors, Q = 0 -14 14. Sunny suggest a corresponding magnetic supercell in units of the crystal lattice vectors.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"suggest_magnetic_supercell([[0, -1/4, 1/4]], sys.latsize)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The function reshape_supercell allows an arbitrary reshaping of the system's supercell. We select the supercell appropriate to the broken-symmetry ground-state, which makes optimization much easier.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sys_min = reshape_supercell(sys, [1 0 0; 0 1 -2; 0 1 2])\nrandomize_spins!(sys_min)\nminimize_energy!(sys_min)\nplot_spins(sys_min; ghost_radius=3)","category":"page"},{"location":"examples/fei2_tutorial/#Linear-spin-wave-theory","page":"Case Study: FeI_2","title":"Linear spin wave theory","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Now that we have found the ground state for a magnetic supercell, we can immediately proceed to perform zero-temperature calculations using linear spin wave theory. We begin by instantiating a SpinWaveTheory type using the supercell.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"swt = SpinWaveTheory(sys_min)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Select a sequence of wavevectors that will define a piecewise linear interpolation in reciprocal lattice units (RLU).","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"q_points = [[0,0,0], [1,0,0], [0,1,0], [1/2,0,0], [0,1,0], [0,0,0]];\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The function reciprocal_space_path will linearly sample a path between the provided q-points with a given density. The xticks return value provides labels for use in plotting.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"density = 50\npath, xticks = reciprocal_space_path(cryst, q_points, density);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The dispersion function defines the quasiparticle excitation energies ω_i(𝐪) for each point 𝐪 along the reciprocal space path.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"disp = dispersion(swt, path);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"In addition to the band energies ω_i(𝐪), Sunny can calculate the inelastic neutron scattering intensity I_i(𝐪) for each band i according to an intensity_formula. We choose to apply a polarization correction (1 - 𝐪𝐪) by setting the mode argument to :perp. Selecting delta_function_kernel specifies that we want the energy and intensity of each band individually.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"formula = intensity_formula(swt, :perp; kernel=delta_function_kernel)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The function intensities_bands uses linear spin wave theory to calculate both the dispersion and intensity data for the provided path.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"disp, intensity = intensities_bands(swt, path, formula);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"These can be plotted in GLMakie.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"fig = Figure()\nax = Axis(fig[1,1]; xlabel=\"𝐪\", ylabel=\"Energy (meV)\", xticks, xticklabelrotation=π/6)\nylims!(ax, 0.0, 7.5)\nxlims!(ax, 1, size(disp, 1))\ncolorrange = extrema(intensity)\nfor i in axes(disp)[2]\n lines!(ax, 1:length(disp[:,i]), disp[:,i]; color=intensity[:,i], colorrange)\nend\nfig","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"To make comparisons with inelastic neutron scattering (INS) data, it is helpful to employ an empirical broadening kernel, e.g., a lorentzian.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"γ = 0.15 # width in meV\nbroadened_formula = intensity_formula(swt, :perp; kernel=lorentzian(γ))","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The intensities_broadened function requires an energy range in addition to the 𝐪-space path.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"energies = collect(0:0.01:10) # 0 < ω < 10 (meV).\nis1 = intensities_broadened(swt, path, energies, broadened_formula);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"A real FeI_2 sample will exhibit competing magnetic domains associated with spontaneous symmetry breaking of the 6-fold rotational symmetry of the triangular lattice. Note that the wavevectors 𝐪 and -𝐪 are equivalent in the structure factor, which leaves three distinct domain orientations, which are related by 120° rotations about the z-axis. Rather than rotating the spin configuration directly, on can rotate the 𝐪-space path. Below, we use rotation_in_rlu to average the intensities over all three possible orientations.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"R = rotation_in_rlu(cryst, [0, 0, 1], 2π/3)\nis2 = intensities_broadened(swt, [R*q for q in path], energies, broadened_formula)\nis3 = intensities_broadened(swt, [R*R*q for q in path], energies, broadened_formula)\nis_averaged = (is1 + is2 + is3) / 3\n\nfig = Figure()\nax = Axis(fig[1,1]; xlabel=\"(H,0,0)\", ylabel=\"Energy (meV)\", xticks, xticklabelrotation=π/6)\nheatmap!(ax, 1:size(is_averaged, 1), energies, is_averaged)\nfig","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"This result can be directly compared to experimental neutron scattering data from Bai et al.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"(The publication figure accidentally used a non-standard coordinate system to label the wave vectors.)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"To get this agreement, the use of SU(3) coherent states is essential. In other words, we needed a theory of multi-flavored bosons. The lower band has large quadrupolar character, and arises from the strong easy-axis anisotropy of FeI_2. By setting mode = :SUN, the calculation captures this coupled dipole-quadrupole dynamics.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"An interesting exercise is to repeat the same study, but using mode = :dipole instead of :SUN. That alternative choice would constrain the coherent state dynamics to the space of dipoles only.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The full dynamical spin structure factor (DSSF) can be retrieved as a 33 matrix with the dssf function, for a given path of 𝐪-vectors.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"disp, is = dssf(swt, path);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The first output disp is identical to that obtained from dispersion. The second output is contains a list of 33 matrix of intensities. For example, is[q,n][2,3] yields the (yz) component of the structure factor intensity for nth mode at the qth wavevector in the path.","category":"page"},{"location":"examples/fei2_tutorial/#What's-next?","page":"Case Study: FeI_2","title":"What's next?","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The multi-boson linear spin wave theory, applied above, can be understood as the quantization of a certain generalization of the Landau-Lifshitz spin dynamics. Rather than dipoles, this dynamics takes places on the space of SU(N) coherent states.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The full SU(N) coherent state dynamics, with appropriate quantum correction factors, can be useful to model finite temperature scattering data. In particular, it captures certain anharmonic effects due to thermal fluctuations. This is the subject of our Structure Factors with Classical Dynamics tutorial.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The classical dynamics is also a good starting point to study non-equilibrium phenomena. Empirical noise and damping terms can be used to model coupling to a thermal bath. This yields a Langevin dynamics of SU(N) coherent states. Our CP^2 Skyrmion Quench tutorial shows how this dynamics gives rise to the formation of novel topological defects in a temperature quench.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Relative to LSWT calculations, it can take much more time to estimate mathcalS(𝐪ω) intensities using classical dynamics simulation. See the SunnyTutorials notebooks for examples of \"production-scale\" simulations.","category":"page"},{"location":"structure-factor/#Structure-Factor-Calculations","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"","category":"section"},{"location":"structure-factor/#Overview","page":"Structure Factor Calculations","title":"Overview","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The dynamical structure factor is of fundamental importance for characterizing a magnetic system, and facilitates quantitative comparison between theory and experimental scattering data.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Consider, for example, a two-point dynamical spin correlation function, s^α(𝐱+Δ𝐱 t+Δt) s^β(𝐱 t). Here s^α(𝐱 t) represents the time dynamics of a spin dipole component α at position 𝐱, and brackets represent an average over equilibrium initial conditions and over (𝐱 t). The dynamical structure factor is defined as the Fourier transform of this two-point correlation in both space and time, up to an overall scaling factor. Using the convolution theorem, the result is,","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"𝒮^αβ(𝐪 ω) = frac1V s^α(𝐪 ω)^ast s^β(𝐪 ω) ","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"with V the system volume. We will restrict attention to lattice systems with periodic boundaries.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Consider a crystal unit cell defined by three lattice vectors 𝐚_1 𝐚_2 𝐚_3, and linear system sizes L_1 L_2 L_3 measured in unit cells. The allowed momentum vectors take on discrete values 𝐪 = sum_α=1^3 m_α 𝐛_α L_α, where m_α are an integers and the reciprocal lattice vectors 𝐛_α are defined to satisfy 𝐚_α 𝐛_β = 2π δ_αβ. For a Bravais lattice, 𝐪 will be periodic in the first Brillouin zone, i.e., under any shift 𝐪 𝐪 𝐛_α. More generally, consider a non-Bravais lattice such that each unit cell may contain multiple spins. By partitioning spins s_j(𝐱t) according to their sublattice index j, the relevant momenta 𝐪 remain discretized as above, but now periodicity in the first Brillouin zone is lost. The structure factor may be written as a phase-average over the displacements between sublattices 𝐫_jk,","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"𝒮^αβ(𝐪 ω) = _jk e^i 𝐫_jk 𝐪 𝒮^αβ_jk(𝐪 ω) ","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"From a theoretical perspective, the quantity","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"𝒮^αβ_jk(𝐪 ω) = frac1V s_j^α(𝐪 ω)^ast s_k^β(𝐪 ω)","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"is fundamental. For each sublattice j, the data s_j^α(𝐪 ω) can be efficiently obtained by fast Fourier tranformation of a real space configuration s_j^α(𝐱 t). Internally, Sunny will calculate and store the discrete 𝒮^αβ_jk(𝐪 ω) correlation data, and use this to construct 𝒮^αβ(𝐪ω) intensities that can be compared with experiment.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Calculating this structure factor involves several steps, with various possible settings. Sunny provides a number of tools to facilitate this calculation and to extract information from the results. These tools are briefly outlined below. Please see the Examples for a \"real life\" use case. Detailed function information is available in the Library API.","category":"page"},{"location":"structure-factor/#Estimating-stucture-factors-with-classical-dynamics","page":"Structure Factor Calculations","title":"Estimating stucture factors with classical dynamics","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Classical dynamics may be used to estimate structure factor data by analyzing the spin-spin correlations of dynamical trajectories. This is fundamentally a Monte Carlo approach, as the trajectories must be started from an initial spin configuration that is sampled at thermal equilibrium. (Note that it is not possible to estimate a true T=0 dynamical structure factor using this method, but the temperature may be very low.) Samples are accumulated into a SampledCorrelations, from which intensity information may be extracted. The user does not typically build their own SampledCorrelations but instead initializes one by calling either dynamical_correlations or instant_correlations, as described below.","category":"page"},{"location":"structure-factor/#Estimating-a-dynamical-structure-factor:-𝒮(𝐪,ω)","page":"Structure Factor Calculations","title":"Estimating a dynamical structure factor: 𝒮(𝐪ω)","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"A SampledCorrelations for estimating the dynamical structure factor, 𝒮^αβ(𝐪ω), may be created by calling dynamical_correlations. This requires three keyword arguments. These will determine the dynamics used to calculate samples and, consequently, the ω information that will be available. ","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Δt: Determines the step size used for simulating the dynamics. A smaller number will require proportionally more calculation time. While a smaller Δt will enable the resolution of higher energies, Δt is typically selected to ensure numerical stability rather than to maximize the largest ω value. A safe choice is to use the smaller value of Δt = 0.1/(J* S^2) or Δt = 0.1/(D * S), where S is magnetic moment of the largest local spin (as specified in SpinInfo), J is the parameter governing the largest bilinear interaction (e.g. exchange), and D is the parameter governing the largest single-site term of the Hamiltonian (e.g., anisotropy or Zeeman term).\nωmax: Sets the maximum resolved energy. Note that this is not independent of Δt. If ωmax too large, Sunny will throw an error and ask you to choose a smaller Δt. \nnω: Determines the number of energy bins to resolve. A larger number will require more calculation time.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"A sample may be added by calling add_sample!(sc, sys). The input sys must be a spin configuration in good thermal equilibrium, e.g., using the continuous Langevin dynamics or using single spin flip trials with LocalSampler. The statistical quality of the 𝒮^αβ(𝐪ω) can be improved by repeatedly generating decorrelated spin configurations in sys and calling add_sample! on each configuration.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The outline of typical use case might look like this:","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"# Make a `SampledCorrelations`\nsc = dynamical_correlations(sys; Δt=0.05, ωmax=10.0, nω=100) \n\n# Add samples\nfor _ in 1:nsamples\n decorrelate_system(sys) # Perform some type of Monte Carlo simulation\n add_sample!(sc, sys) # Use spins to calculate trajectory and accumulate new sample of 𝒮(𝐪,ω)\nend","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The calculation may be configured in a number of ways; see the dynamical_correlations documentation for a list of all keywords.","category":"page"},{"location":"structure-factor/#Estimating-an-instantaneous-(\"static\")-structure-factor:-𝒮(𝐪)","page":"Structure Factor Calculations","title":"Estimating an instantaneous (\"static\") structure factor: 𝒮(𝐪)","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Sunny provides two methods for calculating instantaneous, or static, structure factors: 𝒮^αβ(𝐪). The first involves calculating spatial spin-spin correlations at single time slices. The second involves calculating a dynamic structure factor first and integrating out the ω information. The advantage of the latter approach is that it enables application of an ω-dependent classical-to-quantum rescaling of structure factor intensities, a method that should be preferred whenever comparing results to experimental data or spin wave calculations. A disadvantage of this approach is that it is computationally more expensive. There are also many cases when it is not straightforward to calculate a meaningful dynamics, as when working with Ising spins. In this section we will discuss how to calculate instantaneous structure factors from static spin configurations. Information about calculating instantaneous data from a dynamical correlations can be found in the following section.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The basic usage for the instantaneous case is very similar to the dynamic case, except one calls instant_correlations instead of dynamical_correlations to configure a SampledCorrelations. Note that there are no required keywords as there is no need to specify any dynamics. instant_correlations will return a SampledCorrelations containing no data. Samples may be added by calling add_sample!(sc, sys), where sc is the SampledCorrelations. When performing a finite-temperature calculation, it is important to ensure that the spin configuration in the sys represents a good equilibrium sample, as in the dynamical case. Note, however, that we recommend calculating instantaneous correlations at finite temperature calculations by using full dynamics (i.e., using dynamical_correlations) and then integrating out the energy axis. An approach to doing this is described in the next section.","category":"page"},{"location":"structure-factor/#Extracting-information-from-sampled-correlation-data","page":"Structure Factor Calculations","title":"Extracting information from sampled correlation data","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The basic function for extracting information from a SampledCorrelations at a particular wave vector, 𝐪, is intensities_interpolated. It takes a SampledCorrelations, a list of wave vectors, and an intensity_formula. The intensity_formula specifies how to contract and correct correlation data to arrive at a physical intensity. A simple example is formula = intensity_formula(sc, :perp), which will instruct Sunny apply polarization corrections: sum_αβ(I-q_α q_β) 𝒮^αβ(𝐪ω). An intensity at the wave vector 𝐪 = (𝐛_2 + 𝐛_3)2 may then be retrieved with intensities_interpolated(sf, [[0.0, 0.5, 0.5]], formula) . intensities_interpolated returns a list of nω elements at each wavevector. The corresponding ω values can be retrieved by calling available_energies on sf.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Since Sunny only calculates the structure factor on a finite lattice when performing classical simulations, it is important to realize that exact information is only available at a discrete set of wave vectors. Specifically, for each axis index i, we will get information at q_i = fracnL_i, where n runs from (frac-L_i2+1) to fracL_i2 and L_i is the linear dimension of the lattice used for the calculation. If you request a wave vector that does not fall into this set, Sunny will automatically round to the nearest 𝐪 that is available. If intensities_interpolated is given the keyword argument interpolation=:linear, Sunny will use trilinear interpolation to determine a result at the requested wave vector. ","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"To retrieve the intensities at all wave vectors for which there is exact data, first call the function available_wave_vectors to generate a list of qs. This takes an optional keyword argument bzsize, which must be given a tuple of three integers specifying the number of Brillouin zones to calculate, e.g., bzsize=(2,2,2). The resulting list of wave vectors may then be passed to intensities_interpolated.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Alternatively, intensities_binned can be used to place the exact data into histogram bins for comparison with experiment.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The convenience function reciprocal_space_path returns a list of wavevectors sampled along a path that connects specified 𝐪 points. This list can be used as an input to intensities. Another convenience method, reciprocal_space_shell will generate points on a sphere of a given radius. This is useful for powder averaging. ","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"A number of arguments for intensity_formula are available which modify the calculation of structure factor intensity. It is generally recommended to provide a value of kT corresponding to the temperature of sampled configurations. Given kT, Sunny will include an energy- and temperature-dependent classical-to-quantum rescaling of intensities in the formula.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"To retrieve intensity data from a instantaneous structure factor, use instant_intensities_interpolated, which accepts similar arguments to intensities_interpolated. This function may also be used to calculate instantaneous information from a dynamical correlation data, i.e. from a SampledCorrelations created with dynamical_correlations. Note that it is important to supply a value to kT to reap the benefits of this approach over simply calculating a static structure factor at the outset. ","category":"page"},{"location":"writevtk/#Volumetric-Rendering-with-ParaView","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"section"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"The 4D correlation data produced by Sunny is too high-dimensional to visualize directly. This page describes how to export 3D slices of correlation data from Sunny to the Visual ToolKit (VTK) format, which is compatible with the ParaView visualization software. ParaView supports volumetric rendering:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"page"},{"location":"writevtk/#Simulation-data","page":"Volumetric Rendering with ParaView","title":"Simulation data","text":"","category":"section"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"First, generate some correlation data in Sunny. We will use a 2D lattice, since the correlation data S(Q_xQ_yomega) is 3D and can be exported in its entirety. The following code sets up the system, thermalizes it, and records the correlation data in a SampledCorrelations called dsf.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"using Sunny\n\n# Single layer 12x12 periodic square lattice\nlatsize = (12,12,1);\n\nlatvecs = lattice_vectors(8.,8.,12.,90,100,90)\npositions = [[0,0,0]]\ntypes = [\"Cu\"]\nformfactors = [FormFactor(\"Cu2\")]\nxtal = Crystal(latvecs,positions;types);\n\nsys = System(xtal, latsize, [SpinInfo(1, S=1/2, g=2)], :SUN; seed=1);\n\nJ = 10.\nset_exchange!(sys,J,Bond(1,1,[1,0,0]))\nset_exchange!(sys,J,Bond(1,1,[0,1,0]))\n\nΔt = 0.01\nkT = 0.5\nlangevin = Langevin(Δt; λ=0.5, kT=kT)\nrandomize_spins!(sys);\nfor i in 1:10_000 # Long enough to reach equilibrium\n step!(sys, langevin)\nend \n\nωmax=10.\n\ndsf = dynamical_correlations(sys\n ;Δt=Δt\n ,nω=48\n ,ωmax=ωmax\n ,process_trajectory=:symmetrize)\n\nnsamples = 10\nfor _ in 1:nsamples\n for _ in 1:1000 \n step!(sys, langevin)\n end\n add_sample!(dsf, sys)\nend","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"The default histogram BinningParameters are already integrated over the z direction because the system is 2D:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"unit_resolution_binning_parameters(dsf)","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"⊡ 12 bins from -0.042 to +0.958 along [+1.27 dx] (Δ = 0.065)\n⊡ 12 bins from -0.042 to +0.958 along [+1.27 dy] (Δ = 0.065)\n∫ Integrated from +0.000 to +0.000 along [-0.33 dx +1.88 dz] (Δ = 0.524)\n⊡ 48 bins from -0.107 to +10.134 along [+1.00 dE] (Δ = 0.213)","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"The histogram is very oblong; it's approximately 1x1x10. To make it a nicer shape, we will rescale the energy axis to be be fractions of ωmax:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"params = unit_resolution_binning_parameters(dsf)\nscale_factor = ωmax\nparams.binend[4] /= scale_factor\nparams.binstart[4] /= scale_factor\nparams.binwidth[4] /= scale_factor\nparams.covectors[4,:] ./= scale_factor","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Doing this changes the last axis of the histogram to fit in [0,1]:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"⊡ 49 bins from -0.011 to +1.013 along [+0.10 dE] (Δ = 0.213)","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Now that our histogram is a cube, we compute the intensity in the histogram bins using the usual intensities_binned:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"formula = intensity_formula(dsf,:trace)\nsignal, counts = intensities_binned(dsf, params; formula)\nintensity = signal ./ counts","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Now that we have our intensity data and the binning parameters, we can export to VTK format using export_vtk and move to ParaView for the visualization.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"# Importing WriteVTK enables Sunny's export-to-VTK functions\nimport WriteVTK\n\n# [1,2,4] specifies that the (x,y,z) axes in ParaView are (Qx,Qy,ω)\nexport_vtk(\"square_lattice\", params, intensity; dims_kept = [1,2,4])\n# Writes a file square_lattice.vti in the current directory","category":"page"},{"location":"writevtk/#Loading-in-ParaView","page":"Volumetric Rendering with ParaView","title":"Loading in ParaView","text":"","category":"section"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"In ParaView, use File > Open to open square_lattice.vti. This will add the file to the Pipeline Browser with a closed eye icon, indicating that the data is ready to be loaded.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"In the Properties panel, both bin_centers and data will be selected for import by default. Uncheck bin_centers because we don't need that information for the visualization. Click the green Apply button to load the data.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"By default, only the outline of the data is shown in the 3D viewport. Since we adjusted the energy axis, the outline is a 1x1x1 cube. Optionally enable the axes grid under \"View\", and customize using the adjacent edit button.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"To enable the volumetric render:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Select \"Volume\" from the \"Representation\" drop-down menu under \"Display\".\nThe \"Coloring\" drop-down should automatically select data because it's the only data loaded.\nOpen the Color Map Editor to adjust the opacity of the fog, which may be too faint to see by default.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Depending on your computer and your dataset size, the volumetric rendering may be slow, but our dataset is relatively small, so the render should be fast.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"If nothing shows up at first, don't despair. Often, there are Bragg-like peaks in the correlation data which outshine everything else. To see this, enable Display Data Histogram in the Color Map Editor panel. To zoom in on the lower-intensity data, click and drag the right side handle of the opacity transfer function box to the middle a few times.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"After suitable color mapping, the dispersion curve should become visible:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"page"},{"location":"writevtk/#Experiment-data","page":"Volumetric Rendering with ParaView","title":"Experiment data","text":"","category":"section"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Note that since only the data and binning parameters are required for exporting to VTK, experiment data can be exported in the same way. For example, to visualize S(Q_xQ_yQ_z), do this:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"# Load 4D histogram data from Mantid\nparams, signal = load_nxs(\"experiment_data.nxs\")\n\n# Integrate out the energy axis so we are 3D\nintegrate_axes!(params; axes = 4)\nsignal = sum(signal; dims = 4)\n\n# Export to ParaView\nexport_vtk(\"experiment_data_as_vtk\", params, signal)","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"EditURL = \"../../../examples/ising2d.jl\"","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/ising2d/#Classical-Ising-model","page":"Classical Ising model","title":"Classical Ising model","text":"","category":"section"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"This tutorial illustrates simulation of the classical 2D Ising model.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"using Sunny, Plots","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Sunny expects a 3D Crystal unit cell. To model a square lattice, we create an orthogonal unit cell where the z-spacing is distinct from the x and y spacing.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"a = 1\nlatvecs = lattice_vectors(a,a,10a,90,90,90)\ncrystal = Crystal(latvecs, [[0,0,0]])","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Create a System of spins with linear size L in the x and y directions, and only one layer in the z direction. The option :dipole means that the system will store Heisenberg spins, as opposed to SU(N) coherent states. Polarize the initial spin configuration using polarize_spins!. Following the Ising convention, we will restrict these spins to the z-axis and give them magnitude S=1.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"By default, Sunny uses physical units, e.g. magnetic field in tesla. Here we specify an alternative Units system, so that the Zeeman coupling between the spin dipole 𝐬 and an external field 𝐁 has the dimensionless form -𝐁𝐬.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"L = 128\nsys = System(crystal, (L,L,1), [SpinInfo(1, S=1, g=1)], :dipole, units=Units.theory, seed=0)\npolarize_spins!(sys, (0,0,1))","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Use set_exchange! to include a ferromagnetic Heisenberg interaction along nearest-neighbor bonds. The Bond below connects two spins displaced by one lattice constant in the x-direction. This interaction will be propagated to all nearest-neighbors bonds in the system, consistent with the symmetries of the square lattice.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"set_exchange!(sys, -1.0, Bond(1,1,(1,0,0)))","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"If an external field is desired, it can be set using set_external_field!.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"B = 0\nset_external_field!(sys, (0,0,B))","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"The critical temperature for the Ising model is known analytically.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Tc = 2/log(1+√2)","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Use a LocalSampler to perform nsweeps Monte Carlo sweeps. A sweep consists of, on average, one trial update per spin in the system. Each proposed update is accepted or rejected according to the Metropolis acceptance probability. As its name suggests, the propose_flip function will only propose pure spin flips, 𝐬 rightarrow -𝐬.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"nsweeps = 4000\nsampler = LocalSampler(kT=Tc, propose=propose_flip)\nfor i in 1:nsweeps\n step!(sys, sampler)\nend","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Plot the Ising spins by extracting the z-component of the dipoles","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"heatmap(reshape([s.z for s in sys.dipoles], (L,L)))","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"EditURL = \"../../../examples/powder_averaging.jl\"","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/powder_averaging/#Powder-averaged-CoRh_2O_4","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"","category":"section"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"This tutorial illustrates the calculation of the powder-averaged structure factor by performing an orientational average. We consider a simple model of the diamond-cubic crystal CoRh_2O_4, with parameters extracted from Ge et al., Phys. Rev. B 96, 064413.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"using Sunny, GLMakie","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"Construct a diamond Crystal in the conventional (non-primitive) cubic unit cell. Sunny will populate all eight symmetry-equivalent sites when given the international spacegroup number 227 (\"Fd-3m\") and the appropriate setting. For this spacegroup, there are two conventional translations of the unit cell, and it is necessary to disambiguate through the setting keyword argument. (On your own: what happens if setting is omitted?)","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"a = 8.5031 # (Å)\nlatvecs = lattice_vectors(a, a, a, 90, 90, 90)\ncrystal = Crystal(latvecs, [[0,0,0]], 227, setting=\"1\")","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"Construct a System with an antiferromagnetic nearest neighbor interaction J. Because the diamond crystal is bipartite, the ground state will have unfrustrated Néel order. Selecting latsize=(1,1,1) is sufficient because the ground state is periodic over each cubic unit cell. By passing an explicit seed, the system's random number generator will give repeatable results.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"latsize = (1,1,1)\nseed = 0\nS = 3/2\nJ = 7.5413*meV_per_K # (~ 0.65 meV)\nsys = System(crystal, latsize, [SpinInfo(1; S, g=2)], :dipole; seed=0)\nset_exchange!(sys, J, Bond(1, 3, [0,0,0]))","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"The ground state is non-frustrated. Each spin should be exactly anti-aligned with its 4 nearest-neighbors, such that every bond contributes an energy of -JS^2. This gives an energy per site of -2JS^2. In this calculation, a factor of 1/2 is necessary to avoid double-counting the bonds. Given the small magnetic supercell (which includes only one unit cell), direct energy minimization is successful in finding the ground state.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"randomize_spins!(sys)\nminimize_energy!(sys)\n\nenergy_per_site = energy(sys) / length(eachsite(sys))\n@assert energy_per_site ≈ -2J*S^2","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"Plotting the spins confirms the expected Néel order. Note that the overall, global rotation of dipoles is arbitrary.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"plot_spins(sys; ghost_radius=2.0)","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"We can now estimate 𝒮(𝐪ω) with SpinWaveTheory and intensity_formula. The mode :perp contracts with a dipole factor to return the unpolarized intensity. We will also apply broadening with the lorentzian kernel, and will dampen intensities using the FormFactor for Cobalt(2+).","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"swt = SpinWaveTheory(sys)\nη = 0.4 # (meV)\nkernel = lorentzian(η)\nformfactors = [FormFactor(\"Co2\")]\nformula = intensity_formula(swt, :perp; kernel, formfactors)","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"First, we consider the \"single crystal\" results. Use reciprocal_space_path to construct a path that connects high-symmetry points in reciprocal space. The intensities_broadened function collects intensities along this path for the given set of energy values.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"qpoints = [[0.0, 0.0, 0.0], [0.5, 0.0, 0.0], [0.5, 0.5, 0.0], [0.0, 0.0, 0.0]]\npath, xticks = reciprocal_space_path(crystal, qpoints, 50)\nenergies = collect(0:0.01:6)\nis = intensities_broadened(swt, path, energies, formula)\n\nfig = Figure()\nax = Axis(fig[1,1]; aspect=1.4, ylabel=\"ω (meV)\", xlabel=\"𝐪 (RLU)\",\n xticks, xticklabelrotation=π/10)\nheatmap!(ax, 1:size(is, 1), energies, is, colormap=:gnuplot2)\nfig","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"A powder measurement effectively involves an average over all possible crystal orientations. We use the function reciprocal_space_shell to sample n wavevectors on a sphere of a given radius (inverse angstroms), and then calculate the spherically-averaged intensity.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"radii = 0.01:0.02:3 # (1/Å)\noutput = zeros(Float64, length(radii), length(energies))\nfor (i, radius) in enumerate(radii)\n n = 300\n qs = reciprocal_space_shell(crystal, radius, n)\n is = intensities_broadened(swt, qs, energies, formula)\n output[i, :] = sum(is, dims=1) / size(is, 1)\nend\n\nfig = Figure()\nax = Axis(fig[1,1]; xlabel=\"|Q| (Å⁻¹)\", ylabel=\"ω (meV)\")\nheatmap!(ax, radii, energies, output, colormap=:gnuplot2)\nfig","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"This result can be compared to experimental neutron scattering data from Fig. 5 of Ge et al.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"EditURL = \"../../../examples/out_of_equilibrium.jl\"","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/out_of_equilibrium/#CP2-Skyrmion-Quench","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"","category":"section"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"This example demonstrates Sunny's ability to simulate the out-of-equilibrium dynamics of generalized spin systems. We will implement the model Hamiltonian of Zhang et al., Nature Communications 14, 3626 (2023), which supports a novel type of topological defect, a CP² skyrmion, that involves both the dipolar and quadrupolar parts of a quantum spin.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Beginning from an initial high-temperature state, a disordered gas of CP² skyrmions can be formed by rapidly quenching to low temperature. To model the coupled dynamics of dipoles and quadrupoles, Sunny uses a recently developed generalization of the Landau-Lifshitz spin dynamics, Dahlbom et al., Phys. Rev. B 106, 235154 (2022).","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"using Sunny, GLMakie","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"The Hamiltonian we will implement,","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"mathcalH = sum_langle ij rangle J_ij( hatS_i^x hatS_j^x + hatS_i^y hatS_j^y + DeltahatS_i^z hatS_j^z) - hsum_ihatS_i^z + Dsum_i(hatS_i^z)^2","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"contains competing ferromagnetic nearest-neightbor and antiferromagnetic next-nearest-neighbor exchange terms on a triangular lattice. Both exchanges exhibit anisotropy on the z-term. Additionally, there is an external magnetic field, h, and easy-plane single-ion anisotropy, D. We begin by implementing the Crystal.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"lat_vecs = Sunny.lattice_vectors(1.0, 1.0, 2.0, 90, 90, 120)\nbasis_vecs = [[0,0,0]]\ncryst = Crystal(lat_vecs, basis_vecs)","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"The crystal is then used to create a spin System. All parameters in this model system are dimensionless, so we select \"theory\" units and set the g-factor to one.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"L = 40\ndims = (L, L, 1)\nsys = System(cryst, dims, [SpinInfo(1, S=1, g=1)], :SUN; seed=101, units=Units.theory)","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"We proceed to implement each term of the Hamiltonian, selecting our parameters so that the system occupies a region of the phase diagram that supports skyrmions. The exchange interactions are set as follows.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"J1 = -1 # Nearest-neighbor ferromagnetic\nJ2 = (2.0/(1+√5)) # Tune competing exchange to set skyrmion scale length\nΔ = 2.6 # Exchange anisotropy\n\nex1 = J1 * [1.0 0.0 0.0;\n 0.0 1.0 0.0;\n 0.0 0.0 Δ]\nex2 = J2 * [1.0 0.0 0.0;\n 0.0 1.0 0.0;\n 0.0 0.0 Δ]\nset_exchange!(sys, ex1, Bond(1, 1, [1, 0, 0]))\nset_exchange!(sys, ex2, Bond(1, 1, [1, 2, 0]));\nnothing #hide","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Next we add the external field,","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"h = 15.5\nfield = set_external_field!(sys, [0.0 0.0 h]);\nnothing #hide","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"and finally the single-ion anisotropy,","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"D = 19.0\nSz = Sunny.spin_operators(sys, 1)[3]\nset_onsite_coupling!(sys, D*Sz^2, 1);\nnothing #hide","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Initialize system to an infinite temperature (fully randomized) initial condition.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"randomize_spins!(sys)","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"We are now ready to simulate the quenching process using a generalized Langevin spin dynamics. If we were working with spin dipoles only, then Langevin dynamics would be the usual Landau-Lifshitz spin dynamics, augmented with damping and noise terms. In the present study, we are instead working with quantum spin-1 (an (N=3)-level system that includes both dipoles and quadrupoles). Here, Langevin captures the coupled dipole-quadrupole dynamics using the formalism of SU(N) coherent states.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Selecting kT = 0 in the Langevin dynamics will effective disable the noise term. Then the parameter λ effectively determines the damping time-scale.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Δt = 0.2/D # Integration time step (inverse meV). Typically this will be\n # inversely proportional to the largest energy scale in the\n # system. We can use a fairly large time-step here because\n # accuracy isn't critical.\nkT = 0 # Target equilibrium temperature (meV)\nλ = 0.1 # Magnitude of coupling to thermal bath (dimensionless)\nintegrator = Langevin(Δt; kT, λ);\nnothing #hide","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Finally we run the dynamics. We will record the state of the system at three different times during the quenching process by copying the coherents field of the System.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"τs = [4., 16, 256] # Times to record snapshots\nframes = [] # Empty array to store snapshots\nfor i in eachindex(τs)\n dur = i == 1 ? τs[1] : τs[i] - τs[i-1] # Determine the length of time to simulate\n numsteps = round(Int, dur/Δt)\n for _ in 1:numsteps # Perform the integration\n step!(sys, integrator)\n end\n push!(frames, copy(sys.coherents)) # Save a snapshot spin configuration\nend","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"To visualize the state of the system contained in each snapshot, we will calculate and plot the skyrmion density on each plaquette of our lattice. The function plot_triangular_plaquettes is not part of the core Sunny package, but rather something you could define yourself. We are using the definition in plotting2d.jl from the Sunny examples/extra directory.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"include(joinpath(pkgdir(Sunny), \"examples\", \"extra\", \"plotting2d.jl\"))\n\nfunction sun_berry_curvature(z₁, z₂, z₃)\n z₁, z₂, z₃ = normalize.((z₁, z₂, z₃))\n n₁ = z₁ ⋅ z₂\n n₂ = z₂ ⋅ z₃\n n₃ = z₃ ⋅ z₁\n return angle(n₁ * n₂ * n₃)\nend\n\nplot_triangular_plaquettes(sun_berry_curvature, frames; resolution=(1800,600),\n offset_spacing=10, texts = [\"\\tt = \"*string(τ) for τ in τs], text_offset = (0.0, 6.0)\n)","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"The times are given in hbarJ_1. The white background corresponds to a quantum paramagnetic state, where the local spin exhibits a strong quadrupole moment and little or no dipole moment. Observe that the process has generated a number of well-formed skyrmions of both positive (red) and negative (blue) charge in addition to a number of other metastable spin configurations. A full-sized version of this figure is available in Dahlbom et al..","category":"page"},{"location":"library/#Library-API","page":"Library API","title":"Library API","text":"","category":"section"},{"location":"library/","page":"Library API","title":"Library API","text":"This page describes the public types and functions exported by Sunny. This documentation can be also be accessed using the Julia help system (enter ? at the Julia command prompt).","category":"page"},{"location":"library/","page":"Library API","title":"Library API","text":"","category":"page"},{"location":"library/","page":"Library API","title":"Library API","text":"Sunny.plot_spins\nSunny.export_vtk","category":"page"},{"location":"library/","page":"Library API","title":"Library API","text":"Modules = [Sunny]\nPrivate = false","category":"page"},{"location":"library/#Sunny.Site","page":"Library API","title":"Sunny.Site","text":"(cell1, cell2, cell3, i) :: Site\n\nFour indices identifying a single site in a System. The first three indices select the lattice cell and the last selects the sublattice (i.e., the atom within the unit cell).\n\nThis object can be used to index dipoles and coherents fields of a System. A Site is also required to specify inhomogeneous interactions via functions such as set_external_field_at! or set_exchange_at!.\n\nNote that the definition of a cell may change when a system is reshaped. In this case, it is convenient to construct the Site using position_to_site, which always takes a position in fractional coordinates of the original lattice vectors.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.Units","page":"Library API","title":"Sunny.Units","text":"Units.meV\nUnits.theory\n\nThe unit system is implicitly determined by the definition of two physical constants: the vacuum permeability μ₀ and the Bohr magneton μ_B. Temperatures are effectively measured in units of energy (k_B = 1) and time is effectively measured in units of inverse energy (ħ = 1). The default unit system, Units.meV, employs (meV, Å, tesla). Select alternatively Units.theory for a units system defined so that μ₀ = μ_B = 1.\n\nSee also meV_per_K\n\n\n\n\n\n","category":"constant"},{"location":"library/#Sunny.meV_per_K","page":"Library API","title":"Sunny.meV_per_K","text":"meV_per_K = 0.086173332621451774\n\nA physical constant. Useful for converting kelvin into the default energy units, meV.\n\n\n\n\n\n","category":"constant"},{"location":"library/#Sunny.BinningParameters","page":"Library API","title":"Sunny.BinningParameters","text":"BinningParameters(binstart,binend,binwidth;covectors = I(4))\nBinningParameters(binstart,binend;numbins,covectors = I(4))\n\nDescribes a 4D parallelepided histogram in a format compatible with experimental Inelasitic Neutron Scattering data. See generate_mantid_script_from_binning_parameters to convert BinningParameters to a format understandable by the Mantid software, or load_nxs to load BinningParameters from a Mantid .nxs file.\n\nThe coordinates of the histogram axes are specified by multiplication of (q,ω) with each row of the covectors matrix, with q given in [R.L.U.]. Since the default covectors matrix is the identity matrix, the default axes are (qx,qy,qz,ω) in absolute units.\n\nThe convention for the binning scheme is that:\n\nThe left edge of the first bin starts at binstart\nThe bin width is binwidth\nThe last bin contains binend\nThere are no \"partial bins;\" the last bin may contain values greater than binend. C.f. count_bins.\n\nA value can be binned by computing its bin index:\n\ncoords = covectors * value\nbin_ix = 1 .+ floor.(Int64,(coords .- binstart) ./ binwidth)\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.Bond","page":"Library API","title":"Sunny.Bond","text":"Bond(i, j, n)\n\nRepresents a bond between atom indices i and j. n is a vector of three integers specifying unit cell displacement in terms of lattice vectors.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.Crystal","page":"Library API","title":"Sunny.Crystal","text":"An object describing a crystallographic unit cell and its space group symmetry. Constructors are as follows:\n\nCrystal(filename; symprec=1e-5)\n\nReads the crystal from a .cif file located at the path filename. The optional parameter symprec controls the precision tolerance for spacegroup symmetries.\n\nCrystal(latvecs, positions; types=nothing, symprec=1e-5)\n\nConstructs a crystal from the complete list of atom positions positions, with coordinates (between 0 and 1) in units of lattice vectors latvecs. Spacegroup symmetry information is automatically inferred. The optional parameter types is a list of strings, one for each atom, and can be used to break symmetry-equivalence between atoms.\n\nCrystal(latvecs, positions, spacegroup_number; types=nothing, setting=nothing, symprec=1e-5)\n\nBuilds a crystal by applying symmetry operators for a given international spacegroup number. For certain spacegroups, there are multiple possible unit cell settings; in this case, a warning message will be printed, and a list of crystals will be returned, one for every possible setting. Alternatively, the optional setting string will disambiguate between unit cell conventions.\n\nCurrently, crystals built using only the spacegroup number will be missing some symmetry information. It is generally preferred to build a crystal from a .cif file or from the full specification of the unit cell.\n\nExamples\n\n# Read a Crystal from a .cif file\nCrystal(\"filename.cif\")\n\n# Build an FCC crystal using the primitive unit cell. The spacegroup number\n# 225 is inferred.\nlatvecs = [1 1 0;\n 1 0 1;\n 0 1 1] / 2\npositions = [[0, 0, 0]]\nCrystal(latvecs, positions)\n\n# Build a CsCl crystal (two cubic sublattices). By providing distinct type\n# strings, the spacegroup number 221 is inferred.\nlatvecs = lattice_vectors(1, 1, 1, 90, 90, 90)\npositions = [[0,0,0], [0.5,0.5,0.5]]\ntypes = [\"Na\", \"Cl\"]\ncryst = Crystal(latvecs, positions; types)\n\n# Build a diamond cubic crystal from its spacegroup number 227. This\n# spacegroup has two possible settings (\"1\" or \"2\"), which determine an\n# overall unit cell translation.\nlatvecs = lattice_vectors(1, 1, 1, 90, 90, 90)\npositions = [[1, 1, 1] / 4]\ncryst = Crystal(latvecs, positions, 227; setting=\"1\")\n\nSee also lattice_vectors.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.FormFactor-Tuple{String}","page":"Library API","title":"Sunny.FormFactor","text":"FormFactor(ion::String; g_lande=2)\n\nThe magnetic form factor for a given magnetic ion and charge state. These can optionally be provided to intensity_formula, and will be used to scale the structure factor intensities as a function of wavevector magnitude.\n\nThe parameter ion must be one of the following allowed strings:\n\nSc0,Sc1,Sc2,Ti0,Ti1,Ti2,Ti3,V0,V1,V2,V3,V4,Cr0,Cr1,Cr2,Cr3,Cr4,Mn0,Mn1,Mn2,Mn3,\nMn4,Fe0,Fe1,Fe2,Fe3,Fe4,Co0,Co1,Co2,Co3,Co4,Ni0,Ni1,Ni2,Ni3,Ni4,Cu0,Cu1,Cu2,Cu3,\nCu4,Y0,Zr0,Zr1,Nb0,Nb1,Mo0,Mo1,Tc0,Tc1,Ru0,Ru1,Rh0,Rh1,Pd0,Pd1,Ce2,Nd2,Nd3,Sm2,\nSm3,Eu2,Eu3,Gd2,Gd3,Tb2,Tb3,Dy2,Dy3,Ho2,Ho3,Er2,Er3,Tm2,Tm3,Yb2,Yb3,Pr3,U3,U4,\nU5,Np3,Np4,Np5,Np6,Pu3,Pu4,Pu5,Pu6,Am2,Am3,Am4,Am5,Am6,Am7\n\nA first approximation to the magnetic form factor is\n\nf(s) = langle j_0(s) rangle,\n\nwhere langle j_l(s) rangle is a Bessel function integral of the magnetic dipole.\n\nIf Landé g-factor is distinct from 2, then a correction will be applied,\n\nF(s) = frac2-gg langle j_2(s) rangle s^2 + f(s).\n\nSunny uses the semi-empirical fits for j_0 and j_2 listed from Refs. [1] and [2]. These functions are approximated as a sum of Gaussians in the scalar variable s = k4π, where k can be interpreted as the magnitude of momentum transfer:\n\nlangle j_l(s) rangle = A e^-as^2 + B e^-bs^2 + Ce^-cs^2 + D\n\nwhere A B C D a b c are l-dependent fitting parameters. For transition metals, the parameters are estimated using the Hartree-Fock method. For rare-earth metals and ions, the Dirac-Fock form is used.\n\nReferences:\n\nhttps://www.ill.eu/sites/ccsl/ffacts/ffachtml.html\nJ. Brown, The Neutron Data Booklet, 2nd ed., Sec. 2.5 Magnetic Form Factors (2003).\nMarshall W and Lovesey S W, Theory of thermal neutron scattering Chapter 6 Oxford University Press (1971)\nClementi E and Roetti C, Atomic Data and Nuclear Data Tables, 14 pp 177-478 (1974)\nFreeman A J and Descleaux J P, J. Magn. Mag. Mater., 12 pp 11-21 (1979) Descleaux J P and Freeman A J, J. Magn. Mag. Mater., 8 pp 119-129 (1978) \n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.ImplicitMidpoint","page":"Library API","title":"Sunny.ImplicitMidpoint","text":"ImplicitMidpoint(Δt::Float64; atol=1e-12) where N\n\nEnergy-conserving spin dynamics. One call to the step! function will advance a System by Δt units of time.\n\nUses the spherical midpoint integration scheme for dipole systems and the Schrödinger midpoint integration scheme for SU(N) spin systems. Both integration schemes are symplectic, and therefore avoid energy drift over long periods of simulation time.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.Langevin","page":"Library API","title":"Sunny.Langevin","text":"Langevin(Δt::Float64; λ::Float64, kT::Float64)\n\nSpin dynamics with coupling to a Langevin thermostat, which includes damping and noise terms. One call to the step! function will advance a System by Δt units of time.\n\nAssuming ergodicity, the Langevin dynamics will sample from thermal equilibrium for the target temperature kT. The empirical parameter λ determines the strength of the coupling to the thermal bath. In other words, 1/λ is the decorrelation time-scale. If λ = 0, then the spin dynamics coincides with ImplicitMidpoint.\n\nAn alternative approach to sampling is LocalSampler, which may be preferred when the allowed spin values become effective discrete (e.g. Ising spins).\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.LocalSampler","page":"Library API","title":"Sunny.LocalSampler","text":"LocalSampler(; kT, nsweeps=1.0, propose=propose_uniform)\n\nMonte Carlo simulation involving Metropolis updates to individual spins. One call to the step! function will perform nsweeps of MCMC sampling for a provided System. The default value of 1.0 means that step! performs, on average, one trial update per spin.\n\nAssuming ergodicity, the LocalSampler will sample from thermal equilibrium for the target temperature kT. \n\nThe trial spin updates are sampled using the propose function. Built-in options include propose_uniform, propose_flip, and propose_delta. Multiple proposals can be mixed with the macro @mix_proposals.\n\nThe returned object stores fields ΔE and Δs, which represent the cumulative change to the net energy and dipole, respectively.\n\nAn alternative approach to sampling is Langevin, which may be preferred for simulating continuous spins, especially in the presence of long-range dipole-dipole interactions (cf. enable_dipole_dipole!).\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.SampledCorrelations","page":"Library API","title":"Sunny.SampledCorrelations","text":"SampledCorrelations\n\nBasic data type for storing sampled correlation data. A SampleCorrelations is initialized by calling either dynamical_correlations or instant_correlations.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.SpinInfo","page":"Library API","title":"Sunny.SpinInfo","text":"SpinInfo(atom::Int; S, g=2)\n\nCharacterizes the spin at a given atom index within the crystal unit cell. S is an integer multiple of 1/2 and gives the spin angular momentum in units of ħ. g is the g-factor or tensor, such that an angular momentum dipole s produces a magnetic moment g s in units of the Bohr magneton.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.SpinWaveTheory","page":"Library API","title":"Sunny.SpinWaveTheory","text":"SpinWaveTheory(sys, energy_ϵ::Float64=1e-8, energy_tol=1e-6)\n\nConstructs an object to perform linear spin wave theory. Use it with dispersion and dssf functions.\n\nThe optional parameter energy_ϵ adds a small positive shift to the diagonal of the dynamical matrix D to avoid numerical issues with zero-energy quasi-particle modes. The optional parameter energy_tol relaxes the check on the imaginary part of the eigenvalues.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.System-Tuple{Crystal, Tuple{Int64, Int64, Int64}, Vector{SpinInfo}, Symbol}","page":"Library API","title":"Sunny.System","text":"System(crystal::Crystal, latsize, infos, mode; units=Units.meV, seed::Int)\n\nConstruct a System of spins for a given Crystal symmetry. The latsize parameter determines the number of unit cells in each lattice vector direction. The infos parameter is a list of SpinInfo objects, which determine the magnitude S and g-tensor of each spin.\n\nThe three possible options for mode are :SUN, :dipole, and :large_S. The most variationally accurate choice is :SUN, in which each spin-S degree of freedom is described as an SU(N) coherent state, where N = 2S + 1. Note that an SU(N) coherent state fully describes any local spin state; this description includes expected dipole components Sᵅ, quadrupole components SᵅSᵝ+SᵝSᵅ, etc.\n\nThe mode :dipole projects the SU(N) dynamics onto the space of pure dipoles. In practice this means that Sunny will simulate Landau-Lifshitz dynamics, but all single-ion anisotropy and biquadratic exchange interactions will be automatically renormalized for maximum accuracy.\n\nTo disable such renormalization, e.g. to reproduce results using the historical large-S classical limit, use the experimental mode :large_S. Modes :SUN or :dipole are strongly preferred for the development of new models.\n\nThe default units system of (meV, Å, tesla) can be overridden by with the units parameter; see Units. \n\nAn optional seed may be provided to achieve reproducible random number generation.\n\nAll spins are initially polarized in the z-direction.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.add_sample!-Tuple{SampledCorrelations, System}","page":"Library API","title":"Sunny.add_sample!","text":"add_sample!(sc::SampledCorrelations, sys::System)\n\nadd_trajectory uses the spin configuration contained in the System to generate a correlation data and accumulate it into sc. For static structure factors, this involves analyzing the spin-spin correlations of the spin configuration provided. For a dynamic structure factor, a trajectory is calculated using the given spin configuration as an initial condition. The spin-spin correlations are then calculating in time and accumulated into sc. \n\nThis function will change the state of sys when calculating dynamical structure factor data. To preserve the initial state of sys, it must be saved separately prior to calling add_sample!. Alternatively, the initial spin configuration may be copied into a new System and this new System can be passed to add_sample!.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.available_energies-Tuple{SampledCorrelations}","page":"Library API","title":"Sunny.available_energies","text":"available_energies(sc::SampledCorrelations; negative_energies=false)\n\nReturn the ω values for the energy index of a SampledCorrelations. By default, only returns values for non-negative energies, which corresponds to the default output of intensities. Set negative_energies to true to retrieve all ω values.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.available_wave_vectors-Tuple{SampledCorrelations}","page":"Library API","title":"Sunny.available_wave_vectors","text":"available_wave_vectors(sc::SampledCorrelations; bzsize=(1,1,1))\n\nReturns all wave vectors for which sc contains exact values. bsize specifies the number of Brillouin zones to be included.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.axes_bincenters-Tuple{Any, Any, Any}","page":"Library API","title":"Sunny.axes_bincenters","text":"axes_bincenters(params::BinningParameters)\n\nReturns tick marks which label the bins of the histogram described by BinningParameters by their bin centers.\n\nThe following alternative syntax can be used to compute bin centers for a single axis:\n\naxes_bincenters(binstart,binend,binwidth)\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.broaden_energy-Tuple{SampledCorrelations, Any, Function}","page":"Library API","title":"Sunny.broaden_energy","text":"broaden_energy(sc::SampledCorrelations, vals, kernel::Function; negative_energies=false)\n\nPerforms a real-space convolution along the energy axis of an array of intensities. Assumes the format of the intensities array corresponds to what would be returned by intensities_interpolated. kernel must be a function that takes two numbers: kernel(ω, ω₀), where ω is a frequency, and ω₀ is the center frequency of the kernel. Sunny provides lorentzian for the most common use case:\n\nnewvals = broaden_energy(sc, vals, (ω, ω₀) -> lorentzian(ω-ω₀, 0.2))\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.browser-Tuple{String}","page":"Library API","title":"Sunny.browser","text":"browser(html_str; dir)\n\nLaunch a system browser to display the provided HTML string or SunnyViewer. If a directory dir is provided, an HTML file will be written at that location.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.count_bins-Tuple{Any, Any, Any}","page":"Library API","title":"Sunny.count_bins","text":"count_bins(binstart,binend,binwidth)\n\nReturns the number of bins in the binning scheme implied by binstart, binend, and binwidth. To count the bins in a BinningParameters, use params.numbins.\n\nThis function defines how partial bins are handled, so it should be used preferentially over computing the number of bins manually.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.dispersion-Tuple{SpinWaveTheory, Any}","page":"Library API","title":"Sunny.dispersion","text":"dispersion(swt::SpinWaveTheory, qs)\n\nComputes the spin excitation energy dispersion relations given a SpinWaveTheory and an array of wave vectors qs. Each element q of qs must be a 3-vector in units of reciprocal lattice units. I.e., qᵢ is given in 2πaᵢ with aᵢ the lattice constant of the original chemical lattice.\n\nThe first indices of the returned array correspond to those of qs. A final index, corresponding to mode, is added to these. Each entry of the array is an energy.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.dmvec-Tuple{Any}","page":"Library API","title":"Sunny.dmvec","text":"dmvec(D)\n\nAntisymmetric matrix representation of the Dzyaloshinskii-Moriya pseudo-vector,\n\n [ 0 D[3] -D[2]\n -D[3] 0 D[1]\n D[2] -D[1] 0 ]\n\nUseful in the context of set_exchange!.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.dssf-Tuple{SpinWaveTheory, Any}","page":"Library API","title":"Sunny.dssf","text":"dssf(swt::SpinWaveTheory, qs)\n\nGiven a SpinWaveTheory object, computes the dynamical spin structure factor,\n\n 𝒮^αβ(𝐤 ω) = 1(2πN)dt _𝐫 expi(ωt - 𝐤𝐫) S^α(𝐫 t)S^β(0 0)\n\nusing the result from linear spin-wave theory,\n\n 𝒮^αβ(𝐤 ω) = _n A_n^αβ(𝐤)^2 δω-ω_n(𝐤)\n\nqs is an array of wave vectors of arbitrary dimension. Each element q of qs must be a 3-vector in reciprocal lattice units (RLU), i.e., in the basis of reciprocal lattice vectors.\n\nThe first indices of the returned array correspond to those of qs. A final index, corresponding to mode, is added to these. Each entry of this array is a tensor (3×3 matrix) corresponding to the indices α and β.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.dynamical_correlations-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.dynamical_correlations","text":"dynamical_correlations(sys::System; Δt, nω, ωmax, \n process_trajectory=:none, observables=nothing, correlations=nothing)\n\nCreates a SampledCorrelations for calculating and storing 𝒮(𝐪ω) data. This information will be obtained by running dynamical spin simulations on equilibrium snapshots and measuring pair-correlations. The 𝒮(𝐪ω) data can be retrieved by calling intensities_interpolated. Alternatively, instant_intensities_interpolated will integrate out ω to obtain 𝒮(𝐪), optionally applying classical-to-quantum correction factors.\n\nThe SampleCorrelations that is returned will contain no correlation data. Samples are generated and accumulated by calling add_sample!(sc, sys) where sc is a SampleCorrelations and sys is an appropriately equilibrated System. Note that the sys should be thermalized before each call of add_sample! such that the spin configuration in the system represents a new (fully decorrelated) sample.\n\nThree keywords are required to specify the dynamics used for the trajectory calculation.\n\nΔt: The time step used for calculating the trajectory from which dynamic spin-spin correlations are calculated. The trajectories are calculated with an ImplicitMidpoint integrator.\nωmax: The maximum energy, ω, that will be resolved.\nnω: The number of energy bins to calculated between 0 and ωmax.\n\nAdditional keyword options are the following:\n\nprocess_trajectory: Specifies a function that will be applied to the sample trajectory before correlation analysis. Current options are :none and :symmetrize. The latter will symmetrize the trajectory in time, which can be useful for removing Fourier artifacts that arise when calculating the correlations.\nobservables: Allows the user to specify custom observables. The observables must be given as a list of complex N×N matrices or LinearMaps. It's recommended to name each observable, for example: observables = [:A => a_observable_matrix, :B => b_map, ...]. By default, Sunny uses the 3 components of the dipole, :Sx, :Sy and :Sz.\ncorrelations: Specify which correlation functions are calculated, i.e. which matrix elements αβ of 𝒮^αβ(qω) are calculated and stored. Specified with a vector of tuples. By default Sunny records all auto- and cross-correlations generated by all observables. To retain only the xx and xy correlations, one would set correlations=[(:Sx,:Sx), (:Sx,:Sy)] or correlations=[(1,1),(1,2)].\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.eachsite-Tuple{System}","page":"Library API","title":"Sunny.eachsite","text":"eachsite(sys::System)\n\nAn iterator over all Sites in the system. \n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.enable_dipole_dipole!-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.enable_dipole_dipole!","text":"enable_dipole_dipole!(sys::System)\n\nEnables long-range dipole-dipole interactions,\n\n -(μ_04π) _ij (3 (𝐌_j𝐫_ij)(𝐌_i𝐫_ij) - 𝐌_i𝐌_j) 𝐫_ij^3\n\nwhere the sum is over all pairs of spins (singly counted), including periodic images, regularized using the Ewald summation convention. The magnetic moments are 𝐌_i = μ_B g 𝐒_i where g is the g-factor or g-tensor, and 𝐒_i is the spin angular momentum dipole in units of ħ. The Bohr magneton μ_B and vacuum permeability μ_0 are physical constants, with numerical values determined by the unit system.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.energy-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.energy","text":"energy(sys::System)\n\nComputes the total system energy.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.generate_mantid_script_from_binning_parameters-Tuple{Any}","page":"Library API","title":"Sunny.generate_mantid_script_from_binning_parameters","text":"generate_mantid_script_from_binning_parameters(params::BinningParameters)\n\nGenerate a Mantid script which bins data according to the given BinningParameters.\n\nwarning: Units\nTake care to ensure the units are correct (R.L.U. or absolute). You may want to call Sunny.bin_rlu_as_absolute_units! or Sunny.bin_absolute_units_as_rlu! first.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.global_position-Tuple{System, Any}","page":"Library API","title":"Sunny.global_position","text":"global_position(sys::System, site::Site)\n\nPosition of a Site in global coordinates.\n\nTo precompute a full list of positions, one can use eachsite as below:\n\npos = [global_position(sys, site) for site in eachsite(sys)]\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.instant_correlations-Tuple{System}","page":"Library API","title":"Sunny.instant_correlations","text":"instant_correlations(sys::System; process_trajectory=:none, observables=nothing, correlations=nothing)\n\nCreates a SampledCorrelations object for calculating and storing instantaneous structure factor intensities 𝒮(𝐪). This data will be calculated from the spin-spin correlations of equilibrium snapshots, absent any dynamical information. 𝒮(𝐪) data can be retrieved by calling instant_intensities_interpolated.\n\nImportant note: When dealing with continuous (non-Ising) spins, consider creating using dynamical_correlations instead of instant_correlations. The former will provide full 𝒮(𝐪ω) data, from which 𝒮(𝐪) can be obtained by integrating out ω. During this integration step, Sunny can incorporate temperature- and ω-dependent classical-to-quantum correction factors to produce more accurate 𝒮(𝐪) estimates. See instant_intensities_interpolated for more information.\n\nPrior to calling instant_correlations, ensure that sys represents a good equilibrium sample. Additional sample data may be accumulated by calling add_sample!(sc, sys) with newly equilibrated sys configurations.\n\nThe following optional keywords are available:\n\nprocess_trajectory: Specifies a function that will be applied to the sample trajectory before correlation analysis. Current options are :none and :symmetrize. The latter will symmetrize the trajectory in time, which can be useful for removing Fourier artifacts that arise when calculating the correlations.\nobservables: Allows the user to specify custom observables. The observables must be given as a list of complex N×N matrices or LinearMaps. It's recommended to name each observable, for example: observables = [:A => a_observable_matrix, :B => b_map, ...]. By default, Sunny uses the 3 components of the dipole, :Sx, :Sy and :Sz.\ncorrelations: Specify which correlation functions are calculated, i.e. which matrix elements αβ of 𝒮^αβ(qω) are calculated and stored. Specified with a vector of tuples. By default Sunny records all auto- and cross-correlations generated by all observables. To retain only the xx and xy correlations, one would set correlations=[(:Sx,:Sx), (:Sx,:Sy)] or correlations=[(1,1),(1,2)].\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.instant_intensities_interpolated-Tuple{SampledCorrelations, Any, Any}","page":"Library API","title":"Sunny.instant_intensities_interpolated","text":"instant_intensities_interpolated(sc::SampledCorrelations, qs; kwargs...)\n\nReturn 𝒮(𝐪) intensities at wave vectors qs. The functionality is very similar to intensities_interpolated, except the returned array has dimensions identical to qs. If called on a SampledCorrelations with dynamical information, i.e., 𝒮(𝐪ω), the ω information is integrated out.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.integrate_axes!-Tuple{BinningParameters}","page":"Library API","title":"Sunny.integrate_axes!","text":"integrate_axes!(params::BinningParameters; axes)\n\nIntegrate over one or more axes of the histogram by setting the number of bins in that axis to 1. Examples:\n\nintegrate_axes!(params; axes = [2,3])\nintegrate_axes!(params; axes = 2)\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.integrated_lorentzian-Tuple{Float64}","page":"Library API","title":"Sunny.integrated_lorentzian","text":"integrated_lorentzian(η)\n\nReturns x mapsto atan(xη)π for use with intensities_binned.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensities_bands-Tuple{SpinWaveTheory, Any, Sunny.SpinWaveIntensityFormula}","page":"Library API","title":"Sunny.intensities_bands","text":"dispersion, intensities = intensities_bands(swt::SpinWaveTheory, ks, formula::SpinWaveIntensityFormula)\n\nComputes the scattering intensities at each energy band for each momentum transfer k in ks, according to Linear Spin Wave Theory and the given intensity formula. The formula must have a delta-function kernel, e.g.:\n\nformula = intensity_formula(swt, :perp, formula; kernel = delta_function_kernel)\n\nor else the bands will be broadened, and their intensity can not be computed.\n\nThe outputs will be arrays with indices identical to ks, with the last index giving the band index. dispersions reports the energy of each band, while intensities reports the scattering intensity.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensities_binned-Tuple{SampledCorrelations, BinningParameters, Sunny.ClassicalIntensityFormula}","page":"Library API","title":"Sunny.intensities_binned","text":"intensity, counts = intensities_binned(sc::SampledCorrelations, params::BinningParameters, formula; integrated_kernel)\n\nGiven correlation data contained in a SampledCorrelations and BinningParameters describing the shape of a histogram, compute the intensity and normalization for each histogram bin using a given intensity_formula.\n\nThe BinningParameters are expected to accept (q,ω) in R.L.U. for the (possibly reshaped) crystal associated with sc.\n\nThis is an alternative to intensities_interpolated which bins the scattering intensities into a histogram instead of interpolating between them at specified qs values. See unit_resolution_binning_parameters for a reasonable default choice of BinningParameters which roughly emulates intensities_interpolated with interpolation = :round.\n\nIf a function integrated_kernel(Δω) is passed, it will be used as the CDF of a kernel function for energy broadening. For example, integrated_kernel = Δω -> atan(Δω/η)/pi (c.f. integrated_lorentzian implements Lorentzian broadening with parameter η. Energy-dependent energy broadening can be achieved by providing an integrated_kernel(ω,Δω) whose first argument is the energy transfer ω.\n\nCurrently, energy broadening is only supported if the BinningParameters are such that the first three axes are purely spatial and the last (energy) axis is [0,0,0,1].\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensities_broadened-Tuple{SpinWaveTheory, Any, Any, Any}","page":"Library API","title":"Sunny.intensities_broadened","text":"intensities_broadened(swt::SpinWaveTheory, ks, ωvals, formula)\n\nComputes the scattering intensities at each (Q,ω) according to Linear Spin Wave Theory and the given intensity formula. The required formula must have a non-delta-function kernel, e.g.:\n\nformula = intensity_formula(swt, :perp; kernel = lorentzian(0.05))\n\nor else the intensity at ωvals which are not exactly on the dispersion curve can not be calculated.\n\nThe intensity is computed at each wave vector in ks and each energy in ωvals. The output will be an array with indices identical to ks, with the last index matching ωvals.\n\nNote that ks is an array of wave vectors of arbitrary dimension. Each element k of ks must be a 3-wavevector in absolute units.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensities_interpolated-Tuple{SampledCorrelations, Any, Sunny.ClassicalIntensityFormula}","page":"Library API","title":"Sunny.intensities_interpolated","text":"intensities_interpolated(sc::SampledCorrelations, qs, formula:ClassicalIntensityFormula; interpolation=nothing, negative_energies=false)\n\nThe basic function for retrieving 𝒮(𝐪ω) information from a SampledCorrelations. Maps an array of wave vectors qs to an array of structure factor intensities, including an additional energy index. The values of ω associated with the energy index can be retrieved by calling available_energies. The three coordinates of each wave vector are measured in reciprocal lattice units, i.e., multiples of the reciprocal lattice vectors.\n\ninterpolation: Since 𝒮(𝐪 ω) is calculated on a finite lattice, data is only available at discrete wave vectors. By default, Sunny will round a requested q to the nearest available wave vector. Linear interpolation can be applied by setting interpolation=:linear.\nnegative_energies: If set to true, Sunny will return the periodic extension of the energy axis. Most users will not want this.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensity_formula-Tuple{Function, SampledCorrelations, AbstractVector{Int64}}","page":"Library API","title":"Sunny.intensity_formula","text":"formula = intensity_formula(sc::SampledCorrelations)\n\nEstablish a formula for computing the intensity of the discrete scattering modes (q,ω) using the correlation data 𝒮^αβ(qω) stored in the SampledCorrelations. The formula returned from intensity_formula can be passed to intensities_interpolated or intensities_binned.\n\nintensity_formula(sc,...; kT = Inf, formfactors = ...)\n\nThere are keyword arguments providing temperature and form factor corrections:\n\nkT: If a temperature is provided, the intensities will be rescaled by a temperature- and ω-dependent classical-to-quantum factor. kT should be specified when making comparisons with spin wave calculations or experimental data. If kT is not specified, infinite temperature (no correction) is assumed.\nformfactors: To apply form factor corrections, provide this keyword with a list of FormFactors, one for each symmetry-distinct site in the crystal. The order of FormFactors must correspond to the order of site symmetry classes, e.g., as they appear when printed in display(crystal).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensity_formula-Tuple{Function, SampledCorrelations, Any}","page":"Library API","title":"Sunny.intensity_formula","text":"A custom intensity formula can be specifed by providing a function intensity = f(q,ω,correlations) and specifying which correlations it requires:\n\nintensity_formula(f,sc::SampledCorrelations, required_correlations; kwargs...)\n\nThe function is intended to be specified using do notation. For example, this custom formula sums the off-diagonal correlations:\n\nrequired = [(:Sx,:Sy),(:Sy,:Sz),(:Sx,:Sz)]\nintensity_formula(sc,required,return_type = ComplexF64) do k, ω, off_diagonal_correlations\n sum(off_diagonal_correlations)\nend\n\nIf your custom formula returns a type other than Float64, use the return_type keyword argument to flag this.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensity_formula-Tuple{Function, SpinWaveTheory, AbstractVector{Int64}}","page":"Library API","title":"Sunny.intensity_formula","text":"formula = intensity_formula(swt::SpinWaveTheory; kernel = ...)\n\nEstablish a formula for computing the scattering intensity by diagonalizing the hamiltonian H(q) using Linear Spin Wave Theory.\n\nIf kernel = delta_function_kernel, then the resulting formula can be used with intensities_bands.\n\nIf kernel is an energy broadening kernel function, then the resulting formula can be used with intensities_broadened. Energy broadening kernel functions can either be a function of Δω only, e.g.:\n\nkernel = Δω -> ...\n\nor a function of both the energy transfer ω and of Δω, e.g.:\n\nkernel = (ω,Δω) -> ...\n\nThe integral of a properly normalized kernel function over all Δω is one.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensity_formula-Tuple{SpinWaveTheory, Symbol}","page":"Library API","title":"Sunny.intensity_formula","text":"intensity_formula([swt or sc], contraction_mode::Symbol)\n\nSunny has several built-in formulas that can be selected by setting contraction_mode to one of these values:\n\n:trace (default), which yields operatornametr 𝒮(qω) = _α 𝒮^αα(qω)\n:perp, which contracts 𝒮^αβ(qω) with the dipole factor δ_αβ - q_αq_β, returning the unpolarized intensity.\n:full, which will return all elements 𝒮^αβ(𝐪ω) without contraction.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.lattice_params-Tuple{StaticArraysCore.SMatrix{3, 3, Float64, 9}}","page":"Library API","title":"Sunny.lattice_params","text":"lattice_params(latvecs::Mat3)\n\nCompute the lattice parameters (a b c α β γ) for the three lattice vectors provided as columns of latvecs. The inverse mapping is lattice_vectors.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.lattice_vectors-NTuple{6, Any}","page":"Library API","title":"Sunny.lattice_vectors","text":"lattice_vectors(a, b, c, α, β, γ)\n\nReturn the lattice vectors, as columns of the 33 output matrix, that correspond to the conventional unit cell defined by the lattice constants (a b c) and the angles (α β γ) in degrees. The inverse mapping is lattice_params.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.load_nxs-Tuple{Any}","page":"Library API","title":"Sunny.load_nxs","text":"params, signal = load_nxs(filename)\n\nGiven the name of a Mantid-exported MDHistoWorkspace file, load the BinningParameters and the signal from that file.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.lorentzian-Tuple{Any, Any}","page":"Library API","title":"Sunny.lorentzian","text":"lorentzian(x, η)\n\nReturns η(π(x^2 + η^2)).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.magnetic_moment-Tuple{System, Any}","page":"Library API","title":"Sunny.magnetic_moment","text":"magnetic_moment(sys::System, site::Site)\n\nGet the magnetic moment for a Site. This is the spin dipole multiplied by the Bohr magneton and the local g-tensor.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.merge!-Tuple{SampledCorrelations, Vararg{Any}}","page":"Library API","title":"Sunny.merge!","text":"merge!(sc::SampledCorrelations, others...)\n\nAccumulate the samples in others (one or more SampledCorrelations) into sc.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.minimize_energy!-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.minimize_energy!","text":"minimize_energy!(sys::System{N}; maxiters=100, subiters=20,\n method=Optim.ConjugateGradient(), kwargs...) where N\n\nOptimizes the spin configuration in sys to minimize energy. A total of maxiters iterations will be attempted, with restarts after every subiters iterations. The remaining kwargs will be forwarded to the optimize method of the Optim.jl package.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.polarize_spins!-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.polarize_spins!","text":"polarize_spins!(sys::System, dir)\n\nPolarize all spins in the system along the direction dir.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.position_to_site-Tuple{System, Any}","page":"Library API","title":"Sunny.position_to_site","text":"position_to_site(sys::System, r)\n\nConverts a position r to four indices of a Site. The coordinates of r are given in units of the lattice vectors for the original crystal. This function can be useful for working with systems that have been reshaped using reshape_supercell.\n\nExample\n\n# Find the `site` at the center of a unit cell which is displaced by four\n# multiples of the first lattice vector\nsite = position_to_site(sys, [4.5, 0.5, 0.5])\n\n# Print the dipole at this site\nprintln(sys.dipoles[site])\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.powder_average_binned-Tuple{SampledCorrelations, Any, Sunny.ClassicalIntensityFormula}","page":"Library API","title":"Sunny.powder_average_binned","text":"powder_average_binned(sc::SampledCorrelations, radial_binning_parameters; formula\n ω_binning_parameters, integrated_kernel = nothing, bzsize = nothing)\n\nThis function emulates the experimental situation of \"powder averaging,\" where only the magnitude (and not the direction) of the momentum transfer is resolvable. The intensities are binned similarly to intensities_binned, but the histogram x-axis is |k| in absolute units, which is a nonlinear function of kx,ky,kz. The y-axis is energy.\n\nRadial binning parameters are specified as tuples (start,end,bin_width), e.g. radial_binning_parameters = (0,6π,6π/55).\n\nEnergy broadening is supported in the same way as intensities_binned, and this function accepts the same kind of intensity_formula.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_bond-Tuple{Crystal, Bond}","page":"Library API","title":"Sunny.print_bond","text":"print_bond(cryst::Crystal, bond::Bond; b_ref::Bond)\n\nPrints symmetry information for bond bond. A symmetry-equivalent reference bond b_ref can optionally be provided to fix the meaning of the coefficients A, B, ...\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_site-Tuple{Any, Any}","page":"Library API","title":"Sunny.print_site","text":"print_site(cryst, i; R=I)\n\nPrint symmetry information for the site i, including allowed g-tensor and allowed anisotropy operator. An optional rotation matrix R can be provided to define the reference frame for expression of the anisotropy.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_stevens_expansion-Tuple{Matrix{ComplexF64}}","page":"Library API","title":"Sunny.print_stevens_expansion","text":"function print_stevens_expansion(op)\n\nPrints a local Hermitian operator as a linear combination of Stevens operators. This function works on explicit matrix representations.\n\nExamples\n\nS = spin_matrices(N=5)\nprint_stevens_expansion(S[1]^4 + S[2]^4 + S[3]^4)\n# Prints: (1/20)𝒪₄₀ + (1/4)𝒪₄₄ + 102/5\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_suggested_frame-Tuple{Crystal, Int64}","page":"Library API","title":"Sunny.print_suggested_frame","text":"print_suggested_frame(cryst, i; digits=4)\n\nPrint a suggested reference frame, as a rotation matrix R, that can be used as input to print_site(). This is useful to simplify the description of allowed anisotropies.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_symmetry_table-Tuple{Crystal, Any}","page":"Library API","title":"Sunny.print_symmetry_table","text":"print_symmetry_table(cryst::Crystal, max_dist)\n\nPrint symmetry information for all equivalence classes of sites and bonds, up to a maximum bond distance of max_dist. Equivalent to calling print_bond(cryst, b) for every bond b in reference_bonds(cryst, max_dist), where Bond(i, i, [0,0,0]) refers to a single site i.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_wrapped_intensities-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.print_wrapped_intensities","text":"print_wrapped_intensities(sys::System; nmax=10)\n\nFor Bravais lattices: Prints up to nmax wavevectors according to their instantaneous (static) structure factor intensities, listed in descending order. For non-Bravais lattices: Performs the same analysis for each spin sublattice independently; the output weights are naïvely averaged over sublattices, without incorporating phase shift information. Only wavevectors within the first Brillouin zone are printed. Wavevector coordinates are given in reciprocal lattice units, such that each coordinate is between -12 and 12. The output from this function will typically be used as input to suggest_magnetic_supercell.\n\nBecause this function does not incorporate phase information in its averaging over sublattices, the printed weights are not directly comparable with experiment. For that purpose, use instant_correlations instead.\n\nThe weights printed by print_wrapped_intensities may be given a physical interpretation as follows: All possible q-vectors are periodically wrapped into the first Brillouin zone, and the average over their corresponding instantaneous structure factor intensities produce the output weights.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.propose_delta-Tuple{Any}","page":"Library API","title":"Sunny.propose_delta","text":"propose_delta(magnitude)\n\nGenerate a proposal function that adds a Gaussian perturbation to the existing spin state. In :dipole mode, the procedure is to first introduce a random three-vector perturbation 𝐬 = 𝐬 + 𝐬 ξ and then return the properly normalized spin 𝐬 (𝐬𝐬). Each component of the random vector ξ is Gaussian distributed with a standard deviation of magnitude; the latter is dimensionless and typically smaller than one. \n\nIn :SUN mode, the procedure is analogous, but now involving Gaussian perturbations to each of the N complex components of an SU(N) coherent state.\n\nIn the limit of very large magnitude, this function coincides with propose_uniform.\n\nFor use with LocalSampler.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.propose_flip-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.propose_flip","text":"propose_flip\n\nFunction to propose pure spin flip updates in the context of a LocalSampler. Dipoles are flipped as 𝐬 -𝐬. SU(N) coherent states are flipped using the time-reversal operator.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.propose_uniform","page":"Library API","title":"Sunny.propose_uniform","text":"propose_uniform\n\nFunction to propose a uniformly random spin update in the context of a LocalSampler. In :dipole mode, the result is a random three-vector with appropriate normalization. In :SUN mode, the result is a random SU(N) coherent state with appropriate normalization.\n\n\n\n\n\n","category":"function"},{"location":"library/#Sunny.randomize_spins!-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.randomize_spins!","text":"randomize_spins!(sys::System)\n\nRandomizes all spins under appropriate the uniform distribution.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reciprocal_lattice_vectors-Tuple{Crystal}","page":"Library API","title":"Sunny.reciprocal_lattice_vectors","text":"reciprocal_lattice_vectors(cryst::Crystal)\n\nReturns the 33 matrix (𝐛₁𝐛₂𝐛₃) with columns 𝐛ᵢ as reciprocal lattice vectors. These are defined to satisfy 𝐛ᵢ𝐚ⱼ = 2πδᵢⱼ, where (𝐚₁𝐚₂𝐚₃) are the lattice vectors used to construct cryst.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reciprocal_space_path-Tuple{Crystal, Any, Any}","page":"Library API","title":"Sunny.reciprocal_space_path","text":"reciprocal_space_path(cryst::Crystal, qs, density)\n\nReturns a pair (path, xticks). The path return value is a list of wavevectors that samples linearly between the provided wavevectors qs. The xticks return value can be used to label the special 𝐪 values on the x-axis of a plot.\n\nSpecial note about units: the wavevectors qs must be provided in reciprocal lattice units (RLU) for the given crystal, but the sampling density must be specified in units of inverse length. The path will therefore include more samples between q-points that are further apart in absolute Fourier distance (units of inverse length).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reciprocal_space_path_bins-Tuple{Any, Any, Any, Vararg{Any}}","page":"Library API","title":"Sunny.reciprocal_space_path_bins","text":"reciprocal_space_path_bins(sc,qs,density,args...;kwargs...)\n\nTakes a list of wave vectors, qs in R.L.U., and builds a series of histogram BinningParameters whose first axis traces a path through the provided points. The second and third axes are integrated over according to the args and kwargs, which are passed through to slice_2D_binning_parameters.\n\nAlso returned is a list of marker indices corresponding to the input points, and a list of ranges giving the indices of each histogram x-axis within a concatenated histogram. The density parameter is given in samples per reciprocal lattice unit (R.L.U.).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reciprocal_space_shell-Tuple{Crystal, Any, Any}","page":"Library API","title":"Sunny.reciprocal_space_shell","text":"reciprocal_space_shell(cryst::Crystal, radius, n)\n\nSample n points on the reciprocal space sphere with a given radius (units of inverse length).\n\nExamples\n\n# Sample wavevectors on the sphere at fixed density\nreciprocal_space_shell(cryst, r, 4π*r^2*density)\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reference_bonds-Tuple{Crystal, Float64}","page":"Library API","title":"Sunny.reference_bonds","text":"reference_bonds(cryst::Crystal, max_dist)\n\nReturns a full list of bonds, one for each symmetry equivalence class, up to distance max_dist. The reference bond b for each equivalence class is selected according to a scoring system that prioritizes simplification of the elements in basis_for_symmetry_allowed_couplings(cryst, b).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.remove_periodicity!-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.remove_periodicity!","text":"remove_periodicity!(sys::System, dims)\n\nRemove periodic interactions along the dimensions where dims is true. The system must support inhomogeneous interactions via to_inhomogeneous.\n\nExample\n\n# Remove periodic boundaries along the 1st and 3rd dimensions\nremove_periodicity!(sys::System, (true, false, true))\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.repeat_periodically-Union{Tuple{N}, Tuple{System{N}, Tuple{Int64, Int64, Int64}}} where N","page":"Library API","title":"Sunny.repeat_periodically","text":"repeat_periodically(sys::System{N}, counts) where N\n\nCreates a System identical to sys but repeated a given number of times in each dimension, specified by the tuple counts.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reshape_supercell-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.reshape_supercell","text":"reshape_supercell(sys::System, A)\n\nMaps an existing System to a new one that has the shape and periodicity of a requested supercell. The columns of the 33 integer matrix A represent the supercell lattice vectors measured in units of the original crystal lattice vectors.\n\nThe crystal unit cell may also need to be reshaped to achieve the desired periodicity of the requested supercell. If this is the case, the returned System object will be missing symmetry information. Consequently, certain operations will be unavailable for this system, e.g., setting interactions by symmetry propagation. In practice, one can set all interactions using the original system, and then reshape as a final step.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.resize_supercell-Union{Tuple{N}, Tuple{System{N}, Tuple{Int64, Int64, Int64}}} where N","page":"Library API","title":"Sunny.resize_supercell","text":"resize_supercell(sys::System{N}, latsize) where N\n\nCreates a System identical to sys but enlarged to a given number of unit cells in each lattice vector direction.\n\nAn error will be thrown if sys is incommensurate with latsize. Use reshape_supercell instead to reduce the volume, or to perform an incommensurate reshaping.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.rotate_operator-Tuple{Matrix, Any}","page":"Library API","title":"Sunny.rotate_operator","text":"rotate_operator(A, R)\n\nRotates the local quantum operator A according to the 33 rotation matrix R.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.rotation_in_rlu-Tuple{Crystal, Any, Any}","page":"Library API","title":"Sunny.rotation_in_rlu","text":"rotation_in_rlu(cryst::Crystal, axis, angle)\n\nReturns a 33 matrix that rotates wavevectors in reciprocal lattice units (RLU). The axis vector is a real-space direction in absolute units (but arbitrary magnitude), and the angle is in radians.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_coherent!-Union{Tuple{N}, Tuple{System{N}, Any, Any}} where N","page":"Library API","title":"Sunny.set_coherent!","text":"set_coherent!(sys::System, Z, site::Site)\n\nSet a coherent spin state at a Site using the N complex amplitudes in Z.\n\nFor a standard SpinInfo, these amplitudes will be interpreted in the eigenbasis of 𝒮ᶻ. That is, Z[1] represents the amplitude for the basis state fully polarized along the z-direction, and subsequent components represent states with decreasing angular momentum along this axis (m = S S-1 -S).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_dipole!-Union{Tuple{N}, Tuple{System{N}, Any, Any}} where N","page":"Library API","title":"Sunny.set_dipole!","text":"set_dipole!(sys::System, dir, site::Site)\n\nPolarize the spin at a Site along the direction dir.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_exchange!-Union{Tuple{N}, Tuple{System{N}, Any, Bond}} where N","page":"Library API","title":"Sunny.set_exchange!","text":"set_exchange!(sys::System, J, bond::Bond; biquad=0.)\n\nSets a 3×3 spin-exchange matrix J along bond, yielding a pairwise interaction energy 𝐒_iJ 𝐒_j. This interaction will be propagated to equivalent bonds in consistency with crystal symmetry. Any previous exchange interactions on these bonds will be overwritten. The parameter bond has the form Bond(i, j, offset), where i and j are atom indices within the unit cell, and offset is a displacement in unit cells.\n\nThe parameter J may be scalar or matrix-valued. As a convenience, dmvec(D) can be used to construct the antisymmetric part of the exchange, where D is the Dzyaloshinskii-Moriya pseudo-vector. The resulting interaction will be 𝐃(𝐒_i𝐒_j).\n\nThe optional parameter biquad defines the strength b for scalar biquadratic interactions of the form b (𝐒_i𝐒_j)² For systems restricted to dipoles, b will be automatically renormalized for maximum consistency with the more variationally accurate SU(N) mode. This renormalization introduces also a correction to the quadratic part of the exchange.\n\nExamples\n\nusing Sunny, LinearAlgebra\n\n# An explicit exchange matrix\nJ1 = [2 3 0;\n -3 2 0;\n 0 0 2]\nset_exchange!(sys, J1, bond)\n\n# An equivalent Heisenberg + DM exchange \nJ2 = 2*I + dmvec([0,0,3])\nset_exchange!(sys, J2, bond)\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_exchange_at!-Union{Tuple{N}, Tuple{System{N}, Any, Union{NTuple{4, Int64}, CartesianIndex{4}}, Union{NTuple{4, Int64}, CartesianIndex{4}}}} where N","page":"Library API","title":"Sunny.set_exchange_at!","text":"set_exchange_at!(sys::System, J, site1::Site, site2::Site; biquad=0., offset=nothing)\n\nSets the exchange interaction along the single bond connecting two Sites, ignoring crystal symmetry. The system must support inhomogeneous interactions via to_inhomogeneous.\n\nIf the system is relatively small, the direction of the bond can be ambiguous due to possible periodic wrapping. Resolve this ambiguity by passing an explicit offset vector, in multiples of unit cells.\n\nSee also set_exchange!.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_external_field!-Tuple{System, Any}","page":"Library API","title":"Sunny.set_external_field!","text":"set_external_field!(sys::System, B::Vec3)\n\nSets the external field B that couples to all spins.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_external_field_at!-Tuple{System, Any, Any}","page":"Library API","title":"Sunny.set_external_field_at!","text":"set_external_field_at!(sys::System, B::Vec3, site::Site)\n\nSets a Zeeman coupling between a field B and a single spin. Site includes a unit cell and a sublattice index.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_onsite_coupling!-Union{Tuple{N}, Tuple{System{N}, Matrix{ComplexF64}, Int64}} where N","page":"Library API","title":"Sunny.set_onsite_coupling!","text":"set_onsite_coupling!(sys::System, op::Matrix{ComplexF64}, i::Int)\n\nSet the single-ion anisotropy for the ith atom of every unit cell, as well as all symmetry-equivalent atoms. The local operator op may be constructed using spin_operators or stevens_operators.\n\nFor systems restricted to dipoles, the anisotropy operators interactions will automatically be renormalized to achieve maximum consistency with the more variationally accurate SU(N) mode.\n\nExamples\n\n# An easy axis anisotropy in the z-direction\nS = spin_operators(sys, i)\nset_onsite_coupling!(sys, -D*S[3]^3, i)\n\n# The unique quartic single-ion anisotropy for a site with cubic point group\n# symmetry\nO = stevens_operators(sys, i)\nset_onsite_coupling!(sys, O[4,0] + 5*O[4,4], i)\n\n# An equivalent expression of this quartic anisotropy, up to a constant shift\nset_onsite_coupling!(sys, 20*(S[1]^4 + S[2]^4 + S[3]^4), i)\n\nSee also spin_operators.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_onsite_coupling_at!-Union{Tuple{N}, Tuple{System{N}, Matrix{ComplexF64}, Union{NTuple{4, Int64}, CartesianIndex{4}}}} where N","page":"Library API","title":"Sunny.set_onsite_coupling_at!","text":"set_onsite_coupling_at!(sys::System, op::Matrix{ComplexF64}, site::Site)\n\nSets the single-ion anisotropy operator op for a single Site, ignoring crystal symmetry. The system must support inhomogeneous interactions via to_inhomogeneous.\n\nSee also set_onsite_coupling!.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_vacancy_at!-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.set_vacancy_at!","text":"set_vacancy_at!(sys::System, site::Site)\n\nMake a single site nonmagnetic. Site includes a unit cell and a sublattice index.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.slice_2D_binning_parameters-Tuple{Vector{Float64}, Any, Any, Int64, Any}","page":"Library API","title":"Sunny.slice_2D_binning_parameters","text":"slice_2D_binning_parameter(sc::SampledCorrelations, cut_from_q, cut_to_q, cut_bins::Int64, cut_width::Float64; plane_normal = [0,0,1],cut_height = cutwidth)\n\nCreates BinningParameters which make a cut along one dimension of Q-space.\n\nThe x-axis of the resulting histogram consists of cut_bins-many bins ranging from cut_from_q to cut_to_q. The width of the bins in the transverse direciton is controlled by cut_width and cut_height.\n\nThe binning in the transverse directions is defined in the following way, which sets their normalization and orthogonality properties:\n\ncut_covector = normalize(cut_to_q - cut_from_q)\ntransverse_covector = normalize(plane_normal × cut_covector)\ncotransverse_covector = normalize(transverse_covector × cut_covector)\n\nIn other words, the axes are orthonormal with respect to the Euclidean metric.\n\nIf the cut is too narrow, there will be very few scattering vectors per bin, or the number per bin will vary substantially along the cut. If the output appears under-resolved, try increasing cut_width.\n\nThe four axes of the resulting histogram are:\n\nAlong the cut\nFist transverse Q direction\nSecond transverse Q direction\nEnergy\n\nThis function can be used without reference to a SampledCorrelations using this alternate syntax to manually specify the bin centers for the energy axis:\n\nslice_2D_binning_parameter(ω_bincenters, cut_from, cut_to,...)\n\nwhere ω_bincenters specifies the energy axis, and both cut_from and cut_to are arbitrary covectors, in any units.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.spin_matrices-Tuple{}","page":"Library API","title":"Sunny.spin_matrices","text":"spin_matrices(; N)\n\nConstructs the three spin operators, i.e. the generators of SU(2), in the N-dimensional irrep. See also spin_operators, which determines the appropriate value of N for a given site index.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.spin_operators-Union{Tuple{N}, Tuple{System{N}, Int64}} where N","page":"Library API","title":"Sunny.spin_operators","text":"spin_operators(sys, i::Int)\nspin_operators(sys, site::Int)\n\nReturns the three spin operators appropriate to an atom or Site index. Each is an NN matrix of appropriate dimension N.\n\nSee also print_stevens_expansion.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.step!","page":"Library API","title":"Sunny.step!","text":"step!(sys::System, dynamics)\n\nAdvance the spin configuration one dynamical time-step. The dynamics object may be a continuous spin dynamics, such as Langevin or ImplicitMidpoint, or it may be a discrete Monte Carlo sampling scheme such as LocalSampler.\n\n\n\n\n\n","category":"function"},{"location":"library/#Sunny.stevens_operators-Union{Tuple{N}, Tuple{System{N}, Int64}} where N","page":"Library API","title":"Sunny.stevens_operators","text":"stevens_operators(sys, i::Int)\nstevens_operators(sys, site::Int)\n\nReturns a generator of Stevens operators appropriate to an atom or Site index. The return value O can be indexed as O[k,q], where 0 k 6 labels an irrep and q = -k k. This will produce an NN matrix of appropriate dimension N.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.subcrystal-Union{Tuple{N}, Tuple{Crystal, Vararg{String, N}}} where N","page":"Library API","title":"Sunny.subcrystal","text":"subcrystal(cryst, types) :: Crystal\n\nFilters sublattices of a Crystal by atom types, keeping the space group unchanged.\n\nsubcrystal(cryst, classes) :: Crystal\n\nFilters sublattices of Crystal by equivalence classes, keeping the space group unchanged.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.suggest_magnetic_supercell-Tuple{Any, Any}","page":"Library API","title":"Sunny.suggest_magnetic_supercell","text":"suggest_magnetic_supercell(qs, latsize)\n\nSuggests a magnetic supercell, in units of the crystal lattice vectors, that is consistent with periodicity of the wavevectors in qs. An upper bound for the supercell is given by latsize, which is measured in units of lattice vectors, and must be commensurate with the wavevectors.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.symmetry_equivalent_bonds-Tuple{System, Bond}","page":"Library API","title":"Sunny.symmetry_equivalent_bonds","text":"symmetry_equivalent_bonds(sys::System, bond::Bond)\n\nGiven a Bond for the original (unreshaped) crystal, return all symmetry equivalent bonds in the System. Each returned bond is represented as a pair of Sites, which may be used as input to set_exchange_at!. Reverse bonds are not included (no double counting).\n\nExample\n\nfor (site1, site2, offset) in symmetry_equivalent_bonds(sys, bond)\n @assert site1 < site2\n set_exchange_at!(sys, J, site1, site2; offset)\nend\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.to_inhomogeneous-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.to_inhomogeneous","text":"to_inhomogeneous(sys::System)\n\nReturns a copy of the system that allows for inhomogeneous interactions, which can be set using set_onsite_coupling_at!, set_exchange_at!, and set_vacancy_at!.\n\nInhomogeneous systems do not support symmetry-propagation of interactions or system reshaping.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.unit_resolution_binning_parameters-Tuple{Any, Any, Vararg{Any}}","page":"Library API","title":"Sunny.unit_resolution_binning_parameters","text":"unit_resolution_binning_parameters(sc::SampledCorrelations)\n\nCreate BinningParameters which place one histogram bin centered at each possible (q,ω) scattering vector of the crystal. This is the finest possible binning without creating bins with zero scattering vectors in them.\n\nThis function can be used without reference to a SampledCorrelations using an alternate syntax to manually specify the bin centers for the energy axis and the lattice size:\n\nunit_resolution_binning_parameters(ω_bincenters,latsize,[reciprocal lattice vectors])\n\nThe last argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or a Crystal.\n\nLastly, binning parameters for a single axis may be specifed by their bin centers:\n\n(binstart,binend,binwidth) = unit_resolution_binning_parameters(bincenters::Vector{Float64})\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.view_crystal-Tuple{Crystal, Real}","page":"Library API","title":"Sunny.view_crystal","text":"view_crystal(crystal::Crystal, max_dist::Real)\n\nCreate and show crystal viewer in a VSCode or Jupyter notebook environment. The result can also be displayed using browser().\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.@mix_proposals-Tuple","page":"Library API","title":"Sunny.@mix_proposals","text":"@mix_proposals weight1 propose1 weight2 propose2 ...\n\nMacro to generate a proposal function that randomly selects among the provided functions according to the provided probability weights. For use with LocalSampler.\n\nExample\n\n# A proposal function that proposes a spin flip 40% of the time, and a\n# Gaussian perturbation 60% of the time.\n@mix_proposals 0.4 propose_flip 0.6 propose_delta(0.2)\n\n\n\n\n\n","category":"macro"},{"location":"library/#Optional-Makie-extensions","page":"Library API","title":"Optional Makie extensions","text":"","category":"section"},{"location":"library/","page":"Library API","title":"Library API","text":"The following will be enabled through a package extension if either GLMakie or WGLMakie is loaded.","category":"page"},{"location":"library/","page":"Library API","title":"Library API","text":"plot_spins","category":"page"},{"location":"library/#Sunny.plot_spins","page":"Library API","title":"Sunny.plot_spins","text":"plot_spins(sys::System; arrowscale=1.0, linecolor=:lightgrey,\n arrowcolor=:red, show_axis=false, show_cell=true,\n orthographic=false, ghost_radius=0)\n\nPlot the spin configuration defined by sys. Optional parameters include:\n\narrowscale: Scale all arrows by dimensionless factor.\nshow_axis: Show global Cartesian coordinates axis.\nshow_cell: Show original crystallographic unit cell.\northographic: Use camera with orthographic projection.\nghost_radius: Show translucent periodic images up to a radius, given as a multiple of the characteristic distance between sites.\n\n\n\n\n\n","category":"function"},{"location":"library/#Optional-WriteVTK-extensions","page":"Library API","title":"Optional WriteVTK extensions","text":"","category":"section"},{"location":"library/","page":"Library API","title":"Library API","text":"The following will be enabled through a package extension if WriteVTK is loaded.","category":"page"},{"location":"library/","page":"Library API","title":"Library API","text":"export_vtk","category":"page"},{"location":"library/#Sunny.export_vtk","page":"Library API","title":"Sunny.export_vtk","text":"export_vtk(filename,params::BinningParameters,data)\n\nExport a VTK-compatible file to filename (do not include file extension when specifying the file name) which contains the data as VTK Cell Data on a grid parameterized by params.\n\nAt least one axis of the BinningParameters must be integrated over, since VTK does not support 4D data. See integrate_axes!.\n\n\n\n\n\n","category":"function"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"EditURL = \"../../../examples/fei2_classical.jl\"","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/fei2_classical/#Structure-Factors-with-Classical-Dynamics","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"","category":"section"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"using Sunny, LinearAlgebra, GLMakie","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"In our previous Case Study: FeI_2, we used linear spin wave theory (LSWT) to calculate the dynamical structure factor. Here, we perform a similar calculation using classical spin dynamics. Because we are interested in the coupled dynamics of spin dipoles and quadrupoles, we employ a classical dynamics of SU(3) coherent states that generalizes the Landau-Lifshitz equation.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Compared to LSWT, simulations using classical dynamics are much slower, and are limited in k-space resolution. However, they make it is possible to capture nonlinear effects associated with finite temperature fluctuations. Classical dynamics are also appealing for studying out-of-equilibrium systems (e.g., relaxation of spin glasses), or systems with quenched inhomogeneities that require large simulation volumes.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"In this tutorial, we show how to study the finite temperature dynamics of FeI_2 using the classical approach. It is important to stress that the estimation of S(𝐪ω) with classical dynamics is fundamentally a Monte Carlo calculation: sample spin configurations are drawn from thermal equilibrium and used as initial conditions for generating dissipationless trajectories. The correlations of these trajectories are then averaged and used to calculate scattering intensities. It is therefore important to ensure that the initial spin configurations are sampled appropriately and that sufficient statistics are collected. We will demonstrate one approach here.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"As an overview, we will:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Identify the ground state\nMeasure correlation data describing the excitations around that ground state\nUse the correlation data to compute scattering intensities","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"As the implementation of the FeI_2 model is already covered in detail in the LSWT tutorial, we will not repeat it below. Instead, we will assume that you already have defined a sys in the same way with lattice dimensions 444.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"a = b = 4.05012#hide\nc = 6.75214#hide\nlatvecs = lattice_vectors(a, b, c, 90, 90, 120)#hide\npositions = [[0,0,0], [1/3, 2/3, 1/4], [2/3, 1/3, 3/4]]#hide\ntypes = [\"Fe\", \"I\", \"I\"]#hide\nFeI2 = Crystal(latvecs, positions; types)#hide\ncryst = subcrystal(FeI2, \"Fe\")#hide\nsys = System(cryst, (4,4,4), [SpinInfo(1,S=1,g=2)], :SUN, seed=2)#hide\nJ1pm = -0.236#hide\nJ1pmpm = -0.161#hide\nJ1zpm = -0.261#hide\nJ2pm = 0.026#hide\nJ3pm = 0.166#hide\nJ′0pm = 0.037#hide\nJ′1pm = 0.013#hide\nJ′2apm = 0.068#hide\nJ1zz = -0.236#hide\nJ2zz = 0.113#hide\nJ3zz = 0.211#hide\nJ′0zz = -0.036#hide\nJ′1zz = 0.051#hide\nJ′2azz = 0.073#hide\nJ1xx = J1pm + J1pmpm#hide\nJ1yy = J1pm - J1pmpm#hide\nJ1yz = J1zpm#hide\nset_exchange!(sys, [J1xx 0.0 0.0; 0.0 J1yy J1yz; 0.0 J1yz J1zz], Bond(1,1,[1,0,0]))#hide\nset_exchange!(sys, [J2pm 0.0 0.0; 0.0 J2pm 0.0; 0.0 0.0 J2zz], Bond(1,1,[1,2,0]))#hide\nset_exchange!(sys, [J3pm 0.0 0.0; 0.0 J3pm 0.0; 0.0 0.0 J3zz], Bond(1,1,[2,0,0]))#hide\nset_exchange!(sys, [J′0pm 0.0 0.0; 0.0 J′0pm 0.0; 0.0 0.0 J′0zz], Bond(1,1,[0,0,1]))#hide\nset_exchange!(sys, [J′1pm 0.0 0.0; 0.0 J′1pm 0.0; 0.0 0.0 J′1zz], Bond(1,1,[1,0,1]))#hide\nset_exchange!(sys, [J′2apm 0.0 0.0; 0.0 J′2apm 0.0; 0.0 0.0 J′2azz], Bond(1,1,[1,2,1]))#hide\nD = 2.165#hide\nS = spin_operators(sys, 1)#hide\nset_onsite_coupling!(sys, -D*S[3]^2, 1)#hide","category":"page"},{"location":"examples/fei2_classical/#Finding-a-ground-state","page":"Structure Factors with Classical Dynamics","title":"Finding a ground state","text":"","category":"section"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Sunny uses the Langevin dynamics of SU(N) coherent states to sample spin configurations from the thermal equlibrium. One first constructs a Langevin integrator. This requires a time step, temperature, and a phenomenological damping parameter λ that sets the coupling to the thermal bath.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Δt = 0.05/D # Should be inversely proportional to the largest energy scale\n # in the system. For FeI2, this is the easy-axis anisotropy,\n # `D = 2.165` (meV). The prefactor 0.05 is relatively small,\n # and achieves high accuracy.\nkT = 0.2 # Temperature of the thermal bath (meV).\nλ = 0.1 # This value is typically good for Monte Carlo sampling,\n # independent of system details.\n\nlangevin = Langevin(Δt; kT, λ);\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Sampling with a large number of Langevin time-steps should hopefully thermalize the system to a target temperature. For demonstration purposes, we will here run for a relatively short period of 1,000 timesteps.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"randomize_spins!(sys)\nfor _ in 1:1_000\n step!(sys, langevin)\nend","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"To inspect the structure of the spin configuration, we use the function minimize_energy! to find a nearby local minimum. Then print_wrapped_intensities provides information about the Fourier modes in reciprocal lattice units (RLU).","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"minimize_energy!(sys)\nprint_wrapped_intensities(sys)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The wide distribution of intensities indicates an imperfect magnetic order. The defects are immediately apparent in the real-space spin configuration.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"plot_spins(sys)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"In this case, we can find the correct ground state simply by running the Langevin dynamics for longer.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"for _ in 1:10_000\n step!(sys, langevin)\nend\nminimize_energy!(sys)\nprint_wrapped_intensities(sys)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"This is the perfect single-𝐐 ground state. This worked because the temperature kT = 0.2 was carefully selected. It is below the magnetic ordering temperature, but still large enough that the Langevin dynamics could quickly overcome local energy barriers. More complicated magnetic orderings will frequently require more sophisticated sampling schemes. One possibility is simulated annealing, where kT is slowly lowered over the course of the sampling procedure.","category":"page"},{"location":"examples/fei2_classical/#Calculating-Thermal-Averaged-Correlations-\\langle-S{\\alpha\\beta}(𝐪,ω)\\rangle","page":"Structure Factors with Classical Dynamics","title":"Calculating Thermal-Averaged Correlations langle S^alphabeta(𝐪ω)rangle","text":"","category":"section"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Now that we have identified an appropriate ground state, we will adjust the temperature so that the system still remains near the ground state, but still has thermal fluctuations.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"kT = 3.5 * meV_per_K # 3.5K ≈ 0.30 meV\nlangevin.kT = kT;\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Additionally, since these classical simulations are conducted on a finite-sized lattice, obtaining acceptable resolution in momentum space requires the use of a larger system size. We resize the magnetic supercell to a much larger simulation volume, provided as multiples of the original unit cell.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"sys_large = resize_supercell(sys, (16,16,4)) # 16x16x4 copies of the original unit cell\nplot_spins(sys_large)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"As stressed above, we need to sample multiple spin configurations from the thermal equilibrium distribution. We therefore begin by using Langevin dynamics to bring the system into thermal equilibrium at the new temperature.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"# At the new temperature\nfor _ in 1:10_000\n step!(sys_large, langevin)\nend","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Now that we are in a state drawn from thermal equilibrium, we are ready to begin collecting correlation data S^alphabeta.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"To collect one sample of spin-spin correlation data, we integrate the Hamiltonian dynamics of SU(N) coherent states. This generates trajectories S^alpha(vec rt). However, note that the spins are only defined at the finitely-many lattice sites, so vec r is discrete. From the trajectories, Sunny computes fourier-transformed correlations S^alphabeta(qomega), where q is discrete for the same reason.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The correlation data from this sample is now ready to be averaged together with data from other samples to form the thermal average. Samples of correlation data are accumulated and averaged into a SampledCorrelations, which is initialized by calling dynamical_correlations:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"sc = dynamical_correlations(sys_large; Δt=2Δt, nω=120, ωmax=7.5)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"dynamical_correlations takes a System and three keyword parameters that determine the ω information that will be available: an integration step size, the number of ωs to resolve, and the maximum ω to resolve. For the time step, twice the value used for the Langevin integrator is usually a good choice.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"sc currently contains no data. The first sample can be accumulated into it by calling add_sample!.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"add_sample!(sc, sys_large)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Additional samples can be added after re-sampling new spin configurations from the thermal distribution. The new samples are generated in the same way as the first sample, by running the Langevin dynamics. The dynamics should be run long enough that consecutive samples are uncorrelated, or else the thermal average will converge only very slowly.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"for _ in 1:2\n for _ in 1:1000 # Enough steps to decorrelate spins\n step!(sys_large, langevin)\n end\n add_sample!(sc, sys_large) # Accumulate the sample into `sc`\nend","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Now, sc has more samples included:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"sc","category":"page"},{"location":"examples/fei2_classical/#Computing-Scattering-Intensities","page":"Structure Factors with Classical Dynamics","title":"Computing Scattering Intensities","text":"","category":"section"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"With the thermally-averaged correlation data langle S^alphabeta(qomega)rangle in hand, we now need to specify how to extract a scattering intensity from this information. This is done by constructing an intensity_formula. By way of example, we will use a formula which computes the trace of the structure factor and applies a classical-to-quantum temperature-dependent rescaling kT.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"formula = intensity_formula(sc, :trace; kT = kT)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Recall that langle S^alphabeta(qomega)rangle is only available at certain discrete q values, due to the finite lattice size. There are two basic approaches to handling this discreteness. The first approach is to interpolate between the available data using intensities_interpolated. For example, we can plot single-q slices at (0,0,0) and (π,π,π) using this method:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"qs = [[0, 0, 0], [0.5, 0.5, 0.5]]\nis = intensities_interpolated(sc, qs, formula; interpolation = :round)\n\nωs = available_energies(sc)\nfig = lines(ωs, is[1,:]; axis=(xlabel=\"meV\", ylabel=\"Intensity\"), label=\"(0,0,0)\")\nlines!(ωs, is[2,:]; label=\"(π,π,π)\")\naxislegend()\nfig","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The resolution in energy can be improved by increasing nω (and decreasing Δt), and the general accuracy can be improved by collecting additional samples from the thermal equilibrium.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"For real calculations, one often wants to apply further corrections and more accurate formulas. Here, we apply FormFactor corrections appropriate for Fe2 magnetic ions, and a dipole polarization correction :perp.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"formfactors = [FormFactor(\"Fe2\"; g_lande=3/2)]\nnew_formula = intensity_formula(sc, :perp; kT = kT, formfactors = formfactors)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Frequently, one wants to extract energy intensities along lines that connect special wave vectors–a so-called \"spaghetti plot\". The function reciprocal_space_path creates an appropriate horizontal axis for this plot by linearly sampling between provided q-points, with a given sample density.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"points = [[0, 0, 0], # List of wave vectors that define a path\n [1, 0, 0],\n [0, 1, 0],\n [1/2, 0, 0],\n [0, 1, 0],\n [0, 0, 0]]\ndensity = 40\npath, xticks = reciprocal_space_path(cryst, points, density);\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Again using intensities_interpolated, we can evaluate the (interpolated) intensity at each point on the path. Since scattering intensities are only available at a certain discrete (Qomega) points, the intensity on the path can be calculated by interpolating between these discrete points:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"is_interpolated = intensities_interpolated(sc, path, new_formula;\n interpolation = :linear, # Interpolate between available wave vectors\n);\n# Add artificial broadening\nis_interpolated_broadened = broaden_energy(sc, is, (ω, ω₀)->lorentzian(ω-ω₀, 0.05));\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The second approach to handle the discreteness of the data is to bin the intensity at the discrete points into the bins of a histogram. First, the five sub-histograms are set up using reciprocal_space_path_bins in analogy to reciprocal_space_path.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"cut_width = 0.3\ndensity = 15\nparamsList, markers, ranges = reciprocal_space_path_bins(sc,points,density,cut_width);\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Then, the intensity data is computed using intensities_binned for each sub-histogram:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"total_bins = ranges[end][end]\nenergy_bins = paramsList[1].numbins[4]\nis_binned = zeros(Float64,total_bins,energy_bins)\nintegrated_kernel = integrated_lorentzian(0.05) # Lorentzian broadening\nfor k in eachindex(paramsList)\n bin_data, counts = intensities_binned(sc,paramsList[k], new_formula;\n integrated_kernel = integrated_kernel\n )\n is_binned[ranges[k],:] = bin_data[:,1,1,:] ./ counts[:,1,1,:]\nend","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The graph produced by interpolating (top) is similar to the one produced by binning (bottom):","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"fig = Figure()\nax_top = Axis(fig[1,1],ylabel = \"meV\",xticklabelrotation=π/8,xticklabelsize=12;xticks)\nax_bottom = Axis(fig[2,1],ylabel = \"meV\",xticks = (markers, string.(points)),xticklabelrotation=π/8,xticklabelsize=12)\n\nheatmap!(ax_top,1:size(is_interpolated,1), ωs, is_interpolated;\n colorrange=(0.0,0.07),\n)\n\nheatmap!(ax_bottom,1:size(is_binned,1), ωs, is_binned;\n colorrange=(0.0,0.05),\n)\n\nfig","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Note that we have clipped the colors in order to make the higher-energy excitations more visible.","category":"page"},{"location":"examples/fei2_classical/#Unconventional-R.L.U.-Systems-and-Constant-Energy-Cuts","page":"Structure Factors with Classical Dynamics","title":"Unconventional R.L.U. Systems and Constant Energy Cuts","text":"","category":"section"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Often it is useful to plot cuts across multiple wave vectors but at a single energy. We'll pick an energy,","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"ωidx = 60\ntarget_ω = ωs[ωidx]\nprintln(\"target_ω = $(target_ω)\")#hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"and take a constant-energy cut at that energy. The most straightforward way is to make a plot whose axes are aligned with the conventional reciprocal lattice of the crystal. This is accomplished using unit_resolution_binning_parameters:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"params = unit_resolution_binning_parameters(sc)\nparams.binstart[1:2] .= -1 # Expand plot range slightly\n\n# Set energy integration range\nomega_width = 0.3\nparams.binstart[4] = target_ω - (omega_width/2)\nparams.binend[4] = target_ω # `binend` should be inside (e.g. at the center) of the range\nparams.binwidth[4] = omega_width\n\nintegrate_axes!(params, axes = 3) # Integrate out z direction entirely\nparams#hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"In each of the following plots, black dashed lines represent (direct) lattice vectors. Since these plots are in reciprocal space, direct lattice vectors are represented as covectors (i.e. coordinate grids) instead of as arrows.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"is, counts = intensities_binned(sc,params,new_formula)\n\nfig = Figure()\nax = Axis(fig[1,1];\n title=\"Δω=0.3 meV (Binned)\", aspect=true,\n xlabel = \"[H, 0, 0]\",\n ylabel = \"[0, K, 0]\"\n)\nbcs = axes_bincenters(params)\nhm = heatmap!(ax,bcs[1],bcs[2],is[:,:,1,1] ./ counts[:,:,1,1])\nfunction add_lines!(ax,params)#hide\n bes = Sunny.axes_binedges(params)#hide\n hrange = range(-2,2,length=17)#hide\n linesegments!(ax,[(Point2f(params.covectors[1,1:3] ⋅ [h,-10,0],params.covectors[2,1:3] ⋅ [h,-10,0]),Point2f(params.covectors[1,1:3] ⋅ [h,10,0],params.covectors[2,1:3] ⋅ [h,10,0])) for h = hrange],linestyle=:dash,color=:black)#hide\n krange = range(-2,2,length=17)#hide\n linesegments!(ax,[(Point2f(params.covectors[1,1:3] ⋅ [-10,k,0],params.covectors[2,1:3] ⋅ [-10,k,0]),Point2f(params.covectors[1,1:3] ⋅ [10,k,0],params.covectors[2,1:3] ⋅ [10,k,0])) for k = krange],linestyle=:dash,color=:black)#hide\n xlims!(ax,bes[1][1],bes[1][end])#hide\n ylims!(ax,bes[2][1],bes[2][end])#hide\nend#hide\nadd_lines!(ax,params)\nColorbar(fig[1,2], hm);\nfig","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"In the above plot, the dashed-line (direct) lattice vectors are clearly orthogonal. However, we know that in real space, the lattice vectors a and b are not orthogonal, but rather point along the edges of a hexagon (see lower left corner):","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"

","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Thus, plotting the direct lattice vectors as orthogonal (even in reciprocal space) is somewhat misleading. Worse yet, the [H,0,0] by [0,K,0] plot apparently loses the 6-fold symmetry of the crystal! Lastly, if one works out the components of the real-space metric with respect to the axes of the plot, one finds that there are non-zero off-diagonal entries,","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"latvecs = sys.crystal.latvecs\nmetric = latvecs' * I(3) * latvecs","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"so real-space rotations and angles map into reciprocal space rotations angles in a complicated way.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"To resolve these important issues, we want to use axes which are orthogonal (i.e. they diagonalize the metric and solve all of the problems just mentioned). The canonical choice is to use the combination frac12a + b of lattice vectors (equiv. a^* - frac12b^*), which is orthogonal to a:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"(latvecs * [1/2,1,0]) ⋅ (latvecs * [1,0,0]) == 0","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"This new vector frac12a+b is visibly orthogonal to a in real space:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"f = Figure()#hide\nax = Axis(f[1,1])#hide\narrows!(ax,[Point2f(0,0),Point2f(latvecs[1:2,1] ./ 2)],[Vec2f(latvecs[1:2,1] ./ 2), Vec2f(latvecs[1:2,2])],arrowcolor = :blue,arrowsize = 30.,linewidth = 5.,linecolor = :blue)#hide\narrows!(ax,[Point2f(0,0)],[Vec2f(latvecs[1:2,:] * [1/2,1,0])],arrowcolor = :red,arrowsize = 30.,linewidth = 5.,linecolor = :red, linestyle = :dash)#hide\nscatter!(ax,[Point2f(latvecs[1:2,:] * [a,b,0]) for a in -1:1, b in -1:1][:],color = :black)#hide\nannotations!(ax,[\"0\",\"0+b\",\"0+a\", \"a/2\", \"b\"],[Point2f(0,-0.3),Point2f(latvecs[1:2,2]) .- Vec2f(0,0.3),Point2f(latvecs[1:2,1]) .- Vec2f(0,0.3),Point2f(latvecs[1:2,1] ./ 4) .- Vec2f(0,0.3),Point2f(latvecs[1:2,1] ./ 2) .+ Vec2f(latvecs[1:2,2] ./ 2) .+ Vec2f(0.3,0.3)],color=[:black,:black,:black,:blue,:blue])#hide\nf#hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"To use \"projection onto the new vector\" as a histogram axis, only a single change is needed to the binning parameters. The second covector (previously b) must be swapped out for frac12a + b (recall that reciprocal space covectors, such as those used in BinningParameters correspond to direct space vectors).","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"params.covectors[2,1:3] = [1/2,1,0] # [1/2,1,0] times [a;b;c] is (a/2 + b)\nparams#hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The second axis of the histogram now agrees with what is conventionally labelled as [H,-H/2,0].","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"warning: Length of the new vector\nNote that, although frac12a+b is orthogonal to a, it is not the same length as a. Instead, it is sqrt(3/4) times as long. Note the unsymmetrical axes labels in the plots that follow as a direct result of this!","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"# Zoom out horizontal axis\nparams.binstart[1], params.binend[1] = -2, 2\n\n# Adjust vertical axis bounds to account for\n# length of a/2 + b\nparams.binstart[2], params.binend[2] = -2 * sqrt(3/4), 2 * sqrt(3/4)\n\n# Re-compute in the new coordinate system\nis, counts = intensities_binned(sc,params,new_formula)\n\nfig = Figure(; resolution=(1200,500))#hide\nax_right = Axis(fig[1,3];#hide\n title=\"ω≈$(round(target_ω, digits=2)) meV with Δω=0.3 meV (Binned)\", aspect=true,#hide\n xlabel = \"[H, -1/2H, 0]\"#hide\n)#hide\nbcs = axes_bincenters(params)#hide\nhm_right = heatmap!(ax_right,bcs[1],bcs[2],is[:,:,1,1] ./ counts[:,:,1,1])#hide\nadd_lines!(ax_right,params)\nColorbar(fig[1,4], hm_right);#hide\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"For comparison purposes, we will make the same plot using intensities_interpolated to emulate zero-width bins. This time, it's more convenient to think in terms of reciprocal vectors a^* and b^*. Now, our coordinate transformation consists of establishing a new, orthogonal basis to specify our wave vectors: a^* - frac12b^*, b^* and c^*. Writing this in matrix form allows us to sample a rectilinear grid of wave vectors in this frame. Finally, we'll convert these back into the original RLU system for input into Sunny.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"# New basis matrix\nA = [1 0 0\n -1/2 1 0\n 0 0 1]\n\n# Define our grid of wave vectors\nnpoints = 60\nas = range(-2, 2, npoints)\nbs = range(-3/√3, 3/√3, npoints)\nqs_ortho = [[a, b, 0] for a in as, b in bs]\n\n# Convert to original RLU system for input to Sunny\nqs = [A * q for q in qs_ortho]\n\n# Use interpolation to get intensities\nis = intensities_interpolated(sc, qs, new_formula; interpolation=:linear)\n\nax_left = Axis(fig[1,2];#hide\n title=\"ω≈$(round(ωs[ωidx], digits=2)) meV (Interpolated)\", aspect=true,#hide\n xlabel = \"[H, -1/2H, 0]\", ylabel = \"[0, K, 0]\"#hide\n)#hide\nhm_left = heatmap!(ax_left, as, bs, is[:,:,ωidx])#hide\nadd_lines!(ax_left,params)\nColorbar(fig[1,1], hm_left);#hide\nfig","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Now, not only are the dashed-line lattice vectors no longer misleadingly orthogonal, but the six-fold symmetry has been restored as well! Further, the metric has been diagonalized:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"metric = (latvecs * inv(A'))' * I(3) * (latvecs * inv(A'))","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Finally, we note that instantaneous structure factor data, 𝒮(𝐪), can be obtained from a dynamic structure factor with instant_intensities_interpolated. Here we'll reuse the grid of wave vectors we generated above.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"is_static = instant_intensities_interpolated(sc, qs, new_formula; interpolation = :linear)\n\nhm = heatmap(as, bs, is_static;\n axis=(\n title=\"Instantaneous Structure Factor\",\n xlabel = \"[H, -1/2H, 0]\",\n ylabel = \"[0, K, 0]\",\n aspect=true\n )\n)\nColorbar(hm.figure[1,2], hm.plot)\nhm","category":"page"},{"location":"versions/#Version-0.5.1","page":"Version History","title":"Version 0.5.1","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"Fix binning edge cases.\nplot_spins accepts resolution argument.","category":"page"},{"location":"versions/#Version-0.5.0","page":"Version History","title":"Version 0.5.0","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"New features.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Support for Linear Spin Wave Theory in :dipole and :SUN modes. (Thanks Hao Zhang!)","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"New function minimize_energy! to efficiently find an optimal configuration of spin dipoles or SU(N) coherent states.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Major refactors and enhancements to intensity calculations. This new interface allows unification between LSWT and classical spin dynamics calculations. This interface allows: Custom observables as local quantum operators, better support for linebroadening, and automatic binning to facilitate comparison with experimental data. See intensity_formula for documentation. Use load_nxs to load experimental neutron scattering data.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Breaking changes.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Require Julia 1.9.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Replace set_anisotropy! with a new function set_onsite_coupling! (and similarly set_onsite_coupling_at!). The latter expects an explicit matrix representation for the local Hamiltonian. This can be constructed, e.g., as a linear combination of stevens_operators, or as a polynomial of spin_operators. To understand the mapping between these two, the new function print_stevens_expansion acts on an arbitrary local operator.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Remove set_biquadratic!. Instead, use an optional keyword argument biquad to set_exchange!.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename DynamicStructureFactor to dynamical_correlations. Similarly, replace InstantStructureFactor with instant_correlations. The return type has been renamed SampledCorrelations to emphasize that the object may be holding thermodynamic samples, which are collected using add_sample!.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Remove intensities function. Instead, use one of intensities_interpolated or intensities_binned. These will require an intensity_formula, which defines a calculator (e.g., LSWT).","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename connected_path to reciprocal_space_path, which now returns an xticks object that can be used in plotting. Replace spherical_shell with reciprocal_space_shell that functions similarly.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename polarize_spin! to set_dipole! for consistency with set_coherent!. The behavior of the former function is unchanged: the spin at a given site will still be polarized along the provided direction.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename all_sites to eachsite consistent with Julia convention for iterators.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename reshape_geometry to reshape_supercell, which is the fundamental reshaping function. Rename resize_periodically to resize_supercell.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The constructor SpinInfo now requires a g-factor or tensor as a named argument.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The constructor FormFactor no longer accepts an atom index. Instead, the form factors are associated with site-symmetry classes in order of appearance.","category":"page"},{"location":"versions/#Version-0.4.3","page":"Version History","title":"Version 0.4.3","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"Experimental support for linear SpinWaveTheory, implemented in SU(N) mode. This module may evolve rapidly.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Implement renormalization of single-ion anisotropy and biquadratic interactions when in :dipole mode. This makes the model more faithful to the quantum mechanical Hamiltonian, but is also a breaking change.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Various improvements and bugfixes for to_inhomogeneous. Setting inhomogeneous interactions via set_exchange_at! should now infer the correct bond offset direction, or will report an ambiguity error. Ambiguities can be resolved by passing an explicit offset.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The function remove_periodicity! disables periodicity along specified dimensions.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename StaticStructureFactor to InstantStructureFactor.","category":"page"},{"location":"versions/#Version-0.4.2","page":"Version History","title":"Version 0.4.2","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"Introduce LocalSampler, a framework for MCMC sampling with local spin updates.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename print_dominant_wavevectors to print_wrapped_intensities to reduce confusion with the physical instantaneous intensities.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The function spherical_shell now takes a radius in physical units of inverse Å.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"New exported functions global_position, magnetic_moment, all_sites.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Remove all uses of Base.deepcopy which resolves crashes.","category":"page"},{"location":"versions/#Version-0.4.1","page":"Version History","title":"Version 0.4.1","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"The function to_inhomogeneous creates a system that supports inhomogeneous interactions, which can be set using set_exchange_at!, etc.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"set_biquadratic! replaces set_exchange_with_biquadratic!.","category":"page"},{"location":"versions/#Version-0.4.0","page":"Version History","title":"Version 0.4.0","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"This update includes many breaking changes, and is missing some features of 0.3.0.","category":"page"},{"location":"versions/#Creating-a-spin-System","page":"Version History","title":"Creating a spin System","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename SpinSystem to System. Its constructor now has the form,","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"System(crystal, latsize, infos, mode)","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The parameter infos is now a list of SpinInfo objects. Each defines spin angular momentum S = frac12 1 frac32 , and an optional g-factor or tensor.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The parameter mode is one of :SUN or :dipole.","category":"page"},{"location":"versions/#Setting-interactions","page":"Version History","title":"Setting interactions","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"Interactions are now added mutably to an existing System using the following functions: set_external_field!, set_exchange!, set_onsite_coupling!, enable_dipole_dipole!.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"As a convenience, one can use dmvec(D) to convert a DM vector to a 33 antisymmetric exchange matrix.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Fully general single-ion anisotropy is now possible. The function set_onsite_coupling! expects the single ion anisotropy to be expressed as a polynomial in symbolic spin operators 𝒮, or as a linear combination of symbolic Stevens operators 𝒪. For example, an easy axis anisotropy in the direction n may be written D*(𝒮⋅n)^2.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Stevens operators 𝒪[k,q] admit polynomial expression in spin operators 𝒮[α]. Conversely, a polynomial of spin operators can be expressed as a linear combination of Stevens operators. To see this expansion use print_anisotropy_as_stevens.","category":"page"},{"location":"versions/#Inhomogeneous-field","page":"Version History","title":"Inhomogeneous field","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"An external field can be applied to a single site with set_external_field_at!. ","category":"page"},{"location":"versions/#Structure-factor-rewrite","page":"Version History","title":"Structure factor rewrite","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"The calculation of structure factors has been completely rewritten. For the new interface, see the Structure Factor Calculations page.","category":"page"},{"location":"versions/#Various","page":"Version History","title":"Various","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"The \"Sampler\" interface is in flux. Langevin replaces both LangevinHeunP and LangevinSampler. Local spin-flip Monte Carlo sampling methods are temporarily broken.\nrepeat_periodically replaces extend_periodically.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Additional related functions include resize_periodically and reshape_geometry, the latter being fundamental.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"print_symmetry_table replaces print_bond_table().","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The new function includes the list of symmetry-allowed single ion anisotropies in addition to exchange interactions.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"When reading CIF files, the field _atom_site_label is now used in place of the field _atom_site_type_symbol.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"This is required for correctness. The field _atom_site_label is guaranteed to be present, and is guaranteed to be a distinct label for each symmetry-inequivalent site. Code that explicitly referred to site labels (e.g. in calls to subcrystal) will need to be updated to use the new label.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"EditURL = \"../../../examples/one_dim_chain.jl\"","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/one_dim_chain/#Fitting-model-parameters-in-a-1D-spin-1-ferromagnetic-chain","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"","category":"section"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"using Sunny, LinearAlgebra, GLMakie, Optim","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"In this Example, we consider a 1D chain of spin-1 sites. The sites along the chain interact via a ferromagnetic nearest-neighbor interaction Jsum_langle ijrangle mathbfS_i cdot mathbfS_j, with J 0. By default, the ground state would be ferromagnetic and highly degenerate, since the spins can align in any direction. An on-site interaction, Dsum_i (S^z_i)^2 breaks this isotropy by making it easier for the spins to align in the pm z direction than in any other orientation. Thus, the entire Hamiltonian is:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"mathcalH = overbraceJsum_langle ijrangle mathbfS_i cdot mathbfS_j^textFerromagnetic overbrace-Dsum_i (S^z_i)^2^textEasy-axis single-ion anisotropy","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"The goal of this Example is to illustrate how to determine the parameters J and D from \"experiment\" data by fitting using Sunny's implementation of Linear Spin Wave Theory. In our case, the \"experiment\" data will actually be simulation data produced using Landau-Lifschitz dynamics.","category":"page"},{"location":"examples/one_dim_chain/#Creating-simulated-\"experiment\"-data-using-Landau-Lifschitz-dynamics","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Creating simulated \"experiment\" data using Landau-Lifschitz dynamics","text":"","category":"section"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Our simulated data will use ground truth values J_0 = -1textmeV and D_0 = 10textmeV with a lattice spacing a = 10 angstrom.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"We begin with a 1D chain of spin-1 sites along the x direction.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"# Establish geometry of the unit cell.\n# \"P1\" is required due to the rotational symmetry about the\n# x-axis being broken.\nchain_spacing = 10. # Angstrom\nlatvecs = chain_spacing * I(3)\none_dimensional_chain = Crystal(latvecs,[[0,0,0]],\"P1\")\n\n# Establish geometry of the whole chain.\nchain_length = 16 # Number of atoms\nlatsize = (chain_length,1,1) # 1D chain is Nx1x1 lattice\nspin_one_chain = System(one_dimensional_chain, latsize, [SpinInfo(1,S=1,g=2)], :SUN)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Configure the nearest-neighbor interaction:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"# Scalar J indicates J*(Sᵢ⋅Sⱼ)\nJ_groundtruth = -1.\n\n# Interaction is with the left and right next neighbor along the chain (x-direction)\nnearest_neighbor_right = Bond(1,1,(1,0,0))\nnearest_neighbor_left = Bond(1,1,(-1,0,0))\n\nset_exchange!(spin_one_chain,J_groundtruth,nearest_neighbor_right)\nset_exchange!(spin_one_chain,J_groundtruth,nearest_neighbor_left)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Configure the symmetry-breaking easy-axis term:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"D_groundtruth = 10.\nSz = spin_operators(spin_one_chain, 1)[3]\nset_onsite_coupling!(spin_one_chain, -D_groundtruth*Sz^2, 1)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"With the ground-truth hamiltonian in place, we use Sunny's classical dynamics to generate ficticious experiment data at temperature kT = 0.1.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Δt = 0.05/D_groundtruth\nλ = 0.1\nkT = 0.1\nlangevin = Langevin(Δt; kT, λ);\n\nfunction viz_chain(sys;kwargs...)#hide\n ##ups = map(x -> abs2(x[1]), sys.coherents)[:];#hide\n ##zs = map(x -> abs2(x[2]), sys.coherents)[:];#hide\n ##downs = map(x -> abs2(x[3]), sys.coherents)[:];#hide\n###hide\n ##f = Figure()#hide\n ##ax = LScene(f[1,1];show_axis = false)#hide\n ##_ = Makie.cam3d!(ax.scene, projectiontype=Makie.Orthographic)#hide\n###hide\n ##linewidth = 5.#hide\n ##arrowsize = 10.#hide\n ##lengthscale = 15.#hide\n ##pts = [Point3f(Sunny.global_position(sys,site)) for site in eachsite(sys)][:]#hide\n###hide\n #### Ups#hide\n ##vecs = [Vec3f([0,0,1]) for site in eachsite(sys)][:]#hide\n ##cols = map(x -> (:blue,x), ups)#hide\n ##Makie.arrows!(ax, pts .+ 0.5 .* vecs, vecs;#hide\n ##linecolor = cols, arrowcolor = cols,#hide\n ##lengthscale, arrowsize, linewidth, kwargs...)#hide\n###hide\n #### Downs#hide\n ##vecs = [Vec3f([0,0,-1]) for site in eachsite(sys)][:]#hide\n ##cols = map(x -> (:red,x), downs)#hide\n ##Makie.arrows!(ax, pts .+ 0.5 .* vecs, vecs;#hide\n ##linecolor = cols, arrowcolor = cols,#hide\n ##lengthscale, arrowsize, linewidth, kwargs...)#hide\n###hide\n ##cols = map(x -> (:green,x), zs)#hide\n ##meshscatter!(ax,pts, markersize = 7., color = cols)#hide\n ##f#hide\n Sunny.Plotting.plot_coherents(sys;quantization_axis = [0,0,1],kwargs...)\nend#hide\nrandomize_spins!(spin_one_chain)\nviz_chain(spin_one_chain)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"In this plot, the z-axis has been used as the quantization axis for each site, with the up/down arrows and circle representing the pm hbar and 0hbar spin projections onto the z-axis respectively. The opacity of each object represents the probability (absolute value squared), and the color represents the phase. Since we are using classical dynamics to simulate the data, the phase will be mostly random.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"First, we thermalize the chain, and then take several samples in order get reasonably good \"experiment\" data.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"nStep = 50_000#hide\nfor _ in 1:nStep#hide\n step!(spin_one_chain, langevin)#hide\nend#hide\n# ... thermalize ...\nviz_chain(spin_one_chain)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"sc = dynamical_correlations(spin_one_chain; Δt, nω = 80, ωmax = 20.);#hide\n\nfor _ in 1:10_000#hide\n step!(spin_one_chain, langevin)#hide\nend#hide\nadd_sample!(sc, spin_one_chain)#hide\n# ... some time later ...\nviz_chain(spin_one_chain)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"for _ in 1:10_000#hide\n step!(spin_one_chain, langevin)#hide\nend#hide\nadd_sample!(sc, spin_one_chain)#hide\n# ... some time later ...\nviz_chain(spin_one_chain)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"for _ in 1:20#hide\n for _ in 1:10_000#hide\n step!(spin_one_chain, langevin)#hide\n end#hide\n add_sample!(sc, spin_one_chain)#hide\nend#hide\n# ... some time later ...\nviz_chain(spin_one_chain)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Now that we have collected several samples,","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"sc","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"we are ready to generate the intensity data. Since this is supposed to represent an experiment, the intensity data will go in a histogram:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS = unit_resolution_binning_parameters(sc)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Here's what the experiment data looks like:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"formula = intensity_formula(sc,:perp;kT)\nis, counts = intensities_binned(sc,SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS,formula)\n\nSIMULATED_EXPERIMENT_DATA = (is ./ counts)[:,1,1,:]\n\nbcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)\nf = Figure()#hide\nax = Axis(f[1,1])#hide\nheatmap!(ax,bcs[1],bcs[4],log10.(SIMULATED_EXPERIMENT_DATA))\nf#hide","category":"page"},{"location":"examples/one_dim_chain/#Fitting-to-the-experiment-data","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting to the experiment data","text":"","category":"section"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"To fit this data, we first model the known aspects of the system in Sunny. The first steps are the same whether we are simulating a known system or modelling an unknown system:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"# Same as before\nchain_spacing = 10. # Angstrom\nlatvecs = chain_spacing * I(3)\none_dimensional_chain = Crystal(latvecs,[[0,0,0]],\"P1\")\nchain_length = 16 # Number of atoms\nlatsize = (chain_length,1,1) # 1D chain is Nx1x1 lattice\nspin_one_chain = System(one_dimensional_chain, latsize, [SpinInfo(1,S=1,g=2)], :SUN)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Originally, the next step would have been to configure the hamiltonian by specifying the J and D values. However, since these are unknowns, we will avoid using them as long as possible, and instead proceed to set up the bonds, spin operators, and Langevin integrator–none of which require the values:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Δt = 0.05\nλ = 0.1\nkT = 0. # LSWT uses zero temperature\nlangevin = Langevin(Δt; kT, λ);\n\nnearest_neighbor_right = Bond(1,1,(1,0,0))\nnearest_neighbor_left = Bond(1,1,(-1,0,0))\n\nSz = spin_operators(spin_one_chain, 1)[3]","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"After this setup work is done once, we create a function forward_problem(J_trial,D_trial) which will compute the Linear Spin Wave Theoretic spectrum at the trial values of the J and D fitting parameters. In other words, the part of the original calculation which depends on the fitting parameters gets wrapped into a function:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"function forward_problem(J_trial, D_trial)\n\n # Ensure there is no phase transition (or else LSWT will throw errors)\n J_trial = min(J_trial,0)\n D_trial = max(D_trial,0)\n\n # Uses J_trial\n set_exchange!(spin_one_chain,J_trial,nearest_neighbor_right)\n set_exchange!(spin_one_chain,J_trial,nearest_neighbor_left)\n\n # Uses D_trial\n set_onsite_coupling!(spin_one_chain, -D_trial*Sz^2, 1)\n\n # Perform spin wave calculation, continued below...","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Note that forward_problem refers to variables defined outside of the scope of the function. This allows us to reuse those variables in each call to forward_problem, without reconstructing them each time. In general, the more that is known about the system you are modelling, the later in the code function forward_problem(...) can be inserted, and the more setup work can be re-used.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"tip: `forward_problem` is a closure\nIn computer progrogramming parlance, forward_problem is said to 'capture' variables such as spin_one_chain from the enviroment. Since the result of calling forward_problem depends not only on J_trial and D_trial, but also on spin_one_chain, it's no longer a function of only its arguments.Since forward_problem is not a closed system, but forward_problem + (captured variables) is a closed system, the latter is called the 'closure' of the former.","category":"page"},{"location":"examples/one_dim_chain/#Spin-wave-calculation","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Spin wave calculation","text":"","category":"section"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"We can leverage our knowledge that the ground state should be ferromagnetic to simplify the spin wave calculation. Since the ferrommagnetic unit cell is just one site, the simplified system is extremely simple:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":" # ... perform spin wave calculation, continued from above.\n one_site_system = reshape_supercell(spin_one_chain,[1 0 0; 0 1 0; 0 0 1])","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"After restricting to a single site, it's best to re-thermalize the system at zero temperature to ensure a good classical ground state for LSWT:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":" langevin.kT = 0.\n nStep = 1_000\n for _ in 1:nStep\n step!(one_site_system, langevin)\n end","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"The spin wave intensity data must be placed in a histogram with the same parameters as the experiment data, in order to ensure a good comparision.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"The kernel and intensities_bin_centers used here are temporary, until a better binning method is written.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":" swt = SpinWaveTheory(one_site_system)\n formula = intensity_formula(swt,:perp; kernel = lorentzian(0.5))\n params = SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS\n is_swt = Sunny.intensities_bin_centers(swt, params, formula)\n\n return is_swt[:,1,1,:]\nend # end of forward_problem","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"We can see the different possible results from LSWT by plotting the dispersion:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"function plot_forward(J,D)\n is_swt = forward_problem(J,D)\n bcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)\n heatmap(bcs[1],bcs[4],log10.(is_swt))\nend\n\nplot_forward(-1,10)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"plot_forward(-6,2)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"plot_forward(-0.01,15)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Now, we can easily define a least-squares loss function comparing the \"experiment\" data to the LSWT result:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"function get_loss(parameters)\n J,D = parameters\n is_swt = forward_problem(J,D)\n sqrt(sum(abs2.(SIMULATED_EXPERIMENT_DATA .- is_swt)))\nend","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Sweeping the parameters over a range containing the true value reveals that the loss is minimized near the true parameters (dot). The minimum loss is not exactly at the ground truth parameters in this case. Gradient descent (finite-differenced) can be used to find the actual minimizer:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"nJ = 30\nnD = 35\nloss_landscape = zeros(Float64,nJ,nD)\nJs = range(-2,0,length=nJ)\nDs = range(8,12,length=nD)\nfor (ij,J) in enumerate(Js)\n for (id,D) in enumerate(Ds)\n loss_landscape[ij,id] = get_loss([J,D])\n end\nend\n\nfig = Figure()\nax = Axis(fig[1,1],xlabel = \"J [meV]\", ylabel = \"D [meV]\")\ncontourf!(ax,Js,Ds,loss_landscape)\n\nx0 = [-2,9.5]\nopt_result = optimize(get_loss,x0,method=GradientDescent(alphaguess=1e-3),store_trace=true,extended_trace = true,time_limit=10.)\nlines!(ax,Point2f.(Optim.x_trace(opt_result)))\nscatter!(ax,-1,10)\nfig","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"The fit can be verified by plotting the LSWT band structure over top of the experiment data:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"bcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)\nf = Figure()#hide\nax = Axis(f[1,1]; xlabel=\"Q [R.L.U.]\", ylabel=\"Energy (meV)\")#hide\nheatmap!(ax,bcs[1],bcs[4],log10.(SIMULATED_EXPERIMENT_DATA), colormap = :deepsea)\nf#hide\n\n\nJ_trial, D_trial = opt_result.minimizer\nset_exchange!(spin_one_chain,J_trial,nearest_neighbor_right)#hide\nset_exchange!(spin_one_chain,J_trial,nearest_neighbor_left)#hide\n\nset_onsite_coupling!(spin_one_chain, -D_trial*Sz^2, 1)#hide\none_site_system = reshape_supercell(spin_one_chain,[1 0 0; 0 1 0; 0 0 1])#hide\n\nlangevin.kT = 0.#hide\nnStep = 1_000#hide\nfor _ in 1:nStep#hide\n step!(one_site_system, langevin)#hide\nend#hide\n\nswt = SpinWaveTheory(one_site_system)#hide\nparams = SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS\n\npath = [[q,0,0] for q in bcs[1]]\ndisp, intensity = intensities_bands(swt, path, intensity_formula(swt,:perp, kernel = delta_function_kernel))\n\nfor i in axes(disp)[2]\n lines!(ax, bcs[1], disp[:,i]; color=intensity[:,i], colormap = :turbo,linewidth = 5,colorrange = (0.,1.))\nend\nColorbar(f[1,2],colormap = :turbo, limits = (0.,1.))\nColorbar(f[1,3],colormap = :deepsea, limits = (0.,1.))\nf","category":"page"},{"location":"#Sunny-Overview","page":"Overview","title":"Sunny Overview","text":"","category":"section"},{"location":"","page":"Overview","title":"Overview","text":"Sunny is a Julia package for modeling atomic-scale magnetism. It provides powerful tools to study equilibrium and non-equilibrium magnetic phenomena. In particular, it allows estimation of dynamical structure factor intensities, mathcalS(𝐪ω), to support quantitative modeling of experimental scattering data.","category":"page"},{"location":"","page":"Overview","title":"Overview","text":"Features include:","category":"page"},{"location":"","page":"Overview","title":"Overview","text":"Generalized spin dynamics using SU(N) coherent states.\nAbility specify a crystal by a .cif file, or using its spacegroup symmetry.\nInteractive visualizations of the 3D crystals and magnetic ordering.\nSymmetry analysis to classify allowed interaction terms, and to propagate them by symmetry.\nSingle-ion anisotropy at arbitrary order, which can be specified using Stevens operators or as a polynomial of spin operators.\nMonte Carlo sampling of spin configurations in thermal equilibrium, and optimization tools.\nMeasurements of dynamical correlation functions. For small supercells at low temperature, one can use linear spin wave theory and its multi-boson generalization. Alternatively, one can use the full classical dynamics to study systems with large supercells (e.g., disordered systems), or anharmonic effects with thermal fluctuations.\nLong-range dipole-dipole interactions accelerated with the fast Fourier transform (FFT).\nVarious correction factors to facilitate comparison with experimental data (form factor, dipole factor, temperature-dependent classical-to-quantum factors, intensity binning, etc.).","category":"page"}] +[{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"EditURL = \"../../../examples/fei2_tutorial.jl\"","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/fei2_tutorial/#Case-Study:-FeI_{2}","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"FeI_2 is an effective spin-1 material with strong single-ion anisotropy. Quadrupolar fluctuations give rise to a single-ion bound state that cannot be described by a dipole-only model. This tutorial illustrates how to use the linear spin wave theory of SU(3) coherent states (i.e. 2-flavor bosons) to model the magnetic behavior in FeI_2. The original study was performed in Bai et al., Nature Physics 17, 467–472 (2021).","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The Fe atoms are arranged in stacked triangular layers. The effective spin interactions include various anisotropic exchange interactions, and a strong single-ion anisotropy:","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"mathcalH=sum_(ij) J^alphabeta_ij S^alpha_i S^beta_j - Dsum_i left(S^zright)^2","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"We will formulate this Hamiltonian in Sunny and then calculate its dynamic structure factor.","category":"page"},{"location":"examples/fei2_tutorial/#Get-Julia-and-Sunny","page":"Case Study: FeI_2","title":"Get Julia and Sunny","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Sunny is implemented in Julia. This is a relatively new programming language that allows for interactive development (like Python or Matlab) while also providing high numerical efficiency (like C++ or Fortran). New Julia users may wish to take a look at our Getting Started with Julia guide. Sunny requires Julia 1.9 or later.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"From the Julia prompt, load Sunny. For plotting, one can choose either GLMakie (a pop-up window) or WGLMakie (inline plots for a Jupyter notebook or VSCode).","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"using Sunny, GLMakie","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"If these packages are not yet installed, Julia should offer to install them using its built-in package management system. If old versions are installed, you may need to update them to run this tutorial.","category":"page"},{"location":"examples/fei2_tutorial/#Crystals","page":"Case Study: FeI_2","title":"Crystals","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"A Crystal describes the crystallographic unit cell and will usually be loaded from a .cif file. Here, we instead build a crystal by listing all atoms and their types.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"a = b = 4.05012 # Lattice constants for triangular lattice\nc = 6.75214 # Spacing in the z-direction\n\nlatvecs = lattice_vectors(a, b, c, 90, 90, 120) # A 3x3 matrix of lattice vectors that\n # define the conventional unit cell\npositions = [[0, 0, 0], [1/3, 2/3, 1/4], [2/3, 1/3, 3/4]] # Positions of atoms in fractions\n # of lattice vectors\ntypes = [\"Fe\", \"I\", \"I\"]\nFeI2 = Crystal(latvecs, positions; types)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Observe that Sunny inferred the space group, 'P -3 m 1' (164) and labeled the atoms according to their point group symmetries.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Only the Fe atoms are magnetic, so we discard the I ions using subcrystal.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"cryst = subcrystal(FeI2, \"Fe\")","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Importantly, cryst retains the spacegroup symmetry of the full FeI_2 crystal. This information will be used, for example, to propagate exchange interactions between symmetry-equivalent bonds.","category":"page"},{"location":"examples/fei2_tutorial/#Symmetry-analysis","page":"Case Study: FeI_2","title":"Symmetry analysis","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The command print_symmetry_table provides a list of all the symmetry-allowed interactions up to a cutoff distance.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"print_symmetry_table(cryst, 8.0)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The allowed g-tensor is expressed as a 3×3 matrix in the free coefficients A, B, ... The allowed single-ion anisotropy is expressed as a linear combination of Stevens operators. The latter correspond to polynomials of the spin operators, as we will describe below.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The allowed exchange interactions are given as a 3×3 matrix for representative bonds. The notation Bond(i, j, n) indicates a bond between atom indices i and j, with cell offset n. In the general case, it will be necessary to associate atom indices with their positions in the unit cell; these can be viewed with display(cryst). Note that the order of the pair (i j) is significant if the exchange tensor contains antisymmetric Dzyaloshinskii–Moriya (DM) interactions.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"In the case of FeI_2, Bond(1, 1, [1,0,0]) is one of the 6 nearest-neighbor Fe-Fe bonds on a triangular lattice layer, and Bond(1, 1, [0,0,1]) is an Fe-Fe bond between layers.","category":"page"},{"location":"examples/fei2_tutorial/#Building-a-spin-System","page":"Case Study: FeI_2","title":"Building a spin System","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"In constructing a spin System, we must provide several additional details about the spins.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sys = System(cryst, (4,4,4), [SpinInfo(1, S=1, g=2)], :SUN, seed=2)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"This system includes 444 unit cells, i.e. 64 Fe atoms, each with spin S=1 and a g-factor of 2. Quantum mechanically, spin S=1 involves a superposition of 2S+1=3 distinct angular momentum states. In :SUN mode, this superposition will be modeled explicitly using the formalism of SU(3) coherent states, which captures both dipolar and quadrupolar fluctuations. For the more traditional dipole dynamics, use :dipole mode instead.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Next we will use set_exchange! to assign interaction to bonds. Sunny will automatically propagate each interaction to all symmetry-equivalent bonds in the unit cell. The FeI_2 interactions below follow Bai et al.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"J1pm = -0.236\nJ1pmpm = -0.161\nJ1zpm = -0.261\nJ2pm = 0.026\nJ3pm = 0.166\nJ′0pm = 0.037\nJ′1pm = 0.013\nJ′2apm = 0.068\n\nJ1zz = -0.236\nJ2zz = 0.113\nJ3zz = 0.211\nJ′0zz = -0.036\nJ′1zz = 0.051\nJ′2azz = 0.073\n\nJ1xx = J1pm + J1pmpm\nJ1yy = J1pm - J1pmpm\nJ1yz = J1zpm\n\nset_exchange!(sys, [J1xx 0.0 0.0;\n 0.0 J1yy J1yz;\n 0.0 J1yz J1zz], Bond(1,1,[1,0,0]))\nset_exchange!(sys, [J2pm 0.0 0.0;\n 0.0 J2pm 0.0;\n 0.0 0.0 J2zz], Bond(1,1,[1,2,0]))\nset_exchange!(sys, [J3pm 0.0 0.0;\n 0.0 J3pm 0.0;\n 0.0 0.0 J3zz], Bond(1,1,[2,0,0]))\nset_exchange!(sys, [J′0pm 0.0 0.0;\n 0.0 J′0pm 0.0;\n 0.0 0.0 J′0zz], Bond(1,1,[0,0,1]))\nset_exchange!(sys, [J′1pm 0.0 0.0;\n 0.0 J′1pm 0.0;\n 0.0 0.0 J′1zz], Bond(1,1,[1,0,1]))\nset_exchange!(sys, [J′2apm 0.0 0.0;\n 0.0 J′2apm 0.0;\n 0.0 0.0 J′2azz], Bond(1,1,[1,2,1]))","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The function set_onsite_coupling! assigns a single-ion anisotropy operator. It can be constructed, e.g., from the matrices given by spin_operators or stevens_operators. Here we construct an easy-axis anisotropy along the direction hatz.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"D = 2.165\nS = spin_operators(sys, 1)\nset_onsite_coupling!(sys, -D*S[3]^2, 1)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Any anisotropy operator can be converted to a linear combination of Stevens operators with print_stevens_expansion.","category":"page"},{"location":"examples/fei2_tutorial/#Calculating-structure-factor-intensities","page":"Case Study: FeI_2","title":"Calculating structure factor intensities","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"In the remainder of this tutorial, we will examine Sunny's tools for calculating the dynamical structure factor using a multi-boson generalization of linear spin wave theory (LSWT). This theory describes non-interacting quasi-particle excitations that hybridize dipolar and quadrupolar modes.","category":"page"},{"location":"examples/fei2_tutorial/#Finding-the-ground-state","page":"Case Study: FeI_2","title":"Finding the ground state","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Begin with a random configuration and use minimize_energy! to find a configuration of the SU(3) coherent states (i.e. spin dipoles and quadrupoles) that locally minimizes energy.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"randomize_spins!(sys)\nminimize_energy!(sys);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The expected ground state for FeI_2 is an antiferrogmanetic striped phase with a period of four spins (two up, two down). Visualizing the result of optimization, however, may indicate the system got stuck in a local minimum with defects.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"plot_spins(sys)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"A better understanding of the magnetic ordering can often be obtained by moving to Fourier space. The 'instant' structure factor 𝒮(𝐪) is an experimental observable. To investigate 𝒮(𝐪) as true 3D data, Sunny provides instant_correlations and related functions. Here, however, we will use the lighter weight function print_wrapped_intensities to get a quick understanding of the periodicities present in the spin configuration.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"print_wrapped_intensities(sys)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The precise output may vary with Sunny version due to, e.g., different floating point roundoff effects. Very likely, however, the result will be approximately consistent with the known zero-field energy-minimizing magnetic structure of FeI_2, which is single-Q. Mathematically, spontaneous symmetry breaking should select one of Q = 0 -14 14, 14 0 14, or -141414, associated with the three-fold rotational symmetry of the crystal spacegroup. In practice, however, one will frequently encounter competing \"domains\" associated with the three possible orientations of the ground state.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"If the desired ground state is already known, as with FeI_2, it could be entered by hand using set_dipole!. Alternatively, in the case of FeI_2, we could repeatedly employ the above randomization and minimization procedure until a defect-free configuration is found. Some systems will have more complicated ground states, which can be much more challenging to find. For this, Sunny provides experimental support for powerful simulated annealing via parallel tempering, but that is outside the scope of this tutorial.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Here, let's break the three-fold symmetry of FeI_2 by hand. Given one or more desired Q modes, Sunny can suggest a magnetic supercell with appropriate periodicity. Let's arbitrarily select one of the three possible ordering wavevectors, Q = 0 -14 14. Sunny suggest a corresponding magnetic supercell in units of the crystal lattice vectors.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"suggest_magnetic_supercell([[0, -1/4, 1/4]], sys.latsize)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The function reshape_supercell allows an arbitrary reshaping of the system's supercell. We select the supercell appropriate to the broken-symmetry ground-state, which makes optimization much easier.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sys_min = reshape_supercell(sys, [1 0 0; 0 1 -2; 0 1 2])\nrandomize_spins!(sys_min)\nminimize_energy!(sys_min)\nplot_spins(sys_min; ghost_radius=3)","category":"page"},{"location":"examples/fei2_tutorial/#Linear-spin-wave-theory","page":"Case Study: FeI_2","title":"Linear spin wave theory","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Now that we have found the ground state for a magnetic supercell, we can immediately proceed to perform zero-temperature calculations using linear spin wave theory. We begin by instantiating a SpinWaveTheory type using the supercell.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"swt = SpinWaveTheory(sys_min)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Select a sequence of wavevectors that will define a piecewise linear interpolation in reciprocal lattice units (RLU).","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"q_points = [[0,0,0], [1,0,0], [0,1,0], [1/2,0,0], [0,1,0], [0,0,0]];\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The function reciprocal_space_path will linearly sample a path between the provided q-points with a given density. The xticks return value provides labels for use in plotting.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"density = 50\npath, xticks = reciprocal_space_path(cryst, q_points, density);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The dispersion function defines the quasiparticle excitation energies ω_i(𝐪) for each point 𝐪 along the reciprocal space path.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"disp = dispersion(swt, path);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"In addition to the band energies ω_i(𝐪), Sunny can calculate the inelastic neutron scattering intensity I_i(𝐪) for each band i according to an intensity_formula. We choose to apply a polarization correction (1 - 𝐪𝐪) by setting the mode argument to :perp. Selecting delta_function_kernel specifies that we want the energy and intensity of each band individually.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"formula = intensity_formula(swt, :perp; kernel=delta_function_kernel)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The function intensities_bands uses linear spin wave theory to calculate both the dispersion and intensity data for the provided path.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"disp, intensity = intensities_bands(swt, path, formula);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"These can be plotted in GLMakie.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"fig = Figure()\nax = Axis(fig[1,1]; xlabel=\"𝐪\", ylabel=\"Energy (meV)\", xticks, xticklabelrotation=π/6)\nylims!(ax, 0.0, 7.5)\nxlims!(ax, 1, size(disp, 1))\ncolorrange = extrema(intensity)\nfor i in axes(disp)[2]\n lines!(ax, 1:length(disp[:,i]), disp[:,i]; color=intensity[:,i], colorrange)\nend\nfig","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"To make comparisons with inelastic neutron scattering (INS) data, it is helpful to employ an empirical broadening kernel, e.g., a lorentzian.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"γ = 0.15 # width in meV\nbroadened_formula = intensity_formula(swt, :perp; kernel=lorentzian(γ))","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The intensities_broadened function requires an energy range in addition to the 𝐪-space path.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"energies = collect(0:0.01:10) # 0 < ω < 10 (meV).\nis1 = intensities_broadened(swt, path, energies, broadened_formula);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"A real FeI_2 sample will exhibit competing magnetic domains associated with spontaneous symmetry breaking of the 6-fold rotational symmetry of the triangular lattice. Note that the wavevectors 𝐪 and -𝐪 are equivalent in the structure factor, which leaves three distinct domain orientations, which are related by 120° rotations about the z-axis. Rather than rotating the spin configuration directly, on can rotate the 𝐪-space path. Below, we use rotation_in_rlu to average the intensities over all three possible orientations.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"R = rotation_in_rlu(cryst, [0, 0, 1], 2π/3)\nis2 = intensities_broadened(swt, [R*q for q in path], energies, broadened_formula)\nis3 = intensities_broadened(swt, [R*R*q for q in path], energies, broadened_formula)\nis_averaged = (is1 + is2 + is3) / 3\n\nfig = Figure()\nax = Axis(fig[1,1]; xlabel=\"(H,0,0)\", ylabel=\"Energy (meV)\", xticks, xticklabelrotation=π/6)\nheatmap!(ax, 1:size(is_averaged, 1), energies, is_averaged)\nfig","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"This result can be directly compared to experimental neutron scattering data from Bai et al.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"(The publication figure accidentally used a non-standard coordinate system to label the wave vectors.)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"To get this agreement, the use of SU(3) coherent states is essential. In other words, we needed a theory of multi-flavored bosons. The lower band has large quadrupolar character, and arises from the strong easy-axis anisotropy of FeI_2. By setting mode = :SUN, the calculation captures this coupled dipole-quadrupole dynamics.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"An interesting exercise is to repeat the same study, but using mode = :dipole instead of :SUN. That alternative choice would constrain the coherent state dynamics to the space of dipoles only.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The full dynamical spin structure factor (DSSF) can be retrieved as a 33 matrix with the dssf function, for a given path of 𝐪-vectors.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"disp, is = dssf(swt, path);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The first output disp is identical to that obtained from dispersion. The second output is contains a list of 33 matrix of intensities. For example, is[q,n][2,3] yields the (yz) component of the structure factor intensity for nth mode at the qth wavevector in the path.","category":"page"},{"location":"examples/fei2_tutorial/#What's-next?","page":"Case Study: FeI_2","title":"What's next?","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The multi-boson linear spin wave theory, applied above, can be understood as the quantization of a certain generalization of the Landau-Lifshitz spin dynamics. Rather than dipoles, this dynamics takes places on the space of SU(N) coherent states.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The full SU(N) coherent state dynamics, with appropriate quantum correction factors, can be useful to model finite temperature scattering data. In particular, it captures certain anharmonic effects due to thermal fluctuations. This is the subject of our Structure Factors with Classical Dynamics tutorial.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The classical dynamics is also a good starting point to study non-equilibrium phenomena. Empirical noise and damping terms can be used to model coupling to a thermal bath. This yields a Langevin dynamics of SU(N) coherent states. Our CP^2 Skyrmion Quench tutorial shows how this dynamics gives rise to the formation of novel topological defects in a temperature quench.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Relative to LSWT calculations, it can take much more time to estimate mathcalS(𝐪ω) intensities using classical dynamics simulation. See the SunnyTutorials notebooks for examples of \"production-scale\" simulations.","category":"page"},{"location":"structure-factor/#Structure-Factor-Calculations","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"","category":"section"},{"location":"structure-factor/#Overview","page":"Structure Factor Calculations","title":"Overview","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The dynamical structure factor is of fundamental importance for characterizing a magnetic system, and facilitates quantitative comparison between theory and experimental scattering data.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Consider, for example, a two-point dynamical spin correlation function, s^α(𝐱+Δ𝐱 t+Δt) s^β(𝐱 t). Here s^α(𝐱 t) represents the time dynamics of a spin dipole component α at position 𝐱, and brackets represent an average over equilibrium initial conditions and over (𝐱 t). The dynamical structure factor is defined as the Fourier transform of this two-point correlation in both space and time, up to an overall scaling factor. Using the convolution theorem, the result is,","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"𝒮^αβ(𝐪 ω) = frac1V s^α(𝐪 ω)^ast s^β(𝐪 ω) ","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"with V the system volume. We will restrict attention to lattice systems with periodic boundaries.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Consider a crystal unit cell defined by three lattice vectors 𝐚_1 𝐚_2 𝐚_3, and linear system sizes L_1 L_2 L_3 measured in unit cells. The allowed momentum vectors take on discrete values 𝐪 = sum_α=1^3 m_α 𝐛_α L_α, where m_α are an integers and the reciprocal lattice vectors 𝐛_α are defined to satisfy 𝐚_α 𝐛_β = 2π δ_αβ. For a Bravais lattice, 𝐪 will be periodic in the first Brillouin zone, i.e., under any shift 𝐪 𝐪 𝐛_α. More generally, consider a non-Bravais lattice such that each unit cell may contain multiple spins. By partitioning spins s_j(𝐱t) according to their sublattice index j, the relevant momenta 𝐪 remain discretized as above, but now periodicity in the first Brillouin zone is lost. The structure factor may be written as a phase-average over the displacements between sublattices 𝐫_jk,","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"𝒮^αβ(𝐪 ω) = _jk e^i 𝐫_jk 𝐪 𝒮^αβ_jk(𝐪 ω) ","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"From a theoretical perspective, the quantity","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"𝒮^αβ_jk(𝐪 ω) = frac1V s_j^α(𝐪 ω)^ast s_k^β(𝐪 ω)","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"is fundamental. For each sublattice j, the data s_j^α(𝐪 ω) can be efficiently obtained by fast Fourier tranformation of a real space configuration s_j^α(𝐱 t). Internally, Sunny will calculate and store the discrete 𝒮^αβ_jk(𝐪 ω) correlation data, and use this to construct 𝒮^αβ(𝐪ω) intensities that can be compared with experiment.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Calculating this structure factor involves several steps, with various possible settings. Sunny provides a number of tools to facilitate this calculation and to extract information from the results. These tools are briefly outlined below. Please see the Examples for a \"real life\" use case. Detailed function information is available in the Library API.","category":"page"},{"location":"structure-factor/#Estimating-stucture-factors-with-classical-dynamics","page":"Structure Factor Calculations","title":"Estimating stucture factors with classical dynamics","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Classical dynamics may be used to estimate structure factor data by analyzing the spin-spin correlations of dynamical trajectories. This is fundamentally a Monte Carlo approach, as the trajectories must be started from an initial spin configuration that is sampled at thermal equilibrium. (Note that it is not possible to estimate a true T=0 dynamical structure factor using this method, but the temperature may be very low.) Samples are accumulated into a SampledCorrelations, from which intensity information may be extracted. The user does not typically build their own SampledCorrelations but instead initializes one by calling either dynamical_correlations or instant_correlations, as described below.","category":"page"},{"location":"structure-factor/#Estimating-a-dynamical-structure-factor:-𝒮(𝐪,ω)","page":"Structure Factor Calculations","title":"Estimating a dynamical structure factor: 𝒮(𝐪ω)","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"A SampledCorrelations for estimating the dynamical structure factor, 𝒮^αβ(𝐪ω), may be created by calling dynamical_correlations. This requires three keyword arguments. These will determine the dynamics used to calculate samples and, consequently, the ω information that will be available. ","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Δt: Determines the step size used for simulating the dynamics. A smaller number will require proportionally more calculation time. While a smaller Δt will enable the resolution of higher energies, Δt is typically selected to ensure numerical stability rather than to maximize the largest ω value. A safe choice is to use the smaller value of Δt = 0.1/(J* S^2) or Δt = 0.1/(D * S), where S is magnetic moment of the largest local spin (as specified in SpinInfo), J is the parameter governing the largest bilinear interaction (e.g. exchange), and D is the parameter governing the largest single-site term of the Hamiltonian (e.g., anisotropy or Zeeman term).\nωmax: Sets the maximum resolved energy. Note that this is not independent of Δt. If ωmax too large, Sunny will throw an error and ask you to choose a smaller Δt. \nnω: Determines the number of energy bins to resolve. A larger number will require more calculation time.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"A sample may be added by calling add_sample!(sc, sys). The input sys must be a spin configuration in good thermal equilibrium, e.g., using the continuous Langevin dynamics or using single spin flip trials with LocalSampler. The statistical quality of the 𝒮^αβ(𝐪ω) can be improved by repeatedly generating decorrelated spin configurations in sys and calling add_sample! on each configuration.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The outline of typical use case might look like this:","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"# Make a `SampledCorrelations`\nsc = dynamical_correlations(sys; Δt=0.05, ωmax=10.0, nω=100) \n\n# Add samples\nfor _ in 1:nsamples\n decorrelate_system(sys) # Perform some type of Monte Carlo simulation\n add_sample!(sc, sys) # Use spins to calculate trajectory and accumulate new sample of 𝒮(𝐪,ω)\nend","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The calculation may be configured in a number of ways; see the dynamical_correlations documentation for a list of all keywords.","category":"page"},{"location":"structure-factor/#Estimating-an-instantaneous-(\"static\")-structure-factor:-𝒮(𝐪)","page":"Structure Factor Calculations","title":"Estimating an instantaneous (\"static\") structure factor: 𝒮(𝐪)","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Sunny provides two methods for calculating instantaneous, or static, structure factors: 𝒮^αβ(𝐪). The first involves calculating spatial spin-spin correlations at single time slices. The second involves calculating a dynamic structure factor first and integrating out the ω information. The advantage of the latter approach is that it enables application of an ω-dependent classical-to-quantum rescaling of structure factor intensities, a method that should be preferred whenever comparing results to experimental data or spin wave calculations. A disadvantage of this approach is that it is computationally more expensive. There are also many cases when it is not straightforward to calculate a meaningful dynamics, as when working with Ising spins. In this section we will discuss how to calculate instantaneous structure factors from static spin configurations. Information about calculating instantaneous data from a dynamical correlations can be found in the following section.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The basic usage for the instantaneous case is very similar to the dynamic case, except one calls instant_correlations instead of dynamical_correlations to configure a SampledCorrelations. Note that there are no required keywords as there is no need to specify any dynamics. instant_correlations will return a SampledCorrelations containing no data. Samples may be added by calling add_sample!(sc, sys), where sc is the SampledCorrelations. When performing a finite-temperature calculation, it is important to ensure that the spin configuration in the sys represents a good equilibrium sample, as in the dynamical case. Note, however, that we recommend calculating instantaneous correlations at finite temperature calculations by using full dynamics (i.e., using dynamical_correlations) and then integrating out the energy axis. An approach to doing this is described in the next section.","category":"page"},{"location":"structure-factor/#Extracting-information-from-sampled-correlation-data","page":"Structure Factor Calculations","title":"Extracting information from sampled correlation data","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The basic function for extracting information from a SampledCorrelations at a particular wave vector, 𝐪, is intensities_interpolated. It takes a SampledCorrelations, a list of wave vectors, and an intensity_formula. The intensity_formula specifies how to contract and correct correlation data to arrive at a physical intensity. A simple example is formula = intensity_formula(sc, :perp), which will instruct Sunny apply polarization corrections: sum_αβ(I-q_α q_β) 𝒮^αβ(𝐪ω). An intensity at the wave vector 𝐪 = (𝐛_2 + 𝐛_3)2 may then be retrieved with intensities_interpolated(sf, [[0.0, 0.5, 0.5]], formula) . intensities_interpolated returns a list of nω elements at each wavevector. The corresponding ω values can be retrieved by calling available_energies on sf.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Since Sunny only calculates the structure factor on a finite lattice when performing classical simulations, it is important to realize that exact information is only available at a discrete set of wave vectors. Specifically, for each axis index i, we will get information at q_i = fracnL_i, where n runs from (frac-L_i2+1) to fracL_i2 and L_i is the linear dimension of the lattice used for the calculation. If you request a wave vector that does not fall into this set, Sunny will automatically round to the nearest 𝐪 that is available. If intensities_interpolated is given the keyword argument interpolation=:linear, Sunny will use trilinear interpolation to determine a result at the requested wave vector. ","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"To retrieve the intensities at all wave vectors for which there is exact data, first call the function available_wave_vectors to generate a list of qs. This takes an optional keyword argument bzsize, which must be given a tuple of three integers specifying the number of Brillouin zones to calculate, e.g., bzsize=(2,2,2). The resulting list of wave vectors may then be passed to intensities_interpolated.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Alternatively, intensities_binned can be used to place the exact data into histogram bins for comparison with experiment.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The convenience function reciprocal_space_path returns a list of wavevectors sampled along a path that connects specified 𝐪 points. This list can be used as an input to intensities. Another convenience method, reciprocal_space_shell will generate points on a sphere of a given radius. This is useful for powder averaging. ","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"A number of arguments for intensity_formula are available which modify the calculation of structure factor intensity. It is generally recommended to provide a value of kT corresponding to the temperature of sampled configurations. Given kT, Sunny will include an energy- and temperature-dependent classical-to-quantum rescaling of intensities in the formula.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"To retrieve intensity data from a instantaneous structure factor, use instant_intensities_interpolated, which accepts similar arguments to intensities_interpolated. This function may also be used to calculate instantaneous information from a dynamical correlation data, i.e. from a SampledCorrelations created with dynamical_correlations. Note that it is important to supply a value to kT to reap the benefits of this approach over simply calculating a static structure factor at the outset. ","category":"page"},{"location":"writevtk/#Volumetric-Rendering-with-ParaView","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"section"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"The 4D correlation data produced by Sunny is too high-dimensional to visualize directly. This page describes how to export 3D slices of correlation data from Sunny to the Visual ToolKit (VTK) format, which is compatible with the ParaView visualization software. ParaView supports volumetric rendering:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"page"},{"location":"writevtk/#Simulation-data","page":"Volumetric Rendering with ParaView","title":"Simulation data","text":"","category":"section"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"First, generate some correlation data in Sunny. We will use a 2D lattice, since the correlation data S(Q_xQ_yomega) is 3D and can be exported in its entirety. The following code sets up the system, thermalizes it, and records the correlation data in a SampledCorrelations called dsf.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"using Sunny\n\n# Single layer 12x12 periodic square lattice\nlatsize = (12,12,1);\n\nlatvecs = lattice_vectors(8.,8.,12.,90,100,90)\npositions = [[0,0,0]]\ntypes = [\"Cu\"]\nformfactors = [FormFactor(\"Cu2\")]\nxtal = Crystal(latvecs,positions;types);\n\nsys = System(xtal, latsize, [SpinInfo(1, S=1/2, g=2)], :SUN; seed=1);\n\nJ = 10.\nset_exchange!(sys,J,Bond(1,1,[1,0,0]))\nset_exchange!(sys,J,Bond(1,1,[0,1,0]))\n\nΔt = 0.01\nkT = 0.5\nlangevin = Langevin(Δt; λ=0.5, kT=kT)\nrandomize_spins!(sys);\nfor i in 1:10_000 # Long enough to reach equilibrium\n step!(sys, langevin)\nend \n\nωmax=10.\n\ndsf = dynamical_correlations(sys\n ;Δt=Δt\n ,nω=48\n ,ωmax=ωmax\n ,process_trajectory=:symmetrize)\n\nnsamples = 10\nfor _ in 1:nsamples\n for _ in 1:1000 \n step!(sys, langevin)\n end\n add_sample!(dsf, sys)\nend","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"The default histogram BinningParameters are already integrated over the z direction because the system is 2D:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"unit_resolution_binning_parameters(dsf)","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"⊡ 12 bins from -0.042 to +0.958 along [+1.27 dx] (Δ = 0.065)\n⊡ 12 bins from -0.042 to +0.958 along [+1.27 dy] (Δ = 0.065)\n∫ Integrated from +0.000 to +0.000 along [-0.33 dx +1.88 dz] (Δ = 0.524)\n⊡ 48 bins from -0.107 to +10.134 along [+1.00 dE] (Δ = 0.213)","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"The histogram is very oblong; it's approximately 1x1x10. To make it a nicer shape, we will rescale the energy axis to be be fractions of ωmax:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"params = unit_resolution_binning_parameters(dsf)\nscale_factor = ωmax\nparams.binend[4] /= scale_factor\nparams.binstart[4] /= scale_factor\nparams.binwidth[4] /= scale_factor\nparams.covectors[4,:] ./= scale_factor","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Doing this changes the last axis of the histogram to fit in [0,1]:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"⊡ 49 bins from -0.011 to +1.013 along [+0.10 dE] (Δ = 0.213)","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Now that our histogram is a cube, we compute the intensity in the histogram bins using the usual intensities_binned:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"formula = intensity_formula(dsf,:trace)\nsignal, counts = intensities_binned(dsf, params; formula)\nintensity = signal ./ counts","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Now that we have our intensity data and the binning parameters, we can export to VTK format using export_vtk and move to ParaView for the visualization.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"# Importing WriteVTK enables Sunny's export-to-VTK functions\nimport WriteVTK\n\n# [1,2,4] specifies that the (x,y,z) axes in ParaView are (Qx,Qy,ω)\nexport_vtk(\"square_lattice\", params, intensity; dims_kept = [1,2,4])\n# Writes a file square_lattice.vti in the current directory","category":"page"},{"location":"writevtk/#Loading-in-ParaView","page":"Volumetric Rendering with ParaView","title":"Loading in ParaView","text":"","category":"section"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"In ParaView, use File > Open to open square_lattice.vti. This will add the file to the Pipeline Browser with a closed eye icon, indicating that the data is ready to be loaded.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"In the Properties panel, both bin_centers and data will be selected for import by default. Uncheck bin_centers because we don't need that information for the visualization. Click the green Apply button to load the data.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"By default, only the outline of the data is shown in the 3D viewport. Since we adjusted the energy axis, the outline is a 1x1x1 cube. Optionally enable the axes grid under \"View\", and customize using the adjacent edit button.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"To enable the volumetric render:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Select \"Volume\" from the \"Representation\" drop-down menu under \"Display\".\nThe \"Coloring\" drop-down should automatically select data because it's the only data loaded.\nOpen the Color Map Editor to adjust the opacity of the fog, which may be too faint to see by default.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Depending on your computer and your dataset size, the volumetric rendering may be slow, but our dataset is relatively small, so the render should be fast.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"If nothing shows up at first, don't despair. Often, there are Bragg-like peaks in the correlation data which outshine everything else. To see this, enable Display Data Histogram in the Color Map Editor panel. To zoom in on the lower-intensity data, click and drag the right side handle of the opacity transfer function box to the middle a few times.","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"After suitable color mapping, the dispersion curve should become visible:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"","category":"page"},{"location":"writevtk/#Experiment-data","page":"Volumetric Rendering with ParaView","title":"Experiment data","text":"","category":"section"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"Note that since only the data and binning parameters are required for exporting to VTK, experiment data can be exported in the same way. For example, to visualize S(Q_xQ_yQ_z), do this:","category":"page"},{"location":"writevtk/","page":"Volumetric Rendering with ParaView","title":"Volumetric Rendering with ParaView","text":"# Load 4D histogram data from Mantid\nparams, signal = load_nxs(\"experiment_data.nxs\")\n\n# Integrate out the energy axis so we are 3D\nintegrate_axes!(params; axes = 4)\nsignal = sum(signal; dims = 4)\n\n# Export to ParaView\nexport_vtk(\"experiment_data_as_vtk\", params, signal)","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"EditURL = \"../../../examples/ising2d.jl\"","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/ising2d/#Classical-Ising-model","page":"Classical Ising model","title":"Classical Ising model","text":"","category":"section"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"This tutorial illustrates simulation of the classical 2D Ising model.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"using Sunny, Plots","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Sunny expects a 3D Crystal unit cell. To model a square lattice, we create an orthogonal unit cell where the z-spacing is distinct from the x and y spacing.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"a = 1\nlatvecs = lattice_vectors(a,a,10a,90,90,90)\ncrystal = Crystal(latvecs, [[0,0,0]])","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Create a System of spins with linear size L in the x and y directions, and only one layer in the z direction. The option :dipole means that the system will store Heisenberg spins, as opposed to SU(N) coherent states. Polarize the initial spin configuration using polarize_spins!. Following the Ising convention, we will restrict these spins to the z-axis and give them magnitude S=1.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"By default, Sunny uses physical units, e.g. magnetic field in tesla. Here we specify an alternative Units system, so that the Zeeman coupling between the spin dipole 𝐬 and an external field 𝐁 has the dimensionless form -𝐁𝐬.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"L = 128\nsys = System(crystal, (L,L,1), [SpinInfo(1, S=1, g=1)], :dipole, units=Units.theory, seed=0)\npolarize_spins!(sys, (0,0,1))","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Use set_exchange! to include a ferromagnetic Heisenberg interaction along nearest-neighbor bonds. The Bond below connects two spins displaced by one lattice constant in the x-direction. This interaction will be propagated to all nearest-neighbors bonds in the system, consistent with the symmetries of the square lattice.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"set_exchange!(sys, -1.0, Bond(1,1,(1,0,0)))","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"If an external field is desired, it can be set using set_external_field!.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"B = 0\nset_external_field!(sys, (0,0,B))","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"The critical temperature for the Ising model is known analytically.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Tc = 2/log(1+√2)","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Use a LocalSampler to perform nsweeps Monte Carlo sweeps. A sweep consists of, on average, one trial update per spin in the system. Each proposed update is accepted or rejected according to the Metropolis acceptance probability. As its name suggests, the propose_flip function will only propose pure spin flips, 𝐬 rightarrow -𝐬.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"nsweeps = 4000\nsampler = LocalSampler(kT=Tc, propose=propose_flip)\nfor i in 1:nsweeps\n step!(sys, sampler)\nend","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"Plot the Ising spins by extracting the z-component of the dipoles","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"heatmap(reshape([s.z for s in sys.dipoles], (L,L)))","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"EditURL = \"../../../examples/powder_averaging.jl\"","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/powder_averaging/#Powder-averaged-CoRh_2O_4","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"","category":"section"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"This tutorial illustrates the calculation of the powder-averaged structure factor by performing an orientational average. We consider a simple model of the diamond-cubic crystal CoRh_2O_4, with parameters extracted from Ge et al., Phys. Rev. B 96, 064413.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"using Sunny, GLMakie","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"Construct a diamond Crystal in the conventional (non-primitive) cubic unit cell. Sunny will populate all eight symmetry-equivalent sites when given the international spacegroup number 227 (\"Fd-3m\") and the appropriate setting. For this spacegroup, there are two conventional translations of the unit cell, and it is necessary to disambiguate through the setting keyword argument. (On your own: what happens if setting is omitted?)","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"a = 8.5031 # (Å)\nlatvecs = lattice_vectors(a, a, a, 90, 90, 90)\ncrystal = Crystal(latvecs, [[0,0,0]], 227, setting=\"1\")","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"Construct a System with an antiferromagnetic nearest neighbor interaction J. Because the diamond crystal is bipartite, the ground state will have unfrustrated Néel order. Selecting latsize=(1,1,1) is sufficient because the ground state is periodic over each cubic unit cell. By passing an explicit seed, the system's random number generator will give repeatable results.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"latsize = (1,1,1)\nseed = 0\nS = 3/2\nJ = 7.5413*meV_per_K # (~ 0.65 meV)\nsys = System(crystal, latsize, [SpinInfo(1; S, g=2)], :dipole; seed=0)\nset_exchange!(sys, J, Bond(1, 3, [0,0,0]))","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"The ground state is non-frustrated. Each spin should be exactly anti-aligned with its 4 nearest-neighbors, such that every bond contributes an energy of -JS^2. This gives an energy per site of -2JS^2. In this calculation, a factor of 1/2 is necessary to avoid double-counting the bonds. Given the small magnetic supercell (which includes only one unit cell), direct energy minimization is successful in finding the ground state.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"randomize_spins!(sys)\nminimize_energy!(sys)\n\nenergy_per_site = energy(sys) / length(eachsite(sys))\n@assert energy_per_site ≈ -2J*S^2","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"Plotting the spins confirms the expected Néel order. Note that the overall, global rotation of dipoles is arbitrary.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"plot_spins(sys; ghost_radius=2.0)","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"We can now estimate 𝒮(𝐪ω) with SpinWaveTheory and intensity_formula. The mode :perp contracts with a dipole factor to return the unpolarized intensity. We will also apply broadening with the lorentzian kernel, and will dampen intensities using the FormFactor for Cobalt(2+).","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"swt = SpinWaveTheory(sys)\nη = 0.4 # (meV)\nkernel = lorentzian(η)\nformfactors = [FormFactor(\"Co2\")]\nformula = intensity_formula(swt, :perp; kernel, formfactors)","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"First, we consider the \"single crystal\" results. Use reciprocal_space_path to construct a path that connects high-symmetry points in reciprocal space. The intensities_broadened function collects intensities along this path for the given set of energy values.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"qpoints = [[0.0, 0.0, 0.0], [0.5, 0.0, 0.0], [0.5, 0.5, 0.0], [0.0, 0.0, 0.0]]\npath, xticks = reciprocal_space_path(crystal, qpoints, 50)\nenergies = collect(0:0.01:6)\nis = intensities_broadened(swt, path, energies, formula)\n\nfig = Figure()\nax = Axis(fig[1,1]; aspect=1.4, ylabel=\"ω (meV)\", xlabel=\"𝐪 (RLU)\",\n xticks, xticklabelrotation=π/10)\nheatmap!(ax, 1:size(is, 1), energies, is, colormap=:gnuplot2)\nfig","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"A powder measurement effectively involves an average over all possible crystal orientations. We use the function reciprocal_space_shell to sample n wavevectors on a sphere of a given radius (inverse angstroms), and then calculate the spherically-averaged intensity.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"radii = 0.01:0.02:3 # (1/Å)\noutput = zeros(Float64, length(radii), length(energies))\nfor (i, radius) in enumerate(radii)\n n = 300\n qs = reciprocal_space_shell(crystal, radius, n)\n is = intensities_broadened(swt, qs, energies, formula)\n output[i, :] = sum(is, dims=1) / size(is, 1)\nend\n\nfig = Figure()\nax = Axis(fig[1,1]; xlabel=\"|Q| (Å⁻¹)\", ylabel=\"ω (meV)\")\nheatmap!(ax, radii, energies, output, colormap=:gnuplot2)\nfig","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"This result can be compared to experimental neutron scattering data from Fig. 5 of Ge et al.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder averaged CoRh_2O_4","title":"Powder averaged CoRh_2O_4","text":"","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"EditURL = \"../../../examples/out_of_equilibrium.jl\"","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/out_of_equilibrium/#CP2-Skyrmion-Quench","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"","category":"section"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"This example demonstrates Sunny's ability to simulate the out-of-equilibrium dynamics of generalized spin systems. We will implement the model Hamiltonian of Zhang et al., Nature Communications 14, 3626 (2023), which supports a novel type of topological defect, a CP² skyrmion, that involves both the dipolar and quadrupolar parts of a quantum spin.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Beginning from an initial high-temperature state, a disordered gas of CP² skyrmions can be formed by rapidly quenching to low temperature. To model the coupled dynamics of dipoles and quadrupoles, Sunny uses a recently developed generalization of the Landau-Lifshitz spin dynamics, Dahlbom et al., Phys. Rev. B 106, 235154 (2022).","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"using Sunny, GLMakie","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"The Hamiltonian we will implement,","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"mathcalH = sum_langle ij rangle J_ij( hatS_i^x hatS_j^x + hatS_i^y hatS_j^y + DeltahatS_i^z hatS_j^z) - hsum_ihatS_i^z + Dsum_i(hatS_i^z)^2","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"contains competing ferromagnetic nearest-neightbor and antiferromagnetic next-nearest-neighbor exchange terms on a triangular lattice. Both exchanges exhibit anisotropy on the z-term. Additionally, there is an external magnetic field, h, and easy-plane single-ion anisotropy, D. We begin by implementing the Crystal.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"lat_vecs = Sunny.lattice_vectors(1.0, 1.0, 2.0, 90, 90, 120)\nbasis_vecs = [[0,0,0]]\ncryst = Crystal(lat_vecs, basis_vecs)","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"The crystal is then used to create a spin System. All parameters in this model system are dimensionless, so we select \"theory\" units and set the g-factor to one.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"L = 40\ndims = (L, L, 1)\nsys = System(cryst, dims, [SpinInfo(1, S=1, g=1)], :SUN; seed=101, units=Units.theory)","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"We proceed to implement each term of the Hamiltonian, selecting our parameters so that the system occupies a region of the phase diagram that supports skyrmions. The exchange interactions are set as follows.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"J1 = -1 # Nearest-neighbor ferromagnetic\nJ2 = (2.0/(1+√5)) # Tune competing exchange to set skyrmion scale length\nΔ = 2.6 # Exchange anisotropy\n\nex1 = J1 * [1.0 0.0 0.0;\n 0.0 1.0 0.0;\n 0.0 0.0 Δ]\nex2 = J2 * [1.0 0.0 0.0;\n 0.0 1.0 0.0;\n 0.0 0.0 Δ]\nset_exchange!(sys, ex1, Bond(1, 1, [1, 0, 0]))\nset_exchange!(sys, ex2, Bond(1, 1, [1, 2, 0]));\nnothing #hide","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Next we add the external field,","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"h = 15.5\nfield = set_external_field!(sys, [0.0 0.0 h]);\nnothing #hide","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"and finally the single-ion anisotropy,","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"D = 19.0\nSz = Sunny.spin_operators(sys, 1)[3]\nset_onsite_coupling!(sys, D*Sz^2, 1);\nnothing #hide","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Initialize system to an infinite temperature (fully randomized) initial condition.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"randomize_spins!(sys)","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"We are now ready to simulate the quenching process using a generalized Langevin spin dynamics. If we were working with spin dipoles only, then Langevin dynamics would be the usual Landau-Lifshitz spin dynamics, augmented with damping and noise terms. In the present study, we are instead working with quantum spin-1 (an (N=3)-level system that includes both dipoles and quadrupoles). Here, Langevin captures the coupled dipole-quadrupole dynamics using the formalism of SU(N) coherent states.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Selecting kT = 0 in the Langevin dynamics will effective disable the noise term. Then the parameter λ effectively determines the damping time-scale.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Δt = 0.2/D # Integration time step (inverse meV). Typically this will be\n # inversely proportional to the largest energy scale in the\n # system. We can use a fairly large time-step here because\n # accuracy isn't critical.\nkT = 0 # Target equilibrium temperature (meV)\nλ = 0.1 # Magnitude of coupling to thermal bath (dimensionless)\nintegrator = Langevin(Δt; kT, λ);\nnothing #hide","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"Finally we run the dynamics. We will record the state of the system at three different times during the quenching process by copying the coherents field of the System.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"τs = [4., 16, 256] # Times to record snapshots\nframes = [] # Empty array to store snapshots\nfor i in eachindex(τs)\n dur = i == 1 ? τs[1] : τs[i] - τs[i-1] # Determine the length of time to simulate\n numsteps = round(Int, dur/Δt)\n for _ in 1:numsteps # Perform the integration\n step!(sys, integrator)\n end\n push!(frames, copy(sys.coherents)) # Save a snapshot spin configuration\nend","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"To visualize the state of the system contained in each snapshot, we will calculate and plot the skyrmion density on each plaquette of our lattice. The function plot_triangular_plaquettes is not part of the core Sunny package, but rather something you could define yourself. We are using the definition in plotting2d.jl from the Sunny examples/extra directory.","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"include(joinpath(pkgdir(Sunny), \"examples\", \"extra\", \"plotting2d.jl\"))\n\nfunction sun_berry_curvature(z₁, z₂, z₃)\n z₁, z₂, z₃ = normalize.((z₁, z₂, z₃))\n n₁ = z₁ ⋅ z₂\n n₂ = z₂ ⋅ z₃\n n₃ = z₃ ⋅ z₁\n return angle(n₁ * n₂ * n₃)\nend\n\nplot_triangular_plaquettes(sun_berry_curvature, frames; resolution=(1800,600),\n offset_spacing=10, texts = [\"\\tt = \"*string(τ) for τ in τs], text_offset = (0.0, 6.0)\n)","category":"page"},{"location":"examples/out_of_equilibrium/","page":"CP^2 Skyrmion Quench","title":"CP^2 Skyrmion Quench","text":"The times are given in hbarJ_1. The white background corresponds to a quantum paramagnetic state, where the local spin exhibits a strong quadrupole moment and little or no dipole moment. Observe that the process has generated a number of well-formed skyrmions of both positive (red) and negative (blue) charge in addition to a number of other metastable spin configurations. A full-sized version of this figure is available in Dahlbom et al..","category":"page"},{"location":"library/#Library-API","page":"Library API","title":"Library API","text":"","category":"section"},{"location":"library/","page":"Library API","title":"Library API","text":"This page describes the public types and functions exported by Sunny. This documentation can be also be accessed using the Julia help system (enter ? at the Julia command prompt).","category":"page"},{"location":"library/","page":"Library API","title":"Library API","text":"","category":"page"},{"location":"library/","page":"Library API","title":"Library API","text":"Sunny.plot_spins\nSunny.export_vtk","category":"page"},{"location":"library/","page":"Library API","title":"Library API","text":"Modules = [Sunny]\nPrivate = false","category":"page"},{"location":"library/#Sunny.Site","page":"Library API","title":"Sunny.Site","text":"(cell1, cell2, cell3, i) :: Site\n\nFour indices identifying a single site in a System. The first three indices select the lattice cell and the last selects the sublattice (i.e., the atom within the unit cell).\n\nThis object can be used to index dipoles and coherents fields of a System. A Site is also required to specify inhomogeneous interactions via functions such as set_external_field_at! or set_exchange_at!.\n\nNote that the definition of a cell may change when a system is reshaped. In this case, it is convenient to construct the Site using position_to_site, which always takes a position in fractional coordinates of the original lattice vectors.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.Units","page":"Library API","title":"Sunny.Units","text":"Units.meV\nUnits.theory\n\nThe unit system is implicitly determined by the definition of two physical constants: the vacuum permeability μ₀ and the Bohr magneton μ_B. Temperatures are effectively measured in units of energy (k_B = 1) and time is effectively measured in units of inverse energy (ħ = 1). The default unit system, Units.meV, employs (meV, Å, tesla). Select alternatively Units.theory for a units system defined so that μ₀ = μ_B = 1.\n\nSee also meV_per_K\n\n\n\n\n\n","category":"constant"},{"location":"library/#Sunny.meV_per_K","page":"Library API","title":"Sunny.meV_per_K","text":"meV_per_K = 0.086173332621451774\n\nA physical constant. Useful for converting kelvin into the default energy units, meV.\n\n\n\n\n\n","category":"constant"},{"location":"library/#Sunny.BinningParameters","page":"Library API","title":"Sunny.BinningParameters","text":"BinningParameters(binstart,binend,binwidth;covectors = I(4))\nBinningParameters(binstart,binend;numbins,covectors = I(4))\n\nDescribes a 4D parallelepided histogram in a format compatible with experimental Inelasitic Neutron Scattering data. See generate_mantid_script_from_binning_parameters to convert BinningParameters to a format understandable by the Mantid software, or load_nxs to load BinningParameters from a Mantid .nxs file.\n\nThe coordinates of the histogram axes are specified by multiplication of (q,ω) with each row of the covectors matrix, with q given in [R.L.U.]. Since the default covectors matrix is the identity matrix, the default axes are (qx,qy,qz,ω) in absolute units.\n\nThe convention for the binning scheme is that:\n\nThe left edge of the first bin starts at binstart\nThe bin width is binwidth\nThe last bin contains binend\nThere are no \"partial bins;\" the last bin may contain values greater than binend. C.f. count_bins.\n\nA value can be binned by computing its bin index:\n\ncoords = covectors * value\nbin_ix = 1 .+ floor.(Int64,(coords .- binstart) ./ binwidth)\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.Bond","page":"Library API","title":"Sunny.Bond","text":"Bond(i, j, n)\n\nRepresents a bond between atom indices i and j. n is a vector of three integers specifying unit cell displacement in terms of lattice vectors.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.Crystal","page":"Library API","title":"Sunny.Crystal","text":"An object describing a crystallographic unit cell and its space group symmetry. Constructors are as follows:\n\nCrystal(filename; symprec=1e-5)\n\nReads the crystal from a .cif file located at the path filename. The optional parameter symprec controls the precision tolerance for spacegroup symmetries.\n\nCrystal(latvecs, positions; types=nothing, symprec=1e-5)\n\nConstructs a crystal from the complete list of atom positions positions, with coordinates (between 0 and 1) in units of lattice vectors latvecs. Spacegroup symmetry information is automatically inferred. The optional parameter types is a list of strings, one for each atom, and can be used to break symmetry-equivalence between atoms.\n\nCrystal(latvecs, positions, spacegroup_number; types=nothing, setting=nothing, symprec=1e-5)\n\nBuilds a crystal by applying symmetry operators for a given international spacegroup number. For certain spacegroups, there are multiple possible unit cell settings; in this case, a warning message will be printed, and a list of crystals will be returned, one for every possible setting. Alternatively, the optional setting string will disambiguate between unit cell conventions.\n\nCurrently, crystals built using only the spacegroup number will be missing some symmetry information. It is generally preferred to build a crystal from a .cif file or from the full specification of the unit cell.\n\nExamples\n\n# Read a Crystal from a .cif file\nCrystal(\"filename.cif\")\n\n# Build an FCC crystal using the primitive unit cell. The spacegroup number\n# 225 is inferred.\nlatvecs = [1 1 0;\n 1 0 1;\n 0 1 1] / 2\npositions = [[0, 0, 0]]\nCrystal(latvecs, positions)\n\n# Build a CsCl crystal (two cubic sublattices). By providing distinct type\n# strings, the spacegroup number 221 is inferred.\nlatvecs = lattice_vectors(1, 1, 1, 90, 90, 90)\npositions = [[0,0,0], [0.5,0.5,0.5]]\ntypes = [\"Na\", \"Cl\"]\ncryst = Crystal(latvecs, positions; types)\n\n# Build a diamond cubic crystal from its spacegroup number 227. This\n# spacegroup has two possible settings (\"1\" or \"2\"), which determine an\n# overall unit cell translation.\nlatvecs = lattice_vectors(1, 1, 1, 90, 90, 90)\npositions = [[1, 1, 1] / 4]\ncryst = Crystal(latvecs, positions, 227; setting=\"1\")\n\nSee also lattice_vectors.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.FormFactor-Tuple{String}","page":"Library API","title":"Sunny.FormFactor","text":"FormFactor(ion::String; g_lande=2)\n\nThe magnetic form factor for a given magnetic ion and charge state. These can optionally be provided to intensity_formula, and will be used to scale the structure factor intensities as a function of wavevector magnitude.\n\nThe parameter ion must be one of the following allowed strings:\n\nSc0,Sc1,Sc2,Ti0,Ti1,Ti2,Ti3,V0,V1,V2,V3,V4,Cr0,Cr1,Cr2,Cr3,Cr4,Mn0,Mn1,Mn2,Mn3,\nMn4,Fe0,Fe1,Fe2,Fe3,Fe4,Co0,Co1,Co2,Co3,Co4,Ni0,Ni1,Ni2,Ni3,Ni4,Cu0,Cu1,Cu2,Cu3,\nCu4,Y0,Zr0,Zr1,Nb0,Nb1,Mo0,Mo1,Tc0,Tc1,Ru0,Ru1,Rh0,Rh1,Pd0,Pd1,Ce2,Nd2,Nd3,Sm2,\nSm3,Eu2,Eu3,Gd2,Gd3,Tb2,Tb3,Dy2,Dy3,Ho2,Ho3,Er2,Er3,Tm2,Tm3,Yb2,Yb3,Pr3,U3,U4,\nU5,Np3,Np4,Np5,Np6,Pu3,Pu4,Pu5,Pu6,Am2,Am3,Am4,Am5,Am6,Am7\n\nA first approximation to the magnetic form factor is\n\nf(s) = langle j_0(s) rangle,\n\nwhere langle j_l(s) rangle is a Bessel function integral of the magnetic dipole.\n\nIf Landé g-factor is distinct from 2, then a correction will be applied,\n\nF(s) = frac2-gg langle j_2(s) rangle s^2 + f(s).\n\nSunny uses the semi-empirical fits for j_0 and j_2 listed from Refs. [1] and [2]. These functions are approximated as a sum of Gaussians in the scalar variable s = k4π, where k can be interpreted as the magnitude of momentum transfer:\n\nlangle j_l(s) rangle = A e^-as^2 + B e^-bs^2 + Ce^-cs^2 + D\n\nwhere A B C D a b c are l-dependent fitting parameters. For transition metals, the parameters are estimated using the Hartree-Fock method. For rare-earth metals and ions, the Dirac-Fock form is used.\n\nReferences:\n\nhttps://www.ill.eu/sites/ccsl/ffacts/ffachtml.html\nJ. Brown, The Neutron Data Booklet, 2nd ed., Sec. 2.5 Magnetic Form Factors (2003).\nMarshall W and Lovesey S W, Theory of thermal neutron scattering Chapter 6 Oxford University Press (1971)\nClementi E and Roetti C, Atomic Data and Nuclear Data Tables, 14 pp 177-478 (1974)\nFreeman A J and Descleaux J P, J. Magn. Mag. Mater., 12 pp 11-21 (1979) Descleaux J P and Freeman A J, J. Magn. Mag. Mater., 8 pp 119-129 (1978) \n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.ImplicitMidpoint","page":"Library API","title":"Sunny.ImplicitMidpoint","text":"ImplicitMidpoint(Δt::Float64; atol=1e-12) where N\n\nEnergy-conserving spin dynamics. One call to the step! function will advance a System by Δt units of time.\n\nUses the spherical midpoint integration scheme for dipole systems and the Schrödinger midpoint integration scheme for SU(N) spin systems. Both integration schemes are symplectic, and therefore avoid energy drift over long periods of simulation time.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.Langevin","page":"Library API","title":"Sunny.Langevin","text":"Langevin(Δt::Float64; λ::Float64, kT::Float64)\n\nSpin dynamics with coupling to a Langevin thermostat, which includes damping and noise terms. One call to the step! function will advance a System by Δt units of time.\n\nAssuming ergodicity, the Langevin dynamics will sample from thermal equilibrium for the target temperature kT. The empirical parameter λ determines the strength of the coupling to the thermal bath. In other words, 1/λ is the decorrelation time-scale. If λ = 0, then the spin dynamics coincides with ImplicitMidpoint.\n\nAn alternative approach to sampling is LocalSampler, which may be preferred when the allowed spin values become effective discrete (e.g. Ising spins).\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.LocalSampler","page":"Library API","title":"Sunny.LocalSampler","text":"LocalSampler(; kT, nsweeps=1.0, propose=propose_uniform)\n\nMonte Carlo simulation involving Metropolis updates to individual spins. One call to the step! function will perform nsweeps of MCMC sampling for a provided System. The default value of 1.0 means that step! performs, on average, one trial update per spin.\n\nAssuming ergodicity, the LocalSampler will sample from thermal equilibrium for the target temperature kT. \n\nThe trial spin updates are sampled using the propose function. Built-in options include propose_uniform, propose_flip, and propose_delta. Multiple proposals can be mixed with the macro @mix_proposals.\n\nThe returned object stores fields ΔE and Δs, which represent the cumulative change to the net energy and dipole, respectively.\n\nAn alternative approach to sampling is Langevin, which may be preferred for simulating continuous spins, especially in the presence of long-range dipole-dipole interactions (cf. enable_dipole_dipole!).\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.SampledCorrelations","page":"Library API","title":"Sunny.SampledCorrelations","text":"SampledCorrelations\n\nBasic data type for storing sampled correlation data. A SampleCorrelations is initialized by calling either dynamical_correlations or instant_correlations.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.SpinInfo","page":"Library API","title":"Sunny.SpinInfo","text":"SpinInfo(atom::Int; S, g=2)\n\nCharacterizes the spin at a given atom index within the crystal unit cell. S is an integer multiple of 1/2 and gives the spin angular momentum in units of ħ. g is the g-factor or tensor, such that an angular momentum dipole s produces a magnetic moment g s in units of the Bohr magneton.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.SpinWaveTheory","page":"Library API","title":"Sunny.SpinWaveTheory","text":"SpinWaveTheory(sys, energy_ϵ::Float64=1e-8, energy_tol=1e-6)\n\nConstructs an object to perform linear spin wave theory. Use it with dispersion and dssf functions.\n\nThe optional parameter energy_ϵ adds a small positive shift to the diagonal of the dynamical matrix D to avoid numerical issues with zero-energy quasi-particle modes. The optional parameter energy_tol relaxes the check on the imaginary part of the eigenvalues.\n\n\n\n\n\n","category":"type"},{"location":"library/#Sunny.System-Tuple{Crystal, Tuple{Int64, Int64, Int64}, Vector{SpinInfo}, Symbol}","page":"Library API","title":"Sunny.System","text":"System(crystal::Crystal, latsize, infos, mode; units=Units.meV, seed::Int)\n\nConstruct a System of spins for a given Crystal symmetry. The latsize parameter determines the number of unit cells in each lattice vector direction. The infos parameter is a list of SpinInfo objects, which determine the magnitude S and g-tensor of each spin.\n\nThe three possible options for mode are :SUN, :dipole, and :large_S. The most variationally accurate choice is :SUN, in which each spin-S degree of freedom is described as an SU(N) coherent state, where N = 2S + 1. Note that an SU(N) coherent state fully describes any local spin state; this description includes expected dipole components Sᵅ, quadrupole components SᵅSᵝ+SᵝSᵅ, etc.\n\nThe mode :dipole projects the SU(N) dynamics onto the space of pure dipoles. In practice this means that Sunny will simulate Landau-Lifshitz dynamics, but all single-ion anisotropy and biquadratic exchange interactions will be automatically renormalized for maximum accuracy.\n\nTo disable such renormalization, e.g. to reproduce results using the historical large-S classical limit, use the experimental mode :large_S. Modes :SUN or :dipole are strongly preferred for the development of new models.\n\nThe default units system of (meV, Å, tesla) can be overridden by with the units parameter; see Units. \n\nAn optional seed may be provided to achieve reproducible random number generation.\n\nAll spins are initially polarized in the z-direction.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.add_sample!-Tuple{SampledCorrelations, System}","page":"Library API","title":"Sunny.add_sample!","text":"add_sample!(sc::SampledCorrelations, sys::System)\n\nadd_trajectory uses the spin configuration contained in the System to generate a correlation data and accumulate it into sc. For static structure factors, this involves analyzing the spin-spin correlations of the spin configuration provided. For a dynamic structure factor, a trajectory is calculated using the given spin configuration as an initial condition. The spin-spin correlations are then calculating in time and accumulated into sc. \n\nThis function will change the state of sys when calculating dynamical structure factor data. To preserve the initial state of sys, it must be saved separately prior to calling add_sample!. Alternatively, the initial spin configuration may be copied into a new System and this new System can be passed to add_sample!.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.available_energies-Tuple{SampledCorrelations}","page":"Library API","title":"Sunny.available_energies","text":"available_energies(sc::SampledCorrelations; negative_energies=false)\n\nReturn the ω values for the energy index of a SampledCorrelations. By default, only returns values for non-negative energies, which corresponds to the default output of intensities. Set negative_energies to true to retrieve all ω values.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.available_wave_vectors-Tuple{SampledCorrelations}","page":"Library API","title":"Sunny.available_wave_vectors","text":"available_wave_vectors(sc::SampledCorrelations; bzsize=(1,1,1))\n\nReturns all wave vectors for which sc contains exact values. bsize specifies the number of Brillouin zones to be included.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.axes_bincenters-Tuple{Any, Any, Any}","page":"Library API","title":"Sunny.axes_bincenters","text":"axes_bincenters(params::BinningParameters)\n\nReturns tick marks which label the bins of the histogram described by BinningParameters by their bin centers.\n\nThe following alternative syntax can be used to compute bin centers for a single axis:\n\naxes_bincenters(binstart,binend,binwidth)\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.broaden_energy-Tuple{SampledCorrelations, Any, Function}","page":"Library API","title":"Sunny.broaden_energy","text":"broaden_energy(sc::SampledCorrelations, vals, kernel::Function; negative_energies=false)\n\nPerforms a real-space convolution along the energy axis of an array of intensities. Assumes the format of the intensities array corresponds to what would be returned by intensities_interpolated. kernel must be a function that takes two numbers: kernel(ω, ω₀), where ω is a frequency, and ω₀ is the center frequency of the kernel. Sunny provides lorentzian for the most common use case:\n\nnewvals = broaden_energy(sc, vals, (ω, ω₀) -> lorentzian(ω-ω₀, 0.2))\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.browser-Tuple{String}","page":"Library API","title":"Sunny.browser","text":"browser(html_str; dir)\n\nLaunch a system browser to display the provided HTML string or SunnyViewer. If a directory dir is provided, an HTML file will be written at that location.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.count_bins-Tuple{Any, Any, Any}","page":"Library API","title":"Sunny.count_bins","text":"count_bins(binstart,binend,binwidth)\n\nReturns the number of bins in the binning scheme implied by binstart, binend, and binwidth. To count the bins in a BinningParameters, use params.numbins.\n\nThis function defines how partial bins are handled, so it should be used preferentially over computing the number of bins manually.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.dispersion-Tuple{SpinWaveTheory, Any}","page":"Library API","title":"Sunny.dispersion","text":"dispersion(swt::SpinWaveTheory, qs)\n\nComputes the spin excitation energy dispersion relations given a SpinWaveTheory and an array of wave vectors qs. Each element q of qs must be a 3-vector in units of reciprocal lattice units. I.e., qᵢ is given in 2πaᵢ with aᵢ the lattice constant of the original chemical lattice.\n\nThe first indices of the returned array correspond to those of qs. A final index, corresponding to mode, is added to these. Each entry of the array is an energy.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.dmvec-Tuple{Any}","page":"Library API","title":"Sunny.dmvec","text":"dmvec(D)\n\nAntisymmetric matrix representation of the Dzyaloshinskii-Moriya pseudo-vector,\n\n [ 0 D[3] -D[2]\n -D[3] 0 D[1]\n D[2] -D[1] 0 ]\n\nUseful in the context of set_exchange!.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.dssf-Tuple{SpinWaveTheory, Any}","page":"Library API","title":"Sunny.dssf","text":"dssf(swt::SpinWaveTheory, qs)\n\nGiven a SpinWaveTheory object, computes the dynamical spin structure factor,\n\n 𝒮^αβ(𝐤 ω) = 1(2πN)dt _𝐫 expi(ωt - 𝐤𝐫) S^α(𝐫 t)S^β(0 0)\n\nusing the result from linear spin-wave theory,\n\n 𝒮^αβ(𝐤 ω) = _n A_n^αβ(𝐤)^2 δω-ω_n(𝐤)\n\nqs is an array of wave vectors of arbitrary dimension. Each element q of qs must be a 3-vector in reciprocal lattice units (RLU), i.e., in the basis of reciprocal lattice vectors.\n\nThe first indices of the returned array correspond to those of qs. A final index, corresponding to mode, is added to these. Each entry of this array is a tensor (3×3 matrix) corresponding to the indices α and β.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.dynamical_correlations-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.dynamical_correlations","text":"dynamical_correlations(sys::System; Δt, nω, ωmax, \n process_trajectory=:none, observables=nothing, correlations=nothing)\n\nCreates a SampledCorrelations for calculating and storing 𝒮(𝐪ω) data. This information will be obtained by running dynamical spin simulations on equilibrium snapshots and measuring pair-correlations. The 𝒮(𝐪ω) data can be retrieved by calling intensities_interpolated. Alternatively, instant_intensities_interpolated will integrate out ω to obtain 𝒮(𝐪), optionally applying classical-to-quantum correction factors.\n\nThe SampleCorrelations that is returned will contain no correlation data. Samples are generated and accumulated by calling add_sample!(sc, sys) where sc is a SampleCorrelations and sys is an appropriately equilibrated System. Note that the sys should be thermalized before each call of add_sample! such that the spin configuration in the system represents a new (fully decorrelated) sample.\n\nThree keywords are required to specify the dynamics used for the trajectory calculation.\n\nΔt: The time step used for calculating the trajectory from which dynamic spin-spin correlations are calculated. The trajectories are calculated with an ImplicitMidpoint integrator.\nωmax: The maximum energy, ω, that will be resolved.\nnω: The number of energy bins to calculated between 0 and ωmax.\n\nAdditional keyword options are the following:\n\nprocess_trajectory: Specifies a function that will be applied to the sample trajectory before correlation analysis. Current options are :none and :symmetrize. The latter will symmetrize the trajectory in time, which can be useful for removing Fourier artifacts that arise when calculating the correlations.\nobservables: Allows the user to specify custom observables. The observables must be given as a list of complex N×N matrices or LinearMaps. It's recommended to name each observable, for example: observables = [:A => a_observable_matrix, :B => b_map, ...]. By default, Sunny uses the 3 components of the dipole, :Sx, :Sy and :Sz.\ncorrelations: Specify which correlation functions are calculated, i.e. which matrix elements αβ of 𝒮^αβ(qω) are calculated and stored. Specified with a vector of tuples. By default Sunny records all auto- and cross-correlations generated by all observables. To retain only the xx and xy correlations, one would set correlations=[(:Sx,:Sx), (:Sx,:Sy)] or correlations=[(1,1),(1,2)].\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.eachsite-Tuple{System}","page":"Library API","title":"Sunny.eachsite","text":"eachsite(sys::System)\n\nAn iterator over all Sites in the system. \n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.enable_dipole_dipole!-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.enable_dipole_dipole!","text":"enable_dipole_dipole!(sys::System)\n\nEnables long-range dipole-dipole interactions,\n\n -(μ_04π) _ij (3 (𝐌_j𝐫_ij)(𝐌_i𝐫_ij) - 𝐌_i𝐌_j) 𝐫_ij^3\n\nwhere the sum is over all pairs of spins (singly counted), including periodic images, regularized using the Ewald summation convention. The magnetic moments are 𝐌_i = μ_B g 𝐒_i where g is the g-factor or g-tensor, and 𝐒_i is the spin angular momentum dipole in units of ħ. The Bohr magneton μ_B and vacuum permeability μ_0 are physical constants, with numerical values determined by the unit system.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.energy-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.energy","text":"energy(sys::System)\n\nComputes the total system energy.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.generate_mantid_script_from_binning_parameters-Tuple{Any}","page":"Library API","title":"Sunny.generate_mantid_script_from_binning_parameters","text":"generate_mantid_script_from_binning_parameters(params::BinningParameters)\n\nGenerate a Mantid script which bins data according to the given BinningParameters.\n\nwarning: Units\nTake care to ensure the units are correct (R.L.U. or absolute). You may want to call Sunny.bin_rlu_as_absolute_units! or Sunny.bin_absolute_units_as_rlu! first.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.global_position-Tuple{System, Any}","page":"Library API","title":"Sunny.global_position","text":"global_position(sys::System, site::Site)\n\nPosition of a Site in global coordinates.\n\nTo precompute a full list of positions, one can use eachsite as below:\n\npos = [global_position(sys, site) for site in eachsite(sys)]\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.instant_correlations-Tuple{System}","page":"Library API","title":"Sunny.instant_correlations","text":"instant_correlations(sys::System; process_trajectory=:none, observables=nothing, correlations=nothing)\n\nCreates a SampledCorrelations object for calculating and storing instantaneous structure factor intensities 𝒮(𝐪). This data will be calculated from the spin-spin correlations of equilibrium snapshots, absent any dynamical information. 𝒮(𝐪) data can be retrieved by calling instant_intensities_interpolated.\n\nImportant note: When dealing with continuous (non-Ising) spins, consider creating using dynamical_correlations instead of instant_correlations. The former will provide full 𝒮(𝐪ω) data, from which 𝒮(𝐪) can be obtained by integrating out ω. During this integration step, Sunny can incorporate temperature- and ω-dependent classical-to-quantum correction factors to produce more accurate 𝒮(𝐪) estimates. See instant_intensities_interpolated for more information.\n\nPrior to calling instant_correlations, ensure that sys represents a good equilibrium sample. Additional sample data may be accumulated by calling add_sample!(sc, sys) with newly equilibrated sys configurations.\n\nThe following optional keywords are available:\n\nprocess_trajectory: Specifies a function that will be applied to the sample trajectory before correlation analysis. Current options are :none and :symmetrize. The latter will symmetrize the trajectory in time, which can be useful for removing Fourier artifacts that arise when calculating the correlations.\nobservables: Allows the user to specify custom observables. The observables must be given as a list of complex N×N matrices or LinearMaps. It's recommended to name each observable, for example: observables = [:A => a_observable_matrix, :B => b_map, ...]. By default, Sunny uses the 3 components of the dipole, :Sx, :Sy and :Sz.\ncorrelations: Specify which correlation functions are calculated, i.e. which matrix elements αβ of 𝒮^αβ(qω) are calculated and stored. Specified with a vector of tuples. By default Sunny records all auto- and cross-correlations generated by all observables. To retain only the xx and xy correlations, one would set correlations=[(:Sx,:Sx), (:Sx,:Sy)] or correlations=[(1,1),(1,2)].\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.instant_intensities_interpolated-Tuple{SampledCorrelations, Any, Any}","page":"Library API","title":"Sunny.instant_intensities_interpolated","text":"instant_intensities_interpolated(sc::SampledCorrelations, qs; kwargs...)\n\nReturn 𝒮(𝐪) intensities at wave vectors qs. The functionality is very similar to intensities_interpolated, except the returned array has dimensions identical to qs. If called on a SampledCorrelations with dynamical information, i.e., 𝒮(𝐪ω), the ω information is integrated out.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.integrate_axes!-Tuple{BinningParameters}","page":"Library API","title":"Sunny.integrate_axes!","text":"integrate_axes!(params::BinningParameters; axes)\n\nIntegrate over one or more axes of the histogram by setting the number of bins in that axis to 1. Examples:\n\nintegrate_axes!(params; axes = [2,3])\nintegrate_axes!(params; axes = 2)\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.integrated_lorentzian-Tuple{Float64}","page":"Library API","title":"Sunny.integrated_lorentzian","text":"integrated_lorentzian(η)\n\nReturns x mapsto atan(xη)π for use with intensities_binned.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensities_bands-Tuple{SpinWaveTheory, Any, Sunny.SpinWaveIntensityFormula}","page":"Library API","title":"Sunny.intensities_bands","text":"dispersion, intensities = intensities_bands(swt::SpinWaveTheory, ks, formula::SpinWaveIntensityFormula)\n\nComputes the scattering intensities at each energy band for each momentum transfer k in ks, according to Linear Spin Wave Theory and the given intensity formula. The formula must have a delta-function kernel, e.g.:\n\nformula = intensity_formula(swt, :perp, formula; kernel = delta_function_kernel)\n\nor else the bands will be broadened, and their intensity can not be computed.\n\nThe outputs will be arrays with indices identical to ks, with the last index giving the band index. dispersions reports the energy of each band, while intensities reports the scattering intensity.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensities_binned-Tuple{SampledCorrelations, BinningParameters, Sunny.ClassicalIntensityFormula}","page":"Library API","title":"Sunny.intensities_binned","text":"intensity, counts = intensities_binned(sc::SampledCorrelations, params::BinningParameters, formula; integrated_kernel)\n\nGiven correlation data contained in a SampledCorrelations and BinningParameters describing the shape of a histogram, compute the intensity and normalization for each histogram bin using a given intensity_formula.\n\nThe BinningParameters are expected to accept (q,ω) in R.L.U. for the (possibly reshaped) crystal associated with sc.\n\nThis is an alternative to intensities_interpolated which bins the scattering intensities into a histogram instead of interpolating between them at specified qs values. See unit_resolution_binning_parameters for a reasonable default choice of BinningParameters which roughly emulates intensities_interpolated with interpolation = :round.\n\nIf a function integrated_kernel(Δω) is passed, it will be used as the CDF of a kernel function for energy broadening. For example, integrated_kernel = Δω -> atan(Δω/η)/pi (c.f. integrated_lorentzian implements Lorentzian broadening with parameter η. Energy-dependent energy broadening can be achieved by providing an integrated_kernel(ω,Δω) whose first argument is the energy transfer ω.\n\nCurrently, energy broadening is only supported if the BinningParameters are such that the first three axes are purely spatial and the last (energy) axis is [0,0,0,1].\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensities_broadened-Tuple{SpinWaveTheory, Any, Any, Any}","page":"Library API","title":"Sunny.intensities_broadened","text":"intensities_broadened(swt::SpinWaveTheory, ks, ωvals, formula)\n\nComputes the scattering intensities at each (Q,ω) according to Linear Spin Wave Theory and the given intensity formula. The required formula must have a non-delta-function kernel, e.g.:\n\nformula = intensity_formula(swt, :perp; kernel = lorentzian(0.05))\n\nor else the intensity at ωvals which are not exactly on the dispersion curve can not be calculated.\n\nThe intensity is computed at each wave vector in ks and each energy in ωvals. The output will be an array with indices identical to ks, with the last index matching ωvals.\n\nNote that ks is an array of wave vectors of arbitrary dimension. Each element k of ks must be a 3-wavevector in absolute units.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensities_interpolated-Tuple{SampledCorrelations, Any, Sunny.ClassicalIntensityFormula}","page":"Library API","title":"Sunny.intensities_interpolated","text":"intensities_interpolated(sc::SampledCorrelations, qs, formula:ClassicalIntensityFormula; interpolation=nothing, negative_energies=false)\n\nThe basic function for retrieving 𝒮(𝐪ω) information from a SampledCorrelations. Maps an array of wave vectors qs to an array of structure factor intensities, including an additional energy index. The values of ω associated with the energy index can be retrieved by calling available_energies. The three coordinates of each wave vector are measured in reciprocal lattice units, i.e., multiples of the reciprocal lattice vectors.\n\ninterpolation: Since 𝒮(𝐪 ω) is calculated on a finite lattice, data is only available at discrete wave vectors. By default, Sunny will round a requested q to the nearest available wave vector. Linear interpolation can be applied by setting interpolation=:linear.\nnegative_energies: If set to true, Sunny will return the periodic extension of the energy axis. Most users will not want this.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensity_formula-Tuple{Function, SampledCorrelations, AbstractVector{Int64}}","page":"Library API","title":"Sunny.intensity_formula","text":"formula = intensity_formula(sc::SampledCorrelations)\n\nEstablish a formula for computing the intensity of the discrete scattering modes (q,ω) using the correlation data 𝒮^αβ(qω) stored in the SampledCorrelations. The formula returned from intensity_formula can be passed to intensities_interpolated or intensities_binned.\n\nintensity_formula(sc,...; kT = Inf, formfactors = ...)\n\nThere are keyword arguments providing temperature and form factor corrections:\n\nkT: If a temperature is provided, the intensities will be rescaled by a temperature- and ω-dependent classical-to-quantum factor. kT should be specified when making comparisons with spin wave calculations or experimental data. If kT is not specified, infinite temperature (no correction) is assumed.\nformfactors: To apply form factor corrections, provide this keyword with a list of FormFactors, one for each symmetry-distinct site in the crystal. The order of FormFactors must correspond to the order of site symmetry classes, e.g., as they appear when printed in display(crystal).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensity_formula-Tuple{Function, SampledCorrelations, Any}","page":"Library API","title":"Sunny.intensity_formula","text":"A custom intensity formula can be specifed by providing a function intensity = f(q,ω,correlations) and specifying which correlations it requires:\n\nintensity_formula(f,sc::SampledCorrelations, required_correlations; kwargs...)\n\nThe function is intended to be specified using do notation. For example, this custom formula sums the off-diagonal correlations:\n\nrequired = [(:Sx,:Sy),(:Sy,:Sz),(:Sx,:Sz)]\nintensity_formula(sc,required,return_type = ComplexF64) do k, ω, off_diagonal_correlations\n sum(off_diagonal_correlations)\nend\n\nIf your custom formula returns a type other than Float64, use the return_type keyword argument to flag this.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensity_formula-Tuple{Function, SpinWaveTheory, AbstractVector{Int64}}","page":"Library API","title":"Sunny.intensity_formula","text":"formula = intensity_formula(swt::SpinWaveTheory; kernel = ...)\n\nEstablish a formula for computing the scattering intensity by diagonalizing the hamiltonian H(q) using Linear Spin Wave Theory.\n\nIf kernel = delta_function_kernel, then the resulting formula can be used with intensities_bands.\n\nIf kernel is an energy broadening kernel function, then the resulting formula can be used with intensities_broadened. Energy broadening kernel functions can either be a function of Δω only, e.g.:\n\nkernel = Δω -> ...\n\nor a function of both the energy transfer ω and of Δω, e.g.:\n\nkernel = (ω,Δω) -> ...\n\nThe integral of a properly normalized kernel function over all Δω is one.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensity_formula-Tuple{SpinWaveTheory, Symbol}","page":"Library API","title":"Sunny.intensity_formula","text":"intensity_formula([swt or sc], contraction_mode::Symbol)\n\nSunny has several built-in formulas that can be selected by setting contraction_mode to one of these values:\n\n:trace (default), which yields operatornametr 𝒮(qω) = _α 𝒮^αα(qω)\n:perp, which contracts 𝒮^αβ(qω) with the dipole factor δ_αβ - q_αq_β, returning the unpolarized intensity.\n:full, which will return all elements 𝒮^αβ(𝐪ω) without contraction.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.lattice_params-Tuple{StaticArraysCore.SMatrix{3, 3, Float64, 9}}","page":"Library API","title":"Sunny.lattice_params","text":"lattice_params(latvecs::Mat3)\n\nCompute the lattice parameters (a b c α β γ) for the three lattice vectors provided as columns of latvecs. The inverse mapping is lattice_vectors.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.lattice_vectors-NTuple{6, Any}","page":"Library API","title":"Sunny.lattice_vectors","text":"lattice_vectors(a, b, c, α, β, γ)\n\nReturn the lattice vectors, as columns of the 33 output matrix, that correspond to the conventional unit cell defined by the lattice constants (a b c) and the angles (α β γ) in degrees. The inverse mapping is lattice_params.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.load_nxs-Tuple{Any}","page":"Library API","title":"Sunny.load_nxs","text":"params, signal = load_nxs(filename)\n\nGiven the name of a Mantid-exported MDHistoWorkspace file, load the BinningParameters and the signal from that file.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.lorentzian-Tuple{Any, Any}","page":"Library API","title":"Sunny.lorentzian","text":"lorentzian(x, η)\n\nReturns η(π(x^2 + η^2)).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.magnetic_moment-Tuple{System, Any}","page":"Library API","title":"Sunny.magnetic_moment","text":"magnetic_moment(sys::System, site::Site)\n\nGet the magnetic moment for a Site. This is the spin dipole multiplied by the Bohr magneton and the local g-tensor.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.merge!-Tuple{SampledCorrelations, Vararg{Any}}","page":"Library API","title":"Sunny.merge!","text":"merge!(sc::SampledCorrelations, others...)\n\nAccumulate the samples in others (one or more SampledCorrelations) into sc.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.minimize_energy!-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.minimize_energy!","text":"minimize_energy!(sys::System{N}; maxiters=100, subiters=20,\n method=Optim.ConjugateGradient(), kwargs...) where N\n\nOptimizes the spin configuration in sys to minimize energy. A total of maxiters iterations will be attempted, with restarts after every subiters iterations. The remaining kwargs will be forwarded to the optimize method of the Optim.jl package.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.polarize_spins!-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.polarize_spins!","text":"polarize_spins!(sys::System, dir)\n\nPolarize all spins in the system along the direction dir.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.position_to_site-Tuple{System, Any}","page":"Library API","title":"Sunny.position_to_site","text":"position_to_site(sys::System, r)\n\nConverts a position r to four indices of a Site. The coordinates of r are given in units of the lattice vectors for the original crystal. This function can be useful for working with systems that have been reshaped using reshape_supercell.\n\nExample\n\n# Find the `site` at the center of a unit cell which is displaced by four\n# multiples of the first lattice vector\nsite = position_to_site(sys, [4.5, 0.5, 0.5])\n\n# Print the dipole at this site\nprintln(sys.dipoles[site])\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.powder_average_binned-Tuple{SampledCorrelations, Any, Sunny.ClassicalIntensityFormula}","page":"Library API","title":"Sunny.powder_average_binned","text":"powder_average_binned(sc::SampledCorrelations, radial_binning_parameters; formula\n ω_binning_parameters, integrated_kernel = nothing, bzsize = nothing)\n\nThis function emulates the experimental situation of \"powder averaging,\" where only the magnitude (and not the direction) of the momentum transfer is resolvable. The intensities are binned similarly to intensities_binned, but the histogram x-axis is |k| in absolute units, which is a nonlinear function of kx,ky,kz. The y-axis is energy.\n\nRadial binning parameters are specified as tuples (start,end,bin_width), e.g. radial_binning_parameters = (0,6π,6π/55).\n\nEnergy broadening is supported in the same way as intensities_binned, and this function accepts the same kind of intensity_formula.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_bond-Tuple{Crystal, Bond}","page":"Library API","title":"Sunny.print_bond","text":"print_bond(cryst::Crystal, bond::Bond; b_ref::Bond)\n\nPrints symmetry information for bond bond. A symmetry-equivalent reference bond b_ref can optionally be provided to fix the meaning of the coefficients A, B, ...\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_site-Tuple{Any, Any}","page":"Library API","title":"Sunny.print_site","text":"print_site(cryst, i; R=I)\n\nPrint symmetry information for the site i, including allowed g-tensor and allowed anisotropy operator. An optional rotation matrix R can be provided to define the reference frame for expression of the anisotropy.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_stevens_expansion-Tuple{Matrix{ComplexF64}}","page":"Library API","title":"Sunny.print_stevens_expansion","text":"function print_stevens_expansion(op)\n\nPrints a local Hermitian operator as a linear combination of Stevens operators. This function works on explicit matrix representations.\n\nExamples\n\nS = spin_matrices(N=5)\nprint_stevens_expansion(S[1]^4 + S[2]^4 + S[3]^4)\n# Prints: (1/20)𝒪₄₀ + (1/4)𝒪₄₄ + 102/5\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_suggested_frame-Tuple{Crystal, Int64}","page":"Library API","title":"Sunny.print_suggested_frame","text":"print_suggested_frame(cryst, i; digits=4)\n\nPrint a suggested reference frame, as a rotation matrix R, that can be used as input to print_site(). This is useful to simplify the description of allowed anisotropies.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_symmetry_table-Tuple{Crystal, Any}","page":"Library API","title":"Sunny.print_symmetry_table","text":"print_symmetry_table(cryst::Crystal, max_dist)\n\nPrint symmetry information for all equivalence classes of sites and bonds, up to a maximum bond distance of max_dist. Equivalent to calling print_bond(cryst, b) for every bond b in reference_bonds(cryst, max_dist), where Bond(i, i, [0,0,0]) refers to a single site i.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_wrapped_intensities-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.print_wrapped_intensities","text":"print_wrapped_intensities(sys::System; nmax=10)\n\nFor Bravais lattices: Prints up to nmax wavevectors according to their instantaneous (static) structure factor intensities, listed in descending order. For non-Bravais lattices: Performs the same analysis for each spin sublattice independently; the output weights are naïvely averaged over sublattices, without incorporating phase shift information. Only wavevectors within the first Brillouin zone are printed. Wavevector coordinates are given in reciprocal lattice units, such that each coordinate is between -12 and 12. The output from this function will typically be used as input to suggest_magnetic_supercell.\n\nBecause this function does not incorporate phase information in its averaging over sublattices, the printed weights are not directly comparable with experiment. For that purpose, use instant_correlations instead.\n\nThe weights printed by print_wrapped_intensities may be given a physical interpretation as follows: All possible q-vectors are periodically wrapped into the first Brillouin zone, and the average over their corresponding instantaneous structure factor intensities produce the output weights.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.propose_delta-Tuple{Any}","page":"Library API","title":"Sunny.propose_delta","text":"propose_delta(magnitude)\n\nGenerate a proposal function that adds a Gaussian perturbation to the existing spin state. In :dipole mode, the procedure is to first introduce a random three-vector perturbation 𝐬 = 𝐬 + 𝐬 ξ and then return the properly normalized spin 𝐬 (𝐬𝐬). Each component of the random vector ξ is Gaussian distributed with a standard deviation of magnitude; the latter is dimensionless and typically smaller than one. \n\nIn :SUN mode, the procedure is analogous, but now involving Gaussian perturbations to each of the N complex components of an SU(N) coherent state.\n\nIn the limit of very large magnitude, this function coincides with propose_uniform.\n\nFor use with LocalSampler.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.propose_flip-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.propose_flip","text":"propose_flip\n\nFunction to propose pure spin flip updates in the context of a LocalSampler. Dipoles are flipped as 𝐬 -𝐬. SU(N) coherent states are flipped using the time-reversal operator.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.propose_uniform","page":"Library API","title":"Sunny.propose_uniform","text":"propose_uniform\n\nFunction to propose a uniformly random spin update in the context of a LocalSampler. In :dipole mode, the result is a random three-vector with appropriate normalization. In :SUN mode, the result is a random SU(N) coherent state with appropriate normalization.\n\n\n\n\n\n","category":"function"},{"location":"library/#Sunny.randomize_spins!-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.randomize_spins!","text":"randomize_spins!(sys::System)\n\nRandomizes all spins under appropriate the uniform distribution.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reciprocal_lattice_vectors-Tuple{Crystal}","page":"Library API","title":"Sunny.reciprocal_lattice_vectors","text":"reciprocal_lattice_vectors(cryst::Crystal)\n\nReturns the 33 matrix (𝐛₁𝐛₂𝐛₃) with columns 𝐛ᵢ as reciprocal lattice vectors. These are defined to satisfy 𝐛ᵢ𝐚ⱼ = 2πδᵢⱼ, where (𝐚₁𝐚₂𝐚₃) are the lattice vectors used to construct cryst.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reciprocal_space_path-Tuple{Crystal, Any, Any}","page":"Library API","title":"Sunny.reciprocal_space_path","text":"reciprocal_space_path(cryst::Crystal, qs, density)\n\nReturns a pair (path, xticks). The path return value is a list of wavevectors that samples linearly between the provided wavevectors qs. The xticks return value can be used to label the special 𝐪 values on the x-axis of a plot.\n\nSpecial note about units: the wavevectors qs must be provided in reciprocal lattice units (RLU) for the given crystal, but the sampling density must be specified in units of inverse length. The path will therefore include more samples between q-points that are further apart in absolute Fourier distance (units of inverse length).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reciprocal_space_path_bins-Tuple{Any, Any, Any, Vararg{Any}}","page":"Library API","title":"Sunny.reciprocal_space_path_bins","text":"reciprocal_space_path_bins(sc,qs,density,args...;kwargs...)\n\nTakes a list of wave vectors, qs in R.L.U., and builds a series of histogram BinningParameters whose first axis traces a path through the provided points. The second and third axes are integrated over according to the args and kwargs, which are passed through to slice_2D_binning_parameters.\n\nAlso returned is a list of marker indices corresponding to the input points, and a list of ranges giving the indices of each histogram x-axis within a concatenated histogram. The density parameter is given in samples per reciprocal lattice unit (R.L.U.).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reciprocal_space_shell-Tuple{Crystal, Any, Any}","page":"Library API","title":"Sunny.reciprocal_space_shell","text":"reciprocal_space_shell(cryst::Crystal, radius, n)\n\nSample n points on the reciprocal space sphere with a given radius (units of inverse length).\n\nExamples\n\n# Sample wavevectors on the sphere at fixed density\nreciprocal_space_shell(cryst, r, 4π*r^2*density)\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reference_bonds-Tuple{Crystal, Float64}","page":"Library API","title":"Sunny.reference_bonds","text":"reference_bonds(cryst::Crystal, max_dist)\n\nReturns a full list of bonds, one for each symmetry equivalence class, up to distance max_dist. The reference bond b for each equivalence class is selected according to a scoring system that prioritizes simplification of the elements in basis_for_symmetry_allowed_couplings(cryst, b).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.remove_periodicity!-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.remove_periodicity!","text":"remove_periodicity!(sys::System, dims)\n\nRemove periodic interactions along the dimensions where dims is true. The system must support inhomogeneous interactions via to_inhomogeneous.\n\nExample\n\n# Remove periodic boundaries along the 1st and 3rd dimensions\nremove_periodicity!(sys::System, (true, false, true))\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.repeat_periodically-Union{Tuple{N}, Tuple{System{N}, Tuple{Int64, Int64, Int64}}} where N","page":"Library API","title":"Sunny.repeat_periodically","text":"repeat_periodically(sys::System{N}, counts) where N\n\nCreates a System identical to sys but repeated a given number of times in each dimension, specified by the tuple counts.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.reshape_supercell-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.reshape_supercell","text":"reshape_supercell(sys::System, A)\n\nMaps an existing System to a new one that has the shape and periodicity of a requested supercell. The columns of the 33 integer matrix A represent the supercell lattice vectors measured in units of the original crystal lattice vectors.\n\nThe crystal unit cell may also need to be reshaped to achieve the desired periodicity of the requested supercell. If this is the case, the returned System object will be missing symmetry information. Consequently, certain operations will be unavailable for this system, e.g., setting interactions by symmetry propagation. In practice, one can set all interactions using the original system, and then reshape as a final step.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.resize_supercell-Union{Tuple{N}, Tuple{System{N}, Tuple{Int64, Int64, Int64}}} where N","page":"Library API","title":"Sunny.resize_supercell","text":"resize_supercell(sys::System{N}, latsize) where N\n\nCreates a System identical to sys but enlarged to a given number of unit cells in each lattice vector direction.\n\nAn error will be thrown if sys is incommensurate with latsize. Use reshape_supercell instead to reduce the volume, or to perform an incommensurate reshaping.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.rotate_operator-Tuple{Matrix, Any}","page":"Library API","title":"Sunny.rotate_operator","text":"rotate_operator(A, R)\n\nRotates the local quantum operator A according to the 33 rotation matrix R.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.rotation_in_rlu-Tuple{Crystal, Any, Any}","page":"Library API","title":"Sunny.rotation_in_rlu","text":"rotation_in_rlu(cryst::Crystal, axis, angle)\n\nReturns a 33 matrix that rotates wavevectors in reciprocal lattice units (RLU). The axis vector is a real-space direction in absolute units (but arbitrary magnitude), and the angle is in radians.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_coherent!-Union{Tuple{N}, Tuple{System{N}, Any, Any}} where N","page":"Library API","title":"Sunny.set_coherent!","text":"set_coherent!(sys::System, Z, site::Site)\n\nSet a coherent spin state at a Site using the N complex amplitudes in Z.\n\nFor a standard SpinInfo, these amplitudes will be interpreted in the eigenbasis of 𝒮ᶻ. That is, Z[1] represents the amplitude for the basis state fully polarized along the z-direction, and subsequent components represent states with decreasing angular momentum along this axis (m = S S-1 -S).\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_dipole!-Union{Tuple{N}, Tuple{System{N}, Any, Any}} where N","page":"Library API","title":"Sunny.set_dipole!","text":"set_dipole!(sys::System, dir, site::Site)\n\nPolarize the spin at a Site along the direction dir.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_exchange!-Union{Tuple{N}, Tuple{System{N}, Any, Bond}} where N","page":"Library API","title":"Sunny.set_exchange!","text":"set_exchange!(sys::System, J, bond::Bond; biquad=0.)\n\nSets a 3×3 spin-exchange matrix J along bond, yielding a pairwise interaction energy 𝐒_iJ 𝐒_j. This interaction will be propagated to equivalent bonds in consistency with crystal symmetry. Any previous exchange interactions on these bonds will be overwritten. The parameter bond has the form Bond(i, j, offset), where i and j are atom indices within the unit cell, and offset is a displacement in unit cells.\n\nThe parameter J may be scalar or matrix-valued. As a convenience, dmvec(D) can be used to construct the antisymmetric part of the exchange, where D is the Dzyaloshinskii-Moriya pseudo-vector. The resulting interaction will be 𝐃(𝐒_i𝐒_j).\n\nThe optional parameter biquad defines the strength b for scalar biquadratic interactions of the form b (𝐒_i𝐒_j)² For systems restricted to dipoles, b will be automatically renormalized for maximum consistency with the more variationally accurate SU(N) mode. This renormalization introduces also a correction to the quadratic part of the exchange.\n\nExamples\n\nusing Sunny, LinearAlgebra\n\n# An explicit exchange matrix\nJ1 = [2 3 0;\n -3 2 0;\n 0 0 2]\nset_exchange!(sys, J1, bond)\n\n# An equivalent Heisenberg + DM exchange \nJ2 = 2*I + dmvec([0,0,3])\nset_exchange!(sys, J2, bond)\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_exchange_at!-Union{Tuple{N}, Tuple{System{N}, Any, Union{NTuple{4, Int64}, CartesianIndex{4}}, Union{NTuple{4, Int64}, CartesianIndex{4}}}} where N","page":"Library API","title":"Sunny.set_exchange_at!","text":"set_exchange_at!(sys::System, J, site1::Site, site2::Site; biquad=0., offset=nothing)\n\nSets the exchange interaction along the single bond connecting two Sites, ignoring crystal symmetry. The system must support inhomogeneous interactions via to_inhomogeneous.\n\nIf the system is relatively small, the direction of the bond can be ambiguous due to possible periodic wrapping. Resolve this ambiguity by passing an explicit offset vector, in multiples of unit cells.\n\nSee also set_exchange!.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_external_field!-Tuple{System, Any}","page":"Library API","title":"Sunny.set_external_field!","text":"set_external_field!(sys::System, B::Vec3)\n\nSets the external field B that couples to all spins.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_external_field_at!-Tuple{System, Any, Any}","page":"Library API","title":"Sunny.set_external_field_at!","text":"set_external_field_at!(sys::System, B::Vec3, site::Site)\n\nSets a Zeeman coupling between a field B and a single spin. Site includes a unit cell and a sublattice index.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_onsite_coupling!-Union{Tuple{N}, Tuple{System{N}, Matrix{ComplexF64}, Int64}} where N","page":"Library API","title":"Sunny.set_onsite_coupling!","text":"set_onsite_coupling!(sys::System, op::Matrix{ComplexF64}, i::Int)\n\nSet the single-ion anisotropy for the ith atom of every unit cell, as well as all symmetry-equivalent atoms. The local operator op may be constructed using spin_operators or stevens_operators.\n\nFor systems restricted to dipoles, the anisotropy operators interactions will automatically be renormalized to achieve maximum consistency with the more variationally accurate SU(N) mode.\n\nExamples\n\n# An easy axis anisotropy in the z-direction\nS = spin_operators(sys, i)\nset_onsite_coupling!(sys, -D*S[3]^3, i)\n\n# The unique quartic single-ion anisotropy for a site with cubic point group\n# symmetry\nO = stevens_operators(sys, i)\nset_onsite_coupling!(sys, O[4,0] + 5*O[4,4], i)\n\n# An equivalent expression of this quartic anisotropy, up to a constant shift\nset_onsite_coupling!(sys, 20*(S[1]^4 + S[2]^4 + S[3]^4), i)\n\nSee also spin_operators.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_onsite_coupling_at!-Union{Tuple{N}, Tuple{System{N}, Matrix{ComplexF64}, Union{NTuple{4, Int64}, CartesianIndex{4}}}} where N","page":"Library API","title":"Sunny.set_onsite_coupling_at!","text":"set_onsite_coupling_at!(sys::System, op::Matrix{ComplexF64}, site::Site)\n\nSets the single-ion anisotropy operator op for a single Site, ignoring crystal symmetry. The system must support inhomogeneous interactions via to_inhomogeneous.\n\nSee also set_onsite_coupling!.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.set_vacancy_at!-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.set_vacancy_at!","text":"set_vacancy_at!(sys::System, site::Site)\n\nMake a single site nonmagnetic. Site includes a unit cell and a sublattice index.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.slice_2D_binning_parameters-Tuple{Vector{Float64}, Any, Any, Int64, Any}","page":"Library API","title":"Sunny.slice_2D_binning_parameters","text":"slice_2D_binning_parameter(sc::SampledCorrelations, cut_from_q, cut_to_q, cut_bins::Int64, cut_width::Float64; plane_normal = [0,0,1],cut_height = cutwidth)\n\nCreates BinningParameters which make a cut along one dimension of Q-space.\n\nThe x-axis of the resulting histogram consists of cut_bins-many bins ranging from cut_from_q to cut_to_q. The width of the bins in the transverse direciton is controlled by cut_width and cut_height.\n\nThe binning in the transverse directions is defined in the following way, which sets their normalization and orthogonality properties:\n\ncut_covector = normalize(cut_to_q - cut_from_q)\ntransverse_covector = normalize(plane_normal × cut_covector)\ncotransverse_covector = normalize(transverse_covector × cut_covector)\n\nIn other words, the axes are orthonormal with respect to the Euclidean metric.\n\nIf the cut is too narrow, there will be very few scattering vectors per bin, or the number per bin will vary substantially along the cut. If the output appears under-resolved, try increasing cut_width.\n\nThe four axes of the resulting histogram are:\n\nAlong the cut\nFist transverse Q direction\nSecond transverse Q direction\nEnergy\n\nThis function can be used without reference to a SampledCorrelations using this alternate syntax to manually specify the bin centers for the energy axis:\n\nslice_2D_binning_parameter(ω_bincenters, cut_from, cut_to,...)\n\nwhere ω_bincenters specifies the energy axis, and both cut_from and cut_to are arbitrary covectors, in any units.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.spin_matrices-Tuple{}","page":"Library API","title":"Sunny.spin_matrices","text":"spin_matrices(; N)\n\nConstructs the three spin operators, i.e. the generators of SU(2), in the N-dimensional irrep. See also spin_operators, which determines the appropriate value of N for a given site index.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.spin_operators-Union{Tuple{N}, Tuple{System{N}, Int64}} where N","page":"Library API","title":"Sunny.spin_operators","text":"spin_operators(sys, i::Int)\nspin_operators(sys, site::Int)\n\nReturns the three spin operators appropriate to an atom or Site index. Each is an NN matrix of appropriate dimension N.\n\nSee also print_stevens_expansion.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.step!","page":"Library API","title":"Sunny.step!","text":"step!(sys::System, dynamics)\n\nAdvance the spin configuration one dynamical time-step. The dynamics object may be a continuous spin dynamics, such as Langevin or ImplicitMidpoint, or it may be a discrete Monte Carlo sampling scheme such as LocalSampler.\n\n\n\n\n\n","category":"function"},{"location":"library/#Sunny.stevens_operators-Union{Tuple{N}, Tuple{System{N}, Int64}} where N","page":"Library API","title":"Sunny.stevens_operators","text":"stevens_operators(sys, i::Int)\nstevens_operators(sys, site::Int)\n\nReturns a generator of Stevens operators appropriate to an atom or Site index. The return value O can be indexed as O[k,q], where 0 k 6 labels an irrep and q = -k k. This will produce an NN matrix of appropriate dimension N.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.subcrystal-Union{Tuple{N}, Tuple{Crystal, Vararg{String, N}}} where N","page":"Library API","title":"Sunny.subcrystal","text":"subcrystal(cryst, types) :: Crystal\n\nFilters sublattices of a Crystal by atom types, keeping the space group unchanged.\n\nsubcrystal(cryst, classes) :: Crystal\n\nFilters sublattices of Crystal by equivalence classes, keeping the space group unchanged.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.suggest_magnetic_supercell-Tuple{Any, Any}","page":"Library API","title":"Sunny.suggest_magnetic_supercell","text":"suggest_magnetic_supercell(qs, latsize)\n\nSuggests a magnetic supercell, in units of the crystal lattice vectors, that is consistent with periodicity of the wavevectors in qs. An upper bound for the supercell is given by latsize, which is measured in units of lattice vectors, and must be commensurate with the wavevectors.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.symmetry_equivalent_bonds-Tuple{System, Bond}","page":"Library API","title":"Sunny.symmetry_equivalent_bonds","text":"symmetry_equivalent_bonds(sys::System, bond::Bond)\n\nGiven a Bond for the original (unreshaped) crystal, return all symmetry equivalent bonds in the System. Each returned bond is represented as a pair of Sites, which may be used as input to set_exchange_at!. Reverse bonds are not included (no double counting).\n\nExample\n\nfor (site1, site2, offset) in symmetry_equivalent_bonds(sys, bond)\n @assert site1 < site2\n set_exchange_at!(sys, J, site1, site2; offset)\nend\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.to_inhomogeneous-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.to_inhomogeneous","text":"to_inhomogeneous(sys::System)\n\nReturns a copy of the system that allows for inhomogeneous interactions, which can be set using set_onsite_coupling_at!, set_exchange_at!, and set_vacancy_at!.\n\nInhomogeneous systems do not support symmetry-propagation of interactions or system reshaping.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.unit_resolution_binning_parameters-Tuple{Any, Any, Vararg{Any}}","page":"Library API","title":"Sunny.unit_resolution_binning_parameters","text":"unit_resolution_binning_parameters(sc::SampledCorrelations)\n\nCreate BinningParameters which place one histogram bin centered at each possible (q,ω) scattering vector of the crystal. This is the finest possible binning without creating bins with zero scattering vectors in them.\n\nThis function can be used without reference to a SampledCorrelations using an alternate syntax to manually specify the bin centers for the energy axis and the lattice size:\n\nunit_resolution_binning_parameters(ω_bincenters,latsize,[reciprocal lattice vectors])\n\nThe last argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or a Crystal.\n\nLastly, binning parameters for a single axis may be specifed by their bin centers:\n\n(binstart,binend,binwidth) = unit_resolution_binning_parameters(bincenters::Vector{Float64})\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.view_crystal-Tuple{Crystal, Real}","page":"Library API","title":"Sunny.view_crystal","text":"view_crystal(crystal::Crystal, max_dist::Real)\n\nCreate and show crystal viewer in a VSCode or Jupyter notebook environment. The result can also be displayed using browser().\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.@mix_proposals-Tuple","page":"Library API","title":"Sunny.@mix_proposals","text":"@mix_proposals weight1 propose1 weight2 propose2 ...\n\nMacro to generate a proposal function that randomly selects among the provided functions according to the provided probability weights. For use with LocalSampler.\n\nExample\n\n# A proposal function that proposes a spin flip 40% of the time, and a\n# Gaussian perturbation 60% of the time.\n@mix_proposals 0.4 propose_flip 0.6 propose_delta(0.2)\n\n\n\n\n\n","category":"macro"},{"location":"library/#Optional-Makie-extensions","page":"Library API","title":"Optional Makie extensions","text":"","category":"section"},{"location":"library/","page":"Library API","title":"Library API","text":"The following will be enabled through a package extension if either GLMakie or WGLMakie is loaded.","category":"page"},{"location":"library/","page":"Library API","title":"Library API","text":"plot_spins","category":"page"},{"location":"library/#Sunny.plot_spins","page":"Library API","title":"Sunny.plot_spins","text":"plot_spins(sys::System; arrowscale=1.0, linecolor=:lightgrey,\n arrowcolor=:red, show_axis=false, show_cell=true,\n orthographic=false, ghost_radius=0)\n\nPlot the spin configuration defined by sys. Optional parameters include:\n\narrowscale: Scale all arrows by dimensionless factor.\nshow_axis: Show global Cartesian coordinates axis.\nshow_cell: Show original crystallographic unit cell.\northographic: Use camera with orthographic projection.\nghost_radius: Show translucent periodic images up to a radius, given as a multiple of the characteristic distance between sites.\n\n\n\n\n\n","category":"function"},{"location":"library/#Optional-WriteVTK-extensions","page":"Library API","title":"Optional WriteVTK extensions","text":"","category":"section"},{"location":"library/","page":"Library API","title":"Library API","text":"The following will be enabled through a package extension if WriteVTK is loaded.","category":"page"},{"location":"library/","page":"Library API","title":"Library API","text":"export_vtk","category":"page"},{"location":"library/#Sunny.export_vtk","page":"Library API","title":"Sunny.export_vtk","text":"export_vtk(filename,params::BinningParameters,data)\n\nExport a VTK-compatible file to filename (do not include file extension when specifying the file name) which contains the data as VTK Cell Data on a grid parameterized by params.\n\nAt least one axis of the BinningParameters must be integrated over, since VTK does not support 4D data. See integrate_axes!.\n\n\n\n\n\n","category":"function"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"EditURL = \"../../../examples/fei2_classical.jl\"","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/fei2_classical/#Structure-Factors-with-Classical-Dynamics","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"","category":"section"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"using Sunny, LinearAlgebra, GLMakie","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"In our previous Case Study: FeI_2, we used linear spin wave theory (LSWT) to calculate the dynamical structure factor. Here, we perform a similar calculation using classical spin dynamics. Because we are interested in the coupled dynamics of spin dipoles and quadrupoles, we employ a classical dynamics of SU(3) coherent states that generalizes the Landau-Lifshitz equation.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Compared to LSWT, simulations using classical dynamics are much slower, and are limited in k-space resolution. However, they make it is possible to capture nonlinear effects associated with finite temperature fluctuations. Classical dynamics are also appealing for studying out-of-equilibrium systems (e.g., relaxation of spin glasses), or systems with quenched inhomogeneities that require large simulation volumes.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"In this tutorial, we show how to study the finite temperature dynamics of FeI_2 using the classical approach. It is important to stress that the estimation of S(𝐪ω) with classical dynamics is fundamentally a Monte Carlo calculation: sample spin configurations are drawn from thermal equilibrium and used as initial conditions for generating dissipationless trajectories. The correlations of these trajectories are then averaged and used to calculate scattering intensities. It is therefore important to ensure that the initial spin configurations are sampled appropriately and that sufficient statistics are collected. We will demonstrate one approach here.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"As an overview, we will:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Identify the ground state\nMeasure correlation data describing the excitations around that ground state\nUse the correlation data to compute scattering intensities","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"As the implementation of the FeI_2 model is already covered in detail in the LSWT tutorial, we will not repeat it below. Instead, we will assume that you already have defined a sys in the same way with lattice dimensions 444.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"a = b = 4.05012#hide\nc = 6.75214#hide\nlatvecs = lattice_vectors(a, b, c, 90, 90, 120)#hide\npositions = [[0,0,0], [1/3, 2/3, 1/4], [2/3, 1/3, 3/4]]#hide\ntypes = [\"Fe\", \"I\", \"I\"]#hide\nFeI2 = Crystal(latvecs, positions; types)#hide\ncryst = subcrystal(FeI2, \"Fe\")#hide\nsys = System(cryst, (4,4,4), [SpinInfo(1,S=1,g=2)], :SUN, seed=2)#hide\nJ1pm = -0.236#hide\nJ1pmpm = -0.161#hide\nJ1zpm = -0.261#hide\nJ2pm = 0.026#hide\nJ3pm = 0.166#hide\nJ′0pm = 0.037#hide\nJ′1pm = 0.013#hide\nJ′2apm = 0.068#hide\nJ1zz = -0.236#hide\nJ2zz = 0.113#hide\nJ3zz = 0.211#hide\nJ′0zz = -0.036#hide\nJ′1zz = 0.051#hide\nJ′2azz = 0.073#hide\nJ1xx = J1pm + J1pmpm#hide\nJ1yy = J1pm - J1pmpm#hide\nJ1yz = J1zpm#hide\nset_exchange!(sys, [J1xx 0.0 0.0; 0.0 J1yy J1yz; 0.0 J1yz J1zz], Bond(1,1,[1,0,0]))#hide\nset_exchange!(sys, [J2pm 0.0 0.0; 0.0 J2pm 0.0; 0.0 0.0 J2zz], Bond(1,1,[1,2,0]))#hide\nset_exchange!(sys, [J3pm 0.0 0.0; 0.0 J3pm 0.0; 0.0 0.0 J3zz], Bond(1,1,[2,0,0]))#hide\nset_exchange!(sys, [J′0pm 0.0 0.0; 0.0 J′0pm 0.0; 0.0 0.0 J′0zz], Bond(1,1,[0,0,1]))#hide\nset_exchange!(sys, [J′1pm 0.0 0.0; 0.0 J′1pm 0.0; 0.0 0.0 J′1zz], Bond(1,1,[1,0,1]))#hide\nset_exchange!(sys, [J′2apm 0.0 0.0; 0.0 J′2apm 0.0; 0.0 0.0 J′2azz], Bond(1,1,[1,2,1]))#hide\nD = 2.165#hide\nS = spin_operators(sys, 1)#hide\nset_onsite_coupling!(sys, -D*S[3]^2, 1)#hide","category":"page"},{"location":"examples/fei2_classical/#Finding-a-ground-state","page":"Structure Factors with Classical Dynamics","title":"Finding a ground state","text":"","category":"section"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Sunny uses the Langevin dynamics of SU(N) coherent states to sample spin configurations from the thermal equlibrium. One first constructs a Langevin integrator. This requires a time step, temperature, and a phenomenological damping parameter λ that sets the coupling to the thermal bath.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Δt = 0.05/D # Should be inversely proportional to the largest energy scale\n # in the system. For FeI2, this is the easy-axis anisotropy,\n # `D = 2.165` (meV). The prefactor 0.05 is relatively small,\n # and achieves high accuracy.\nkT = 0.2 # Temperature of the thermal bath (meV).\nλ = 0.1 # This value is typically good for Monte Carlo sampling,\n # independent of system details.\n\nlangevin = Langevin(Δt; kT, λ);\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Sampling with a large number of Langevin time-steps should hopefully thermalize the system to a target temperature. For demonstration purposes, we will here run for a relatively short period of 1,000 timesteps.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"randomize_spins!(sys)\nfor _ in 1:1_000\n step!(sys, langevin)\nend","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"To inspect the structure of the spin configuration, we use the function minimize_energy! to find a nearby local minimum. Then print_wrapped_intensities provides information about the Fourier modes in reciprocal lattice units (RLU).","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"minimize_energy!(sys)\nprint_wrapped_intensities(sys)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The wide distribution of intensities indicates an imperfect magnetic order. The defects are immediately apparent in the real-space spin configuration.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"plot_spins(sys)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"In this case, we can find the correct ground state simply by running the Langevin dynamics for longer.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"for _ in 1:10_000\n step!(sys, langevin)\nend\nminimize_energy!(sys)\nprint_wrapped_intensities(sys)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"This is the perfect single-𝐐 ground state. This worked because the temperature kT = 0.2 was carefully selected. It is below the magnetic ordering temperature, but still large enough that the Langevin dynamics could quickly overcome local energy barriers. More complicated magnetic orderings will frequently require more sophisticated sampling schemes. One possibility is simulated annealing, where kT is slowly lowered over the course of the sampling procedure.","category":"page"},{"location":"examples/fei2_classical/#Calculating-Thermal-Averaged-Correlations-\\langle-S{\\alpha\\beta}(𝐪,ω)\\rangle","page":"Structure Factors with Classical Dynamics","title":"Calculating Thermal-Averaged Correlations langle S^alphabeta(𝐪ω)rangle","text":"","category":"section"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Now that we have identified an appropriate ground state, we will adjust the temperature so that the system still remains near the ground state, but still has thermal fluctuations.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"kT = 3.5 * meV_per_K # 3.5K ≈ 0.30 meV\nlangevin.kT = kT;\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Additionally, since these classical simulations are conducted on a finite-sized lattice, obtaining acceptable resolution in momentum space requires the use of a larger system size. We resize the magnetic supercell to a much larger simulation volume, provided as multiples of the original unit cell.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"sys_large = resize_supercell(sys, (16,16,4)) # 16x16x4 copies of the original unit cell\nplot_spins(sys_large)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"As stressed above, we need to sample multiple spin configurations from the thermal equilibrium distribution. We therefore begin by using Langevin dynamics to bring the system into thermal equilibrium at the new temperature.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"# At the new temperature\nfor _ in 1:10_000\n step!(sys_large, langevin)\nend","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Now that we are in a state drawn from thermal equilibrium, we are ready to begin collecting correlation data S^alphabeta.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"To collect one sample of spin-spin correlation data, we integrate the Hamiltonian dynamics of SU(N) coherent states. This generates trajectories S^alpha(vec rt). However, note that the spins are only defined at the finitely-many lattice sites, so vec r is discrete. From the trajectories, Sunny computes fourier-transformed correlations S^alphabeta(qomega), where q is discrete for the same reason.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The correlation data from this sample is now ready to be averaged together with data from other samples to form the thermal average. Samples of correlation data are accumulated and averaged into a SampledCorrelations, which is initialized by calling dynamical_correlations:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"sc = dynamical_correlations(sys_large; Δt=2Δt, nω=120, ωmax=7.5)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"dynamical_correlations takes a System and three keyword parameters that determine the ω information that will be available: an integration step size, the number of ωs to resolve, and the maximum ω to resolve. For the time step, twice the value used for the Langevin integrator is usually a good choice.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"sc currently contains no data. The first sample can be accumulated into it by calling add_sample!.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"add_sample!(sc, sys_large)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Additional samples can be added after re-sampling new spin configurations from the thermal distribution. The new samples are generated in the same way as the first sample, by running the Langevin dynamics. The dynamics should be run long enough that consecutive samples are uncorrelated, or else the thermal average will converge only very slowly.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"for _ in 1:2\n for _ in 1:1000 # Enough steps to decorrelate spins\n step!(sys_large, langevin)\n end\n add_sample!(sc, sys_large) # Accumulate the sample into `sc`\nend","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Now, sc has more samples included:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"sc","category":"page"},{"location":"examples/fei2_classical/#Computing-Scattering-Intensities","page":"Structure Factors with Classical Dynamics","title":"Computing Scattering Intensities","text":"","category":"section"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"With the thermally-averaged correlation data langle S^alphabeta(qomega)rangle in hand, we now need to specify how to extract a scattering intensity from this information. This is done by constructing an intensity_formula. By way of example, we will use a formula which computes the trace of the structure factor and applies a classical-to-quantum temperature-dependent rescaling kT.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"formula = intensity_formula(sc, :trace; kT = kT)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Recall that langle S^alphabeta(qomega)rangle is only available at certain discrete q values, due to the finite lattice size. There are two basic approaches to handling this discreteness. The first approach is to interpolate between the available data using intensities_interpolated. For example, we can plot single-q slices at (0,0,0) and (π,π,π) using this method:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"qs = [[0, 0, 0], [0.5, 0.5, 0.5]]\nis = intensities_interpolated(sc, qs, formula; interpolation = :round)\n\nωs = available_energies(sc)\nfig = lines(ωs, is[1,:]; axis=(xlabel=\"meV\", ylabel=\"Intensity\"), label=\"(0,0,0)\")\nlines!(ωs, is[2,:]; label=\"(π,π,π)\")\naxislegend()\nfig","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The resolution in energy can be improved by increasing nω (and decreasing Δt), and the general accuracy can be improved by collecting additional samples from the thermal equilibrium.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"For real calculations, one often wants to apply further corrections and more accurate formulas. Here, we apply FormFactor corrections appropriate for Fe2 magnetic ions, and a dipole polarization correction :perp.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"formfactors = [FormFactor(\"Fe2\"; g_lande=3/2)]\nnew_formula = intensity_formula(sc, :perp; kT = kT, formfactors = formfactors)","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Frequently, one wants to extract energy intensities along lines that connect special wave vectors–a so-called \"spaghetti plot\". The function reciprocal_space_path creates an appropriate horizontal axis for this plot by linearly sampling between provided q-points, with a given sample density.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"points = [[0, 0, 0], # List of wave vectors that define a path\n [1, 0, 0],\n [0, 1, 0],\n [1/2, 0, 0],\n [0, 1, 0],\n [0, 0, 0]]\ndensity = 40\npath, xticks = reciprocal_space_path(cryst, points, density);\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Again using intensities_interpolated, we can evaluate the (interpolated) intensity at each point on the path. Since scattering intensities are only available at a certain discrete (Qomega) points, the intensity on the path can be calculated by interpolating between these discrete points:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"is_interpolated = intensities_interpolated(sc, path, new_formula;\n interpolation = :linear, # Interpolate between available wave vectors\n);\n# Add artificial broadening\nis_interpolated_broadened = broaden_energy(sc, is, (ω, ω₀)->lorentzian(ω-ω₀, 0.05));\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The second approach to handle the discreteness of the data is to bin the intensity at the discrete points into the bins of a histogram. First, the five sub-histograms are set up using reciprocal_space_path_bins in analogy to reciprocal_space_path.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"cut_width = 0.3\ndensity = 15\nparamsList, markers, ranges = reciprocal_space_path_bins(sc,points,density,cut_width);\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Then, the intensity data is computed using intensities_binned for each sub-histogram:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"total_bins = ranges[end][end]\nenergy_bins = paramsList[1].numbins[4]\nis_binned = zeros(Float64,total_bins,energy_bins)\nintegrated_kernel = integrated_lorentzian(0.05) # Lorentzian broadening\nfor k in eachindex(paramsList)\n bin_data, counts = intensities_binned(sc,paramsList[k], new_formula;\n integrated_kernel = integrated_kernel\n )\n is_binned[ranges[k],:] = bin_data[:,1,1,:] ./ counts[:,1,1,:]\nend","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The graph produced by interpolating (top) is similar to the one produced by binning (bottom):","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"fig = Figure()\nax_top = Axis(fig[1,1],ylabel = \"meV\",xticklabelrotation=π/8,xticklabelsize=12;xticks)\nax_bottom = Axis(fig[2,1],ylabel = \"meV\",xticks = (markers, string.(points)),xticklabelrotation=π/8,xticklabelsize=12)\n\nheatmap!(ax_top,1:size(is_interpolated,1), ωs, is_interpolated;\n colorrange=(0.0,0.07),\n)\n\nheatmap!(ax_bottom,1:size(is_binned,1), ωs, is_binned;\n colorrange=(0.0,0.05),\n)\n\nfig","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Note that we have clipped the colors in order to make the higher-energy excitations more visible.","category":"page"},{"location":"examples/fei2_classical/#Unconventional-R.L.U.-Systems-and-Constant-Energy-Cuts","page":"Structure Factors with Classical Dynamics","title":"Unconventional R.L.U. Systems and Constant Energy Cuts","text":"","category":"section"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Often it is useful to plot cuts across multiple wave vectors but at a single energy. We'll pick an energy,","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"ωidx = 60\ntarget_ω = ωs[ωidx]\nprintln(\"target_ω = $(target_ω)\")#hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"and take a constant-energy cut at that energy. The most straightforward way is to make a plot whose axes are aligned with the conventional reciprocal lattice of the crystal. This is accomplished using unit_resolution_binning_parameters:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"params = unit_resolution_binning_parameters(sc)\nparams.binstart[1:2] .= -1 # Expand plot range slightly\n\n# Set energy integration range\nomega_width = 0.3\nparams.binstart[4] = target_ω - (omega_width/2)\nparams.binend[4] = target_ω # `binend` should be inside (e.g. at the center) of the range\nparams.binwidth[4] = omega_width\n\nintegrate_axes!(params, axes = 3) # Integrate out z direction entirely\nparams#hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"In each of the following plots, black dashed lines represent (direct) lattice vectors. Since these plots are in reciprocal space, direct lattice vectors are represented as covectors (i.e. coordinate grids) instead of as arrows.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"is, counts = intensities_binned(sc,params,new_formula)\n\nfig = Figure()\nax = Axis(fig[1,1];\n title=\"Δω=0.3 meV (Binned)\", aspect=true,\n xlabel = \"[H, 0, 0]\",\n ylabel = \"[0, K, 0]\"\n)\nbcs = axes_bincenters(params)\nhm = heatmap!(ax,bcs[1],bcs[2],is[:,:,1,1] ./ counts[:,:,1,1])\nfunction add_lines!(ax,params)#hide\n bes = Sunny.axes_binedges(params)#hide\n hrange = range(-2,2,length=17)#hide\n linesegments!(ax,[(Point2f(params.covectors[1,1:3] ⋅ [h,-10,0],params.covectors[2,1:3] ⋅ [h,-10,0]),Point2f(params.covectors[1,1:3] ⋅ [h,10,0],params.covectors[2,1:3] ⋅ [h,10,0])) for h = hrange],linestyle=:dash,color=:black)#hide\n krange = range(-2,2,length=17)#hide\n linesegments!(ax,[(Point2f(params.covectors[1,1:3] ⋅ [-10,k,0],params.covectors[2,1:3] ⋅ [-10,k,0]),Point2f(params.covectors[1,1:3] ⋅ [10,k,0],params.covectors[2,1:3] ⋅ [10,k,0])) for k = krange],linestyle=:dash,color=:black)#hide\n xlims!(ax,bes[1][1],bes[1][end])#hide\n ylims!(ax,bes[2][1],bes[2][end])#hide\nend#hide\nadd_lines!(ax,params)\nColorbar(fig[1,2], hm);\nfig","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"In the above plot, the dashed-line (direct) lattice vectors are clearly orthogonal. However, we know that in real space, the lattice vectors a and b are not orthogonal, but rather point along the edges of a hexagon (see lower left corner):","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"

","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Thus, plotting the direct lattice vectors as orthogonal (even in reciprocal space) is somewhat misleading. Worse yet, the [H,0,0] by [0,K,0] plot apparently loses the 6-fold symmetry of the crystal! Lastly, if one works out the components of the real-space metric with respect to the axes of the plot, one finds that there are non-zero off-diagonal entries,","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"latvecs = sys.crystal.latvecs\nmetric = latvecs' * I(3) * latvecs","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"so real-space rotations and angles map into reciprocal space rotations angles in a complicated way.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"To resolve these important issues, we want to use axes which are orthogonal (i.e. they diagonalize the metric and solve all of the problems just mentioned). The canonical choice is to use the combination frac12a + b of lattice vectors (equiv. a^* - frac12b^*), which is orthogonal to a:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"(latvecs * [1/2,1,0]) ⋅ (latvecs * [1,0,0]) == 0","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"This new vector frac12a+b is visibly orthogonal to a in real space:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"f = Figure()#hide\nax = Axis(f[1,1])#hide\narrows!(ax,[Point2f(0,0),Point2f(latvecs[1:2,1] ./ 2)],[Vec2f(latvecs[1:2,1] ./ 2), Vec2f(latvecs[1:2,2])],arrowcolor = :blue,arrowsize = 30.,linewidth = 5.,linecolor = :blue)#hide\narrows!(ax,[Point2f(0,0)],[Vec2f(latvecs[1:2,:] * [1/2,1,0])],arrowcolor = :red,arrowsize = 30.,linewidth = 5.,linecolor = :red, linestyle = :dash)#hide\nscatter!(ax,[Point2f(latvecs[1:2,:] * [a,b,0]) for a in -1:1, b in -1:1][:],color = :black)#hide\nannotations!(ax,[\"0\",\"0+b\",\"0+a\", \"a/2\", \"b\"],[Point2f(0,-0.3),Point2f(latvecs[1:2,2]) .- Vec2f(0,0.3),Point2f(latvecs[1:2,1]) .- Vec2f(0,0.3),Point2f(latvecs[1:2,1] ./ 4) .- Vec2f(0,0.3),Point2f(latvecs[1:2,1] ./ 2) .+ Vec2f(latvecs[1:2,2] ./ 2) .+ Vec2f(0.3,0.3)],color=[:black,:black,:black,:blue,:blue])#hide\nf#hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"To use \"projection onto the new vector\" as a histogram axis, only a single change is needed to the binning parameters. The second covector (previously b) must be swapped out for frac12a + b (recall that reciprocal space covectors, such as those used in BinningParameters correspond to direct space vectors).","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"params.covectors[2,1:3] = [1/2,1,0] # [1/2,1,0] times [a;b;c] is (a/2 + b)\nparams#hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"The second axis of the histogram now agrees with what is conventionally labelled as [H,-H/2,0].","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"warning: Length of the new vector\nNote that, although frac12a+b is orthogonal to a, it is not the same length as a. Instead, it is sqrt(3/4) times as long. Note the unsymmetrical axes labels in the plots that follow as a direct result of this!","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"# Zoom out horizontal axis\nparams.binstart[1], params.binend[1] = -2, 2\n\n# Adjust vertical axis bounds to account for\n# length of a/2 + b\nparams.binstart[2], params.binend[2] = -2 * sqrt(3/4), 2 * sqrt(3/4)\n\n# Re-compute in the new coordinate system\nis, counts = intensities_binned(sc,params,new_formula)\n\nfig = Figure(; resolution=(1200,500))#hide\nax_right = Axis(fig[1,3];#hide\n title=\"ω≈$(round(target_ω, digits=2)) meV with Δω=0.3 meV (Binned)\", aspect=true,#hide\n xlabel = \"[H, -1/2H, 0]\"#hide\n)#hide\nbcs = axes_bincenters(params)#hide\nhm_right = heatmap!(ax_right,bcs[1],bcs[2],is[:,:,1,1] ./ counts[:,:,1,1])#hide\nadd_lines!(ax_right,params)\nColorbar(fig[1,4], hm_right);#hide\nnothing #hide","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"For comparison purposes, we will make the same plot using intensities_interpolated to emulate zero-width bins. This time, it's more convenient to think in terms of reciprocal vectors a^* and b^*. Now, our coordinate transformation consists of establishing a new, orthogonal basis to specify our wave vectors: a^* - frac12b^*, b^* and c^*. Writing this in matrix form allows us to sample a rectilinear grid of wave vectors in this frame. Finally, we'll convert these back into the original RLU system for input into Sunny.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"# New basis matrix\nA = [1 0 0\n -1/2 1 0\n 0 0 1]\n\n# Define our grid of wave vectors\nnpoints = 60\nas = range(-2, 2, npoints)\nbs = range(-3/√3, 3/√3, npoints)\nqs_ortho = [[a, b, 0] for a in as, b in bs]\n\n# Convert to original RLU system for input to Sunny\nqs = [A * q for q in qs_ortho]\n\n# Use interpolation to get intensities\nis = intensities_interpolated(sc, qs, new_formula; interpolation=:linear)\n\nax_left = Axis(fig[1,2];#hide\n title=\"ω≈$(round(ωs[ωidx], digits=2)) meV (Interpolated)\", aspect=true,#hide\n xlabel = \"[H, -1/2H, 0]\", ylabel = \"[0, K, 0]\"#hide\n)#hide\nhm_left = heatmap!(ax_left, as, bs, is[:,:,ωidx])#hide\nadd_lines!(ax_left,params)\nColorbar(fig[1,1], hm_left);#hide\nfig","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Now, not only are the dashed-line lattice vectors no longer misleadingly orthogonal, but the six-fold symmetry has been restored as well! Further, the metric has been diagonalized:","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"metric = (latvecs * inv(A'))' * I(3) * (latvecs * inv(A'))","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"Finally, we note that instantaneous structure factor data, 𝒮(𝐪), can be obtained from a dynamic structure factor with instant_intensities_interpolated. Here we'll reuse the grid of wave vectors we generated above.","category":"page"},{"location":"examples/fei2_classical/","page":"Structure Factors with Classical Dynamics","title":"Structure Factors with Classical Dynamics","text":"is_static = instant_intensities_interpolated(sc, qs, new_formula; interpolation = :linear)\n\nhm = heatmap(as, bs, is_static;\n axis=(\n title=\"Instantaneous Structure Factor\",\n xlabel = \"[H, -1/2H, 0]\",\n ylabel = \"[0, K, 0]\",\n aspect=true\n )\n)\nColorbar(hm.figure[1,2], hm.plot)\nhm","category":"page"},{"location":"versions/#Version-0.5.1","page":"Version History","title":"Version 0.5.1","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"Fix binning edge cases.\nplot_spins accepts resolution argument.","category":"page"},{"location":"versions/#Version-0.5.0","page":"Version History","title":"Version 0.5.0","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"New features.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Support for Linear Spin Wave Theory in :dipole and :SUN modes. (Thanks Hao Zhang!)","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"New function minimize_energy! to efficiently find an optimal configuration of spin dipoles or SU(N) coherent states.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Major refactors and enhancements to intensity calculations. This new interface allows unification between LSWT and classical spin dynamics calculations. This interface allows: Custom observables as local quantum operators, better support for linebroadening, and automatic binning to facilitate comparison with experimental data. See intensity_formula for documentation. Use load_nxs to load experimental neutron scattering data.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Breaking changes.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Require Julia 1.9.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Replace set_anisotropy! with a new function set_onsite_coupling! (and similarly set_onsite_coupling_at!). The latter expects an explicit matrix representation for the local Hamiltonian. This can be constructed, e.g., as a linear combination of stevens_operators, or as a polynomial of spin_operators. To understand the mapping between these two, the new function print_stevens_expansion acts on an arbitrary local operator.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Remove set_biquadratic!. Instead, use an optional keyword argument biquad to set_exchange!.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename DynamicStructureFactor to dynamical_correlations. Similarly, replace InstantStructureFactor with instant_correlations. The return type has been renamed SampledCorrelations to emphasize that the object may be holding thermodynamic samples, which are collected using add_sample!.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Remove intensities function. Instead, use one of intensities_interpolated or intensities_binned. These will require an intensity_formula, which defines a calculator (e.g., LSWT).","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename connected_path to reciprocal_space_path, which now returns an xticks object that can be used in plotting. Replace spherical_shell with reciprocal_space_shell that functions similarly.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename polarize_spin! to set_dipole! for consistency with set_coherent!. The behavior of the former function is unchanged: the spin at a given site will still be polarized along the provided direction.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename all_sites to eachsite consistent with Julia convention for iterators.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename reshape_geometry to reshape_supercell, which is the fundamental reshaping function. Rename resize_periodically to resize_supercell.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The constructor SpinInfo now requires a g-factor or tensor as a named argument.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The constructor FormFactor no longer accepts an atom index. Instead, the form factors are associated with site-symmetry classes in order of appearance.","category":"page"},{"location":"versions/#Version-0.4.3","page":"Version History","title":"Version 0.4.3","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"Experimental support for linear SpinWaveTheory, implemented in SU(N) mode. This module may evolve rapidly.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Implement renormalization of single-ion anisotropy and biquadratic interactions when in :dipole mode. This makes the model more faithful to the quantum mechanical Hamiltonian, but is also a breaking change.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Various improvements and bugfixes for to_inhomogeneous. Setting inhomogeneous interactions via set_exchange_at! should now infer the correct bond offset direction, or will report an ambiguity error. Ambiguities can be resolved by passing an explicit offset.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The function remove_periodicity! disables periodicity along specified dimensions.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename StaticStructureFactor to InstantStructureFactor.","category":"page"},{"location":"versions/#Version-0.4.2","page":"Version History","title":"Version 0.4.2","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"Introduce LocalSampler, a framework for MCMC sampling with local spin updates.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename print_dominant_wavevectors to print_wrapped_intensities to reduce confusion with the physical instantaneous intensities.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The function spherical_shell now takes a radius in physical units of inverse Å.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"New exported functions global_position, magnetic_moment, all_sites.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Remove all uses of Base.deepcopy which resolves crashes.","category":"page"},{"location":"versions/#Version-0.4.1","page":"Version History","title":"Version 0.4.1","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"The function to_inhomogeneous creates a system that supports inhomogeneous interactions, which can be set using set_exchange_at!, etc.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"set_biquadratic! replaces set_exchange_with_biquadratic!.","category":"page"},{"location":"versions/#Version-0.4.0","page":"Version History","title":"Version 0.4.0","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"This update includes many breaking changes, and is missing some features of 0.3.0.","category":"page"},{"location":"versions/#Creating-a-spin-System","page":"Version History","title":"Creating a spin System","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"Rename SpinSystem to System. Its constructor now has the form,","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"System(crystal, latsize, infos, mode)","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The parameter infos is now a list of SpinInfo objects. Each defines spin angular momentum S = frac12 1 frac32 , and an optional g-factor or tensor.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The parameter mode is one of :SUN or :dipole.","category":"page"},{"location":"versions/#Setting-interactions","page":"Version History","title":"Setting interactions","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"Interactions are now added mutably to an existing System using the following functions: set_external_field!, set_exchange!, set_onsite_coupling!, enable_dipole_dipole!.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"As a convenience, one can use dmvec(D) to convert a DM vector to a 33 antisymmetric exchange matrix.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Fully general single-ion anisotropy is now possible. The function set_onsite_coupling! expects the single ion anisotropy to be expressed as a polynomial in symbolic spin operators 𝒮, or as a linear combination of symbolic Stevens operators 𝒪. For example, an easy axis anisotropy in the direction n may be written D*(𝒮⋅n)^2.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Stevens operators 𝒪[k,q] admit polynomial expression in spin operators 𝒮[α]. Conversely, a polynomial of spin operators can be expressed as a linear combination of Stevens operators. To see this expansion use print_anisotropy_as_stevens.","category":"page"},{"location":"versions/#Inhomogeneous-field","page":"Version History","title":"Inhomogeneous field","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"An external field can be applied to a single site with set_external_field_at!. ","category":"page"},{"location":"versions/#Structure-factor-rewrite","page":"Version History","title":"Structure factor rewrite","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"The calculation of structure factors has been completely rewritten. For the new interface, see the Structure Factor Calculations page.","category":"page"},{"location":"versions/#Various","page":"Version History","title":"Various","text":"","category":"section"},{"location":"versions/","page":"Version History","title":"Version History","text":"The \"Sampler\" interface is in flux. Langevin replaces both LangevinHeunP and LangevinSampler. Local spin-flip Monte Carlo sampling methods are temporarily broken.\nrepeat_periodically replaces extend_periodically.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Additional related functions include resize_periodically and reshape_geometry, the latter being fundamental.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"print_symmetry_table replaces print_bond_table().","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"The new function includes the list of symmetry-allowed single ion anisotropies in addition to exchange interactions.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"When reading CIF files, the field _atom_site_label is now used in place of the field _atom_site_type_symbol.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"This is required for correctness. The field _atom_site_label is guaranteed to be present, and is guaranteed to be a distinct label for each symmetry-inequivalent site. Code that explicitly referred to site labels (e.g. in calls to subcrystal) will need to be updated to use the new label.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"EditURL = \"../../../examples/one_dim_chain.jl\"","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Download as a Jupyter notebook","category":"page"},{"location":"examples/one_dim_chain/#Fitting-model-parameters-in-a-1D-spin-1-ferromagnetic-chain","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"","category":"section"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"using Sunny, LinearAlgebra, GLMakie, Optim","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"In this Example, we consider a 1D chain of spin-1 sites. The sites along the chain interact via a ferromagnetic nearest-neighbor interaction Jsum_langle ijrangle mathbfS_i cdot mathbfS_j, with J 0. By default, the ground state would be ferromagnetic and highly degenerate, since the spins can align in any direction. An on-site interaction, Dsum_i (S^z_i)^2 breaks this isotropy by making it easier for the spins to align in the pm z direction than in any other orientation. Thus, the entire Hamiltonian is:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"mathcalH = overbraceJsum_langle ijrangle mathbfS_i cdot mathbfS_j^textFerromagnetic overbrace-Dsum_i (S^z_i)^2^textEasy-axis single-ion anisotropy","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"The goal of this Example is to illustrate how to determine the parameters J and D from \"experiment\" data by fitting using Sunny's implementation of Linear Spin Wave Theory. In our case, the \"experiment\" data will actually be simulation data produced using Landau-Lifschitz dynamics.","category":"page"},{"location":"examples/one_dim_chain/#Creating-simulated-\"experiment\"-data-using-Landau-Lifschitz-dynamics","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Creating simulated \"experiment\" data using Landau-Lifschitz dynamics","text":"","category":"section"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Our simulated data will use ground truth values J_0 = -1textmeV and D_0 = 10textmeV with a lattice spacing a = 10 angstrom.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"We begin with a 1D chain of spin-1 sites along the x direction.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"# Establish geometry of the unit cell.\n# \"P1\" is required due to the rotational symmetry about the\n# x-axis being broken.\nchain_spacing = 10. # Angstrom\nlatvecs = chain_spacing * I(3)\none_dimensional_chain = Crystal(latvecs,[[0,0,0]],\"P1\")\n\n# Establish geometry of the whole chain.\nchain_length = 16 # Number of atoms\nlatsize = (chain_length,1,1) # 1D chain is Nx1x1 lattice\nspin_one_chain = System(one_dimensional_chain, latsize, [SpinInfo(1,S=1,g=2)], :SUN)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Configure the nearest-neighbor interaction:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"# Scalar J indicates J*(Sᵢ⋅Sⱼ)\nJ_groundtruth = -1.\n\n# Interaction is with the left and right next neighbor along the chain (x-direction)\nnearest_neighbor_right = Bond(1,1,(1,0,0))\nnearest_neighbor_left = Bond(1,1,(-1,0,0))\n\nset_exchange!(spin_one_chain,J_groundtruth,nearest_neighbor_right)\nset_exchange!(spin_one_chain,J_groundtruth,nearest_neighbor_left)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Configure the symmetry-breaking easy-axis term:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"D_groundtruth = 10.\nSz = spin_operators(spin_one_chain, 1)[3]\nset_onsite_coupling!(spin_one_chain, -D_groundtruth*Sz^2, 1)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"With the ground-truth hamiltonian in place, we use Sunny's classical dynamics to generate ficticious experiment data at temperature kT = 0.1.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Δt = 0.05/D_groundtruth\nλ = 0.1\nkT = 0.1\nlangevin = Langevin(Δt; kT, λ);\n\nfunction viz_chain(sys;kwargs...)#hide\n ##ups = map(x -> abs2(x[1]), sys.coherents)[:];#hide\n ##zs = map(x -> abs2(x[2]), sys.coherents)[:];#hide\n ##downs = map(x -> abs2(x[3]), sys.coherents)[:];#hide\n###hide\n ##f = Figure()#hide\n ##ax = LScene(f[1,1];show_axis = false)#hide\n ##_ = Makie.cam3d!(ax.scene, projectiontype=Makie.Orthographic)#hide\n###hide\n ##linewidth = 5.#hide\n ##arrowsize = 10.#hide\n ##lengthscale = 15.#hide\n ##pts = [Point3f(Sunny.global_position(sys,site)) for site in eachsite(sys)][:]#hide\n###hide\n #### Ups#hide\n ##vecs = [Vec3f([0,0,1]) for site in eachsite(sys)][:]#hide\n ##cols = map(x -> (:blue,x), ups)#hide\n ##Makie.arrows!(ax, pts .+ 0.5 .* vecs, vecs;#hide\n ##linecolor = cols, arrowcolor = cols,#hide\n ##lengthscale, arrowsize, linewidth, kwargs...)#hide\n###hide\n #### Downs#hide\n ##vecs = [Vec3f([0,0,-1]) for site in eachsite(sys)][:]#hide\n ##cols = map(x -> (:red,x), downs)#hide\n ##Makie.arrows!(ax, pts .+ 0.5 .* vecs, vecs;#hide\n ##linecolor = cols, arrowcolor = cols,#hide\n ##lengthscale, arrowsize, linewidth, kwargs...)#hide\n###hide\n ##cols = map(x -> (:green,x), zs)#hide\n ##meshscatter!(ax,pts, markersize = 7., color = cols)#hide\n ##f#hide\n Sunny.Plotting.plot_coherents(sys;quantization_axis = [0,0,1],kwargs...)\nend#hide\nrandomize_spins!(spin_one_chain)\nviz_chain(spin_one_chain)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"In this plot, the z-axis has been used as the quantization axis for each site, with the up/down arrows and circle representing the pm hbar and 0hbar spin projections onto the z-axis respectively. The opacity of each object represents the probability (absolute value squared), and the color represents the phase. Since we are using classical dynamics to simulate the data, the phase will be mostly random.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"First, we thermalize the chain, and then take several samples in order get reasonably good \"experiment\" data.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"nStep = 50_000#hide\nfor _ in 1:nStep#hide\n step!(spin_one_chain, langevin)#hide\nend#hide\n# ... thermalize ...\nviz_chain(spin_one_chain)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"sc = dynamical_correlations(spin_one_chain; Δt, nω = 80, ωmax = 20.);#hide\n\nfor _ in 1:10_000#hide\n step!(spin_one_chain, langevin)#hide\nend#hide\nadd_sample!(sc, spin_one_chain)#hide\n# ... some time later ...\nviz_chain(spin_one_chain)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"for _ in 1:10_000#hide\n step!(spin_one_chain, langevin)#hide\nend#hide\nadd_sample!(sc, spin_one_chain)#hide\n# ... some time later ...\nviz_chain(spin_one_chain)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"for _ in 1:20#hide\n for _ in 1:10_000#hide\n step!(spin_one_chain, langevin)#hide\n end#hide\n add_sample!(sc, spin_one_chain)#hide\nend#hide\n# ... some time later ...\nviz_chain(spin_one_chain)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Now that we have collected several samples,","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"sc","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"we are ready to generate the intensity data. Since this is supposed to represent an experiment, the intensity data will go in a histogram:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS = unit_resolution_binning_parameters(sc)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Here's what the experiment data looks like:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"formula = intensity_formula(sc,:perp;kT)\nis, counts = intensities_binned(sc,SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS,formula)\n\nSIMULATED_EXPERIMENT_DATA = (is ./ counts)[:,1,1,:]\n\nbcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)\nf = Figure()#hide\nax = Axis(f[1,1])#hide\nheatmap!(ax,bcs[1],bcs[4],log10.(SIMULATED_EXPERIMENT_DATA))\nf#hide","category":"page"},{"location":"examples/one_dim_chain/#Fitting-to-the-experiment-data","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting to the experiment data","text":"","category":"section"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"To fit this data, we first model the known aspects of the system in Sunny. The first steps are the same whether we are simulating a known system or modelling an unknown system:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"# Same as before\nchain_spacing = 10. # Angstrom\nlatvecs = chain_spacing * I(3)\none_dimensional_chain = Crystal(latvecs,[[0,0,0]],\"P1\")\nchain_length = 16 # Number of atoms\nlatsize = (chain_length,1,1) # 1D chain is Nx1x1 lattice\nspin_one_chain = System(one_dimensional_chain, latsize, [SpinInfo(1,S=1,g=2)], :SUN)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Originally, the next step would have been to configure the hamiltonian by specifying the J and D values. However, since these are unknowns, we will avoid using them as long as possible, and instead proceed to set up the bonds, spin operators, and Langevin integrator–none of which require the values:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Δt = 0.05\nλ = 0.1\nkT = 0. # LSWT uses zero temperature\nlangevin = Langevin(Δt; kT, λ);\n\nnearest_neighbor_right = Bond(1,1,(1,0,0))\nnearest_neighbor_left = Bond(1,1,(-1,0,0))\n\nSz = spin_operators(spin_one_chain, 1)[3]","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"After this setup work is done once, we create a function forward_problem(J_trial,D_trial) which will compute the Linear Spin Wave Theoretic spectrum at the trial values of the J and D fitting parameters. In other words, the part of the original calculation which depends on the fitting parameters gets wrapped into a function:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"function forward_problem(J_trial, D_trial)\n\n # Ensure there is no phase transition (or else LSWT will throw errors)\n J_trial = min(J_trial,0)\n D_trial = max(D_trial,0)\n\n # Uses J_trial\n set_exchange!(spin_one_chain,J_trial,nearest_neighbor_right)\n set_exchange!(spin_one_chain,J_trial,nearest_neighbor_left)\n\n # Uses D_trial\n set_onsite_coupling!(spin_one_chain, -D_trial*Sz^2, 1)\n\n # Perform spin wave calculation, continued below...","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Note that forward_problem refers to variables defined outside of the scope of the function. This allows us to reuse those variables in each call to forward_problem, without reconstructing them each time. In general, the more that is known about the system you are modelling, the later in the code function forward_problem(...) can be inserted, and the more setup work can be re-used.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"tip: `forward_problem` is a closure\nIn computer progrogramming parlance, forward_problem is said to 'capture' variables such as spin_one_chain from the enviroment. Since the result of calling forward_problem depends not only on J_trial and D_trial, but also on spin_one_chain, it's no longer a function of only its arguments.Since forward_problem is not a closed system, but forward_problem + (captured variables) is a closed system, the latter is called the 'closure' of the former.","category":"page"},{"location":"examples/one_dim_chain/#Spin-wave-calculation","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Spin wave calculation","text":"","category":"section"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"We can leverage our knowledge that the ground state should be ferromagnetic to simplify the spin wave calculation. Since the ferrommagnetic unit cell is just one site, the simplified system is extremely simple:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":" # ... perform spin wave calculation, continued from above.\n one_site_system = reshape_supercell(spin_one_chain,[1 0 0; 0 1 0; 0 0 1])","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"After restricting to a single site, it's best to re-thermalize the system at zero temperature to ensure a good classical ground state for LSWT:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":" langevin.kT = 0.\n nStep = 1_000\n for _ in 1:nStep\n step!(one_site_system, langevin)\n end","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"The spin wave intensity data must be placed in a histogram with the same parameters as the experiment data, in order to ensure a good comparision.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"The kernel and intensities_bin_centers used here are temporary, until a better binning method is written.","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":" swt = SpinWaveTheory(one_site_system)\n formula = intensity_formula(swt,:perp; kernel = lorentzian(0.5))\n params = SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS\n is_swt = Sunny.intensities_bin_centers(swt, params, formula)\n\n return is_swt[:,1,1,:]\nend # end of forward_problem","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"We can see the different possible results from LSWT by plotting the dispersion:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"function plot_forward(J,D)\n is_swt = forward_problem(J,D)\n bcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)\n heatmap(bcs[1],bcs[4],log10.(is_swt))\nend\n\nplot_forward(-1,10)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"plot_forward(-6,2)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"plot_forward(-0.01,15)","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Now, we can easily define a least-squares loss function comparing the \"experiment\" data to the LSWT result:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"function get_loss(parameters)\n J,D = parameters\n is_swt = forward_problem(J,D)\n sqrt(sum(abs2.(SIMULATED_EXPERIMENT_DATA .- is_swt)))\nend","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"Sweeping the parameters over a range containing the true value reveals that the loss is minimized near the true parameters (dot). The minimum loss is not exactly at the ground truth parameters in this case. Gradient descent (finite-differenced) can be used to find the actual minimizer:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"nJ = 30\nnD = 35\nloss_landscape = zeros(Float64,nJ,nD)\nJs = range(-2,0,length=nJ)\nDs = range(8,12,length=nD)\nfor (ij,J) in enumerate(Js)\n for (id,D) in enumerate(Ds)\n loss_landscape[ij,id] = get_loss([J,D])\n end\nend\n\nfig = Figure()\nax = Axis(fig[1,1],xlabel = \"J [meV]\", ylabel = \"D [meV]\")\ncontourf!(ax,Js,Ds,loss_landscape)\n\nx0 = [-2,9.5]\nopt_result = optimize(get_loss,x0,method=GradientDescent(alphaguess=1e-3),store_trace=true,extended_trace = true,time_limit=10.)\nlines!(ax,Point2f.(Optim.x_trace(opt_result)))\nscatter!(ax,-1,10)\nfig","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"The fit can be verified by plotting the LSWT band structure over top of the experiment data:","category":"page"},{"location":"examples/one_dim_chain/","page":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","title":"Fitting model parameters in a 1D spin-1 ferromagnetic chain","text":"bcs = axes_bincenters(SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS)\nf = Figure()#hide\nax = Axis(f[1,1]; xlabel=\"Q [R.L.U.]\", ylabel=\"Energy (meV)\")#hide\nheatmap!(ax,bcs[1],bcs[4],log10.(SIMULATED_EXPERIMENT_DATA), colormap = :deepsea)\nf#hide\n\n\nJ_trial, D_trial = opt_result.minimizer\nset_exchange!(spin_one_chain,J_trial,nearest_neighbor_right)#hide\nset_exchange!(spin_one_chain,J_trial,nearest_neighbor_left)#hide\n\nset_onsite_coupling!(spin_one_chain, -D_trial*Sz^2, 1)#hide\none_site_system = reshape_supercell(spin_one_chain,[1 0 0; 0 1 0; 0 0 1])#hide\n\nlangevin.kT = 0.#hide\nnStep = 1_000#hide\nfor _ in 1:nStep#hide\n step!(one_site_system, langevin)#hide\nend#hide\n\nswt = SpinWaveTheory(one_site_system)#hide\nparams = SIMULATED_EXPERIMENT_HISTOGRAM_PARAMS\n\npath = [[q,0,0] for q in bcs[1]]\ndisp, intensity = intensities_bands(swt, path, intensity_formula(swt,:perp, kernel = delta_function_kernel))\n\nfor i in axes(disp)[2]\n lines!(ax, bcs[1], disp[:,i]; color=intensity[:,i], colormap = :turbo,linewidth = 5,colorrange = (0.,1.))\nend\nColorbar(f[1,2],colormap = :turbo, limits = (0.,1.))\nColorbar(f[1,3],colormap = :deepsea, limits = (0.,1.))\nf","category":"page"},{"location":"#Sunny-Overview","page":"Overview","title":"Sunny Overview","text":"","category":"section"},{"location":"","page":"Overview","title":"Overview","text":"Sunny is a Julia package for modeling atomic-scale magnetism. It provides powerful tools to study equilibrium and non-equilibrium magnetic phenomena. In particular, it allows estimation of dynamical structure factor intensities, mathcalS(𝐪ω), to support quantitative modeling of experimental scattering data.","category":"page"},{"location":"","page":"Overview","title":"Overview","text":"Features include:","category":"page"},{"location":"","page":"Overview","title":"Overview","text":"Generalized spin dynamics using SU(N) coherent states.\nAbility specify a crystal by a .cif file, or using its spacegroup symmetry.\nInteractive visualizations of the 3D crystals and magnetic ordering.\nSymmetry analysis to classify allowed interaction terms, and to propagate them by symmetry.\nSingle-ion anisotropy at arbitrary order, which can be specified using Stevens operators or as a polynomial of spin operators.\nMonte Carlo sampling of spin configurations in thermal equilibrium, and optimization tools.\nMeasurements of dynamical correlation functions. For small supercells at low temperature, one can use linear spin wave theory and its multi-boson generalization. Alternatively, one can use the full classical dynamics to study systems with large supercells (e.g., disordered systems), or anharmonic effects with thermal fluctuations.\nLong-range dipole-dipole interactions accelerated with the fast Fourier transform (FFT).\nVarious correction factors to facilitate comparison with experimental data (form factor, dipole factor, temperature-dependent classical-to-quantum factors, intensity binning, etc.).","category":"page"}] } diff --git a/dev/structure-factor/index.html b/dev/structure-factor/index.html index 470abba0c..b6fb0a5be 100644 --- a/dev/structure-factor/index.html +++ b/dev/structure-factor/index.html @@ -6,4 +6,4 @@ for _ in 1:nsamples decorrelate_system(sys) # Perform some type of Monte Carlo simulation add_sample!(sc, sys) # Use spins to calculate trajectory and accumulate new sample of 𝒮(𝐪,ω) -end

The calculation may be configured in a number of ways; see the dynamical_correlations documentation for a list of all keywords.

Estimating an instantaneous ("static") structure factor: $𝒮(𝐪)$

Sunny provides two methods for calculating instantaneous, or static, structure factors: $𝒮^{αβ}(𝐪)$. The first involves calculating spatial spin-spin correlations at single time slices. The second involves calculating a dynamic structure factor first and integrating out the $ω$ information. The advantage of the latter approach is that it enables application of an $ω$-dependent classical-to-quantum rescaling of structure factor intensities, a method that should be preferred whenever comparing results to experimental data or spin wave calculations. A disadvantage of this approach is that it is computationally more expensive. There are also many cases when it is not straightforward to calculate a meaningful dynamics, as when working with Ising spins. In this section we will discuss how to calculate instantaneous structure factors from static spin configurations. Information about calculating instantaneous data from a dynamical correlations can be found in the following section.

The basic usage for the instantaneous case is very similar to the dynamic case, except one calls instant_correlations instead of dynamical_correlations to configure a SampledCorrelations. Note that there are no required keywords as there is no need to specify any dynamics. instant_correlations will return a SampledCorrelations containing no data. Samples may be added by calling add_sample!(sc, sys), where sc is the SampledCorrelations. When performing a finite-temperature calculation, it is important to ensure that the spin configuration in the sys represents a good equilibrium sample, as in the dynamical case. Note, however, that we recommend calculating instantaneous correlations at finite temperature calculations by using full dynamics (i.e., using dynamical_correlations) and then integrating out the energy axis. An approach to doing this is described in the next section.

Extracting information from sampled correlation data

The basic function for extracting information from a SampledCorrelations at a particular wave vector, $𝐪$, is intensities_interpolated. It takes a SampledCorrelations, a list of wave vectors, and an intensity_formula. The intensity_formula specifies how to contract and correct correlation data to arrive at a physical intensity. A simple example is formula = intensity_formula(sc, :perp), which will instruct Sunny apply polarization corrections: $\sum_{αβ}(I-q_α q_β) 𝒮^{αβ}(𝐪,ω)$. An intensity at the wave vector $𝐪 = (𝐛_2 + 𝐛_3)/2$ may then be retrieved with intensities_interpolated(sf, [[0.0, 0.5, 0.5]], formula) . intensities_interpolated returns a list of elements at each wavevector. The corresponding $ω$ values can be retrieved by calling available_energies on sf.

Since Sunny only calculates the structure factor on a finite lattice when performing classical simulations, it is important to realize that exact information is only available at a discrete set of wave vectors. Specifically, for each axis index $i$, we will get information at $q_i = \frac{n}{L_i}$, where $n$ runs from $(\frac{-L_i}{2}+1)$ to $\frac{L_i}{2}$ and $L_i$ is the linear dimension of the lattice used for the calculation. If you request a wave vector that does not fall into this set, Sunny will automatically round to the nearest $𝐪$ that is available. If intensities_interpolated is given the keyword argument interpolation=:linear, Sunny will use trilinear interpolation to determine a result at the requested wave vector.

To retrieve the intensities at all wave vectors for which there is exact data, first call the function available_wave_vectors to generate a list of qs. This takes an optional keyword argument bzsize, which must be given a tuple of three integers specifying the number of Brillouin zones to calculate, e.g., bzsize=(2,2,2). The resulting list of wave vectors may then be passed to intensities_interpolated.

Alternatively, intensities_binned can be used to place the exact data into histogram bins for comparison with experiment.

The convenience function reciprocal_space_path returns a list of wavevectors sampled along a path that connects specified $𝐪$ points. This list can be used as an input to intensities. Another convenience method, reciprocal_space_shell will generate points on a sphere of a given radius. This is useful for powder averaging.

A number of arguments for intensity_formula are available which modify the calculation of structure factor intensity. It is generally recommended to provide a value of kT corresponding to the temperature of sampled configurations. Given kT, Sunny will include an energy- and temperature-dependent classical-to-quantum rescaling of intensities in the formula.

To retrieve intensity data from a instantaneous structure factor, use instant_intensities_interpolated, which accepts similar arguments to intensities_interpolated. This function may also be used to calculate instantaneous information from a dynamical correlation data, i.e. from a SampledCorrelations created with dynamical_correlations. Note that it is important to supply a value to kT to reap the benefits of this approach over simply calculating a static structure factor at the outset.

+end

The calculation may be configured in a number of ways; see the dynamical_correlations documentation for a list of all keywords.

Estimating an instantaneous ("static") structure factor: $𝒮(𝐪)$

Sunny provides two methods for calculating instantaneous, or static, structure factors: $𝒮^{αβ}(𝐪)$. The first involves calculating spatial spin-spin correlations at single time slices. The second involves calculating a dynamic structure factor first and integrating out the $ω$ information. The advantage of the latter approach is that it enables application of an $ω$-dependent classical-to-quantum rescaling of structure factor intensities, a method that should be preferred whenever comparing results to experimental data or spin wave calculations. A disadvantage of this approach is that it is computationally more expensive. There are also many cases when it is not straightforward to calculate a meaningful dynamics, as when working with Ising spins. In this section we will discuss how to calculate instantaneous structure factors from static spin configurations. Information about calculating instantaneous data from a dynamical correlations can be found in the following section.

The basic usage for the instantaneous case is very similar to the dynamic case, except one calls instant_correlations instead of dynamical_correlations to configure a SampledCorrelations. Note that there are no required keywords as there is no need to specify any dynamics. instant_correlations will return a SampledCorrelations containing no data. Samples may be added by calling add_sample!(sc, sys), where sc is the SampledCorrelations. When performing a finite-temperature calculation, it is important to ensure that the spin configuration in the sys represents a good equilibrium sample, as in the dynamical case. Note, however, that we recommend calculating instantaneous correlations at finite temperature calculations by using full dynamics (i.e., using dynamical_correlations) and then integrating out the energy axis. An approach to doing this is described in the next section.

Extracting information from sampled correlation data

The basic function for extracting information from a SampledCorrelations at a particular wave vector, $𝐪$, is intensities_interpolated. It takes a SampledCorrelations, a list of wave vectors, and an intensity_formula. The intensity_formula specifies how to contract and correct correlation data to arrive at a physical intensity. A simple example is formula = intensity_formula(sc, :perp), which will instruct Sunny apply polarization corrections: $\sum_{αβ}(I-q_α q_β) 𝒮^{αβ}(𝐪,ω)$. An intensity at the wave vector $𝐪 = (𝐛_2 + 𝐛_3)/2$ may then be retrieved with intensities_interpolated(sf, [[0.0, 0.5, 0.5]], formula) . intensities_interpolated returns a list of elements at each wavevector. The corresponding $ω$ values can be retrieved by calling available_energies on sf.

Since Sunny only calculates the structure factor on a finite lattice when performing classical simulations, it is important to realize that exact information is only available at a discrete set of wave vectors. Specifically, for each axis index $i$, we will get information at $q_i = \frac{n}{L_i}$, where $n$ runs from $(\frac{-L_i}{2}+1)$ to $\frac{L_i}{2}$ and $L_i$ is the linear dimension of the lattice used for the calculation. If you request a wave vector that does not fall into this set, Sunny will automatically round to the nearest $𝐪$ that is available. If intensities_interpolated is given the keyword argument interpolation=:linear, Sunny will use trilinear interpolation to determine a result at the requested wave vector.

To retrieve the intensities at all wave vectors for which there is exact data, first call the function available_wave_vectors to generate a list of qs. This takes an optional keyword argument bzsize, which must be given a tuple of three integers specifying the number of Brillouin zones to calculate, e.g., bzsize=(2,2,2). The resulting list of wave vectors may then be passed to intensities_interpolated.

Alternatively, intensities_binned can be used to place the exact data into histogram bins for comparison with experiment.

The convenience function reciprocal_space_path returns a list of wavevectors sampled along a path that connects specified $𝐪$ points. This list can be used as an input to intensities. Another convenience method, reciprocal_space_shell will generate points on a sphere of a given radius. This is useful for powder averaging.

A number of arguments for intensity_formula are available which modify the calculation of structure factor intensity. It is generally recommended to provide a value of kT corresponding to the temperature of sampled configurations. Given kT, Sunny will include an energy- and temperature-dependent classical-to-quantum rescaling of intensities in the formula.

To retrieve intensity data from a instantaneous structure factor, use instant_intensities_interpolated, which accepts similar arguments to intensities_interpolated. This function may also be used to calculate instantaneous information from a dynamical correlation data, i.e. from a SampledCorrelations created with dynamical_correlations. Note that it is important to supply a value to kT to reap the benefits of this approach over simply calculating a static structure factor at the outset.

diff --git a/dev/versions/index.html b/dev/versions/index.html index 6a580d1dd..7c8b677a3 100644 --- a/dev/versions/index.html +++ b/dev/versions/index.html @@ -1,2 +1,2 @@ -Version History · Sunny documentation

Version 0.5.1

  • Fix binning edge cases.
  • plot_spins accepts resolution argument.

Version 0.5.0

New features.

Support for Linear Spin Wave Theory in :dipole and :SUN modes. (Thanks Hao Zhang!)

New function minimize_energy! to efficiently find an optimal configuration of spin dipoles or SU(N) coherent states.

Major refactors and enhancements to intensity calculations. This new interface allows unification between LSWT and classical spin dynamics calculations. This interface allows: Custom observables as local quantum operators, better support for linebroadening, and automatic binning to facilitate comparison with experimental data. See intensity_formula for documentation. Use load_nxs to load experimental neutron scattering data.

Breaking changes.

Require Julia 1.9.

Replace set_anisotropy! with a new function set_onsite_coupling! (and similarly set_onsite_coupling_at!). The latter expects an explicit matrix representation for the local Hamiltonian. This can be constructed, e.g., as a linear combination of stevens_operators, or as a polynomial of spin_operators. To understand the mapping between these two, the new function print_stevens_expansion acts on an arbitrary local operator.

Remove set_biquadratic!. Instead, use an optional keyword argument biquad to set_exchange!.

Rename DynamicStructureFactor to dynamical_correlations. Similarly, replace InstantStructureFactor with instant_correlations. The return type has been renamed SampledCorrelations to emphasize that the object may be holding thermodynamic samples, which are collected using add_sample!.

Remove intensities function. Instead, use one of intensities_interpolated or intensities_binned. These will require an intensity_formula, which defines a calculator (e.g., LSWT).

Rename connected_path to reciprocal_space_path, which now returns an xticks object that can be used in plotting. Replace spherical_shell with reciprocal_space_shell that functions similarly.

Rename polarize_spin! to set_dipole! for consistency with set_coherent!. The behavior of the former function is unchanged: the spin at a given site will still be polarized along the provided direction.

Rename all_sites to eachsite consistent with Julia convention for iterators.

Rename reshape_geometry to reshape_supercell, which is the fundamental reshaping function. Rename resize_periodically to resize_supercell.

The constructor SpinInfo now requires a $g$-factor or tensor as a named argument.

The constructor FormFactor no longer accepts an atom index. Instead, the form factors are associated with site-symmetry classes in order of appearance.

Version 0.4.3

Experimental support for linear SpinWaveTheory, implemented in SU(N) mode. This module may evolve rapidly.

Implement renormalization of single-ion anisotropy and biquadratic interactions when in :dipole mode. This makes the model more faithful to the quantum mechanical Hamiltonian, but is also a breaking change.

Various improvements and bugfixes for to_inhomogeneous. Setting inhomogeneous interactions via set_exchange_at! should now infer the correct bond offset direction, or will report an ambiguity error. Ambiguities can be resolved by passing an explicit offset.

The function remove_periodicity! disables periodicity along specified dimensions.

Rename StaticStructureFactor to InstantStructureFactor.

Version 0.4.2

Introduce LocalSampler, a framework for MCMC sampling with local spin updates.

Rename print_dominant_wavevectors to print_wrapped_intensities to reduce confusion with the physical instantaneous intensities.

The function spherical_shell now takes a radius in physical units of inverse Å.

New exported functions global_position, magnetic_moment, all_sites.

Remove all uses of Base.deepcopy which resolves crashes.

Version 0.4.1

The function to_inhomogeneous creates a system that supports inhomogeneous interactions, which can be set using set_exchange_at!, etc.

set_biquadratic! replaces set_exchange_with_biquadratic!.

Version 0.4.0

This update includes many breaking changes, and is missing some features of 0.3.0.

Creating a spin System

Rename SpinSystem to System. Its constructor now has the form,

System(crystal, latsize, infos, mode)

The parameter infos is now a list of SpinInfo objects. Each defines spin angular momentum $S = \frac{1}{2}, 1, \frac{3}{2}, …$, and an optional $g$-factor or tensor.

The parameter mode is one of :SUN or :dipole.

Setting interactions

Interactions are now added mutably to an existing System using the following functions: set_external_field!, set_exchange!, set_onsite_coupling!, enable_dipole_dipole!.

As a convenience, one can use dmvec(D) to convert a DM vector to a $3×3$ antisymmetric exchange matrix.

Fully general single-ion anisotropy is now possible. The function set_onsite_coupling! expects the single ion anisotropy to be expressed as a polynomial in symbolic spin operators 𝒮, or as a linear combination of symbolic Stevens operators 𝒪. For example, an easy axis anisotropy in the direction n may be written D*(𝒮⋅n)^2.

Stevens operators 𝒪[k,q] admit polynomial expression in spin operators 𝒮[α]. Conversely, a polynomial of spin operators can be expressed as a linear combination of Stevens operators. To see this expansion use print_anisotropy_as_stevens.

Inhomogeneous field

An external field can be applied to a single site with set_external_field_at!.

Structure factor rewrite

The calculation of structure factors has been completely rewritten. For the new interface, see the Structure Factor Calculations page.

Various

  • The "Sampler" interface is in flux. Langevin replaces both LangevinHeunP and LangevinSampler. Local spin-flip Monte Carlo sampling methods are temporarily broken.

  • repeat_periodically replaces extend_periodically.

Additional related functions include resize_periodically and reshape_geometry, the latter being fundamental.

The new function includes the list of symmetry-allowed single ion anisotropies in addition to exchange interactions.

  • When reading CIF files, the field _atom_site_label is now used in place of the field _atom_site_type_symbol.

This is required for correctness. The field _atom_site_label is guaranteed to be present, and is guaranteed to be a distinct label for each symmetry-inequivalent site. Code that explicitly referred to site labels (e.g. in calls to subcrystal) will need to be updated to use the new label.

+Version History · Sunny documentation

Version 0.5.1

  • Fix binning edge cases.
  • plot_spins accepts resolution argument.

Version 0.5.0

New features.

Support for Linear Spin Wave Theory in :dipole and :SUN modes. (Thanks Hao Zhang!)

New function minimize_energy! to efficiently find an optimal configuration of spin dipoles or SU(N) coherent states.

Major refactors and enhancements to intensity calculations. This new interface allows unification between LSWT and classical spin dynamics calculations. This interface allows: Custom observables as local quantum operators, better support for linebroadening, and automatic binning to facilitate comparison with experimental data. See intensity_formula for documentation. Use load_nxs to load experimental neutron scattering data.

Breaking changes.

Require Julia 1.9.

Replace set_anisotropy! with a new function set_onsite_coupling! (and similarly set_onsite_coupling_at!). The latter expects an explicit matrix representation for the local Hamiltonian. This can be constructed, e.g., as a linear combination of stevens_operators, or as a polynomial of spin_operators. To understand the mapping between these two, the new function print_stevens_expansion acts on an arbitrary local operator.

Remove set_biquadratic!. Instead, use an optional keyword argument biquad to set_exchange!.

Rename DynamicStructureFactor to dynamical_correlations. Similarly, replace InstantStructureFactor with instant_correlations. The return type has been renamed SampledCorrelations to emphasize that the object may be holding thermodynamic samples, which are collected using add_sample!.

Remove intensities function. Instead, use one of intensities_interpolated or intensities_binned. These will require an intensity_formula, which defines a calculator (e.g., LSWT).

Rename connected_path to reciprocal_space_path, which now returns an xticks object that can be used in plotting. Replace spherical_shell with reciprocal_space_shell that functions similarly.

Rename polarize_spin! to set_dipole! for consistency with set_coherent!. The behavior of the former function is unchanged: the spin at a given site will still be polarized along the provided direction.

Rename all_sites to eachsite consistent with Julia convention for iterators.

Rename reshape_geometry to reshape_supercell, which is the fundamental reshaping function. Rename resize_periodically to resize_supercell.

The constructor SpinInfo now requires a $g$-factor or tensor as a named argument.

The constructor FormFactor no longer accepts an atom index. Instead, the form factors are associated with site-symmetry classes in order of appearance.

Version 0.4.3

Experimental support for linear SpinWaveTheory, implemented in SU(N) mode. This module may evolve rapidly.

Implement renormalization of single-ion anisotropy and biquadratic interactions when in :dipole mode. This makes the model more faithful to the quantum mechanical Hamiltonian, but is also a breaking change.

Various improvements and bugfixes for to_inhomogeneous. Setting inhomogeneous interactions via set_exchange_at! should now infer the correct bond offset direction, or will report an ambiguity error. Ambiguities can be resolved by passing an explicit offset.

The function remove_periodicity! disables periodicity along specified dimensions.

Rename StaticStructureFactor to InstantStructureFactor.

Version 0.4.2

Introduce LocalSampler, a framework for MCMC sampling with local spin updates.

Rename print_dominant_wavevectors to print_wrapped_intensities to reduce confusion with the physical instantaneous intensities.

The function spherical_shell now takes a radius in physical units of inverse Å.

New exported functions global_position, magnetic_moment, all_sites.

Remove all uses of Base.deepcopy which resolves crashes.

Version 0.4.1

The function to_inhomogeneous creates a system that supports inhomogeneous interactions, which can be set using set_exchange_at!, etc.

set_biquadratic! replaces set_exchange_with_biquadratic!.

Version 0.4.0

This update includes many breaking changes, and is missing some features of 0.3.0.

Creating a spin System

Rename SpinSystem to System. Its constructor now has the form,

System(crystal, latsize, infos, mode)

The parameter infos is now a list of SpinInfo objects. Each defines spin angular momentum $S = \frac{1}{2}, 1, \frac{3}{2}, …$, and an optional $g$-factor or tensor.

The parameter mode is one of :SUN or :dipole.

Setting interactions

Interactions are now added mutably to an existing System using the following functions: set_external_field!, set_exchange!, set_onsite_coupling!, enable_dipole_dipole!.

As a convenience, one can use dmvec(D) to convert a DM vector to a $3×3$ antisymmetric exchange matrix.

Fully general single-ion anisotropy is now possible. The function set_onsite_coupling! expects the single ion anisotropy to be expressed as a polynomial in symbolic spin operators 𝒮, or as a linear combination of symbolic Stevens operators 𝒪. For example, an easy axis anisotropy in the direction n may be written D*(𝒮⋅n)^2.

Stevens operators 𝒪[k,q] admit polynomial expression in spin operators 𝒮[α]. Conversely, a polynomial of spin operators can be expressed as a linear combination of Stevens operators. To see this expansion use print_anisotropy_as_stevens.

Inhomogeneous field

An external field can be applied to a single site with set_external_field_at!.

Structure factor rewrite

The calculation of structure factors has been completely rewritten. For the new interface, see the Structure Factor Calculations page.

Various

  • The "Sampler" interface is in flux. Langevin replaces both LangevinHeunP and LangevinSampler. Local spin-flip Monte Carlo sampling methods are temporarily broken.

  • repeat_periodically replaces extend_periodically.

Additional related functions include resize_periodically and reshape_geometry, the latter being fundamental.

The new function includes the list of symmetry-allowed single ion anisotropies in addition to exchange interactions.

  • When reading CIF files, the field _atom_site_label is now used in place of the field _atom_site_type_symbol.

This is required for correctness. The field _atom_site_label is guaranteed to be present, and is guaranteed to be a distinct label for each symmetry-inequivalent site. Code that explicitly referred to site labels (e.g. in calls to subcrystal) will need to be updated to use the new label.

diff --git a/dev/writevtk/index.html b/dev/writevtk/index.html index cff24d3ce..7460773be 100644 --- a/dev/writevtk/index.html +++ b/dev/writevtk/index.html @@ -61,4 +61,4 @@ signal = sum(signal; dims = 4) # Export to ParaView -export_vtk("experiment_data_as_vtk", params, signal) +export_vtk("experiment_data_as_vtk", params, signal)