diff --git a/dev/examples/binning_tutorial/index.html b/dev/examples/binning_tutorial/index.html index b7377a76b..157c69739 100644 --- a/dev/examples/binning_tutorial/index.html +++ b/dev/examples/binning_tutorial/index.html @@ -1,5 +1,5 @@ -Histogram Binning Tutorial · Sunny documentation

Histogram Binning Tutorial

using Sunny, GLMakie

This Tutorial demonstrates how to use Sunny's histogram binning capabilities (via intensities_binned). This functionality allows the simulation data produced by Sunny to be compared to experimental data produced by Inelastic Neutron Scattering (INS) in an apples-to-apples fashion. Experimental data can be loaded from a MDHistoWorkspace stored in a .nxs file by the Mantid software using load_nxs.

For this example, we will examine the CTFD compound, which is crystallographically approximately a square lattice. We specify the crystal lattice structure of CTFD using the lattice parameters specified by

W Wan et al 2020 J. Phys.: Condens. Matter 32 374007 DOI 10.1088/1361-648X/ab757a

latvecs = lattice_vectors(8.113,8.119,12.45,90,100,90)
+Histogram Binning Tutorial · Sunny documentation

Histogram Binning Tutorial

using Sunny, GLMakie

This Tutorial demonstrates how to use Sunny's histogram binning capabilities (via intensities_binned). This functionality allows the simulation data produced by Sunny to be compared to experimental data produced by Inelastic Neutron Scattering (INS) in an apples-to-apples fashion. Experimental data can be loaded from a MDHistoWorkspace stored in a .nxs file by the Mantid software using load_nxs.

For this example, we will examine the CTFD compound, which is crystallographically approximately a square lattice. We specify the crystal lattice structure of CTFD using the lattice parameters specified by

W Wan et al 2020 J. Phys.: Condens. Matter 32 374007 DOI 10.1088/1361-648X/ab757a

latvecs = lattice_vectors(8.113,8.119,12.45,90,100,90)
 positions = [[0,0,0]]
 types = ["Cu"]
 formfactors  = [FormFactor(1,"Cu2")]
@@ -15,21 +15,15 @@
 for i in 1:10_000 # Long enough to reach equilibrium
     step!(sys, langevin)
 end

The neutron spectrometer used in the experiment had an incident neutron energy of 36.25 meV. Since this is the most amount of energy that can be deposited by the neutron into the sample, we don't need to consider energies higher than this.

ωmax = 36.25;

We choose the resolution in energy (specified by the number of nω modes resolved) to be ≈20× better than the experimental resolution in order to demonstrate the effect of over-resolving in energy.

nω = 480;
-dsf = DynamicStructureFactor(sys; Δt=Δt, nω=nω, ωmax=ωmax, process_trajectory=:symmetrize)
StructureFactor (21.075 MiB)
-[S(q,ω) | nω = 959 | 1 sample]
-Lattice: (6, 6, 4)×1
-6 correlations in Dipole mode:
-╔ ⬤ ⬤ ⬤ Sx
-║ ⋅ ⬤ ⬤ Sy
-╚ ⋅ ⋅ ⬤ Sz
-

We re-sample from the thermal equilibrium distribution several times to increase our sample size

nsamples = 3
+sc = dynamical_correlations(sys; Δt=Δt, nω=nω, ωmax=ωmax, process_trajectory=:symmetrize)
+add_sample!(sc, sys)

We re-sample from the thermal equilibrium distribution several times to increase our sample size

nsamples = 3
 for _ in 1:nsamples
     for _ in 1:8000
         step!(sys, langevin)
     end
-    add_sample!(dsf, sys)
+    add_sample!(sc, sys)
 end

Since the SU(N)NY crystal has only finitely many lattice sites, there are finitely many ways for a neutron to scatter off of the sample. We can visualize this discreteness by plotting each possible Qx and Qz, for example:

# Compute some scattering vectors at and around the first BZ...
-scatter!(ax,Qx,Qz)

One way to display the structure factor is to create a histogram with one bin centered at each discrete scattering possibility using unit_resolution_binning_parameters to create a set of BinningParameters.

params = unit_resolution_binning_parameters(dsf)
Binning Parameters
+scatter!(ax,Qx,Qz)

One way to display the structure factor is to create a histogram with one bin centered at each discrete scattering possibility using unit_resolution_binning_parameters to create a set of BinningParameters.

params = unit_resolution_binning_parameters(sc)
Binning Parameters
 ⊡     6 bins from -0.083 to +0.917 along [+1.29 dx] (Δ = 0.129)
 ⊡     6 bins from -0.083 to +0.917 along [+1.29 dy] (Δ = 0.129)
 ⊡     4 bins from -0.125 to +0.875 along [-0.34 dx +1.95 dz] (Δ = 0.126)
@@ -39,23 +33,23 @@
 ∫ Integrated from -0.083 to +1.750 along [+1.29 dy] (Δ = 1.419)
 ⊡     4 bins from -0.125 to +0.875 along [-0.34 dx +1.95 dz] (Δ = 0.126)
 ∫ Integrated from -0.041 to +77.745 along [+1.00 dE] (Δ = 77.786)
-

Now that we have parameterized the histogram, we can bin our data. In addition to the BinningParameters, an intensity_formula needs to be provided to specify which dipole, temperature, and atomic form factor corrections should be applied during the intensity calculation.

formula = intensity_formula(dsf, :perp; kT, formfactors)
-intensity,counts = intensities_binned(dsf, params; formula)
+

Now that we have parameterized the histogram, we can bin our data. In addition to the BinningParameters, an intensity_formula needs to be provided to specify which dipole, temperature, and atomic form factor corrections should be applied during the intensity calculation.

formula = intensity_formula(sc, :perp; kT, formfactors)
+intensity,counts = intensities_binned(sc, params; formula)
 normalized_intensity = intensity ./ counts;

With the data binned, we can now plot it. The axes labels give the bin centers of each bin, as given by axes_bincenters.

bin_centers = axes_bincenters(params);
 
 heatmap!(ax,bin_centers[1],bin_centers[3],normalized_intensity[:,1,:,1])
 scatter!(ax,Qx,Qz)
 xlims!(ax,params.binstart[1],params.binend[1])
-ylims!(ax,params.binstart[3],params.binend[3])

Note that some bins have no scattering vectors at all when the bin size is made too small:

params.binwidth[1] /= 1.2
-params.binwidth[3] /= 2.5

Conversely, making the bins bigger doesn't break anything, but loses resolution:

params.binwidth[1] *= 2
-params.binwidth[3] *= 2

Recall that while we under-resolved in Q by choosing a small lattice, we over-resolved in energy:

scatter!(ax,x,y)
MakieCore.Scatter{Tuple{Vector{GeometryBasics.Point{2, Float32}}}}

Let's make a new histogram which includes the energy axis. The x-axis of the histogram will be a 1D cut from Q = [0,0,0] to Q = [1,1,0]. See slice_2D_binning_parameters.

x_axis_bin_count = 10
+ylims!(ax,params.binstart[3],params.binend[3])

Note that some bins have no scattering vectors at all when the bin size is made too small:

params.binwidth[1] /= 1.2
+params.binwidth[3] /= 2.5

Conversely, making the bins bigger doesn't break anything, but loses resolution:

params.binwidth[1] *= 2
+params.binwidth[3] *= 2

Recall that while we under-resolved in Q by choosing a small lattice, we over-resolved in energy:

scatter!(ax,x,y)
MakieCore.Scatter{Tuple{Vector{GeometryBasics.Point{2, Float32}}}}

Let's make a new histogram which includes the energy axis. The x-axis of the histogram will be a 1D cut from Q = [0,0,0] to Q = [1,1,0]. See slice_2D_binning_parameters.

x_axis_bin_count = 10
 cut_width = 0.3
-params = slice_2D_binning_parameters(dsf,[0,0,0],[1,1,0],x_axis_bin_count,cut_width)
Binning Parameters
+params = slice_2D_binning_parameters(sc,[0,0,0],[1,1,0],x_axis_bin_count,cut_width)
Binning Parameters
 ⊡    10 bins from -0.079 to +1.493 along [+0.91 dx +0.91 dy] (Δ = 0.122)
 ∫ Integrated from -0.150 to +0.150 along [-0.91 dx +0.91 dy] (Δ = 0.232)
 ∫ Integrated from -0.150 to +0.150 along [+0.34 dx -1.95 dz] (Δ = 0.151)
 ⊡   480 bins from -0.041 to +38.893 along [+1.00 dE] (Δ = 0.081)
-

There are no longer any scattering vectors exactly in the plane of the cut. Instead, as described in the BinningParameters output above, the transverse Q directions are integrated over, so slightly out of plane points are included.

We plot the intensity on a log-scale to improve visibility.

intensity,counts = intensities_binned(dsf, params; formula)
+

There are no longer any scattering vectors exactly in the plane of the cut. Instead, as described in the BinningParameters output above, the transverse Q directions are integrated over, so slightly out of plane points are included.

We plot the intensity on a log-scale to improve visibility.

intensity,counts = intensities_binned(sc, params; formula)
 log_intensity = log10.(intensity ./ counts);
-heatmap!(ax,bin_centers[1],bin_centers[4],log_intensity[:,1,1,:])

By reducing the number of energy bins to be closer to the number of bins on the x-axis, we can make the dispersion curve look nicer:

params.binwidth[4] *= 20
-heatmap!(ax,bin_centers[1],bin_centers[4],log_intensity[:,1,1,:])

This page was generated using Literate.jl.

+heatmap!(ax,bin_centers[1],bin_centers[4],log_intensity[:,1,1,:])

By reducing the number of energy bins to be closer to the number of bins on the x-axis, we can make the dispersion curve look nicer:

params.binwidth[4] *= 20
+heatmap!(ax,bin_centers[1],bin_centers[4],log_intensity[:,1,1,:])

This page was generated using Literate.jl.

diff --git a/dev/examples/fei2_tutorial/index.html b/dev/examples/fei2_tutorial/index.html index 5cdda6602..492806ec9 100644 --- a/dev/examples/fei2_tutorial/index.html +++ b/dev/examples/fei2_tutorial/index.html @@ -104,7 +104,7 @@ for kT in range(2, 0, 20_000) langevin.kT = kT step!(sys, langevin) -end

Because the quench was relatively fast, it is expected to find defects in the magnetic order. These can be visualized.

plot_spins(sys; arrowlength=2.5, linewidth=0.75, arrowsize=1.5)

If we had used a slower annealing procedure, involving 100,000 or more Langevin time-steps, it would very likely find the correct ground state. Instead, for purposes of illustration, let's analyze the imperfect spin configuration currently stored in sys.

An experimental probe of magnetic order order is the 'instantaneous' or 'static' structure factor intensity, available via InstantStructureFactor and related functions. To infer periodicities of the magnetic supercell, however, it is sufficient to look at the structure factor weights of spin sublattices individually, without phase averaging. This information is provided by print_wrapped_intensities (see the API documentation for a physical interpretation).

print_wrapped_intensities(sys)
Dominant wavevectors for spin sublattices:
+end

Because the quench was relatively fast, it is expected to find defects in the magnetic order. These can be visualized.

plot_spins(sys; arrowlength=2.5, linewidth=0.75, arrowsize=1.5)

If we had used a slower annealing procedure, involving 100,000 or more Langevin time-steps, it would very likely find the correct ground state. Instead, for purposes of illustration, let's analyze the imperfect spin configuration currently stored in sys.

An experimental probe of magnetic order order is the 'instantaneous' or 'static' structure factor intensity, available via instant_correlations and related functions. To infer periodicities of the magnetic supercell, however, it is sufficient to look at the structure factor weights of spin sublattices individually, without phase averaging. This information is provided by print_wrapped_intensities (see the API documentation for a physical interpretation).

print_wrapped_intensities(sys)
Dominant wavevectors for spin sublattices:
 
     [1/4, 0, 1/4]          49.79% weight
     [-1/4, 0, -1/4]        49.79%
@@ -136,7 +136,7 @@
           [0,   0, 0]]
 labels = ["($(p[1]),$(p[2]),$(p[3]))" for p in points]
 density = 600
-path, markers = connected_path(swt, points, density);

dispersion may now be called on the wave vectors along the generated path. Each column of the returned matrix corresponds to a different mode.

disp = dispersion(swt, path);

In addition to the band energies $\omega_i$, Sunny can calculate the inelastic neutron scattering intensity $I(q,\omega_i(q))$ according to an intensity_formula. The default formula applies a polarization correction $(1 - Q\otimes Q)$.

formula = intensity_formula(swt; kernel = delta_function_kernel)
Quantum Scattering Intensity Formula
+path, markers = connected_path(swt, points, density);

dispersion may now be called on the wave vectors along the generated path. Each column of the returned matrix corresponds to a different mode.

disp = dispersion(swt, path);

In addition to the band energies $\omega_i$, Sunny can calculate the inelastic neutron scattering intensity $I(q,\omega_i(q))$ according to an intensity_formula. The default formula applies a polarization correction $(1 - Q\otimes Q)$.

formula = intensity_formula(swt; kernel = delta_function_kernel)
Quantum Scattering Intensity Formula
 At any Q and for each band ωᵢ = εᵢ(Q), with S = S(Q,ωᵢ):
 
   Intensity(Q,ω) = ∑ᵢ δ(ω-ωᵢ) ∑_ij (I - Q⊗Q){i,j} S{i,j}
@@ -174,25 +174,25 @@
 )

The existence of a lower-energy, single-ion bound state is in qualitative agreement with the experimental data in Bai et al. (Note that the publication figure uses a different coordinate system to label the same wave vectors and the experimental data necessarily averages over the three degenerate ground states.)

The full data from the dynamical spin structure factor (DSSF) can be retrieved with the dssf function. Like dispersion and intensities, dssf takes an array of wave vectors.

disp, Sαβ = dssf(swt, [[0, 0, 0]]);

disp is identical to the output that is obtained from dispersion and contains the energy of each mode at the specified wave vectors. Sαβ contains a 3x3 matrix for each of these modes. The matrix elements of Sαβ correspond to correlations of the different spin components (ordered x, y, z). For example, the full set of matrix elements for the first mode may be obtained as follows,

Sαβ[1]
3×3 StaticArraysCore.SMatrix{3, 3, ComplexF64, 9} with indices SOneTo(3)×SOneTo(3):
   3.45531e-30+0.0im          …  6.90657e-32+1.76065e-32im
  -2.76136e-31-3.60465e-32im     -5.3358e-33-2.12755e-33im
-    -0.133536+0.105808im        1.47021e-33+0.0im

and the xx matrix element is

Sαβ[1][1,1]
3.455313922490678e-30 + 0.0im

Dynamical structure factors with classical dynamics

Linear spin wave calculations are very useful for getting quick, high-quality, results at zero temperature. Moreover, these results are obtained in the thermodynamic limit. Classical dynamics may also be used to produce similar results, albeit at a higher computational cost and on a finite sized lattice. The classical approach nonetheless provides a number of complementary advantages: it is possible perform simulations at finite temperature while retaining nonlinearities; out-of-equilibrium behavior may be examined directly; and it is straightforward to incorporate inhomogenties, chemical or otherwise.

Because classical simulations are conducted on a finite-sized lattice, obtaining acceptable resolution in momentum space requires the use of a larger system size. We can now resize the magnetic supercell to a much larger simulation volume, provided as multiples of the original unit cell.

sys_large = resize_periodically(sys_supercell, (16,16,4))
+    -0.148992-0.073203im        1.47021e-33+0.0im

and the xx matrix element is

Sαβ[1][1,1]
3.455313922490678e-30 + 0.0im

Dynamical structure factors with classical dynamics

Linear spin wave calculations are very useful for getting quick, high-quality, results at zero temperature. Moreover, these results are obtained in the thermodynamic limit. Classical dynamics may also be used to produce similar results, albeit at a higher computational cost and on a finite sized lattice. The classical approach nonetheless provides a number of complementary advantages: it is possible perform simulations at finite temperature while retaining nonlinearities; out-of-equilibrium behavior may be examined directly; and it is straightforward to incorporate inhomogenties, chemical or otherwise.

Because classical simulations are conducted on a finite-sized lattice, obtaining acceptable resolution in momentum space requires the use of a larger system size. We can now resize the magnetic supercell to a much larger simulation volume, provided as multiples of the original unit cell.

sys_large = resize_periodically(sys_supercell, (16,16,4))
 plot_spins(sys_large; arrowlength=2.5, linewidth=0.75, arrowsize=1.5)

Apply Langevin dynamics to thermalize the system to a target temperature.

kT = 0.5 * meV_per_K     # 0.5K in units of meV
 langevin.kT = kT
 
 for _ in 1:10_000
     step!(sys_large, langevin)
-end

We can measure the DynamicStructureFactor by integrating the Hamiltonian dynamics of SU(N) coherent states. Three keyword parameters are required to determine the ω information that will be calculated: 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.

sf = DynamicStructureFactor(sys_large; Δt=2Δt, nω=120, ωmax=7.5)
StructureFactor (37.348 MiB)
-[S(q,ω) | nω = 239 | 1 sample]
+end

To estimate the dynamic structure factor, we can collect spin-spin correlation data by first generating an initial condition at thermal equilibrium and then integrating the Hamiltonian dynamics of SU(N) coherent states. Samples are accumulated into a SampledCorrelations, which is initialized by calling dynamical_correlations. 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.

sc = dynamical_correlations(sys_large; Δt=2Δt, nω=120, ωmax=7.5)
SampledCorrelations (37.348 MiB)
+[S(q,ω) | nω = 239 | 0 sample]
 Lattice: (16, 16, 4)×1
 6 correlations in SU(3) mode:
 ╔ ⬤ ⬤ ⬤ Sx
 ║ ⋅ ⬤ ⬤ Sy
 ╚ ⋅ ⋅ ⬤ Sz
-

sf currently contains dynamical structure data generated from a single sample. Additional samples can be added by generating a new spin configuration and calling add_sample!:

for _ in 1:2
+

sc currently contains no data. A sample can be accumulated into it by calling add_sample!.

add_sample!(sc, sys_large)

Additional samples can be added after generating new spin configurations:

for _ in 1:2
     for _ in 1:1000               # Fewer steps needed in equilibrium
         step!(sys_large, langevin)
     end
-    add_sample!(sf, sys_large)    # Accumulate the sample into `sf`
-end

Accessing structure factor data

The basic functions for accessing intensity data are intensities_interpolated and intensities_binned. Both functions accept an intensity_formula to specify how to combine the correlations recorded in the StructureFactor into intensity data. By default, a formula computing the unpolarized intensity is used, but alternative formulas can be specified.

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.

formula = intensity_formula(sf, :trace; kT = kT)
Classical Scattering Intensity Formula
+    add_sample!(sc, sys_large)    # Accumulate the sample into `sc`
+end

Accessing structure factor data

The basic functions for accessing intensity data are intensities_interpolated and intensities_binned. Both functions accept an intensity_formula to specify how to combine the correlations recorded in the SampledCorrelations into intensity data. By default, a formula computing the unpolarized intensity is used, but alternative formulas can be specified.

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.

formula = intensity_formula(sc, :trace; kT = kT)
Classical Scattering Intensity Formula
 At discrete scattering modes S = S[ix_q,ix_ω], use:
 
   Intensity[ix_q,ix_ω] = Tr S
@@ -200,13 +200,13 @@
 No form factors specified
 Temperature corrected (kT = 0.043086666310725885) ✓
 

Using the formula, we plot single-$q$ slices at (0,0,0) and (π,π,π):

qs = [[0, 0, 0], [0.5, 0.5, 0.5]]
-is = intensities_interpolated(sf, qs; interpolation = :round, formula = formula)
+is = intensities_interpolated(sc, qs; interpolation = :round, formula = formula)
 
-fig = lines(ωs(sf), is[1,:]; axis=(xlabel="meV", ylabel="Intensity"), label="(0,0,0)")
-lines!(ωs(sf), is[2,:]; label="(π,π,π)")
+fig = lines(ωs(sc), is[1,:]; axis=(xlabel="meV", ylabel="Intensity"), label="(0,0,0)")
+lines!(ωs(sc), is[2,:]; label="(π,π,π)")
 axislegend()
 fig

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(1, "Fe2"; g_lande=3/2)]
-new_formula = intensity_formula(sf, :perp; kT = kT, formfactors = formfactors)
Classical Scattering Intensity Formula
+new_formula = intensity_formula(sc, :perp; kT = kT, formfactors = formfactors)
Classical Scattering Intensity Formula
 At discrete scattering modes S = S[ix_q,ix_ω], use:
 
   Intensity[ix_q,ix_ω] = ∑_ij (I - Q⊗Q){i,j} S{i,j}
@@ -222,35 +222,35 @@
           [0,   1, 0],
           [0,   0, 0]]
 density = 40
-path, markers = connected_path(sf, points, density);

Since scattering intensities are only available at a certain discrete $(Q,\omega)$ points, the intensity on the path can be calculated by interpolating between these discrete points:

is = intensities_interpolated(sf, path;
+path, markers = connected_path(sc, points, density);

Since scattering intensities are only available at a certain discrete $(Q,\omega)$ points, the intensity on the path can be calculated by interpolating between these discrete points:

is = intensities_interpolated(sc, path;
     interpolation = :linear,       # Interpolate between available wave vectors
     formula = new_formula
 )
-is = broaden_energy(sf, is, (ω, ω₀)->lorentzian(ω-ω₀, 0.05))  # Add artificial broadening
+is = broaden_energy(sc, is, (ω, ω₀)->lorentzian(ω-ω₀, 0.05))  # Add artificial broadening
 
 labels = ["($(p[1]),$(p[2]),$(p[3]))" for p in points]
 
-heatmap(1:size(is,1), ωs(sf), is;
+heatmap(1:size(is,1), ωs(sc), is;
     axis = (
         ylabel = "meV",
         xticks = (markers, labels),
         xticklabelrotation=π/8,
         xticklabelsize=12,
     )
-)

Whereas intensities_interpolated either rounds or linearly interpolates between the discrete $(Q,\omega)$ points Sunny calculates correlations at, intensities_binned performs histogram binning analgous to what is done in experiments. The graphs produced by each method are similar.

cut_width = 0.3
+)

Whereas intensities_interpolated either rounds or linearly interpolates between the discrete $(Q,\omega)$ points Sunny calculates correlations at, intensities_binned performs histogram binning analgous to what is done in experiments. The graphs produced by each method are similar.

cut_width = 0.3
 density = 15
-paramsList, markers, ranges = connected_path_bins(sf,points,density,cut_width)
+paramsList, markers, ranges = connected_path_bins(sc,points,density,cut_width)
 
 total_bins = ranges[end][end]
 energy_bins = paramsList[1].numbins[4]
 is = zeros(Float64,total_bins,energy_bins)
 integrated_kernel = integrated_lorentzian(0.05) # Lorentzian broadening
 for k in 1:length(paramsList)
-    h,c = intensities_binned(sf,paramsList[k];formula = new_formula,integrated_kernel = integrated_kernel)
+    h,c = intensities_binned(sc,paramsList[k];formula = new_formula,integrated_kernel = integrated_kernel)
     is[ranges[k],:] = h[:,1,1,:] ./ c[:,1,1,:]
 end
 
-heatmap(1:size(is,1), ωs(sf), is;
+heatmap(1:size(is,1), ωs(sc), is;
     axis = (
         ylabel = "meV",
         xticks = (markers, labels),
@@ -261,10 +261,10 @@
 qvals = range(-2, 2, length=npoints)
 qs = [[a, b, 0] for a in qvals, b in qvals]
 
-is = intensities_interpolated(sf, qs; formula = new_formula,interpolation = :linear);
+is = intensities_interpolated(sc, qs; formula = new_formula,interpolation = :linear);
 
 ωidx = 30
-hm = heatmap(is[:,:,ωidx]; axis=(title="ω=$(ωs(sf)[ωidx]) meV", aspect=true))
+hm = heatmap(is[:,:,ωidx]; axis=(title="ω=$(ωs(sc)[ωidx]) meV", aspect=true))
 Colorbar(hm.figure[1,2], hm.plot)
 hidedecorations!(hm.axis); hidespines!(hm.axis)
 hm

Note that Brillouin zones appear 'skewed'. This is a consequence of the fact that Sunny measures $q$-vectors as multiples of reciprocal lattice vectors, which are not orthogonal. It is often useful to express our wave vectors in terms of an orthogonal basis, where each basis element is specified as a linear combination of reciprocal lattice vectors. For our crystal, with reciprocal vectors $a^*$, $b^*$ and $c^*$, we can define an orthogonal basis by taking $\hat{a}^* = 0.5(a^* + b^*)$, $\hat{b}^*=a^* - b^*$, and $\hat{c}^*=c^*$. Below, we map qs to wavevectors ks in the new coordinate system and get their intensities.

A = [0.5  1  0;
@@ -272,14 +272,14 @@
      0    0  1]
 ks = [A*q for q in qs]
 
-is_ortho = intensities_interpolated(sf, ks; formula = new_formula, interpolation = :linear)
+is_ortho = intensities_interpolated(sc, ks; formula = new_formula, interpolation = :linear)
 
-hm = heatmap(is_ortho[:,:,ωidx]; axis=(title="ω=$(ωs(sf)[ωidx]) meV", aspect=true))
+hm = heatmap(is_ortho[:,:,ωidx]; axis=(title="ω=$(ωs(sc)[ωidx]) meV", aspect=true))
 Colorbar(hm.figure[1,2], hm.plot)
 hidedecorations!(hm.axis); hidespines!(hm.axis)
-hm

Finally, we note that instantaneous structure factor data, $𝒮(𝐪)$, can be obtained from a dynamic structure factor with instant_intensities_interpolated.

is_static = instant_intensities_interpolated(sf, ks; formula = new_formula, interpolation = :linear)
+hm

Finally, we note that instantaneous structure factor data, $𝒮(𝐪)$, can be obtained from a dynamic structure factor with instant_intensities_interpolated.

is_static = instant_intensities_interpolated(sc, ks; formula = new_formula, interpolation = :linear)
 
 hm = heatmap(is_static; axis=(title="Instantaneous Structure Factor", aspect=true))
 Colorbar(hm.figure[1,2], hm.plot)
 hidedecorations!(hm.axis); hidespines!(hm.axis)
-hm

This page was generated using Literate.jl.

+hm

This page was generated using Literate.jl.

diff --git a/dev/examples/ising2d/index.html b/dev/examples/ising2d/index.html index 05b3ba77a..6fd67c566 100644 --- a/dev/examples/ising2d/index.html +++ b/dev/examples/ising2d/index.html @@ -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)))
- + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + -

This page was generated using Literate.jl.

+

This page was generated using Literate.jl.

diff --git a/dev/examples/powder_averaging/index.html b/dev/examples/powder_averaging/index.html index ae7d19642..5e69d4c7f 100644 --- a/dev/examples/powder_averaging/index.html +++ b/dev/examples/powder_averaging/index.html @@ -15,23 +15,17 @@ for _ ∈ 1:3000 step!(sys, integrator) -end;

We can now calculate $𝒮(𝐪,ω)$ with DynamicStructureFactor. We will tell Sunny to symmetrize the sample trajectory along the time-axis to minimize Fourier artifacts.

sf = DynamicStructureFactor(sys;
+end;

We can now estimate $𝒮(𝐪,ω)$ with dynamical_correlations. We will tell Sunny to symmetrize the sample trajectory along the time-axis to minimize Fourier artifacts.

sc = dynamical_correlations(sys;
     Δt=2Δt,
     nω=100,
     ωmax=5.5,
     process_trajectory=:symmetrize
-)
StructureFactor (635.888 MiB)
-[S(q,ω) | nω = 199 | 1 sample]
-Lattice: (8, 8, 8)×8
-6 correlations in Dipole mode:
-╔ ⬤ ⬤ ⬤ Sx
-║ ⋅ ⬤ ⬤ Sy
-╚ ⋅ ⋅ ⬤ Sz
-

To get some intuition about the expected results, we first look at the "single crystal" results along a high-symmetry path in the first Brillouin zone. While doing so, we will add some artificial broadening along the energy axis with broaden_energy. To use this function, it is necessary to define a kernel function with the form, kernel(ω, ω₀), where ω is energy and ω₀ is the center frequency of the kernel. In this example we apply some Lorentzian broadening using an anonymous function: (ω, ω₀) -> lorentzian(ω-ω₀, 0.1).

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]]
-qs, markers = connected_path(sf, qpoints, 50)
+)
+add_sample!(sc, sys)

To get some intuition about the expected results, we first look at the "single crystal" results along a high-symmetry path in the first Brillouin zone. While doing so, we will add some artificial broadening along the energy axis with broaden_energy. To use this function, it is necessary to define a kernel function with the form, kernel(ω, ω₀), where ω is energy and ω₀ is the center frequency of the kernel. In this example we apply some Lorentzian broadening using an anonymous function: (ω, ω₀) -> lorentzian(ω-ω₀, 0.1).

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]]
+qs, markers = connected_path(sc, qpoints, 50)
 
-is = intensities_interpolated(sf, qs; interpolation=:round, formula = intensity_formula(sf,:trace))
-is_broad = broaden_energy(sf, is, (ω, ω₀) -> lorentzian(ω-ω₀, 0.1))
+is = intensities_interpolated(sc, qs; interpolation=:round, formula = intensity_formula(sc,:trace))
+is_broad = broaden_energy(sc, is, (ω, ω₀) -> lorentzian(ω-ω₀, 0.1))
 
 # Plot results
 fig = Figure(; resolution=(1000,400))
@@ -45,21 +39,21 @@
     xticklabelsize=14,
 )
 ax1 = Axis(fig[1,1]; title="No artificial broadening", plotparams...)
-heatmap!(ax1, 1:size(is, 1), ωs(sf), is; colorrange=(0,0.5))
+heatmap!(ax1, 1:size(is, 1), ωs(sc), is; colorrange=(0,0.5))
 ax2 = Axis(fig[1,2]; title="Lorentzian broadening (η=0.1)", plotparams...)
-heatmap!(ax2, 1:size(is, 1), ωs(sf), is_broad; colorrange=(0,2.0))
-fig

We next write a simple powder averaging function that takes a structure factor, a list of radius values (Å⁻¹), and a density parameter (Å⁻²) that will control the number of wave vectors to sample at each radius. For each radius r, the function will generate wavevectors on a sphere of this radius and retrieve their intensities_interpolated. These intensities will be broadened, as just demonstrated above, and then averaged to produce a single vector of energy-intensities for each r. Note that our powder_average function passes most of its keywords through to intensities_interpolated, so it can be given an intensity_formula.

function powder_average(sf, rs, density; η=0.1, kwargs...)
-    nω = length(ωs(sf))
+heatmap!(ax2, 1:size(is, 1), ωs(sc), is_broad; colorrange=(0,2.0))
+fig

We next write a simple powder averaging function that takes a structure factor, a list of radius values (Å⁻¹), and a density parameter (Å⁻²) that will control the number of wave vectors to sample at each radius. For each radius r, the function will generate wavevectors on a sphere of this radius and retrieve their intensities_interpolated. These intensities will be broadened, as just demonstrated above, and then averaged to produce a single vector of energy-intensities for each r. Note that our powder_average function passes most of its keywords through to intensities_interpolated, so it can be given an intensity_formula.

function powder_average(sc, rs, density; η=0.1, kwargs...)
+    nω = length(ωs(sc))
     output = zeros(Float64, length(rs), nω)
 
     for (i, r) in enumerate(rs)
-        qs = spherical_shell(sf, r, density)  # Get points on a sphere of radius r
+        qs = spherical_shell(sc, r, density)  # Get points on a sphere of radius r
         if length(qs) == 0
             qs = [[0., 0., 0.]]  # If no points (r is too small), just look at 0 vector
         end
-        vals = intensities_interpolated(sf, qs; kwargs...)  # Retrieve energy intensities
+        vals = intensities_interpolated(sc, qs; kwargs...)  # Retrieve energy intensities
         vals[:,1] .*= 0.0  # Remove elastic peaks before broadening
-        vals = broaden_energy(sf, vals, (ω,ω₀)->lorentzian(ω-ω₀, η))  # Apply Lorentzian broadening
+        vals = broaden_energy(sc, vals, (ω,ω₀)->lorentzian(ω-ω₀, η))  # Apply Lorentzian broadening
         output[i,:] = reshape(mean(vals, dims=1), (nω,))  # Average single radius results and save
     end
 
@@ -68,27 +62,27 @@
 η = 0.05                      # Lorentzian broadening parameter
 density = 0.15                # Number of samples in Å⁻²
 
-formula = intensity_formula(sf,:perp)
-pa = powder_average(sf, rs, density; η, formula);

and plot the results.

fig1= Figure()
+formula = intensity_formula(sc,:perp)
+pa = powder_average(sc, rs, density; η, formula);

and plot the results.

fig1= Figure()
 ax = Axis(fig1[1,1]; xlabel = "|Q| (Å⁻¹)", ylabel = "ω (meV)")
-heatmap!(ax, rs, ωs(sf), pa; colorrange=(0, 25.0))
-fig1

Note that the bandwidth is similar to what we saw above along the high symmetry path.

This was a very quick calculation. The structure factor calculation itself and the powder averaging will each execute in < 10 s on a typical laptop. Higher quality results can be obtained by:

The intensity data can alternatively be collected into bonafide histogram bins. See integrated_lorentzian, powder_average_binned, and axes_bincenters.

radial_binning_parameters = (0,6π,6π/55)
+heatmap!(ax, rs, ωs(sc), pa; colorrange=(0, 25.0))
+fig1

Note that the bandwidth is similar to what we saw above along the high symmetry path.

This was a very quick calculation. The structure factor calculation itself and the powder averaging will each execute in < 10 s on a typical laptop. Higher quality results can be obtained by:

The intensity data can alternatively be collected into bonafide histogram bins. See integrated_lorentzian, powder_average_binned, and axes_bincenters.

radial_binning_parameters = (0,6π,6π/55)
 integrated_kernel = integrated_lorentzian(0.05) # Lorentzian broadening
 
-pa_intensities, pa_counts = powder_average_binned(sf,radial_binning_parameters;integrated_kernel = integrated_kernel,formula)
+pa_intensities, pa_counts = powder_average_binned(sc,radial_binning_parameters;integrated_kernel = integrated_kernel,formula)
 
 pa_normalized_intensities = pa_intensities ./ pa_counts
 
 fig = Figure()
 ax = Axis(fig[1,1]; xlabel = "|k| (Å⁻¹)", ylabel = "ω (meV)")
 rs_bincenters = axes_bincenters(radial_binning_parameters...)
-heatmap!(ax, rs_bincenters[1], ωs(sf), pa_normalized_intensities; colorrange=(0,3.0))
-fig

The striations in the graph tell us that the simulation is under resolved for this bin size. We should increase the size of either the periodic lattice, or the bins.

Using the bzsize option, we can even resolve the contribution from each brillouin zone:

intensity_firstBZ, counts_firstBZ = powder_average_binned(sf,radial_binning_parameters;integrated_kernel = integrated_kernel, bzsize=(1,1,1),formula)
+heatmap!(ax, rs_bincenters[1], ωs(sc), pa_normalized_intensities; colorrange=(0,3.0))
+fig

The striations in the graph tell us that the simulation is under resolved for this bin size. We should increase the size of either the periodic lattice, or the bins.

Using the bzsize option, we can even resolve the contribution from each brillouin zone:

intensity_firstBZ, counts_firstBZ = powder_average_binned(sc,radial_binning_parameters;integrated_kernel = integrated_kernel, bzsize=(1,1,1),formula)
 #intensity_secondBZ, counts_secondBZ = powder_average_binned(..., bzsize=(2,2,2))
-#intensity_thirdBZ, counts_thirdBZ = powder_average_binned(..., bzsize=(3,3,3))

First BZ:

heatmap!(ax, rs_bincenters[1], ωs(sf),
+#intensity_thirdBZ, counts_thirdBZ = powder_average_binned(..., bzsize=(3,3,3))

First BZ:

heatmap!(ax, rs_bincenters[1], ωs(sc),
          intensity_firstBZ ./ counts_firstBZ
-         ; colorrange=(0,3.0))

Second BZ:

heatmap!(ax, rs_bincenters[1], ωs(sf),
+         ; colorrange=(0,3.0))

Second BZ:

heatmap!(ax, rs_bincenters[1], ωs(sc),
          (intensity_secondBZ .- intensity_firstBZ) ./ (counts_secondBZ .- counts_firstBZ)
-         ; colorrange=(0,3.0))

Third BZ:

heatmap!(ax, rs_bincenters[1], ωs(sf),
+         ; colorrange=(0,3.0))

Third BZ:

heatmap!(ax, rs_bincenters[1], ωs(sc),
          (intensity_thirdBZ .- intensity_secondBZ) ./ (counts_thirdBZ .- counts_secondBZ)
-         ; colorrange=(0,3.0))

This page was generated using Literate.jl.

+ ; colorrange=(0,3.0))

This page was generated using Literate.jl.

diff --git a/dev/index.html b/dev/index.html index c91a0f832..e46d86cf4 100644 --- a/dev/index.html +++ b/dev/index.html @@ -1,2 +1,2 @@ -Overview · Sunny documentation

Sunny.jl

Sunny is a package for simulating classical spin systems, including the Landau-Lifshitz dynamics of spin dipoles and its generalization to multipolar spin components. The latter is especially powerful for modeling magnetic compounds with strong single-ion anisotropy interactions.

Sunny provides the following features:

  • Generalized spin dynamics using SU(N) coherent states.
  • Ability specify a crystal by a .cif file, or using its spacegroup symmetry.
  • 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.
  • Ewald summation for long-range dipole-dipole interactions, accelerated with the fast Fourier transform (FFT).
  • Estimation of the $\mathcal{S}(\mathbf{q}, \omega)$ dynamical structure factor data, with options for various corrections (form factor, classical-to-quantum factors, ...)

Work in progress includes:

  • Linear spin wave theory and its generalization to SU(N) coherent states.
  • Interactive visualizations of the 3D crystals and structure factor data.
  • MPI-distributed Monte Carlo sampling, including parallel tempering.
+Overview · Sunny documentation

Sunny.jl

Sunny is a package for simulating classical spin systems, including the Landau-Lifshitz dynamics of spin dipoles and its generalization to multipolar spin components. The latter is especially powerful for modeling magnetic compounds with strong single-ion anisotropy interactions.

Sunny provides the following features:

  • Generalized spin dynamics using SU(N) coherent states.
  • Ability specify a crystal by a .cif file, or using its spacegroup symmetry.
  • 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.
  • Ewald summation for long-range dipole-dipole interactions, accelerated with the fast Fourier transform (FFT).
  • Estimation of the $\mathcal{S}(\mathbf{q}, \omega)$ dynamical structure factor data, with options for various corrections (form factor, classical-to-quantum factors, ...)

Work in progress includes:

  • Linear spin wave theory and its generalization to SU(N) coherent states.
  • Interactive visualizations of the 3D crystals and structure factor data.
  • MPI-distributed Monte Carlo sampling, including parallel tempering.
diff --git a/dev/library/index.html b/dev/library/index.html index 5f4168a90..e8c076360 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.𝒪Constant
𝒪[k,q]

Abstract symbols for the Stevens operators. Linear combinations of these can be used to define a single-ion anisotropy.

source
Sunny.𝒮Constant
𝒮[1], 𝒮[2], 𝒮[3]

Abstract symbols for the spin operators. Polynomials of these can be used to define a single-ion anisotropy.

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.𝒪Constant
𝒪[k,q]

Abstract symbols for the Stevens operators. Linear combinations of these can be used to define a single-ion anisotropy.

source
Sunny.𝒮Constant
𝒮[1], 𝒮[2], 𝒮[3]

Abstract symbols for the spin operators. Polynomials of these can be used to define a single-ion anisotropy.

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 (k,ω) with each row of the covectors matrix, with k given in absolute units. Since the default covectors matrix is the identity matrix, the default axes are (kx,ky,kz,ω) in absolute units. To bin (q,ω) values given in reciprocal lattice units (R.L.U.) instead, see bin_rlu_as_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,33 +25,32 @@
 # 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(atom::Int64, elem::String; g_lande=nothing)

Basic type for specifying form factor parameters. Must be provided a site within the unit cell (atom) and a string specifying the element name. This used when creating an intensity_formula, which accepts a list of FormFactorss.

A list of supported element names is available at:

https://www.ill.eu/sites/ccsl/ffacts/ffachtml.html

The Landé g-factor may also be specified.

In more detail, the data stored in a FormFactor will be used to compute the form factor for each momentum space magnitude |k|, measured in inverse angstroms. The result is dependent on the magnetic ion species. By default, a first order form factor $f$ is returned. If the keyword g_lande is given a numerical value, then a second order form factor $F$ is returned.

It is traditional to define the form factors using a sum of Gaussian broadening functions in the scalar variable $s = |k|/4π$, where $|k|$ can be interpreted as the magnitude of momentum transfer.

The Neutron Data Booklet, 2nd ed., Sec. 2.5 Magnetic Form Factors, defines the approximation

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

where coefficients $A, B, C, D, a, b, c$ are obtained from semi-empirical fits, depending on the orbital angular momentum index $l = 0, 2$. For transition metals, the form-factors are calculated using the Hartree-Fock method. For rare-earth metals and ions, Dirac-Fock form is used for the calculations.

A first approximation to the magnetic form factor is

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

A second order correction is given by

$F(s) = \frac{2-g}{g} \langle j_2(s) \rangle s^2 + f(s)$, where $g$ is the Landé g-factor.

Digital tables are available at:

  • https://www.ill.eu/sites/ccsl/ffacts/ffachtml.html

Additional references are:

  • Marshall W and Lovesey S W, Theory of thermal neutron scattering Chapter 6 Oxford University Press (1971)
  • Clementi E and Roetti C, Atomic Data and Nuclear Data Tables, 14 pp 177-478 (1974)
  • 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)

Experimental. 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.DynamicStructureFactorMethod
DynamicStructureFactor(sys::System; Δt, nω, ωmax, 
-    process_trajectory=:none, observables=nothing, correlations=nothing)

Creates a StructureFactor 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.

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

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.InstantStructureFactorMethod
InstantStructureFactor(sys::System; process_trajectory=:none,
-                        observables=nothing, correlations=nothing)

Creates a StructureFactor 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 a full DynamicStructureFactor object instead of an InstantStructureFactor. 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 InstantStructureFactor, ensure that sys represents a good equilibrium sample. Additional sample data may be accumulated by calling add_sample!(sf, 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.add_sample!Method
add_sample!(sf::StructureFactor, sys::System)

add_trajectory uses the spin configuration contained in the System to generate a correlation data and accumulate it into sf. 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 sf.

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.all_exact_wave_vectorsMethod
all_exact_wave_vectors(sf::StructureFactor; bzsize=(1,1,1))

Returns all wave vectors for which sf 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.bin_absolute_units_as_rlu!Function

If params expects to bin values (k,ω) in absolute units, then calling

bin_rlu_as_absolute_units!(params::BinningParameters,[reciprocal lattice vectors])

will modifiy the covectors in params so that they will accept (q,ω) in Reciprocal Lattice Units (R.L.U.) instead. Conversly, if params expects (q,ω) R.L.U., calling

bin_absolute_units_as_rlu!(params::BinningParameters,[reciprocal lattice vectors])

will adjust params to instead accept (k,ω) absolute units.

The second argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:

source
Sunny.bin_rlu_as_absolute_units!Function

If params expects to bin values (k,ω) in absolute units, then calling

bin_rlu_as_absolute_units!(params::BinningParameters,[reciprocal lattice vectors])

will modifiy the covectors in params so that they will accept (q,ω) in Reciprocal Lattice Units (R.L.U.) instead. Conversly, if params expects (q,ω) R.L.U., calling

bin_absolute_units_as_rlu!(params::BinningParameters,[reciprocal lattice vectors])

will adjust params to instead accept (k,ω) absolute units.

The second argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:

source
Sunny.broaden_energyMethod
broaden_energy(sf::StructureFactor, 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(sf, 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.connected_pathMethod
connected_path(recip_vecs, qs::Vector, density)

Takes a list of wave vectors, qs, and builds an expanded list of wave vectors that traces a path through the provided points. Also returned is a list of marker indices corresponding to the input points. The density parameter is given in samples per inverse Å.

Instead of recip_vecs, the first argument may be either a StructureFactor or a SpinWaveTheory.

source
Sunny.connected_path_binsMethod
connected_path_bins(sf,qs,density,args...;kwargs...)

Takes a list of wave vectors, qs, 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.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)

Experimental. 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 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]
+cryst = Crystal(latvecs, positions, 227; setting="1")

See also lattice_vectors.

source
Sunny.FormFactorMethod
FormFactor(atom::Int64, elem::String; g_lande=nothing)

Basic type for specifying form factor parameters. Must be provided a site within the unit cell (atom) and a string specifying the element name. This used when creating an intensity_formula, which accepts a list of FormFactorss.

A list of supported element names is available at:

https://www.ill.eu/sites/ccsl/ffacts/ffachtml.html

The Landé g-factor may also be specified.

In more detail, the data stored in a FormFactor will be used to compute the form factor for each momentum space magnitude |k|, measured in inverse angstroms. The result is dependent on the magnetic ion species. By default, a first order form factor $f$ is returned. If the keyword g_lande is given a numerical value, then a second order form factor $F$ is returned.

It is traditional to define the form factors using a sum of Gaussian broadening functions in the scalar variable $s = |k|/4π$, where $|k|$ can be interpreted as the magnitude of momentum transfer.

The Neutron Data Booklet, 2nd ed., Sec. 2.5 Magnetic Form Factors, defines the approximation

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

where coefficients $A, B, C, D, a, b, c$ are obtained from semi-empirical fits, depending on the orbital angular momentum index $l = 0, 2$. For transition metals, the form-factors are calculated using the Hartree-Fock method. For rare-earth metals and ions, Dirac-Fock form is used for the calculations.

A first approximation to the magnetic form factor is

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

A second order correction is given by

$F(s) = \frac{2-g}{g} \langle j_2(s) \rangle s^2 + f(s)$, where $g$ is the Landé g-factor.

Digital tables are available at:

  • https://www.ill.eu/sites/ccsl/ffacts/ffachtml.html

Additional references are:

  • Marshall W and Lovesey S W, Theory of thermal neutron scattering Chapter 6 Oxford University Press (1971)
  • Clementi E and Roetti C, Atomic Data and Nuclear Data Tables, 14 pp 177-478 (1974)
  • 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)

Experimental. 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.all_exact_wave_vectorsMethod
all_exact_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.bin_absolute_units_as_rlu!Function

If params expects to bin values (k,ω) in absolute units, then calling

bin_rlu_as_absolute_units!(params::BinningParameters,[reciprocal lattice vectors])

will modifiy the covectors in params so that they will accept (q,ω) in Reciprocal Lattice Units (R.L.U.) instead. Conversly, if params expects (q,ω) R.L.U., calling

bin_absolute_units_as_rlu!(params::BinningParameters,[reciprocal lattice vectors])

will adjust params to instead accept (k,ω) absolute units.

The second argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:

source
Sunny.bin_rlu_as_absolute_units!Function

If params expects to bin values (k,ω) in absolute units, then calling

bin_rlu_as_absolute_units!(params::BinningParameters,[reciprocal lattice vectors])

will modifiy the covectors in params so that they will accept (q,ω) in Reciprocal Lattice Units (R.L.U.) instead. Conversly, if params expects (q,ω) R.L.U., calling

bin_absolute_units_as_rlu!(params::BinningParameters,[reciprocal lattice vectors])

will adjust params to instead accept (k,ω) absolute units.

The second argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:

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.connected_pathMethod
connected_path(recip_vecs, qs::Vector, density)

Takes a list of wave vectors, qs, and builds an expanded list of wave vectors that traces a path through the provided points. Also returned is a list of marker indices corresponding to the input points. The density parameter is given in samples per inverse Å.

Instead of recip_vecs, the first argument may be either a SampledCorrelations or a SpinWaveTheory.

source
Sunny.connected_path_binsMethod
connected_path_bins(sc,qs,density,args...;kwargs...)

Takes a list of wave vectors, qs, 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.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)

Experimental. 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 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)

Experimental. 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. I.e., $q_i$ is given in $2π/|a_i|$ with $|a_i|$ the lattice constant of the 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 this array is a tensor (3×3 matrix) corresponding to the indices $α$ and $β$.

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.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 all_sites as below:

pos = [global_position(sys, site) for site in all_sites(sys)]
source
Sunny.instant_intensities_interpolatedMethod
instant_intensities_interpolated(sf::StructureFactor, 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 StructureFactor 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, qs; [formula])

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

formula = intensity_formula(swt; 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 qs, 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(sf::StructureFactor, params::BinningParameters; formula, integrated_kernel)

Given correlation data contained in a StructureFactor and BinningParameters describing the shape of a histogram, compute the intensity and normalization for each histogram bin using a given intensity_formula, or intensity_formula(sf,:perp) by default.

The BinningParameters are expected to accept (k,ω) in absolute units.

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 η. 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, qs, ω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; 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 qs and each energy in ωvals. The output will be an array with indices identical to qs, with the last index matching ωvals.

Note that qs is an array of wave vectors of arbitrary dimension. Each element $q$ of qs must be a 3-vector in reciprocal lattice units. I.e., $qᵢ$ is given in $2π/|aᵢ|$ with $|aᵢ|$ the lattice constant of the chemical lattice.

source
Sunny.intensities_interpolatedMethod
intensities_interpolated(sf::StructureFactor, qs; interpolation = nothing, formula = intensity_formula(sf,:perp), negative_energies = false)

The basic function for retrieving $𝒮(𝐪,ω)$ information from a StructureFactor. 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 ωs. 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(sf::StructureFactor; kwargs...)
-formula.calc_intensity(sf,q,ix_q,ix_ω)

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

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

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

Additionally, 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 vector of FormFactors, one for each unique site in the unit cell. The form factors will be symmetry propagated to all equivalent sites.

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

intensity_formula(f,sf::StructureFactor, 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(sf,required,return_type = ComplexF64) do k, ω, off_diagonal_correlations
+    D[2] -D[1]   0  ]

Useful in the context of set_exchange!.

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

Experimental. 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. I.e., $q_i$ is given in $2π/|a_i|$ with $|a_i|$ the lattice constant of the 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 this array is a tensor (3×3 matrix) corresponding to the indices $α$ and $β$.

source
Sunny.dynamical_correlationsMethod
dynamic_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.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 all_sites as below:

pos = [global_position(sys, site) for site in all_sites(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, qs; [formula])

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

formula = intensity_formula(swt; 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 qs, 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, or intensity_formula(sc,:perp) by default.

The BinningParameters are expected to accept (k,ω) in absolute units.

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 η. 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, qs, ω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; 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 qs and each energy in ωvals. The output will be an array with indices identical to qs, with the last index matching ωvals.

Note that qs is an array of wave vectors of arbitrary dimension. Each element $q$ of qs must be a 3-vector in reciprocal lattice units. I.e., $qᵢ$ is given in $2π/|aᵢ|$ with $|aᵢ|$ the lattice constant of the chemical lattice.

source
Sunny.intensities_interpolatedMethod
intensities_interpolated(sc::SampledCorrelations, qs; interpolation = nothing, formula = intensity_formula(sc,:perp), 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 ωs. 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; kwargs...)
+formula.calc_intensity(sc,q,ix_q,ix_ω)

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.

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

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

Additionally, 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 vector of FormFactors, one for each unique site in the unit cell. The form factors will be symmetry propagated to all equivalent sites.

Alternatively, a custom 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.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!(sf::StructureFactor, others...)

Accumulate the samples in others (one or more StructureFactors) into sf.

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.plot_spinsMethod
plot_spins(sys::System; linecolor=:grey, arrowcolor=:red, linewidth=0.1,
-                            arrowsize=0.3, arrowlength=1.0, kwargs...)

Plot the spin configuration defined by sys. kwargs are passed to Makie.arrows.

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_geometry.

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.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.plot_spinsMethod
plot_spins(sys::System; linecolor=:grey, arrowcolor=:red, linewidth=0.1,
+                            arrowsize=0.3, arrowlength=1.0, kwargs...)

Plot the spin configuration defined by sys. kwargs are passed to Makie.arrows.

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_geometry.

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(sf::StructureFactor, 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_classical_spin_polynomialMethod
function print_classical_spin_polynomial(op)

Prints an operator (e.g., a linear combination of Stevens operators 𝒪) as a polynomial in the classical dipole components.

This function works in the "large-$S$" classical limit, which corresponds to replacing each spin operator with its expected dipole. There are ambiguities in defining this limit at sub-leading order in $S$. The procedure in Sunny is as follows: First, uniquely decompose op as a linear combination of Stevens operators, each of which is defined as a polynomial in the spin operators. To take the large-$S$ limit, Sunny replaces each Stevens operator with a corresponding polynomial in the expected dipole components, keeping only leading order terms in $S$. The resulting "classical Stevens functions" are essentially the spherical harmonics $Yᵐₗ$, up to $m$- and $l$- dependent scaling factors.

Example

using DynamicPolynomials, Sunny
+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_classical_spin_polynomialMethod
function print_classical_spin_polynomial(op)

Prints an operator (e.g., a linear combination of Stevens operators 𝒪) as a polynomial in the classical dipole components.

This function works in the "large-$S$" classical limit, which corresponds to replacing each spin operator with its expected dipole. There are ambiguities in defining this limit at sub-leading order in $S$. The procedure in Sunny is as follows: First, uniquely decompose op as a linear combination of Stevens operators, each of which is defined as a polynomial in the spin operators. To take the large-$S$ limit, Sunny replaces each Stevens operator with a corresponding polynomial in the expected dipole components, keeping only leading order terms in $S$. The resulting "classical Stevens functions" are essentially the spherical harmonics $Yᵐₗ$, up to $m$- and $l$- dependent scaling factors.

Example

using DynamicPolynomials, Sunny
 
 print_classical_spin_polynomial((1/4)𝒪[4,4] + (1/20)𝒪[4,0] + (3/5)*(𝒮'*𝒮)^2)
-# Prints: 𝒮₁⁴ + 𝒮₂⁴ + 𝒮₃⁴

See also print_classical_stevens_expansion for the inverse mapping.

source
Sunny.print_classical_stevens_expansionMethod
function print_classical_stevens_expansion(op)

Prints an operator (e.g. a polynomial of the spin operators 𝒮) as a linear combination of Stevens operators. This function works in the large-$S$ classical limit, as described in the documentation for print_classical_spin_polynomial.

In the output, the symbol X denotes the spin magnitude squared, which can be entered symbolically as 𝒮'*𝒮.

Examples

using DynamicPolynomials, Sunny
+# Prints: 𝒮₁⁴ + 𝒮₂⁴ + 𝒮₃⁴

See also print_classical_stevens_expansion for the inverse mapping.

source
Sunny.print_classical_stevens_expansionMethod
function print_classical_stevens_expansion(op)

Prints an operator (e.g. a polynomial of the spin operators 𝒮) as a linear combination of Stevens operators. This function works in the large-$S$ classical limit, as described in the documentation for print_classical_spin_polynomial.

In the output, the symbol X denotes the spin magnitude squared, which can be entered symbolically as 𝒮'*𝒮.

Examples

using DynamicPolynomials, Sunny
 
 print_classical_stevens_expansion(𝒮[1]^4 + 𝒮[2]^4 + 𝒮[3]^4)
-# Prints: (1/20)𝒪₄₀ + (1/4)𝒪₄₄ + (3/5)X²

See also print_classical_spin_polynomial for the inverse mapping.

The function print_stevens_expansion is analogous to this one, but expects a quantum operator in a finite-$S$ representation.

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. The analogous function in the large-$S$ classical limit is print_classical_stevens_expansion.

Examples

S = spin_matrices(N=5)
+# Prints: (1/20)𝒪₄₀ + (1/4)𝒪₄₄ + (3/5)X²

See also print_classical_spin_polynomial for the inverse mapping.

The function print_stevens_expansion is analogous to this one, but expects a quantum operator in a finite-$S$ representation.

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. The analogous function in the large-$S$ classical limit is print_classical_stevens_expansion.

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 InstantStructureFactor 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.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_geometryMethod
reshape_geometry(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_periodicallyMethod
resize_periodically(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_geometry 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.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.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_geometryMethod
reshape_geometry(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_periodicallyMethod
resize_periodically(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_geometry 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.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;
@@ -61,7 +60,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)
 
@@ -71,11 +70,11 @@
 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(sf::StructureFactor, cut_from_q, cut_to_q, cut_bins::Int64, cut_width::Float64; plane_normal = [0,0,1],cut_height = cutwidth, units = :absolute)

Creates BinningParameters which make a 1D cut in 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 orientation of the binning in the transverse directions is determined automatically using plane_normal. The width of the bins in the transverse direciton is controlled by cut_width and cut_height.

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

Setting units = :rlu returns BinningParameters which accept values in R.L.U. instead of absolute units.

This function can be used without reference to a StructureFactor 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.spherical_shellMethod
spherical_shell(sf::StructureFactor, radius, density)

Returns a set of wave vectors lying on a sphere of specified radius, where radius is given in $Å^{-1}$. density controls how many points to select per $Å^{-2}$.

The points are generated by mapping a Fibonacci lattice onto a sphere.

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)
+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, units = :absolute)

Creates BinningParameters which make a 1D cut in 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 orientation of the binning in the transverse directions is determined automatically using plane_normal. The width of the bins in the transverse direciton is controlled by cut_width and cut_height.

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

Setting units = :rlu returns BinningParameters which accept values in R.L.U. instead of absolute units.

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.spherical_shellMethod
spherical_shell(sc::SampledCorrelations, radius, density)

Returns a set of wave vectors lying on a sphere of specified radius, where radius is given in $Å^{-1}$. density controls how many points to select per $Å^{-2}$.

The points are generated by mapping a Fibonacci lattice onto a sphere.

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(sf::StructureFactor; units = :absolute)

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.

Setting units = :rlu returns BinningParameters which accept values in R.L.U. instead of absolute units.

This function can be used without reference to a StructureFactor 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]; [units])

As in bin_absolute_units_as_rlu!, the last argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:

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.ωsMethod
ωs(sf::StructureFactor; negative_energies=false)

Return the ω values for the energy index of a StructureFactor. 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.@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; units = :absolute)

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.

Setting units = :rlu returns BinningParameters which accept values in R.L.U. instead of absolute units.

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]; [units])

As in bin_absolute_units_as_rlu!, the last argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:

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.ωsMethod
ωs(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.@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

Plotting

To reduce package load times, certain plotting functions are only available when the user explicitly loads Makie, e.g., with using GLMakie or using WGLMakie.

+@mix_proposals 0.4 propose_flip 0.6 propose_delta(0.2)
source

Plotting

To reduce package load times, certain plotting functions are only available when the user explicitly loads Makie, e.g., with using GLMakie or using WGLMakie.

diff --git a/dev/quick-start/index.html b/dev/quick-start/index.html index 28c064df4..780fdf50a 100644 --- a/dev/quick-start/index.html +++ b/dev/quick-start/index.html @@ -33,4 +33,4 @@ Allowed exchange matrix: | A C -D | | C A -D | | D D B | -Allowed DM vector: [-D D 0]

Sunny reported that a single-ion anisotropy is only allowed at quartic and hexic orders, which is consistent with the cubic point group symmetry. Additionally, Sunny reported the allowed forms of nearest and next-nearest neighbor interaction.

The next steps are typically the following

  1. Build a System which contains spins on a finite size lattice of crystal unit cells.
  2. Add interactions to the system using functions like set_external_field!, set_exchange!, and set_onsite_coupling!.
  3. Perform Monte Carlo simulation to equilibrate the spin configuration. Options include the continuous Langevin dynamics, or single-spin flip updates with LocalSampler. The former can efficiently handle long-range dipole-dipole interactions, while the latter may be better in the presence of strong anisotropy (e.g., the Ising limit).
  4. Measure the static or dynamical structure factor. For details, see the page Structure Factor Calculations.
+Allowed DM vector: [-D D 0]

Sunny reported that a single-ion anisotropy is only allowed at quartic and hexic orders, which is consistent with the cubic point group symmetry. Additionally, Sunny reported the allowed forms of nearest and next-nearest neighbor interaction.

The next steps are typically the following

  1. Build a System which contains spins on a finite size lattice of crystal unit cells.
  2. Add interactions to the system using functions like set_external_field!, set_exchange!, and set_onsite_coupling!.
  3. Perform Monte Carlo simulation to equilibrate the spin configuration. Options include the continuous Langevin dynamics, or single-spin flip updates with LocalSampler. The former can efficiently handle long-range dipole-dipole interactions, while the latter may be better in the presence of strong anisotropy (e.g., the Ising limit).
  4. Measure the static or dynamical structure factor. For details, see the page Structure Factor Calculations.
diff --git a/dev/search/index.html b/dev/search/index.html index d26122bc5..af035fb7d 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -1,2 +1,2 @@ -Search · Sunny documentation

Loading search...

    +Search · Sunny documentation

    Loading search...

      diff --git a/dev/search_index.js b/dev/search_index.js index 2443d6a37..e332e1a7b 100644 --- a/dev/search_index.js +++ b/dev/search_index.js @@ -1,3 +1,3 @@ var documenterSearchIndex = {"docs": -[{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"EditURL = \"https://github.com/SunnySuite/Sunny.jl/blob/main/examples/powder_averaging.jl\"","category":"page"},{"location":"examples/powder_averaging/#Powder-Averaging","page":"Powder Averaging","title":"Powder Averaging","text":"","category":"section"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"This tutorial gives a brief demonstration of how to calculate polycrystalline data using Sunny's structure factor tools.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"We begin by constructing a simple anti-ferromagnetic model on a diamond lattice.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"using Sunny, GLMakie\nusing Statistics: mean\n\ndims = (8,8,8) # Lattice dimensions\nseed = 1 # RNG seed for repeatable behavior\nJ = Sunny.meV_per_K*7.5413 # Nearest-neighbor exchange parameter\n\ncrystal = Sunny.diamond_crystal()\nsys = System(crystal, dims, [SpinInfo(1, S=3/2)], :dipole; seed)\nset_exchange!(sys, J, Bond(1, 3, [0,0,0]))","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"We next set up a Langevin integrator and thermalize the system.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Δt = 0.07 # Step size for Langevin integrator\nkT = Sunny.meV_per_K * 2 # Temperature of simulation (2K)\nλ = 0.1 # Damping parameter\nintegrator = Langevin(Δt; kT, λ);\n\nfor _ ∈ 1:3000\n step!(sys, integrator)\nend;\nnothing #hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"We can now calculate 𝒮(𝐪ω) with DynamicStructureFactor. We will tell Sunny to symmetrize the sample trajectory along the time-axis to minimize Fourier artifacts.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"sf = DynamicStructureFactor(sys;\n Δt=2Δt,\n nω=100,\n ωmax=5.5,\n process_trajectory=:symmetrize\n)","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"To get some intuition about the expected results, we first look at the \"single crystal\" results along a high-symmetry path in the first Brillouin zone. While doing so, we will add some artificial broadening along the energy axis with broaden_energy. To use this function, it is necessary to define a kernel function with the form, kernel(ω, ω₀), where ω is energy and ω₀ is the center frequency of the kernel. In this example we apply some Lorentzian broadening using an anonymous function: (ω, ω₀) -> lorentzian(ω-ω₀, 0.1).","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","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]]\nqs, markers = connected_path(sf, qpoints, 50)\n\nis = intensities_interpolated(sf, qs; interpolation=:round, formula = intensity_formula(sf,:trace))\nis_broad = broaden_energy(sf, is, (ω, ω₀) -> lorentzian(ω-ω₀, 0.1))\n\n# Plot results\nfig = Figure(; resolution=(1000,400))\nxticklabels = [string(tuple(qs[i]...)) for i in markers]\nplotparams = (;\n aspect=1.4,\n ylabel = \"ω (meV)\",\n xlabel = \"𝐪 (RLU)\",\n xticks=(markers, xticklabels),\n xticklabelrotation=π/10,\n xticklabelsize=14,\n)\nax1 = Axis(fig[1,1]; title=\"No artificial broadening\", plotparams...)\nheatmap!(ax1, 1:size(is, 1), ωs(sf), is; colorrange=(0,0.5))\nax2 = Axis(fig[1,2]; title=\"Lorentzian broadening (η=0.1)\", plotparams...)\nheatmap!(ax2, 1:size(is, 1), ωs(sf), is_broad; colorrange=(0,2.0))\nfig","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"We next write a simple powder averaging function that takes a structure factor, a list of radius values (Å⁻¹), and a density parameter (Å⁻²) that will control the number of wave vectors to sample at each radius. For each radius r, the function will generate wavevectors on a sphere of this radius and retrieve their intensities_interpolated. These intensities will be broadened, as just demonstrated above, and then averaged to produce a single vector of energy-intensities for each r. Note that our powder_average function passes most of its keywords through to intensities_interpolated, so it can be given an intensity_formula.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"function powder_average(sf, rs, density; η=0.1, kwargs...)\n nω = length(ωs(sf))\n output = zeros(Float64, length(rs), nω)\n\n for (i, r) in enumerate(rs)\n qs = spherical_shell(sf, r, density) # Get points on a sphere of radius r\n if length(qs) == 0\n qs = [[0., 0., 0.]] # If no points (r is too small), just look at 0 vector\n end\n vals = intensities_interpolated(sf, qs; kwargs...) # Retrieve energy intensities\n vals[:,1] .*= 0.0 # Remove elastic peaks before broadening\n vals = broaden_energy(sf, vals, (ω,ω₀)->lorentzian(ω-ω₀, η)) # Apply Lorentzian broadening\n output[i,:] = reshape(mean(vals, dims=1), (nω,)) # Average single radius results and save\n end\n\n return output\nend;\nnothing #hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Finally, we perform the calculation,","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"rs = range(0, 6π, length=55) # Set of radius values\nη = 0.05 # Lorentzian broadening parameter\ndensity = 0.15 # Number of samples in Å⁻²\n\nformula = intensity_formula(sf,:perp)\npa = powder_average(sf, rs, density; η, formula);\nnothing #hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"and plot the results.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"fig1= Figure()\nax = Axis(fig1[1,1]; xlabel = \"|Q| (Å⁻¹)\", ylabel = \"ω (meV)\")\nheatmap!(ax, rs, ωs(sf), pa; colorrange=(0, 25.0))\nfig1","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Note that the bandwidth is similar to what we saw above along the high symmetry path.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"This was a very quick calculation. The structure factor calculation itself and the powder averaging will each execute in < 10 s on a typical laptop. Higher quality results can be obtained by:","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Increasing the number of samples used to calculate 𝒮(𝐪ω) using add_sample!\nIncreasing the system size to improve momentum space resolution\nIncreasing the energy resolution (nω keyword of DynamicStructureFactor)\nApplying instrument-specific energy broadening by giving broaden_energy a custom kernel function.\nIncluding FormFactor corrections\nSetting interpolation=:linear when retrieving intensities in the powder averaging loop.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"The intensity data can alternatively be collected into bonafide histogram bins. See integrated_lorentzian, powder_average_binned, and axes_bincenters.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"radial_binning_parameters = (0,6π,6π/55)\nintegrated_kernel = integrated_lorentzian(0.05) # Lorentzian broadening\n\npa_intensities, pa_counts = powder_average_binned(sf,radial_binning_parameters;integrated_kernel = integrated_kernel,formula)\n\npa_normalized_intensities = pa_intensities ./ pa_counts\n\nfig = Figure()\nax = Axis(fig[1,1]; xlabel = \"|k| (Å⁻¹)\", ylabel = \"ω (meV)\")\nrs_bincenters = axes_bincenters(radial_binning_parameters...)\nheatmap!(ax, rs_bincenters[1], ωs(sf), pa_normalized_intensities; colorrange=(0,3.0))\nfig","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"The striations in the graph tell us that the simulation is under resolved for this bin size. We should increase the size of either the periodic lattice, or the bins.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Using the bzsize option, we can even resolve the contribution from each brillouin zone:","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"intensity_firstBZ, counts_firstBZ = powder_average_binned(sf,radial_binning_parameters;integrated_kernel = integrated_kernel, bzsize=(1,1,1),formula)\n#intensity_secondBZ, counts_secondBZ = powder_average_binned(..., bzsize=(2,2,2))\nintensity_secondBZ, counts_secondBZ = powder_average_binned(sf,radial_binning_parameters;integrated_kernel = integrated_kernel, bzsize=(2,2,2),formula)#hide\n#intensity_thirdBZ, counts_thirdBZ = powder_average_binned(..., bzsize=(3,3,3))\nintensity_thirdBZ = pa_intensities;#hide\ncounts_thirdBZ = pa_counts;#hide\nnothing #hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"First BZ:","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"fig = Figure()#hide\nax = Axis(fig[1,1]; xlabel = \"|k| (Å⁻¹)\", ylabel = \"ω (meV)\")#hide\nrs_bincenters = axes_bincenters(radial_binning_parameters...)#hide\nheatmap!(ax, rs_bincenters[1], ωs(sf),\n intensity_firstBZ ./ counts_firstBZ\n ; colorrange=(0,3.0))\nfig#hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Second BZ:","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"fig = Figure()#hide\nax = Axis(fig[1,1]; xlabel = \"|k| (Å⁻¹)\", ylabel = \"ω (meV)\")#hide\nrs_bincenters = axes_bincenters(radial_binning_parameters...)#hide\nheatmap!(ax, rs_bincenters[1], ωs(sf),\n (intensity_secondBZ .- intensity_firstBZ) ./ (counts_secondBZ .- counts_firstBZ)\n ; colorrange=(0,3.0))\nfig#hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Third BZ:","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"fig = Figure()#hide\nax = Axis(fig[1,1]; xlabel = \"|k| (Å⁻¹)\", ylabel = \"ω (meV)\")#hide\nrs_bincenters = axes_bincenters(radial_binning_parameters...)#hide\nheatmap!(ax, rs_bincenters[1], ωs(sf),\n (intensity_thirdBZ .- intensity_secondBZ) ./ (counts_thirdBZ .- counts_secondBZ)\n ; colorrange=(0,3.0))\nfig#hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"This page was generated using Literate.jl.","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":"This version includes many breaking changes.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Added support for Dipole-mode Linear Spin Wave Theory. (Thanks Hao Zhang!)","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Split intensities into calculation (intensity_formula) and presentation (intensities_interpolated, intensities_binned). This is a breaking change, see the docs to migrate your code.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Broadened support for custom observables in StructureFactor for use in intensity_formula.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Added function load_nxs to load experimental neutron scattering data to compare with intensities_binned.","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":"Replace set_biquadratic! with an optional keyword argument biquad to set_exchange!.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Symbolic representations of operators are now hidden unless the package DynamicPolynomials is explicitly loaded by the user. The functionality of print_anisotropy_as_stevens has been replaced with print_classical_stevens_expansion, while print_anisotropy_as_classical_spins has become print_classical_spin_polynomial.","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":"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":"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.𝒪","page":"Library API","title":"Sunny.𝒪","text":"𝒪[k,q]\n\nAbstract symbols for the Stevens operators. Linear combinations of these can be used to define a single-ion anisotropy.\n\n\n\n\n\n","category":"constant"},{"location":"library/#Sunny.𝒮","page":"Library API","title":"Sunny.𝒮","text":"𝒮[1], 𝒮[2], 𝒮[3]\n\nAbstract symbols for the spin operators. Polynomials of these can be used to define a single-ion anisotropy.\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 (k,ω) with each row of the covectors matrix, with k given in absolute units. Since the default covectors matrix is the identity matrix, the default axes are (kx,ky,kz,ω) in absolute units. To bin (q,ω) values given in reciprocal lattice units (R.L.U.) instead, see bin_rlu_as_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{Int64, Union{Nothing, String}}","page":"Library API","title":"Sunny.FormFactor","text":"FormFactor(atom::Int64, elem::String; g_lande=nothing)\n\nBasic type for specifying form factor parameters. Must be provided a site within the unit cell (atom) and a string specifying the element name. This used when creating an intensity_formula, which accepts a list of FormFactorss.\n\nA list of supported element names is available at:\n\nhttps://www.ill.eu/sites/ccsl/ffacts/ffachtml.html\n\nThe Landé g-factor may also be specified. \n\nIn more detail, the data stored in a FormFactor will be used to compute the form factor for each momentum space magnitude |k|, measured in inverse angstroms. The result is dependent on the magnetic ion species. By default, a first order form factor f is returned. If the keyword g_lande is given a numerical value, then a second order form factor F is returned.\n\nIt is traditional to define the form factors using a sum of Gaussian broadening functions in the scalar variable s = k4π, where k can be interpreted as the magnitude of momentum transfer.\n\nThe Neutron Data Booklet, 2nd ed., Sec. 2.5 Magnetic Form Factors, defines the approximation\n\nlangle j_l(s) rangle = A e^-as^2 + B e^-bs^2 + Ce^-cs^2 + D\n\nwhere coefficients A B C D a b c are obtained from semi-empirical fits, depending on the orbital angular momentum index l = 0 2. For transition metals, the form-factors are calculated using the Hartree-Fock method. For rare-earth metals and ions, Dirac-Fock form is used for the calculations.\n\nA first approximation to the magnetic form factor is\n\nf(s) = langle j_0(s) rangle\n\nA second order correction is given by\n\nF(s) = frac2-gg langle j_2(s) rangle s^2 + f(s), where g is the Landé g-factor. \n\nDigital tables are available at:\n\nhttps://www.ill.eu/sites/ccsl/ffacts/ffachtml.html\n\nAdditional references are:\n\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)\nDescleaux 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.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\nExperimental. Constructs 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.StructureFactor-Union{Tuple{System{N}}, Tuple{N}} where N","page":"Library API","title":"Sunny.StructureFactor","text":"StructureFactor\n\nAn object holding 𝒮(𝐪ω) or 𝒮(𝐪) data. Construct a StructureFactor using DynamicStructureFactor or InstantStructureFactor, respectively.\n\n\n\n\n\n","category":"method"},{"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.DynamicStructureFactor-Tuple{System}","page":"Library API","title":"Sunny.DynamicStructureFactor","text":"DynamicStructureFactor(sys::System; Δt, nω, ωmax, \n process_trajectory=:none, observables=nothing, correlations=nothing)\n\nCreates a StructureFactor 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\nPrior to calling DynamicStructureFactor, ensure that sys represents a good equilibrium sample. Additional sample data may be accumulated by calling add_sample!(sf, sys) with newly equilibrated sys configurations.\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.InstantStructureFactor-Tuple{System}","page":"Library API","title":"Sunny.InstantStructureFactor","text":"InstantStructureFactor(sys::System; process_trajectory=:none,\n observables=nothing, correlations=nothing)\n\nCreates a StructureFactor 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 a full DynamicStructureFactor object instead of an InstantStructureFactor. 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 InstantStructureFactor, ensure that sys represents a good equilibrium sample. Additional sample data may be accumulated by calling add_sample!(sf, 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.add_sample!-Tuple{StructureFactor, System}","page":"Library API","title":"Sunny.add_sample!","text":"add_sample!(sf::StructureFactor, sys::System)\n\nadd_trajectory uses the spin configuration contained in the System to generate a correlation data and accumulate it into sf. 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 sf. \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.all_exact_wave_vectors-Tuple{StructureFactor}","page":"Library API","title":"Sunny.all_exact_wave_vectors","text":"all_exact_wave_vectors(sf::StructureFactor; bzsize=(1,1,1))\n\nReturns all wave vectors for which sf contains exact values. bsize specifies the number of Brillouin zones to be included.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.all_sites-Tuple{System}","page":"Library API","title":"Sunny.all_sites","text":"all_sites(sys::System)\n\nAn iterator over all Sites in the system. \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.bin_absolute_units_as_rlu!","page":"Library API","title":"Sunny.bin_absolute_units_as_rlu!","text":"If params expects to bin values (k,ω) in absolute units, then calling\n\nbin_rlu_as_absolute_units!(params::BinningParameters,[reciprocal lattice vectors])\n\nwill modifiy the covectors in params so that they will accept (q,ω) in Reciprocal Lattice Units (R.L.U.) instead. Conversly, if params expects (q,ω) R.L.U., calling\n\nbin_absolute_units_as_rlu!(params::BinningParameters,[reciprocal lattice vectors])\n\nwill adjust params to instead accept (k,ω) absolute units.\n\nThe second argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:\n\nCrystal\nSystem\nStructureFactor\nSpinWaveTheory\n\n\n\n\n\n","category":"function"},{"location":"library/#Sunny.bin_rlu_as_absolute_units!","page":"Library API","title":"Sunny.bin_rlu_as_absolute_units!","text":"If params expects to bin values (k,ω) in absolute units, then calling\n\nbin_rlu_as_absolute_units!(params::BinningParameters,[reciprocal lattice vectors])\n\nwill modifiy the covectors in params so that they will accept (q,ω) in Reciprocal Lattice Units (R.L.U.) instead. Conversly, if params expects (q,ω) R.L.U., calling\n\nbin_absolute_units_as_rlu!(params::BinningParameters,[reciprocal lattice vectors])\n\nwill adjust params to instead accept (k,ω) absolute units.\n\nThe second argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:\n\nCrystal\nSystem\nStructureFactor\nSpinWaveTheory\n\n\n\n\n\n","category":"function"},{"location":"library/#Sunny.broaden_energy-Tuple{StructureFactor, Any, Function}","page":"Library API","title":"Sunny.broaden_energy","text":"broaden_energy(sf::StructureFactor, 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(sf, 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.connected_path-Tuple{Any, Vector, Any}","page":"Library API","title":"Sunny.connected_path","text":"connected_path(recip_vecs, qs::Vector, density)\n\nTakes a list of wave vectors, qs, and builds an expanded list of wave vectors that traces a path through the provided points. Also returned is a list of marker indices corresponding to the input points. The density parameter is given in samples per inverse Å.\n\nInstead of recip_vecs, the first argument may be either a StructureFactor or a SpinWaveTheory.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.connected_path_bins-Tuple{Any, Any, Any, Any, Vararg{Any}}","page":"Library API","title":"Sunny.connected_path_bins","text":"connected_path_bins(sf,qs,density,args...;kwargs...)\n\nTakes a list of wave vectors, qs, 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.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\nExperimental. 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 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\nExperimental. Given 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. I.e., q_i is given in 2πa_i with a_i the lattice constant of the 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 this array is a tensor (3×3 matrix) corresponding to the indices α and β.\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. Take care to ensure the units are correct (R.L.U. or absolute). You may want to call bin_rlu_as_absolute_units! or 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 all_sites as below:\n\npos = [global_position(sys, site) for site in all_sites(sys)]\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.instant_intensities_interpolated-Tuple{StructureFactor, Any}","page":"Library API","title":"Sunny.instant_intensities_interpolated","text":"instant_intensities_interpolated(sf::StructureFactor, 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 StructureFactor 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}","page":"Library API","title":"Sunny.intensities_bands","text":"dispersion, intensities = intensities_bands(swt::SpinWaveTheory, qs; [formula])\n\nComputes the scattering intensities at each energy band for each q in qs, according to Linear Spin Wave Theory and the given intensity formula. The optional formula must have a delta-function kernel, e.g.:\n\nformula = intensity_formula(swt; 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 qs, 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{StructureFactor, BinningParameters}","page":"Library API","title":"Sunny.intensities_binned","text":"intensity, counts = intensities_binned(sf::StructureFactor, params::BinningParameters; formula, integrated_kernel)\n\nGiven correlation data contained in a StructureFactor and BinningParameters describing the shape of a histogram, compute the intensity and normalization for each histogram bin using a given intensity_formula, or intensity_formula(sf,:perp) by default.\n\nThe BinningParameters are expected to accept (k,ω) in absolute units.\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 η. 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].\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, qs, ω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; 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 qs and each energy in ωvals. The output will be an array with indices identical to qs, with the last index matching ωvals.\n\nNote that qs is an array of wave vectors of arbitrary dimension. Each element q of qs must be a 3-vector in reciprocal lattice units. I.e., qᵢ is given in 2πaᵢ with aᵢ the lattice constant of the chemical lattice.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensities_interpolated-Tuple{StructureFactor, Any}","page":"Library API","title":"Sunny.intensities_interpolated","text":"intensities_interpolated(sf::StructureFactor, qs; interpolation = nothing, formula = intensity_formula(sf,:perp), negative_energies = false)\n\nThe basic function for retrieving 𝒮(𝐪ω) information from a StructureFactor. 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 ωs. 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, StructureFactor, Any}","page":"Library API","title":"Sunny.intensity_formula","text":"formula = intensity_formula(sf::StructureFactor; kwargs...)\nformula.calc_intensity(sf,q,ix_q,ix_ω)\n\nEstablish a formula for computing the intensity of the discrete scattering modes (q,ω) using the correlation data 𝒮^αβ(qω) stored in the StructureFactor. The formula returned from intensity_formula can be passed to intensities_interpolated or intensities_binned.\n\nSunny has several built-in formulas that can be selected by setting contraction_mode to one of these values:\n\n:perp (default), which contracts 𝒮^αβ(qω) with the dipole factor δ_αβ - q_αq_β, returning the unpolarized intensity.\n:trace, which yields operatornametr 𝒮(qω) = _α 𝒮^αα(qω)\n:full, which will return all elements 𝒮^αβ(𝐪ω) without contraction.\n\nAdditionally, there 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 vector of FormFactors, one for each unique site in the unit cell. The form factors will be symmetry propagated to all equivalent sites.\n\nAlternatively, a custom formula can be specifed by providing a function intensity = f(q,ω,correlations) and specifying which correlations it requires:\n\nintensity_formula(f,sf::StructureFactor, 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(sf,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.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{StructureFactor, Vararg{Any}}","page":"Library API","title":"Sunny.merge!","text":"merge!(sf::StructureFactor, others...)\n\nAccumulate the samples in others (one or more StructureFactors) into sf.\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.plot_spins-Tuple{System}","page":"Library API","title":"Sunny.plot_spins","text":"plot_spins(sys::System; linecolor=:grey, arrowcolor=:red, linewidth=0.1,\n arrowsize=0.3, arrowlength=1.0, kwargs...)\n\nPlot the spin configuration defined by sys. kwargs are passed to Makie.arrows. \n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.polarize_spin!-Union{Tuple{N}, Tuple{System{N}, Any, Any}} where N","page":"Library API","title":"Sunny.polarize_spin!","text":"polarize_spin!(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.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_geometry.\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{StructureFactor, Any}","page":"Library API","title":"Sunny.powder_average_binned","text":"powder_average_binned(sf::StructureFactor, 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_classical_spin_polynomial-Tuple{Any}","page":"Library API","title":"Sunny.print_classical_spin_polynomial","text":"function print_classical_spin_polynomial(op)\n\nPrints an operator (e.g., a linear combination of Stevens operators 𝒪) as a polynomial in the classical dipole components.\n\nThis function works in the \"large-S\" classical limit, which corresponds to replacing each spin operator with its expected dipole. There are ambiguities in defining this limit at sub-leading order in S. The procedure in Sunny is as follows: First, uniquely decompose op as a linear combination of Stevens operators, each of which is defined as a polynomial in the spin operators. To take the large-S limit, Sunny replaces each Stevens operator with a corresponding polynomial in the expected dipole components, keeping only leading order terms in S. The resulting \"classical Stevens functions\" are essentially the spherical harmonics Yᵐₗ, up to m- and l- dependent scaling factors.\n\nExample\n\nusing DynamicPolynomials, Sunny\n\nprint_classical_spin_polynomial((1/4)𝒪[4,4] + (1/20)𝒪[4,0] + (3/5)*(𝒮'*𝒮)^2)\n# Prints: 𝒮₁⁴ + 𝒮₂⁴ + 𝒮₃⁴\n\nSee also print_classical_stevens_expansion for the inverse mapping.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_classical_stevens_expansion-Tuple{Any}","page":"Library API","title":"Sunny.print_classical_stevens_expansion","text":"function print_classical_stevens_expansion(op)\n\nPrints an operator (e.g. a polynomial of the spin operators 𝒮) as a linear combination of Stevens operators. This function works in the large-S classical limit, as described in the documentation for print_classical_spin_polynomial.\n\nIn the output, the symbol X denotes the spin magnitude squared, which can be entered symbolically as 𝒮'*𝒮.\n\nExamples\n\nusing DynamicPolynomials, Sunny\n\nprint_classical_stevens_expansion(𝒮[1]^4 + 𝒮[2]^4 + 𝒮[3]^4)\n# Prints: (1/20)𝒪₄₀ + (1/4)𝒪₄₄ + (3/5)X²\n\nSee also print_classical_spin_polynomial for the inverse mapping.\n\nThe function print_stevens_expansion is analogous to this one, but expects a quantum operator in a finite-S representation.\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. The analogous function in the large-S classical limit is print_classical_stevens_expansion.\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 InstantStructureFactor 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.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_geometry-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.reshape_geometry","text":"reshape_geometry(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_periodically-Union{Tuple{N}, Tuple{System{N}, Tuple{Int64, Int64, Int64}}} where N","page":"Library API","title":"Sunny.resize_periodically","text":"resize_periodically(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_geometry 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.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(sf::StructureFactor, cut_from_q, cut_to_q, cut_bins::Int64, cut_width::Float64; plane_normal = [0,0,1],cut_height = cutwidth, units = :absolute)\n\nCreates BinningParameters which make a 1D cut in 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 orientation of the binning in the transverse directions is determined automatically using plane_normal. The width of the bins in the transverse direciton is controlled by cut_width and cut_height.\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\nSetting units = :rlu returns BinningParameters which accept values in R.L.U. instead of absolute units.\n\nThis function can be used without reference to a StructureFactor 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.spherical_shell-Tuple{StructureFactor, Any, Any}","page":"Library API","title":"Sunny.spherical_shell","text":"spherical_shell(sf::StructureFactor, radius, density)\n\nReturns a set of wave vectors lying on a sphere of specified radius, where radius is given in Å^-1. density controls how many points to select per Å^-2. \n\nThe points are generated by mapping a Fibonacci lattice onto a sphere. \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(sf::StructureFactor; units = :absolute)\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\nSetting units = :rlu returns BinningParameters which accept values in R.L.U. instead of absolute units.\n\nThis function can be used without reference to a StructureFactor 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]; [units])\n\nAs in bin_absolute_units_as_rlu!, the last argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:\n\nCrystal\nSystem\nStructureFactor\nSpinWaveTheory\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.ωs-Tuple{StructureFactor}","page":"Library API","title":"Sunny.ωs","text":"ωs(sf::StructureFactor; negative_energies=false)\n\nReturn the ω values for the energy index of a StructureFactor. 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.@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/#Plotting","page":"Library API","title":"Plotting","text":"","category":"section"},{"location":"library/","page":"Library API","title":"Library API","text":"To reduce package load times, certain plotting functions are only available when the user explicitly loads Makie, e.g., with using GLMakie or using WGLMakie.","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/#Basic-Usage","page":"Structure Factor Calculations","title":"Basic Usage","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The basic data type for calculating, storing and retrieving structure factor data is StructureFactor. Rather than creating a StructureFactor directly, one should call either DynamicStructureFactor, for 𝒮^αβ(𝐪ω), or InstantStructureFactor, for 𝒮^αβ(𝐪). These functions will configure and return an appropriate StructureFactor.","category":"page"},{"location":"structure-factor/#Calculating-a-dynamical-stucture-factor:-𝒮(𝐪,ω)","page":"Structure Factor Calculations","title":"Calculating a dynamical stucture factor: 𝒮(𝐪ω)","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Calling DynamicStructureFactor(sys; Δt, ωmax, nω) will create a StructureFactor for the user and calculate an initial sample. There are three keywords that must be specified. These keywords will determine the dynamics used to calculate the sample and, consequently, the ω information that will be available after the calculation has completed.","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":"Upon constructing DynamicStructureFactor, classical spin dynamics will be performed, and spin correlation data will be accumulated into 𝒮^αβ(𝐪ω). 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 generating a decorrelated spin configuration in sys, and then calling add_sample!.","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 `StructureFactor` and calculate an initial sample\nsf = DynamicStructureFactor(sys; Δt=0.05, ωmax=10.0, nω=100) \n\n# Add additional samples\nfor _ in 1:nsamples\n decorrelate_system(sys) # Perform some type of Monte Carlo simulation\n add_sample!(sf, sys) # Use spins to calculate 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 DynamicStructureFactor documentation for a list of all keywords.","category":"page"},{"location":"structure-factor/#Calculating-an-instantaneous-(\"static\")-structure-factor:-𝒮(𝐪)","page":"Structure Factor Calculations","title":"Calculating 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 spin-spin correlations at single instances of time. 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 fixed spin configurations. Information about calculating instantaneous data from a dynamic structure factor 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 InstantStructureFactor instead of DynamicStructureFactor. Note that there are no required keywords as there is no need to specify any dynamics. InstantStructureFactor will immediately calculate a sample of 𝒮(𝐪) using the spin configuration contained in sys. It is therefore important that sys be properly thermalized before calling this function. Additional samples may be added with add_sample!(sf, sys), just as was done in the dynamic case. As was true there, it is important to ensure that the spins in sys represents a new equilibrium sample before calling add_sample!.","category":"page"},{"location":"structure-factor/#Extracting-information-from-structure-factors","page":"Structure Factor Calculations","title":"Extracting information from structure factors","text":"","category":"section"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"The basic function for extracting information from a dynamic StructureFactor at a particular wave vector, 𝐪, is intensities_interpolated. It takes a StructureFactor, a list of wave vectors, and a contraction mode. For example, intensities_interpolated(sf, [[0.0, 0.5, 0.5]]) will calculate intensities for the wavevector 𝐪 = (𝐛_2 + 𝐛_3)2. The keyword argument formula can be used to specify an intensity_formula for greater control over the intensity calculation. The default formula performs a contraction of 𝒮^αβ(𝐪ω) that includes polarization corrections. intensities_interpolated returns a list of nω elements at each wavevector. The corresponding ω values can be retrieved by calling ωs on sf.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Since Sunny currently only calculates the structure factor on a finite lattice, 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 all_exact_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 connected_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, spherical_shell will provide a list of wave vectors on a sphere of a specified 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 structure factor. 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":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"EditURL = \"https://github.com/SunnySuite/Sunny.jl/blob/main/examples/fei2_tutorial.jl\"","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 classical dynamics of SU(N) coherent state 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/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Begin by importing Sunny and GLMakie, a plotting package.","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 you see an error Package not found in current path, add the package by typing ] add at the Julia prompt.","category":"page"},{"location":"examples/fei2_tutorial/#Crystals-and-symmetry-analysis","page":"Case Study: FeI_2","title":"Crystals and symmetry analysis","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/#Spin-systems","page":"Case Study: FeI_2","title":"Spin systems","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"To simulate a system of many spins, construct a System.","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)], :SUN, seed=2)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The system includes 444 unit cells, i.e. 64 Fe atoms, each with spin S=1. The default g-factor is 2, but this could be overriden with an additional argument to SpinInfo. Spin S=1 involves a superposition of 2S+1=3 distinct angular momentum states. In :SUN mode, this superposition will be modeled 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/#Interactions-and-anisotropies","page":"Case Study: FeI_2","title":"Interactions and anisotropies","text":"","category":"section"},{"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 next step is to add interactions to the system. The command print_symmetry_table shows all 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/#Assigning-interactions-and-anisotropies","page":"Case Study: FeI_2","title":"Assigning interactions and anisotropies","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The function set_exchange! assigns an exchange interaction to a bond, and will propagate the 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 structure factors using generalized SU(N) classical dynamics. This will involve the sampling of spin configurations from the Boltzmann distribution at a finite temperature. Spin-spin correlations measured dynamically then provide an estimate of the structure factor mathcalS^alphabeta(mathbfqomega).","category":"page"},{"location":"examples/fei2_tutorial/#Simulated-annealing","page":"Case Study: FeI_2","title":"Simulated annealing","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The Langevin dynamics of SU(N) coherent states can be used to sample spin configurations in thermal equlibrium. Begin by constructing a Langevin object.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Δt = 0.05/D # Single-ion anisotropy is the strongest interaction, so 1/D is","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"a natural dynamical time-scale (in units with ħ=1).","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"λ = 0.1 # Dimensionless magnitude of coupling to thermal bath\nlangevin = Langevin(Δt; kT=0, λ);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Attempt to find a low-energy spin configuration by lowering the temperature kT from 2 to 0 using 20,000 Langevin time-steps.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"randomize_spins!(sys)\nfor kT in range(2, 0, 20_000)\n langevin.kT = kT\n step!(sys, langevin)\nend","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Because the quench was relatively fast, it is expected to find defects in the magnetic order. These can be visualized.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"plot_spins(sys; arrowlength=2.5, linewidth=0.75, arrowsize=1.5)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"If we had used a slower annealing procedure, involving 100,000 or more Langevin time-steps, it would very likely find the correct ground state. Instead, for purposes of illustration, let's analyze the imperfect spin configuration currently stored in sys.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"An experimental probe of magnetic order order is the 'instantaneous' or 'static' structure factor intensity, available via InstantStructureFactor and related functions. To infer periodicities of the magnetic supercell, however, it is sufficient to look at the structure factor weights of spin sublattices individually, without phase averaging. This information is provided by print_wrapped_intensities (see the API documentation for a physical interpretation).","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 above is consistent with known results. The zero-field energy-minimizing magnetic structure of FeI_2 is single-q. If annealing were perfect, then spontaneous symmetry breaking would select one of q = 0 -14 14, 14 0 14, or -141414.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Let's break the symmetry by hand. Given a list of q modes, Sunny can suggest a magnetic supercell with appropriate periodicity. The result is printed 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_geometry allows an arbitrary reshaping of the system. After selecting the supercell geometry, it becomes much easier to find the energy-minimizing spin configuration.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sys_supercell = reshape_geometry(sys, [1 0 0; 0 1 -2; 0 1 2])\n\nlangevin.kT = 0\nfor i in 1:10_000\n step!(sys_supercell, langevin)\nend\n\nplot_spins(sys_supercell; arrowlength=2.5, linewidth=0.75, arrowsize=1.5)","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_supercell);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The dispersion relation can be calculated by providing dispersion with a SpinWaveTheory and a list of wave vectors. For each wave vector, dispersion will return a list of energies, one for each band. Frequently one wants dispersion information along lines that connect special wave vectors. The function connected_path linearly samples between provided q-points, with a given sample density.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","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]]\nlabels = [\"($(p[1]),$(p[2]),$(p[3]))\" for p in points]\ndensity = 600\npath, markers = connected_path(swt, points, density);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"dispersion may now be called on the wave vectors along the generated path. Each column of the returned matrix corresponds to a different mode.","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 omega_i, Sunny can calculate the inelastic neutron scattering intensity I(qomega_i(q)) according to an intensity_formula. The default formula applies a polarization correction (1 - Qotimes Q).","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"formula = intensity_formula(swt; kernel = delta_function_kernel)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The 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":"disp, intensity = intensities_bands(swt, path; formula = formula)\n\nfig = Figure()\nax = Axis(fig[1,1]; xlabel=\"𝐪\", ylabel=\"Energy (meV)\",\n xticks=(markers, labels), xticklabelrotation=π/6,\n)\nylims!(ax, 0.0, 7.5)\nxlims!(ax, 1, size(disp, 1))\nfor i in axes(disp)[2]\n lines!(ax, 1:length(disp[:,i]), disp[:,i]; color=intensity[:,i])\nend\nfig","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"For comparison with inelastic neutron scattering (INS) data, it's often appropriate to apply a lorentzian broadening to the bands.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"γ = 0.05 # Lorentzian broadening parameter\nbroadened_formula = intensity_formula(swt; kernel = lorentzian(γ))","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The broadened intensity can be calculated for any (qomega) using intensities_broadened:","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"energies = collect(0.0:0.01:7.5) # Energies to calculate\nis = intensities_broadened(swt, path, energies, broadened_formula)\n\nheatmap(1:size(is, 1), energies, is;\n axis=(xlabel = \"(H,0,0)\", ylabel=\"Energy (meV)\", xticks=(markers, labels),\n xticklabelrotation=π/8,\n ),\n)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The existence of a lower-energy, single-ion bound state is in qualitative agreement with the experimental data in Bai et al. (Note that the publication figure uses a different coordinate system to label the same wave vectors and the experimental data necessarily averages over the three degenerate ground states.)","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 full data from the dynamical spin structure factor (DSSF) can be retrieved with the dssf function. Like dispersion and intensities, dssf takes an array of wave vectors.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"disp, Sαβ = dssf(swt, [[0, 0, 0]]);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"disp is identical to the output that is obtained from dispersion and contains the energy of each mode at the specified wave vectors. Sαβ contains a 3x3 matrix for each of these modes. The matrix elements of Sαβ correspond to correlations of the different spin components (ordered x, y, z). For example, the full set of matrix elements for the first mode may be obtained as follows,","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Sαβ[1]","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"and the xx matrix element is","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Sαβ[1][1,1]","category":"page"},{"location":"examples/fei2_tutorial/#Dynamical-structure-factors-with-classical-dynamics","page":"Case Study: FeI_2","title":"Dynamical structure factors with classical dynamics","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Linear spin wave calculations are very useful for getting quick, high-quality, results at zero temperature. Moreover, these results are obtained in the thermodynamic limit. Classical dynamics may also be used to produce similar results, albeit at a higher computational cost and on a finite sized lattice. The classical approach nonetheless provides a number of complementary advantages: it is possible perform simulations at finite temperature while retaining nonlinearities; out-of-equilibrium behavior may be examined directly; and it is straightforward to incorporate inhomogenties, chemical or otherwise.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Because classical simulations are conducted on a finite-sized lattice, obtaining acceptable resolution in momentum space requires the use of a larger system size. We can now resize the magnetic supercell to a much larger simulation volume, provided as multiples of the original unit cell.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sys_large = resize_periodically(sys_supercell, (16,16,4))\nplot_spins(sys_large; arrowlength=2.5, linewidth=0.75, arrowsize=1.5)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Apply Langevin dynamics to thermalize the system to a target temperature.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"kT = 0.5 * meV_per_K # 0.5K in units of meV\nlangevin.kT = kT\n\nfor _ in 1:10_000\n step!(sys_large, langevin)\nend","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"We can measure the DynamicStructureFactor by integrating the Hamiltonian dynamics of SU(N) coherent states. Three keyword parameters are required to determine the ω information that will be calculated: 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_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sf = DynamicStructureFactor(sys_large; Δt=2Δt, nω=120, ωmax=7.5)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sf currently contains dynamical structure data generated from a single sample. Additional samples can be added by generating a new spin configuration and calling add_sample!:","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"for _ in 1:2\n for _ in 1:1000 # Fewer steps needed in equilibrium\n step!(sys_large, langevin)\n end\n add_sample!(sf, sys_large) # Accumulate the sample into `sf`\nend","category":"page"},{"location":"examples/fei2_tutorial/#Accessing-structure-factor-data","page":"Case Study: FeI_2","title":"Accessing structure factor data","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The basic functions for accessing intensity data are intensities_interpolated and intensities_binned. Both functions accept an intensity_formula to specify how to combine the correlations recorded in the StructureFactor into intensity data. By default, a formula computing the unpolarized intensity is used, but alternative formulas can be specified.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"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_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"formula = intensity_formula(sf, :trace; kT = kT)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Using the formula, we plot single-q slices at (0,0,0) and (π,π,π):","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"qs = [[0, 0, 0], [0.5, 0.5, 0.5]]\nis = intensities_interpolated(sf, qs; interpolation = :round, formula = formula)\n\nfig = lines(ωs(sf), is[1,:]; axis=(xlabel=\"meV\", ylabel=\"Intensity\"), label=\"(0,0,0)\")\nlines!(ωs(sf), is[2,:]; label=\"(π,π,π)\")\naxislegend()\nfig","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","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_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"formfactors = [FormFactor(1, \"Fe2\"; g_lande=3/2)]\nnew_formula = intensity_formula(sf, :perp; kT = kT, formfactors = formfactors)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Frequently one wants to extract energy intensities along lines that connect special wave vectors. The function connected_path linearly samples between provided q-points, with a given sample density.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","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, markers = connected_path(sf, points, density);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"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_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"is = intensities_interpolated(sf, path;\n interpolation = :linear, # Interpolate between available wave vectors\n formula = new_formula\n)\nis = broaden_energy(sf, is, (ω, ω₀)->lorentzian(ω-ω₀, 0.05)) # Add artificial broadening\n\nlabels = [\"($(p[1]),$(p[2]),$(p[3]))\" for p in points]\n\nheatmap(1:size(is,1), ωs(sf), is;\n axis = (\n ylabel = \"meV\",\n xticks = (markers, labels),\n xticklabelrotation=π/8,\n xticklabelsize=12,\n )\n)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Whereas intensities_interpolated either rounds or linearly interpolates between the discrete (Qomega) points Sunny calculates correlations at, intensities_binned performs histogram binning analgous to what is done in experiments. The graphs produced by each method are similar.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"cut_width = 0.3\ndensity = 15\nparamsList, markers, ranges = connected_path_bins(sf,points,density,cut_width)\n\ntotal_bins = ranges[end][end]\nenergy_bins = paramsList[1].numbins[4]\nis = zeros(Float64,total_bins,energy_bins)\nintegrated_kernel = integrated_lorentzian(0.05) # Lorentzian broadening\nfor k in 1:length(paramsList)\n h,c = intensities_binned(sf,paramsList[k];formula = new_formula,integrated_kernel = integrated_kernel)\n is[ranges[k],:] = h[:,1,1,:] ./ c[:,1,1,:]\nend\n\nheatmap(1:size(is,1), ωs(sf), is;\n axis = (\n ylabel = \"meV\",\n xticks = (markers, labels),\n xticklabelrotation=π/8,\n xticklabelsize=12,\n )\n)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Often it is useful to plot cuts across multiple wave vectors but at a single energy.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"npoints = 60\nqvals = range(-2, 2, length=npoints)\nqs = [[a, b, 0] for a in qvals, b in qvals]\n\nis = intensities_interpolated(sf, qs; formula = new_formula,interpolation = :linear);\n\nωidx = 30\nhm = heatmap(is[:,:,ωidx]; axis=(title=\"ω=$(ωs(sf)[ωidx]) meV\", aspect=true))\nColorbar(hm.figure[1,2], hm.plot)\nhidedecorations!(hm.axis); hidespines!(hm.axis)\nhm","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Note that Brillouin zones appear 'skewed'. This is a consequence of the fact that Sunny measures q-vectors as multiples of reciprocal lattice vectors, which are not orthogonal. It is often useful to express our wave vectors in terms of an orthogonal basis, where each basis element is specified as a linear combination of reciprocal lattice vectors. For our crystal, with reciprocal vectors a^*, b^* and c^*, we can define an orthogonal basis by taking hata^* = 05(a^* + b^*), hatb^*=a^* - b^*, and hatc^*=c^*. Below, we map qs to wavevectors ks in the new coordinate system and get their intensities.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"A = [0.5 1 0;\n 0.5 -1 0;\n 0 0 1]\nks = [A*q for q in qs]\n\nis_ortho = intensities_interpolated(sf, ks; formula = new_formula, interpolation = :linear)\n\nhm = heatmap(is_ortho[:,:,ωidx]; axis=(title=\"ω=$(ωs(sf)[ωidx]) meV\", aspect=true))\nColorbar(hm.figure[1,2], hm.plot)\nhidedecorations!(hm.axis); hidespines!(hm.axis)\nhm","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Finally, we note that instantaneous structure factor data, 𝒮(𝐪), can be obtained from a dynamic structure factor with instant_intensities_interpolated.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"is_static = instant_intensities_interpolated(sf, ks; formula = new_formula, interpolation = :linear)\n\nhm = heatmap(is_static; axis=(title=\"Instantaneous Structure Factor\", aspect=true))\nColorbar(hm.figure[1,2], hm.plot)\nhidedecorations!(hm.axis); hidespines!(hm.axis)\nhm","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":"This page was generated using Literate.jl.","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 DynamicalStructureFactor 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(1,\"Cu2\")]\nxtal = Crystal(latvecs,positions;types);\n\nsys = System(xtal, latsize, [SpinInfo(1;S = 1/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 = DynamicStructureFactor(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/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"EditURL = \"https://github.com/SunnySuite/Sunny.jl/blob/main/examples/binning_tutorial.jl\"","category":"page"},{"location":"examples/binning_tutorial/#Histogram-Binning-Tutorial","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"","category":"section"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"using Sunny, GLMakie","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"This Tutorial demonstrates how to use Sunny's histogram binning capabilities (via intensities_binned). This functionality allows the simulation data produced by Sunny to be compared to experimental data produced by Inelastic Neutron Scattering (INS) in an apples-to-apples fashion. Experimental data can be loaded from a MDHistoWorkspace stored in a .nxs file by the Mantid software using load_nxs.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"For this example, we will examine the CTFD compound, which is crystallographically approximately a square lattice. We specify the crystal lattice structure of CTFD using the lattice parameters specified by","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"W Wan et al 2020 J. Phys.: Condens. Matter 32 374007 DOI 10.1088/1361-648X/ab757a","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"latvecs = lattice_vectors(8.113,8.119,12.45,90,100,90)\npositions = [[0,0,0]]\ntypes = [\"Cu\"]\nformfactors = [FormFactor(1,\"Cu2\")]\nxtal = Crystal(latvecs,positions;types);\nnothing #hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"We will use a somewhat small periodic lattice size of 6x6x4 in order to showcase the effect of a finite lattice size.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"latsize = (6,6,4);\nnothing #hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"In this system, the magnetic lattice is the same as the chemical lattice, and there is a spin-1/2 dipole on each site.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"magxtal = xtal;\nvalS = 1/2;\nsys = System(magxtal, latsize, [SpinInfo(1;S = valS)], :dipole; seed=1);\nnothing #hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Quoted value of J = +6.19(2) meV (antiferromagnetic) between nearest neighbors on the square lattice","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"J = 6.19 # meV\ncharacteristic_energy_scale = abs(J * valS)\nset_exchange!(sys,J,Bond(1,1,[1,0,0]))\nset_exchange!(sys,J,Bond(1,1,[0,1,0]))","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Thermalize the system using the Langevin intergator. The timestep and the temperature are roughly based off the characteristic energy scale of the problem.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Δt = 0.05 / characteristic_energy_scale\nkT = 0.01 * characteristic_energy_scale\nlangevin = Langevin(Δt; λ=0.1, kT=kT)\nrandomize_spins!(sys);\nfor i in 1:10_000 # Long enough to reach equilibrium\n step!(sys, langevin)\nend","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"The neutron spectrometer used in the experiment had an incident neutron energy of 36.25 meV. Since this is the most amount of energy that can be deposited by the neutron into the sample, we don't need to consider energies higher than this.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"ωmax = 36.25;\nnothing #hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"We choose the resolution in energy (specified by the number of nω modes resolved) to be ≈20× better than the experimental resolution in order to demonstrate the effect of over-resolving in energy.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"nω = 480;\ndsf = DynamicStructureFactor(sys; Δt=Δt, nω=nω, ωmax=ωmax, process_trajectory=:symmetrize)","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"We re-sample from the thermal equilibrium distribution several times to increase our sample size","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"nsamples = 3\nfor _ in 1:nsamples\n for _ in 1:8000\n step!(sys, langevin)\n end\n add_sample!(dsf, sys)\nend","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Since the SU(N)NY crystal has only finitely many lattice sites, there are finitely many ways for a neutron to scatter off of the sample. We can visualize this discreteness by plotting each possible Qx and Qz, for example:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"params = unit_resolution_binning_parameters(dsf)#hide\nbin_rlu_as_absolute_units!(params,dsf)#hide\nlower_aabb_q, upper_aabb_q = Sunny.binning_parameters_aabb(params)#hide\nlower_aabb_cell = floor.(Int64,lower_aabb_q .* latsize .+ 1)#hide\nupper_aabb_cell = ceil.(Int64,upper_aabb_q .* latsize .+ 1)#hide\n\nQx = zeros(Float64,0)#hide\nQz = zeros(Float64,0)#hide\nfor cell in CartesianIndices(Tuple(((:).(lower_aabb_cell,upper_aabb_cell))))#hide\n q = (cell.I .- 1) ./ latsize # q is in R.L.U.#hide\n push!(Qx,q[1])#hide\n push!(Qz,q[3])#hide\nend#hide\nfig = Figure()#hide\nax = Axis(fig[1,1];xlabel=\"Qx [r.l.u]\",ylabel=\"Qz [r.l.u.]\")#hide\n# Compute some scattering vectors at and around the first BZ...\nscatter!(ax,Qx,Qz)\nfig#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"One way to display the structure factor is to create a histogram with one bin centered at each discrete scattering possibility using unit_resolution_binning_parameters to create a set of BinningParameters.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"params = unit_resolution_binning_parameters(dsf)","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Since this is a 4D histogram, it further has to be integrated over two of those directions in order to be displayed. Here, we integrate over Qy and Energy using integrate_axes!:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"integrate_axes!(params;axes = [2,4]) # Integrate over Qy (2) and E (4)","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Now that we have parameterized the histogram, we can bin our data. In addition to the BinningParameters, an intensity_formula needs to be provided to specify which dipole, temperature, and atomic form factor corrections should be applied during the intensity calculation.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"formula = intensity_formula(dsf, :perp; kT, formfactors)\nintensity,counts = intensities_binned(dsf, params; formula)\nnormalized_intensity = intensity ./ counts;\nnothing #hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"With the data binned, we can now plot it. The axes labels give the bin centers of each bin, as given by axes_bincenters.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"function plot_data(params) #hide\nintensity,counts = intensities_binned(dsf, params; formula)#hide\nnormalized_intensity = intensity ./ counts;#hide\nbin_centers = axes_bincenters(params);\n\nfig = Figure()#hide\nax = Axis(fig[1,1];xlabel=\"Qx [r.l.u]\",ylabel=\"Qz [r.l.u.]\")#hide\nheatmap!(ax,bin_centers[1],bin_centers[3],normalized_intensity[:,1,:,1])\nscatter!(ax,Qx,Qz)\nxlims!(ax,params.binstart[1],params.binend[1])\nylims!(ax,params.binstart[3],params.binend[3])\nreturn fig#hide\n\nend#hide\n\nplot_data(params)#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Note that some bins have no scattering vectors at all when the bin size is made too small:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"params = unit_resolution_binning_parameters(dsf)#hide\nintegrate_axes!(params;axes = [2,4])#hide\nparams.binwidth[1] /= 1.2\nparams.binwidth[3] /= 2.5\nplot_data(params)#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Conversely, making the bins bigger doesn't break anything, but loses resolution:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"params = unit_resolution_binning_parameters(dsf)#hide\nintegrate_axes!(params;axes = [2,4])#hide\nparams.binwidth[1] *= 2\nparams.binwidth[3] *= 2\nplot_data(params)#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Recall that while we under-resolved in Q by choosing a small lattice, we over-resolved in energy:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"x = zeros(Float64,0)#hide\ny = zeros(Float64,0)#hide\nfor omega = ωs(dsf), qx = unique(Qx)#hide\n push!(x,qx)#hide\n push!(y,omega)#hide\nend#hide\nax = Axis(fig[1,1];xlabel=\"Qx [r.l.u]\",ylabel=\"Energy [meV]\")#hide\nscatter!(ax,x,y)","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Let's make a new histogram which includes the energy axis. The x-axis of the histogram will be a 1D cut from Q = [0,0,0] to Q = [1,1,0]. See slice_2D_binning_parameters.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"x_axis_bin_count = 10\ncut_width = 0.3\nparams = slice_2D_binning_parameters(dsf,[0,0,0],[1,1,0],x_axis_bin_count,cut_width)","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"There are no longer any scattering vectors exactly in the plane of the cut. Instead, as described in the BinningParameters output above, the transverse Q directions are integrated over, so slightly out of plane points are included.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"We plot the intensity on a log-scale to improve visibility.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"intensity,counts = intensities_binned(dsf, params; formula)\nlog_intensity = log10.(intensity ./ counts);\nbin_centers = axes_bincenters(params);#hide\nfig = Figure()#hide\nax = Axis(fig[1,1];xlabel=\"Progress along cut [r.l.u]\",ylabel=\"Energy [meV]\")#hide\nheatmap!(ax,bin_centers[1],bin_centers[4],log_intensity[:,1,1,:])\nxlims!(ax,params.binstart[1],params.binend[1])#hide\nylims!(ax,params.binstart[4],params.binend[4])#hide\nfig#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"By reducing the number of energy bins to be closer to the number of bins on the x-axis, we can make the dispersion curve look nicer:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"params.binwidth[4] *= 20\nintensity,counts = intensities_binned(dsf, params; formula)#hide\nlog_intensity = log10.(intensity ./ counts);#hide\nbin_centers = axes_bincenters(params);#hide\nfig = Figure()#hide\nax = Axis(fig[1,1];xlabel=\"Progress along cut [r.l.u]\",ylabel=\"Energy [meV]\")#hide\nheatmap!(ax,bin_centers[1],bin_centers[4],log_intensity[:,1,1,:])\nxlims!(ax,params.binstart[1],params.binend[1])#hide\nylims!(ax,params.binstart[4],params.binend[4])#hide\nfig#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"This page was generated using Literate.jl.","category":"page"},{"location":"#Sunny.jl","page":"Overview","title":"Sunny.jl","text":"","category":"section"},{"location":"","page":"Overview","title":"Overview","text":"Sunny is a package for simulating classical spin systems, including the Landau-Lifshitz dynamics of spin dipoles and its generalization to multipolar spin components. The latter is especially powerful for modeling magnetic compounds with strong single-ion anisotropy interactions.","category":"page"},{"location":"","page":"Overview","title":"Overview","text":"Sunny provides the following features:","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.\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.\nEwald summation for long-range dipole-dipole interactions, accelerated with the fast Fourier transform (FFT).\nEstimation of the mathcalS(mathbfq omega) dynamical structure factor data, with options for various corrections (form factor, classical-to-quantum factors, ...)","category":"page"},{"location":"","page":"Overview","title":"Overview","text":"Work in progress includes:","category":"page"},{"location":"","page":"Overview","title":"Overview","text":"Linear spin wave theory and its generalization to SU(N) coherent states.\nInteractive visualizations of the 3D crystals and structure factor data.\nMPI-distributed Monte Carlo sampling, including parallel tempering.","category":"page"},{"location":"quick-start/#Install-Julia-and-Sunny","page":"Quick Start","title":"Install Julia and Sunny","text":"","category":"section"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Download Julia 1.8 or later. Run the Julia executable, which should open a terminal with the prompt: julia>. Load Sunny with the command:","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"using Sunny","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"If Sunny has not yet been installed, Julia will ask your permission to download and install it within the Julia environment.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"To learn more about Julia, read our Getting Started with Julia wiki page.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"For an interactive, notebook-like experience, we recommend the Julia extension for VSCode. Alternatively, the IJulia package provides Julia-enabled Jupyter notebooks.","category":"page"},{"location":"quick-start/#Example-usage","page":"Quick Start","title":"Example usage","text":"","category":"section"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"At the Julia prompt, create a diamond cubic crystal using the Crystal constructor:","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"crystal = Crystal(lattice_vectors(1, 1, 1, 90, 90, 90), [[0,0,0]], 227; setting=\"1\")","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"The first argument defines a unit cell via the convenience function lattice_vectors. The second argument is a list of basis atom positions. The third, optional argument specifies an international spacegroup number (if it's missing, Sunny will infer a spacegroup). Arguments appearing after the semicolon ; are named. Here, we are selecting the first (out of two) setting conventions for spacegroup 227.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Sunny outputs:","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Crystal\nHM symbol 'F d -3 m' (227)\nLattice params a=1, b=1, c=1, α=90°, β=90°, γ=90°\nCell volume 1\nWyckoff 8a (point group '-43m'):\n 1. [0, 0, 0]\n 2. [0.5, 0.5, 0]\n 3. [0.25, 0.25, 0.25]\n 4. [0.75, 0.75, 0.25]\n 5. [0.5, 0, 0.5]\n 6. [0, 0.5, 0.5]\n 7. [0.75, 0.25, 0.75]\n 8. [0.25, 0.75, 0.75]","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Observe that Sunny filled all eight symmetry-equivalent atom positions for the diamond cubic unit cell. The coordinates are measured in units of the lattice vectors.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Alternatively, Sunny can read the crystal structure from a .cif file. Or, if a complete list of atoms is provided, Sunny can infer the spacegroup symmetry using spglib.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"The crystal object can be used as an argument to other Sunny functions. For example, print_symmetry_table lists all symmetry-allowed exchange interactions up to a maximum distance,","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"print_symmetry_table(crystal, 0.8)","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"which prints,","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Atom 1\nPosition [0, 0, 0], multiplicity 8\nAllowed g-tensor: | A 0 0 |\n | 0 A 0 |\n | 0 0 A |\nAllowed anisotropy in Stevens operators 𝒪[k,q]:\n c₁*(𝒪[4,0]+5𝒪[4,4]) +\n c₂*(𝒪[6,0]-21𝒪[6,4])\n\nBond(1, 3, [0, 0, 0])\nDistance 0.433, coordination 4\nConnects [0, 0, 0] to [0.25, 0.25, 0.25]\nAllowed exchange matrix: | A B B |\n | B A B |\n | B B A |\n\nBond(1, 2, [0, 0, 0])\nDistance 0.7071, coordination 12\nConnects [0, 0, 0] to [0.5, 0.5, 0]\nAllowed exchange matrix: | A C -D |\n | C A -D |\n | D D B |\nAllowed DM vector: [-D D 0]","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Sunny reported that a single-ion anisotropy is only allowed at quartic and hexic orders, which is consistent with the cubic point group symmetry. Additionally, Sunny reported the allowed forms of nearest and next-nearest neighbor interaction.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"The next steps are typically the following","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Build a System which contains spins on a finite size lattice of crystal unit cells.\nAdd interactions to the system using functions like set_external_field!, set_exchange!, and set_onsite_coupling!.\nPerform Monte Carlo simulation to equilibrate the spin configuration. Options include the continuous Langevin dynamics, or single-spin flip updates with LocalSampler. The former can efficiently handle long-range dipole-dipole interactions, while the latter may be better in the presence of strong anisotropy (e.g., the Ising limit).\nMeasure the static or dynamical structure factor. For details, see the page Structure Factor Calculations.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"EditURL = \"https://github.com/SunnySuite/Sunny.jl/blob/main/examples/ising2d.jl\"","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/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"This page was generated using Literate.jl.","category":"page"}] +[{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"EditURL = \"https://github.com/SunnySuite/Sunny.jl/blob/main/examples/powder_averaging.jl\"","category":"page"},{"location":"examples/powder_averaging/#Powder-Averaging","page":"Powder Averaging","title":"Powder Averaging","text":"","category":"section"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"This tutorial gives a brief demonstration of how to calculate polycrystalline data using Sunny's structure factor tools.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"We begin by constructing a simple anti-ferromagnetic model on a diamond lattice.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"using Sunny, GLMakie\nusing Statistics: mean\n\ndims = (8,8,8) # Lattice dimensions\nseed = 1 # RNG seed for repeatable behavior\nJ = Sunny.meV_per_K*7.5413 # Nearest-neighbor exchange parameter\n\ncrystal = Sunny.diamond_crystal()\nsys = System(crystal, dims, [SpinInfo(1, S=3/2)], :dipole; seed)\nset_exchange!(sys, J, Bond(1, 3, [0,0,0]))","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"We next set up a Langevin integrator and thermalize the system.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Δt = 0.07 # Step size for Langevin integrator\nkT = Sunny.meV_per_K * 2 # Temperature of simulation (2K)\nλ = 0.1 # Damping parameter\nintegrator = Langevin(Δt; kT, λ);\n\nfor _ ∈ 1:3000\n step!(sys, integrator)\nend;\nnothing #hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"We can now estimate 𝒮(𝐪ω) with dynamical_correlations. We will tell Sunny to symmetrize the sample trajectory along the time-axis to minimize Fourier artifacts.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"sc = dynamical_correlations(sys;\n Δt=2Δt,\n nω=100,\n ωmax=5.5,\n process_trajectory=:symmetrize\n)\nadd_sample!(sc, sys)","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"To get some intuition about the expected results, we first look at the \"single crystal\" results along a high-symmetry path in the first Brillouin zone. While doing so, we will add some artificial broadening along the energy axis with broaden_energy. To use this function, it is necessary to define a kernel function with the form, kernel(ω, ω₀), where ω is energy and ω₀ is the center frequency of the kernel. In this example we apply some Lorentzian broadening using an anonymous function: (ω, ω₀) -> lorentzian(ω-ω₀, 0.1).","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","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]]\nqs, markers = connected_path(sc, qpoints, 50)\n\nis = intensities_interpolated(sc, qs; interpolation=:round, formula = intensity_formula(sc,:trace))\nis_broad = broaden_energy(sc, is, (ω, ω₀) -> lorentzian(ω-ω₀, 0.1))\n\n# Plot results\nfig = Figure(; resolution=(1000,400))\nxticklabels = [string(tuple(qs[i]...)) for i in markers]\nplotparams = (;\n aspect=1.4,\n ylabel = \"ω (meV)\",\n xlabel = \"𝐪 (RLU)\",\n xticks=(markers, xticklabels),\n xticklabelrotation=π/10,\n xticklabelsize=14,\n)\nax1 = Axis(fig[1,1]; title=\"No artificial broadening\", plotparams...)\nheatmap!(ax1, 1:size(is, 1), ωs(sc), is; colorrange=(0,0.5))\nax2 = Axis(fig[1,2]; title=\"Lorentzian broadening (η=0.1)\", plotparams...)\nheatmap!(ax2, 1:size(is, 1), ωs(sc), is_broad; colorrange=(0,2.0))\nfig","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"We next write a simple powder averaging function that takes a structure factor, a list of radius values (Å⁻¹), and a density parameter (Å⁻²) that will control the number of wave vectors to sample at each radius. For each radius r, the function will generate wavevectors on a sphere of this radius and retrieve their intensities_interpolated. These intensities will be broadened, as just demonstrated above, and then averaged to produce a single vector of energy-intensities for each r. Note that our powder_average function passes most of its keywords through to intensities_interpolated, so it can be given an intensity_formula.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"function powder_average(sc, rs, density; η=0.1, kwargs...)\n nω = length(ωs(sc))\n output = zeros(Float64, length(rs), nω)\n\n for (i, r) in enumerate(rs)\n qs = spherical_shell(sc, r, density) # Get points on a sphere of radius r\n if length(qs) == 0\n qs = [[0., 0., 0.]] # If no points (r is too small), just look at 0 vector\n end\n vals = intensities_interpolated(sc, qs; kwargs...) # Retrieve energy intensities\n vals[:,1] .*= 0.0 # Remove elastic peaks before broadening\n vals = broaden_energy(sc, vals, (ω,ω₀)->lorentzian(ω-ω₀, η)) # Apply Lorentzian broadening\n output[i,:] = reshape(mean(vals, dims=1), (nω,)) # Average single radius results and save\n end\n\n return output\nend;\nnothing #hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Finally, we perform the calculation,","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"rs = range(0, 6π, length=55) # Set of radius values\nη = 0.05 # Lorentzian broadening parameter\ndensity = 0.15 # Number of samples in Å⁻²\n\nformula = intensity_formula(sc,:perp)\npa = powder_average(sc, rs, density; η, formula);\nnothing #hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"and plot the results.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"fig1= Figure()\nax = Axis(fig1[1,1]; xlabel = \"|Q| (Å⁻¹)\", ylabel = \"ω (meV)\")\nheatmap!(ax, rs, ωs(sc), pa; colorrange=(0, 25.0))\nfig1","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Note that the bandwidth is similar to what we saw above along the high symmetry path.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"This was a very quick calculation. The structure factor calculation itself and the powder averaging will each execute in < 10 s on a typical laptop. Higher quality results can be obtained by:","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Increasing the number of samples used to calculate 𝒮(𝐪ω) using add_sample!\nIncreasing the system size to improve momentum space resolution\nIncreasing the energy resolution (nω keyword of dynamical_correlations)\nApplying instrument-specific energy broadening by giving broaden_energy a custom kernel function.\nIncluding FormFactor corrections\nSetting interpolation=:linear when retrieving intensities in the powder averaging loop.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"The intensity data can alternatively be collected into bonafide histogram bins. See integrated_lorentzian, powder_average_binned, and axes_bincenters.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"radial_binning_parameters = (0,6π,6π/55)\nintegrated_kernel = integrated_lorentzian(0.05) # Lorentzian broadening\n\npa_intensities, pa_counts = powder_average_binned(sc,radial_binning_parameters;integrated_kernel = integrated_kernel,formula)\n\npa_normalized_intensities = pa_intensities ./ pa_counts\n\nfig = Figure()\nax = Axis(fig[1,1]; xlabel = \"|k| (Å⁻¹)\", ylabel = \"ω (meV)\")\nrs_bincenters = axes_bincenters(radial_binning_parameters...)\nheatmap!(ax, rs_bincenters[1], ωs(sc), pa_normalized_intensities; colorrange=(0,3.0))\nfig","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"The striations in the graph tell us that the simulation is under resolved for this bin size. We should increase the size of either the periodic lattice, or the bins.","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Using the bzsize option, we can even resolve the contribution from each brillouin zone:","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"intensity_firstBZ, counts_firstBZ = powder_average_binned(sc,radial_binning_parameters;integrated_kernel = integrated_kernel, bzsize=(1,1,1),formula)\n#intensity_secondBZ, counts_secondBZ = powder_average_binned(..., bzsize=(2,2,2))\nintensity_secondBZ, counts_secondBZ = powder_average_binned(sc,radial_binning_parameters;integrated_kernel = integrated_kernel, bzsize=(2,2,2),formula)#hide\n#intensity_thirdBZ, counts_thirdBZ = powder_average_binned(..., bzsize=(3,3,3))\nintensity_thirdBZ = pa_intensities;#hide\ncounts_thirdBZ = pa_counts;#hide\nnothing #hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"First BZ:","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"fig = Figure()#hide\nax = Axis(fig[1,1]; xlabel = \"|k| (Å⁻¹)\", ylabel = \"ω (meV)\")#hide\nrs_bincenters = axes_bincenters(radial_binning_parameters...)#hide\nheatmap!(ax, rs_bincenters[1], ωs(sc),\n intensity_firstBZ ./ counts_firstBZ\n ; colorrange=(0,3.0))\nfig#hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Second BZ:","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"fig = Figure()#hide\nax = Axis(fig[1,1]; xlabel = \"|k| (Å⁻¹)\", ylabel = \"ω (meV)\")#hide\nrs_bincenters = axes_bincenters(radial_binning_parameters...)#hide\nheatmap!(ax, rs_bincenters[1], ωs(sc),\n (intensity_secondBZ .- intensity_firstBZ) ./ (counts_secondBZ .- counts_firstBZ)\n ; colorrange=(0,3.0))\nfig#hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"Third BZ:","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"fig = Figure()#hide\nax = Axis(fig[1,1]; xlabel = \"|k| (Å⁻¹)\", ylabel = \"ω (meV)\")#hide\nrs_bincenters = axes_bincenters(radial_binning_parameters...)#hide\nheatmap!(ax, rs_bincenters[1], ωs(sc),\n (intensity_thirdBZ .- intensity_secondBZ) ./ (counts_thirdBZ .- counts_secondBZ)\n ; colorrange=(0,3.0))\nfig#hide","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"","category":"page"},{"location":"examples/powder_averaging/","page":"Powder Averaging","title":"Powder Averaging","text":"This page was generated using Literate.jl.","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":"This version includes many breaking changes.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Added support for Dipole-mode Linear Spin Wave Theory. (Thanks Hao Zhang!)","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Split intensities into calculation (intensity_formula) and presentation (intensities_interpolated, intensities_binned). This is a breaking change, see the docs to migrate your code.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"StructureFactor type renamed SampledCorrelations. An appropriate SampledCorrelations is created by calling either dynamical_correlations or instant_correlations(@ref) instead of DynamicStructureFactor or InstantStructureFactor.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Broadened support for custom observables in SampledCorrelations for use in intensity_formula.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Added function load_nxs to load experimental neutron scattering data to compare with intensities_binned.","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":"Replace set_biquadratic! with an optional keyword argument biquad to set_exchange!.","category":"page"},{"location":"versions/","page":"Version History","title":"Version History","text":"Symbolic representations of operators are now hidden unless the package DynamicPolynomials is explicitly loaded by the user. The functionality of print_anisotropy_as_stevens has been replaced with print_classical_stevens_expansion, while print_anisotropy_as_classical_spins has become print_classical_spin_polynomial.","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":"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":"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.𝒪","page":"Library API","title":"Sunny.𝒪","text":"𝒪[k,q]\n\nAbstract symbols for the Stevens operators. Linear combinations of these can be used to define a single-ion anisotropy.\n\n\n\n\n\n","category":"constant"},{"location":"library/#Sunny.𝒮","page":"Library API","title":"Sunny.𝒮","text":"𝒮[1], 𝒮[2], 𝒮[3]\n\nAbstract symbols for the spin operators. Polynomials of these can be used to define a single-ion anisotropy.\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 (k,ω) with each row of the covectors matrix, with k given in absolute units. Since the default covectors matrix is the identity matrix, the default axes are (kx,ky,kz,ω) in absolute units. To bin (q,ω) values given in reciprocal lattice units (R.L.U.) instead, see bin_rlu_as_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{Int64, Union{Nothing, String}}","page":"Library API","title":"Sunny.FormFactor","text":"FormFactor(atom::Int64, elem::String; g_lande=nothing)\n\nBasic type for specifying form factor parameters. Must be provided a site within the unit cell (atom) and a string specifying the element name. This used when creating an intensity_formula, which accepts a list of FormFactorss.\n\nA list of supported element names is available at:\n\nhttps://www.ill.eu/sites/ccsl/ffacts/ffachtml.html\n\nThe Landé g-factor may also be specified. \n\nIn more detail, the data stored in a FormFactor will be used to compute the form factor for each momentum space magnitude |k|, measured in inverse angstroms. The result is dependent on the magnetic ion species. By default, a first order form factor f is returned. If the keyword g_lande is given a numerical value, then a second order form factor F is returned.\n\nIt is traditional to define the form factors using a sum of Gaussian broadening functions in the scalar variable s = k4π, where k can be interpreted as the magnitude of momentum transfer.\n\nThe Neutron Data Booklet, 2nd ed., Sec. 2.5 Magnetic Form Factors, defines the approximation\n\nlangle j_l(s) rangle = A e^-as^2 + B e^-bs^2 + Ce^-cs^2 + D\n\nwhere coefficients A B C D a b c are obtained from semi-empirical fits, depending on the orbital angular momentum index l = 0 2. For transition metals, the form-factors are calculated using the Hartree-Fock method. For rare-earth metals and ions, Dirac-Fock form is used for the calculations.\n\nA first approximation to the magnetic form factor is\n\nf(s) = langle j_0(s) rangle\n\nA second order correction is given by\n\nF(s) = frac2-gg langle j_2(s) rangle s^2 + f(s), where g is the Landé g-factor. \n\nDigital tables are available at:\n\nhttps://www.ill.eu/sites/ccsl/ffacts/ffachtml.html\n\nAdditional references are:\n\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)\nDescleaux 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\nExperimental. Constructs 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.all_exact_wave_vectors-Tuple{SampledCorrelations}","page":"Library API","title":"Sunny.all_exact_wave_vectors","text":"all_exact_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.all_sites-Tuple{System}","page":"Library API","title":"Sunny.all_sites","text":"all_sites(sys::System)\n\nAn iterator over all Sites in the system. \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.bin_absolute_units_as_rlu!","page":"Library API","title":"Sunny.bin_absolute_units_as_rlu!","text":"If params expects to bin values (k,ω) in absolute units, then calling\n\nbin_rlu_as_absolute_units!(params::BinningParameters,[reciprocal lattice vectors])\n\nwill modifiy the covectors in params so that they will accept (q,ω) in Reciprocal Lattice Units (R.L.U.) instead. Conversly, if params expects (q,ω) R.L.U., calling\n\nbin_absolute_units_as_rlu!(params::BinningParameters,[reciprocal lattice vectors])\n\nwill adjust params to instead accept (k,ω) absolute units.\n\nThe second argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:\n\nCrystal\nSystem\nSampledCorrelations\nSpinWaveTheory\n\n\n\n\n\n","category":"function"},{"location":"library/#Sunny.bin_rlu_as_absolute_units!","page":"Library API","title":"Sunny.bin_rlu_as_absolute_units!","text":"If params expects to bin values (k,ω) in absolute units, then calling\n\nbin_rlu_as_absolute_units!(params::BinningParameters,[reciprocal lattice vectors])\n\nwill modifiy the covectors in params so that they will accept (q,ω) in Reciprocal Lattice Units (R.L.U.) instead. Conversly, if params expects (q,ω) R.L.U., calling\n\nbin_absolute_units_as_rlu!(params::BinningParameters,[reciprocal lattice vectors])\n\nwill adjust params to instead accept (k,ω) absolute units.\n\nThe second argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:\n\nCrystal\nSystem\nSampledCorrelations\nSpinWaveTheory\n\n\n\n\n\n","category":"function"},{"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.connected_path-Tuple{Any, Vector, Any}","page":"Library API","title":"Sunny.connected_path","text":"connected_path(recip_vecs, qs::Vector, density)\n\nTakes a list of wave vectors, qs, and builds an expanded list of wave vectors that traces a path through the provided points. Also returned is a list of marker indices corresponding to the input points. The density parameter is given in samples per inverse Å.\n\nInstead of recip_vecs, the first argument may be either a SampledCorrelations or a SpinWaveTheory.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.connected_path_bins-Tuple{Any, Any, Any, Any, Vararg{Any}}","page":"Library API","title":"Sunny.connected_path_bins","text":"connected_path_bins(sc,qs,density,args...;kwargs...)\n\nTakes a list of wave vectors, qs, 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.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\nExperimental. 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 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\nExperimental. Given 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. I.e., q_i is given in 2πa_i with a_i the lattice constant of the 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 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":"dynamic_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.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. Take care to ensure the units are correct (R.L.U. or absolute). You may want to call bin_rlu_as_absolute_units! or 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 all_sites as below:\n\npos = [global_position(sys, site) for site in all_sites(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}","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}","page":"Library API","title":"Sunny.intensities_bands","text":"dispersion, intensities = intensities_bands(swt::SpinWaveTheory, qs; [formula])\n\nComputes the scattering intensities at each energy band for each q in qs, according to Linear Spin Wave Theory and the given intensity formula. The optional formula must have a delta-function kernel, e.g.:\n\nformula = intensity_formula(swt; 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 qs, 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}","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, or intensity_formula(sc,:perp) by default.\n\nThe BinningParameters are expected to accept (k,ω) in absolute units.\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 η. 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].\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, qs, ω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; 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 qs and each energy in ωvals. The output will be an array with indices identical to qs, with the last index matching ωvals.\n\nNote that qs is an array of wave vectors of arbitrary dimension. Each element q of qs must be a 3-vector in reciprocal lattice units. I.e., qᵢ is given in 2πaᵢ with aᵢ the lattice constant of the chemical lattice.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.intensities_interpolated-Tuple{SampledCorrelations, Any}","page":"Library API","title":"Sunny.intensities_interpolated","text":"intensities_interpolated(sc::SampledCorrelations, qs; interpolation = nothing, formula = intensity_formula(sc,:perp), 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 ωs. 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, Any}","page":"Library API","title":"Sunny.intensity_formula","text":"formula = intensity_formula(sc::SampledCorrelations; kwargs...)\nformula.calc_intensity(sc,q,ix_q,ix_ω)\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\nSunny has several built-in formulas that can be selected by setting contraction_mode to one of these values:\n\n:perp (default), which contracts 𝒮^αβ(qω) with the dipole factor δ_αβ - q_αq_β, returning the unpolarized intensity.\n:trace, which yields operatornametr 𝒮(qω) = _α 𝒮^αα(qω)\n:full, which will return all elements 𝒮^αβ(𝐪ω) without contraction.\n\nAdditionally, there 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 vector of FormFactors, one for each unique site in the unit cell. The form factors will be symmetry propagated to all equivalent sites.\n\nAlternatively, a custom 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.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.plot_spins-Tuple{System}","page":"Library API","title":"Sunny.plot_spins","text":"plot_spins(sys::System; linecolor=:grey, arrowcolor=:red, linewidth=0.1,\n arrowsize=0.3, arrowlength=1.0, kwargs...)\n\nPlot the spin configuration defined by sys. kwargs are passed to Makie.arrows. \n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.polarize_spin!-Union{Tuple{N}, Tuple{System{N}, Any, Any}} where N","page":"Library API","title":"Sunny.polarize_spin!","text":"polarize_spin!(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.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_geometry.\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}","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_classical_spin_polynomial-Tuple{Any}","page":"Library API","title":"Sunny.print_classical_spin_polynomial","text":"function print_classical_spin_polynomial(op)\n\nPrints an operator (e.g., a linear combination of Stevens operators 𝒪) as a polynomial in the classical dipole components.\n\nThis function works in the \"large-S\" classical limit, which corresponds to replacing each spin operator with its expected dipole. There are ambiguities in defining this limit at sub-leading order in S. The procedure in Sunny is as follows: First, uniquely decompose op as a linear combination of Stevens operators, each of which is defined as a polynomial in the spin operators. To take the large-S limit, Sunny replaces each Stevens operator with a corresponding polynomial in the expected dipole components, keeping only leading order terms in S. The resulting \"classical Stevens functions\" are essentially the spherical harmonics Yᵐₗ, up to m- and l- dependent scaling factors.\n\nExample\n\nusing DynamicPolynomials, Sunny\n\nprint_classical_spin_polynomial((1/4)𝒪[4,4] + (1/20)𝒪[4,0] + (3/5)*(𝒮'*𝒮)^2)\n# Prints: 𝒮₁⁴ + 𝒮₂⁴ + 𝒮₃⁴\n\nSee also print_classical_stevens_expansion for the inverse mapping.\n\n\n\n\n\n","category":"method"},{"location":"library/#Sunny.print_classical_stevens_expansion-Tuple{Any}","page":"Library API","title":"Sunny.print_classical_stevens_expansion","text":"function print_classical_stevens_expansion(op)\n\nPrints an operator (e.g. a polynomial of the spin operators 𝒮) as a linear combination of Stevens operators. This function works in the large-S classical limit, as described in the documentation for print_classical_spin_polynomial.\n\nIn the output, the symbol X denotes the spin magnitude squared, which can be entered symbolically as 𝒮'*𝒮.\n\nExamples\n\nusing DynamicPolynomials, Sunny\n\nprint_classical_stevens_expansion(𝒮[1]^4 + 𝒮[2]^4 + 𝒮[3]^4)\n# Prints: (1/20)𝒪₄₀ + (1/4)𝒪₄₄ + (3/5)X²\n\nSee also print_classical_spin_polynomial for the inverse mapping.\n\nThe function print_stevens_expansion is analogous to this one, but expects a quantum operator in a finite-S representation.\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. The analogous function in the large-S classical limit is print_classical_stevens_expansion.\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.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_geometry-Union{Tuple{N}, Tuple{System{N}, Any}} where N","page":"Library API","title":"Sunny.reshape_geometry","text":"reshape_geometry(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_periodically-Union{Tuple{N}, Tuple{System{N}, Tuple{Int64, Int64, Int64}}} where N","page":"Library API","title":"Sunny.resize_periodically","text":"resize_periodically(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_geometry 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.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, units = :absolute)\n\nCreates BinningParameters which make a 1D cut in 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 orientation of the binning in the transverse directions is determined automatically using plane_normal. The width of the bins in the transverse direciton is controlled by cut_width and cut_height.\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\nSetting units = :rlu returns BinningParameters which accept values in R.L.U. instead of absolute units.\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.spherical_shell-Tuple{SampledCorrelations, Any, Any}","page":"Library API","title":"Sunny.spherical_shell","text":"spherical_shell(sc::SampledCorrelations, radius, density)\n\nReturns a set of wave vectors lying on a sphere of specified radius, where radius is given in Å^-1. density controls how many points to select per Å^-2. \n\nThe points are generated by mapping a Fibonacci lattice onto a sphere. \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; units = :absolute)\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\nSetting units = :rlu returns BinningParameters which accept values in R.L.U. instead of absolute units.\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]; [units])\n\nAs in bin_absolute_units_as_rlu!, the last argument may be a 3x3 matrix specifying the reciprocal lattice vectors, or any of these objects:\n\nCrystal\nSystem\nSampledCorrelations\nSpinWaveTheory\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.ωs-Tuple{SampledCorrelations}","page":"Library API","title":"Sunny.ωs","text":"ωs(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.@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/#Plotting","page":"Library API","title":"Plotting","text":"","category":"section"},{"location":"library/","page":"Library API","title":"Library API","text":"To reduce package load times, certain plotting functions are only available when the user explicitly loads Makie, e.g., with using GLMakie or using WGLMakie.","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-correlation-data","page":"Structure Factor Calculations","title":"Extracting information from 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 and a list of wave vectors. For example, intensities_interpolated(sf, [[0.0, 0.5, 0.5]]) will calculate intensities for the wavevector 𝐪 = (𝐛_2 + 𝐛_3)2. The keyword argument formula can be used to specify an intensity_formula for greater control over the intensity calculation. The default formula performs a contraction of 𝒮^αβ(𝐪ω) that includes polarization corrections. intensities_interpolated returns a list of nω elements at each wavevector. The corresponding ω values can be retrieved by calling ωs on sf.","category":"page"},{"location":"structure-factor/","page":"Structure Factor Calculations","title":"Structure Factor Calculations","text":"Since Sunny currently only calculates the structure factor on a finite lattice, 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 all_exact_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 connected_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, spherical_shell will provide a list of wave vectors on a sphere of a specified 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 structure factor, 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":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"EditURL = \"https://github.com/SunnySuite/Sunny.jl/blob/main/examples/fei2_tutorial.jl\"","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 classical dynamics of SU(N) coherent state 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/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Begin by importing Sunny and GLMakie, a plotting package.","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 you see an error Package not found in current path, add the package by typing ] add at the Julia prompt.","category":"page"},{"location":"examples/fei2_tutorial/#Crystals-and-symmetry-analysis","page":"Case Study: FeI_2","title":"Crystals and symmetry analysis","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/#Spin-systems","page":"Case Study: FeI_2","title":"Spin systems","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"To simulate a system of many spins, construct a System.","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)], :SUN, seed=2)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The system includes 444 unit cells, i.e. 64 Fe atoms, each with spin S=1. The default g-factor is 2, but this could be overriden with an additional argument to SpinInfo. Spin S=1 involves a superposition of 2S+1=3 distinct angular momentum states. In :SUN mode, this superposition will be modeled 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/#Interactions-and-anisotropies","page":"Case Study: FeI_2","title":"Interactions and anisotropies","text":"","category":"section"},{"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 next step is to add interactions to the system. The command print_symmetry_table shows all 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/#Assigning-interactions-and-anisotropies","page":"Case Study: FeI_2","title":"Assigning interactions and anisotropies","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The function set_exchange! assigns an exchange interaction to a bond, and will propagate the 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 structure factors using generalized SU(N) classical dynamics. This will involve the sampling of spin configurations from the Boltzmann distribution at a finite temperature. Spin-spin correlations measured dynamically then provide an estimate of the structure factor mathcalS^alphabeta(mathbfqomega).","category":"page"},{"location":"examples/fei2_tutorial/#Simulated-annealing","page":"Case Study: FeI_2","title":"Simulated annealing","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The Langevin dynamics of SU(N) coherent states can be used to sample spin configurations in thermal equlibrium. Begin by constructing a Langevin object.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Δt = 0.05/D # Single-ion anisotropy is the strongest interaction, so 1/D is","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"a natural dynamical time-scale (in units with ħ=1).","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"λ = 0.1 # Dimensionless magnitude of coupling to thermal bath\nlangevin = Langevin(Δt; kT=0, λ);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Attempt to find a low-energy spin configuration by lowering the temperature kT from 2 to 0 using 20,000 Langevin time-steps.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"randomize_spins!(sys)\nfor kT in range(2, 0, 20_000)\n langevin.kT = kT\n step!(sys, langevin)\nend","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Because the quench was relatively fast, it is expected to find defects in the magnetic order. These can be visualized.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"plot_spins(sys; arrowlength=2.5, linewidth=0.75, arrowsize=1.5)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"If we had used a slower annealing procedure, involving 100,000 or more Langevin time-steps, it would very likely find the correct ground state. Instead, for purposes of illustration, let's analyze the imperfect spin configuration currently stored in sys.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"An experimental probe of magnetic order order is the 'instantaneous' or 'static' structure factor intensity, available via instant_correlations and related functions. To infer periodicities of the magnetic supercell, however, it is sufficient to look at the structure factor weights of spin sublattices individually, without phase averaging. This information is provided by print_wrapped_intensities (see the API documentation for a physical interpretation).","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 above is consistent with known results. The zero-field energy-minimizing magnetic structure of FeI_2 is single-q. If annealing were perfect, then spontaneous symmetry breaking would select one of q = 0 -14 14, 14 0 14, or -141414.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Let's break the symmetry by hand. Given a list of q modes, Sunny can suggest a magnetic supercell with appropriate periodicity. The result is printed 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_geometry allows an arbitrary reshaping of the system. After selecting the supercell geometry, it becomes much easier to find the energy-minimizing spin configuration.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sys_supercell = reshape_geometry(sys, [1 0 0; 0 1 -2; 0 1 2])\n\nlangevin.kT = 0\nfor i in 1:10_000\n step!(sys_supercell, langevin)\nend\n\nplot_spins(sys_supercell; arrowlength=2.5, linewidth=0.75, arrowsize=1.5)","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_supercell);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The dispersion relation can be calculated by providing dispersion with a SpinWaveTheory and a list of wave vectors. For each wave vector, dispersion will return a list of energies, one for each band. Frequently one wants dispersion information along lines that connect special wave vectors. The function connected_path linearly samples between provided q-points, with a given sample density.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","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]]\nlabels = [\"($(p[1]),$(p[2]),$(p[3]))\" for p in points]\ndensity = 600\npath, markers = connected_path(swt, points, density);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"dispersion may now be called on the wave vectors along the generated path. Each column of the returned matrix corresponds to a different mode.","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 omega_i, Sunny can calculate the inelastic neutron scattering intensity I(qomega_i(q)) according to an intensity_formula. The default formula applies a polarization correction (1 - Qotimes Q).","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"formula = intensity_formula(swt; kernel = delta_function_kernel)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The 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":"disp, intensity = intensities_bands(swt, path; formula = formula)\n\nfig = Figure()\nax = Axis(fig[1,1]; xlabel=\"𝐪\", ylabel=\"Energy (meV)\",\n xticks=(markers, labels), xticklabelrotation=π/6,\n)\nylims!(ax, 0.0, 7.5)\nxlims!(ax, 1, size(disp, 1))\nfor i in axes(disp)[2]\n lines!(ax, 1:length(disp[:,i]), disp[:,i]; color=intensity[:,i])\nend\nfig","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"For comparison with inelastic neutron scattering (INS) data, it's often appropriate to apply a lorentzian broadening to the bands.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"γ = 0.05 # Lorentzian broadening parameter\nbroadened_formula = intensity_formula(swt; kernel = lorentzian(γ))","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The broadened intensity can be calculated for any (qomega) using intensities_broadened:","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"energies = collect(0.0:0.01:7.5) # Energies to calculate\nis = intensities_broadened(swt, path, energies, broadened_formula)\n\nheatmap(1:size(is, 1), energies, is;\n axis=(xlabel = \"(H,0,0)\", ylabel=\"Energy (meV)\", xticks=(markers, labels),\n xticklabelrotation=π/8,\n ),\n)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The existence of a lower-energy, single-ion bound state is in qualitative agreement with the experimental data in Bai et al. (Note that the publication figure uses a different coordinate system to label the same wave vectors and the experimental data necessarily averages over the three degenerate ground states.)","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 full data from the dynamical spin structure factor (DSSF) can be retrieved with the dssf function. Like dispersion and intensities, dssf takes an array of wave vectors.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"disp, Sαβ = dssf(swt, [[0, 0, 0]]);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"disp is identical to the output that is obtained from dispersion and contains the energy of each mode at the specified wave vectors. Sαβ contains a 3x3 matrix for each of these modes. The matrix elements of Sαβ correspond to correlations of the different spin components (ordered x, y, z). For example, the full set of matrix elements for the first mode may be obtained as follows,","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Sαβ[1]","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"and the xx matrix element is","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Sαβ[1][1,1]","category":"page"},{"location":"examples/fei2_tutorial/#Dynamical-structure-factors-with-classical-dynamics","page":"Case Study: FeI_2","title":"Dynamical structure factors with classical dynamics","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Linear spin wave calculations are very useful for getting quick, high-quality, results at zero temperature. Moreover, these results are obtained in the thermodynamic limit. Classical dynamics may also be used to produce similar results, albeit at a higher computational cost and on a finite sized lattice. The classical approach nonetheless provides a number of complementary advantages: it is possible perform simulations at finite temperature while retaining nonlinearities; out-of-equilibrium behavior may be examined directly; and it is straightforward to incorporate inhomogenties, chemical or otherwise.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Because classical simulations are conducted on a finite-sized lattice, obtaining acceptable resolution in momentum space requires the use of a larger system size. We can now resize the magnetic supercell to a much larger simulation volume, provided as multiples of the original unit cell.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sys_large = resize_periodically(sys_supercell, (16,16,4))\nplot_spins(sys_large; arrowlength=2.5, linewidth=0.75, arrowsize=1.5)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Apply Langevin dynamics to thermalize the system to a target temperature.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"kT = 0.5 * meV_per_K # 0.5K in units of meV\nlangevin.kT = kT\n\nfor _ in 1:10_000\n step!(sys_large, langevin)\nend","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"To estimate the dynamic structure factor, we can collect spin-spin correlation data by first generating an initial condition at thermal equilibrium and then integrating the Hamiltonian dynamics of SU(N) coherent states. Samples are accumulated into a SampledCorrelations, which is initialized by calling dynamical_correlations. 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_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sc = dynamical_correlations(sys_large; Δt=2Δt, nω=120, ωmax=7.5)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"sc currently contains no data. A sample can be accumulated into it by calling add_sample!.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"add_sample!(sc, sys_large)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Additional samples can be added after generating new spin configurations:","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"for _ in 1:2\n for _ in 1:1000 # Fewer steps needed in equilibrium\n step!(sys_large, langevin)\n end\n add_sample!(sc, sys_large) # Accumulate the sample into `sc`\nend","category":"page"},{"location":"examples/fei2_tutorial/#Accessing-structure-factor-data","page":"Case Study: FeI_2","title":"Accessing structure factor data","text":"","category":"section"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"The basic functions for accessing intensity data are intensities_interpolated and intensities_binned. Both functions accept an intensity_formula to specify how to combine the correlations recorded in the SampledCorrelations into intensity data. By default, a formula computing the unpolarized intensity is used, but alternative formulas can be specified.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"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_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"formula = intensity_formula(sc, :trace; kT = kT)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Using the formula, we plot single-q slices at (0,0,0) and (π,π,π):","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"qs = [[0, 0, 0], [0.5, 0.5, 0.5]]\nis = intensities_interpolated(sc, qs; interpolation = :round, formula = formula)\n\nfig = lines(ωs(sc), is[1,:]; axis=(xlabel=\"meV\", ylabel=\"Intensity\"), label=\"(0,0,0)\")\nlines!(ωs(sc), is[2,:]; label=\"(π,π,π)\")\naxislegend()\nfig","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","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_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"formfactors = [FormFactor(1, \"Fe2\"; g_lande=3/2)]\nnew_formula = intensity_formula(sc, :perp; kT = kT, formfactors = formfactors)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Frequently one wants to extract energy intensities along lines that connect special wave vectors. The function connected_path linearly samples between provided q-points, with a given sample density.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","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, markers = connected_path(sc, points, density);\nnothing #hide","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"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_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"is = intensities_interpolated(sc, path;\n interpolation = :linear, # Interpolate between available wave vectors\n formula = new_formula\n)\nis = broaden_energy(sc, is, (ω, ω₀)->lorentzian(ω-ω₀, 0.05)) # Add artificial broadening\n\nlabels = [\"($(p[1]),$(p[2]),$(p[3]))\" for p in points]\n\nheatmap(1:size(is,1), ωs(sc), is;\n axis = (\n ylabel = \"meV\",\n xticks = (markers, labels),\n xticklabelrotation=π/8,\n xticklabelsize=12,\n )\n)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Whereas intensities_interpolated either rounds or linearly interpolates between the discrete (Qomega) points Sunny calculates correlations at, intensities_binned performs histogram binning analgous to what is done in experiments. The graphs produced by each method are similar.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"cut_width = 0.3\ndensity = 15\nparamsList, markers, ranges = connected_path_bins(sc,points,density,cut_width)\n\ntotal_bins = ranges[end][end]\nenergy_bins = paramsList[1].numbins[4]\nis = zeros(Float64,total_bins,energy_bins)\nintegrated_kernel = integrated_lorentzian(0.05) # Lorentzian broadening\nfor k in 1:length(paramsList)\n h,c = intensities_binned(sc,paramsList[k];formula = new_formula,integrated_kernel = integrated_kernel)\n is[ranges[k],:] = h[:,1,1,:] ./ c[:,1,1,:]\nend\n\nheatmap(1:size(is,1), ωs(sc), is;\n axis = (\n ylabel = \"meV\",\n xticks = (markers, labels),\n xticklabelrotation=π/8,\n xticklabelsize=12,\n )\n)","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Often it is useful to plot cuts across multiple wave vectors but at a single energy.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"npoints = 60\nqvals = range(-2, 2, length=npoints)\nqs = [[a, b, 0] for a in qvals, b in qvals]\n\nis = intensities_interpolated(sc, qs; formula = new_formula,interpolation = :linear);\n\nωidx = 30\nhm = heatmap(is[:,:,ωidx]; axis=(title=\"ω=$(ωs(sc)[ωidx]) meV\", aspect=true))\nColorbar(hm.figure[1,2], hm.plot)\nhidedecorations!(hm.axis); hidespines!(hm.axis)\nhm","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Note that Brillouin zones appear 'skewed'. This is a consequence of the fact that Sunny measures q-vectors as multiples of reciprocal lattice vectors, which are not orthogonal. It is often useful to express our wave vectors in terms of an orthogonal basis, where each basis element is specified as a linear combination of reciprocal lattice vectors. For our crystal, with reciprocal vectors a^*, b^* and c^*, we can define an orthogonal basis by taking hata^* = 05(a^* + b^*), hatb^*=a^* - b^*, and hatc^*=c^*. Below, we map qs to wavevectors ks in the new coordinate system and get their intensities.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"A = [0.5 1 0;\n 0.5 -1 0;\n 0 0 1]\nks = [A*q for q in qs]\n\nis_ortho = intensities_interpolated(sc, ks; formula = new_formula, interpolation = :linear)\n\nhm = heatmap(is_ortho[:,:,ωidx]; axis=(title=\"ω=$(ωs(sc)[ωidx]) meV\", aspect=true))\nColorbar(hm.figure[1,2], hm.plot)\nhidedecorations!(hm.axis); hidespines!(hm.axis)\nhm","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"Finally, we note that instantaneous structure factor data, 𝒮(𝐪), can be obtained from a dynamic structure factor with instant_intensities_interpolated.","category":"page"},{"location":"examples/fei2_tutorial/","page":"Case Study: FeI_2","title":"Case Study: FeI_2","text":"is_static = instant_intensities_interpolated(sc, ks; formula = new_formula, interpolation = :linear)\n\nhm = heatmap(is_static; axis=(title=\"Instantaneous Structure Factor\", aspect=true))\nColorbar(hm.figure[1,2], hm.plot)\nhidedecorations!(hm.axis); hidespines!(hm.axis)\nhm","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":"This page was generated using Literate.jl.","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(1,\"Cu2\")]\nxtal = Crystal(latvecs,positions;types);\n\nsys = System(xtal, latsize, [SpinInfo(1;S = 1/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/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"EditURL = \"https://github.com/SunnySuite/Sunny.jl/blob/main/examples/binning_tutorial.jl\"","category":"page"},{"location":"examples/binning_tutorial/#Histogram-Binning-Tutorial","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"","category":"section"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"using Sunny, GLMakie","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"This Tutorial demonstrates how to use Sunny's histogram binning capabilities (via intensities_binned). This functionality allows the simulation data produced by Sunny to be compared to experimental data produced by Inelastic Neutron Scattering (INS) in an apples-to-apples fashion. Experimental data can be loaded from a MDHistoWorkspace stored in a .nxs file by the Mantid software using load_nxs.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"For this example, we will examine the CTFD compound, which is crystallographically approximately a square lattice. We specify the crystal lattice structure of CTFD using the lattice parameters specified by","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"W Wan et al 2020 J. Phys.: Condens. Matter 32 374007 DOI 10.1088/1361-648X/ab757a","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"latvecs = lattice_vectors(8.113,8.119,12.45,90,100,90)\npositions = [[0,0,0]]\ntypes = [\"Cu\"]\nformfactors = [FormFactor(1,\"Cu2\")]\nxtal = Crystal(latvecs,positions;types);\nnothing #hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"We will use a somewhat small periodic lattice size of 6x6x4 in order to showcase the effect of a finite lattice size.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"latsize = (6,6,4);\nnothing #hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"In this system, the magnetic lattice is the same as the chemical lattice, and there is a spin-1/2 dipole on each site.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"magxtal = xtal;\nvalS = 1/2;\nsys = System(magxtal, latsize, [SpinInfo(1;S = valS)], :dipole; seed=1);\nnothing #hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Quoted value of J = +6.19(2) meV (antiferromagnetic) between nearest neighbors on the square lattice","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"J = 6.19 # meV\ncharacteristic_energy_scale = abs(J * valS)\nset_exchange!(sys,J,Bond(1,1,[1,0,0]))\nset_exchange!(sys,J,Bond(1,1,[0,1,0]))","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Thermalize the system using the Langevin intergator. The timestep and the temperature are roughly based off the characteristic energy scale of the problem.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Δt = 0.05 / characteristic_energy_scale\nkT = 0.01 * characteristic_energy_scale\nlangevin = Langevin(Δt; λ=0.1, kT=kT)\nrandomize_spins!(sys);\nfor i in 1:10_000 # Long enough to reach equilibrium\n step!(sys, langevin)\nend","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"The neutron spectrometer used in the experiment had an incident neutron energy of 36.25 meV. Since this is the most amount of energy that can be deposited by the neutron into the sample, we don't need to consider energies higher than this.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"ωmax = 36.25;\nnothing #hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"We choose the resolution in energy (specified by the number of nω modes resolved) to be ≈20× better than the experimental resolution in order to demonstrate the effect of over-resolving in energy.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"nω = 480;\nsc = dynamical_correlations(sys; Δt=Δt, nω=nω, ωmax=ωmax, process_trajectory=:symmetrize)\nadd_sample!(sc, sys)","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"We re-sample from the thermal equilibrium distribution several times to increase our sample size","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"nsamples = 3\nfor _ in 1:nsamples\n for _ in 1:8000\n step!(sys, langevin)\n end\n add_sample!(sc, sys)\nend","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Since the SU(N)NY crystal has only finitely many lattice sites, there are finitely many ways for a neutron to scatter off of the sample. We can visualize this discreteness by plotting each possible Qx and Qz, for example:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"params = unit_resolution_binning_parameters(sc)#hide\nbin_rlu_as_absolute_units!(params,sc)#hide\nlower_aabb_q, upper_aabb_q = Sunny.binning_parameters_aabb(params)#hide\nlower_aabb_cell = floor.(Int64,lower_aabb_q .* latsize .+ 1)#hide\nupper_aabb_cell = ceil.(Int64,upper_aabb_q .* latsize .+ 1)#hide\n\nQx = zeros(Float64,0)#hide\nQz = zeros(Float64,0)#hide\nfor cell in CartesianIndices(Tuple(((:).(lower_aabb_cell,upper_aabb_cell))))#hide\n q = (cell.I .- 1) ./ latsize # q is in R.L.U.#hide\n push!(Qx,q[1])#hide\n push!(Qz,q[3])#hide\nend#hide\nfig = Figure()#hide\nax = Axis(fig[1,1];xlabel=\"Qx [r.l.u]\",ylabel=\"Qz [r.l.u.]\")#hide\n# Compute some scattering vectors at and around the first BZ...\nscatter!(ax,Qx,Qz)\nfig#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"One way to display the structure factor is to create a histogram with one bin centered at each discrete scattering possibility using unit_resolution_binning_parameters to create a set of BinningParameters.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"params = unit_resolution_binning_parameters(sc)","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Since this is a 4D histogram, it further has to be integrated over two of those directions in order to be displayed. Here, we integrate over Qy and Energy using integrate_axes!:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"integrate_axes!(params;axes = [2,4]) # Integrate over Qy (2) and E (4)","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Now that we have parameterized the histogram, we can bin our data. In addition to the BinningParameters, an intensity_formula needs to be provided to specify which dipole, temperature, and atomic form factor corrections should be applied during the intensity calculation.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"formula = intensity_formula(sc, :perp; kT, formfactors)\nintensity,counts = intensities_binned(sc, params; formula)\nnormalized_intensity = intensity ./ counts;\nnothing #hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"With the data binned, we can now plot it. The axes labels give the bin centers of each bin, as given by axes_bincenters.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"function plot_data(params) #hide\nintensity,counts = intensities_binned(sc, params; formula)#hide\nnormalized_intensity = intensity ./ counts;#hide\nbin_centers = axes_bincenters(params);\n\nfig = Figure()#hide\nax = Axis(fig[1,1];xlabel=\"Qx [r.l.u]\",ylabel=\"Qz [r.l.u.]\")#hide\nheatmap!(ax,bin_centers[1],bin_centers[3],normalized_intensity[:,1,:,1])\nscatter!(ax,Qx,Qz)\nxlims!(ax,params.binstart[1],params.binend[1])\nylims!(ax,params.binstart[3],params.binend[3])\nreturn fig#hide\n\nend#hide\n\nplot_data(params)#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Note that some bins have no scattering vectors at all when the bin size is made too small:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"params = unit_resolution_binning_parameters(sc)#hide\nintegrate_axes!(params;axes = [2,4])#hide\nparams.binwidth[1] /= 1.2\nparams.binwidth[3] /= 2.5\nplot_data(params)#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Conversely, making the bins bigger doesn't break anything, but loses resolution:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"params = unit_resolution_binning_parameters(sc)#hide\nintegrate_axes!(params;axes = [2,4])#hide\nparams.binwidth[1] *= 2\nparams.binwidth[3] *= 2\nplot_data(params)#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Recall that while we under-resolved in Q by choosing a small lattice, we over-resolved in energy:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"x = zeros(Float64,0)#hide\ny = zeros(Float64,0)#hide\nfor omega = ωs(sc), qx = unique(Qx)#hide\n push!(x,qx)#hide\n push!(y,omega)#hide\nend#hide\nax = Axis(fig[1,1];xlabel=\"Qx [r.l.u]\",ylabel=\"Energy [meV]\")#hide\nscatter!(ax,x,y)","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"Let's make a new histogram which includes the energy axis. The x-axis of the histogram will be a 1D cut from Q = [0,0,0] to Q = [1,1,0]. See slice_2D_binning_parameters.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"x_axis_bin_count = 10\ncut_width = 0.3\nparams = slice_2D_binning_parameters(sc,[0,0,0],[1,1,0],x_axis_bin_count,cut_width)","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"There are no longer any scattering vectors exactly in the plane of the cut. Instead, as described in the BinningParameters output above, the transverse Q directions are integrated over, so slightly out of plane points are included.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"We plot the intensity on a log-scale to improve visibility.","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"intensity,counts = intensities_binned(sc, params; formula)\nlog_intensity = log10.(intensity ./ counts);\nbin_centers = axes_bincenters(params);#hide\nfig = Figure()#hide\nax = Axis(fig[1,1];xlabel=\"Progress along cut [r.l.u]\",ylabel=\"Energy [meV]\")#hide\nheatmap!(ax,bin_centers[1],bin_centers[4],log_intensity[:,1,1,:])\nxlims!(ax,params.binstart[1],params.binend[1])#hide\nylims!(ax,params.binstart[4],params.binend[4])#hide\nfig#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"By reducing the number of energy bins to be closer to the number of bins on the x-axis, we can make the dispersion curve look nicer:","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"params.binwidth[4] *= 20\nintensity,counts = intensities_binned(sc, params; formula)#hide\nlog_intensity = log10.(intensity ./ counts);#hide\nbin_centers = axes_bincenters(params);#hide\nfig = Figure()#hide\nax = Axis(fig[1,1];xlabel=\"Progress along cut [r.l.u]\",ylabel=\"Energy [meV]\")#hide\nheatmap!(ax,bin_centers[1],bin_centers[4],log_intensity[:,1,1,:])\nxlims!(ax,params.binstart[1],params.binend[1])#hide\nylims!(ax,params.binstart[4],params.binend[4])#hide\nfig#hide","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"","category":"page"},{"location":"examples/binning_tutorial/","page":"Histogram Binning Tutorial","title":"Histogram Binning Tutorial","text":"This page was generated using Literate.jl.","category":"page"},{"location":"#Sunny.jl","page":"Overview","title":"Sunny.jl","text":"","category":"section"},{"location":"","page":"Overview","title":"Overview","text":"Sunny is a package for simulating classical spin systems, including the Landau-Lifshitz dynamics of spin dipoles and its generalization to multipolar spin components. The latter is especially powerful for modeling magnetic compounds with strong single-ion anisotropy interactions.","category":"page"},{"location":"","page":"Overview","title":"Overview","text":"Sunny provides the following features:","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.\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.\nEwald summation for long-range dipole-dipole interactions, accelerated with the fast Fourier transform (FFT).\nEstimation of the mathcalS(mathbfq omega) dynamical structure factor data, with options for various corrections (form factor, classical-to-quantum factors, ...)","category":"page"},{"location":"","page":"Overview","title":"Overview","text":"Work in progress includes:","category":"page"},{"location":"","page":"Overview","title":"Overview","text":"Linear spin wave theory and its generalization to SU(N) coherent states.\nInteractive visualizations of the 3D crystals and structure factor data.\nMPI-distributed Monte Carlo sampling, including parallel tempering.","category":"page"},{"location":"quick-start/#Install-Julia-and-Sunny","page":"Quick Start","title":"Install Julia and Sunny","text":"","category":"section"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Download Julia 1.8 or later. Run the Julia executable, which should open a terminal with the prompt: julia>. Load Sunny with the command:","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"using Sunny","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"If Sunny has not yet been installed, Julia will ask your permission to download and install it within the Julia environment.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"To learn more about Julia, read our Getting Started with Julia wiki page.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"For an interactive, notebook-like experience, we recommend the Julia extension for VSCode. Alternatively, the IJulia package provides Julia-enabled Jupyter notebooks.","category":"page"},{"location":"quick-start/#Example-usage","page":"Quick Start","title":"Example usage","text":"","category":"section"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"At the Julia prompt, create a diamond cubic crystal using the Crystal constructor:","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"crystal = Crystal(lattice_vectors(1, 1, 1, 90, 90, 90), [[0,0,0]], 227; setting=\"1\")","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"The first argument defines a unit cell via the convenience function lattice_vectors. The second argument is a list of basis atom positions. The third, optional argument specifies an international spacegroup number (if it's missing, Sunny will infer a spacegroup). Arguments appearing after the semicolon ; are named. Here, we are selecting the first (out of two) setting conventions for spacegroup 227.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Sunny outputs:","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Crystal\nHM symbol 'F d -3 m' (227)\nLattice params a=1, b=1, c=1, α=90°, β=90°, γ=90°\nCell volume 1\nWyckoff 8a (point group '-43m'):\n 1. [0, 0, 0]\n 2. [0.5, 0.5, 0]\n 3. [0.25, 0.25, 0.25]\n 4. [0.75, 0.75, 0.25]\n 5. [0.5, 0, 0.5]\n 6. [0, 0.5, 0.5]\n 7. [0.75, 0.25, 0.75]\n 8. [0.25, 0.75, 0.75]","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Observe that Sunny filled all eight symmetry-equivalent atom positions for the diamond cubic unit cell. The coordinates are measured in units of the lattice vectors.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Alternatively, Sunny can read the crystal structure from a .cif file. Or, if a complete list of atoms is provided, Sunny can infer the spacegroup symmetry using spglib.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"The crystal object can be used as an argument to other Sunny functions. For example, print_symmetry_table lists all symmetry-allowed exchange interactions up to a maximum distance,","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"print_symmetry_table(crystal, 0.8)","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"which prints,","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Atom 1\nPosition [0, 0, 0], multiplicity 8\nAllowed g-tensor: | A 0 0 |\n | 0 A 0 |\n | 0 0 A |\nAllowed anisotropy in Stevens operators 𝒪[k,q]:\n c₁*(𝒪[4,0]+5𝒪[4,4]) +\n c₂*(𝒪[6,0]-21𝒪[6,4])\n\nBond(1, 3, [0, 0, 0])\nDistance 0.433, coordination 4\nConnects [0, 0, 0] to [0.25, 0.25, 0.25]\nAllowed exchange matrix: | A B B |\n | B A B |\n | B B A |\n\nBond(1, 2, [0, 0, 0])\nDistance 0.7071, coordination 12\nConnects [0, 0, 0] to [0.5, 0.5, 0]\nAllowed exchange matrix: | A C -D |\n | C A -D |\n | D D B |\nAllowed DM vector: [-D D 0]","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Sunny reported that a single-ion anisotropy is only allowed at quartic and hexic orders, which is consistent with the cubic point group symmetry. Additionally, Sunny reported the allowed forms of nearest and next-nearest neighbor interaction.","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"The next steps are typically the following","category":"page"},{"location":"quick-start/","page":"Quick Start","title":"Quick Start","text":"Build a System which contains spins on a finite size lattice of crystal unit cells.\nAdd interactions to the system using functions like set_external_field!, set_exchange!, and set_onsite_coupling!.\nPerform Monte Carlo simulation to equilibrate the spin configuration. Options include the continuous Langevin dynamics, or single-spin flip updates with LocalSampler. The former can efficiently handle long-range dipole-dipole interactions, while the latter may be better in the presence of strong anisotropy (e.g., the Ising limit).\nMeasure the static or dynamical structure factor. For details, see the page Structure Factor Calculations.","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"EditURL = \"https://github.com/SunnySuite/Sunny.jl/blob/main/examples/ising2d.jl\"","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/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"","category":"page"},{"location":"examples/ising2d/","page":"Classical Ising model","title":"Classical Ising model","text":"This page was generated using Literate.jl.","category":"page"}] } diff --git a/dev/structure-factor/index.html b/dev/structure-factor/index.html index e627eec2c..f7d790d6b 100644 --- a/dev/structure-factor/index.html +++ b/dev/structure-factor/index.html @@ -1,9 +1,9 @@ -Structure Factor Calculations · Sunny documentation

      Structure Factor Calculations

      Overview

      The dynamical structure factor is of fundamental importance for characterizing a magnetic system, and facilitates quantitative comparison between theory and experimental scattering data.

      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,

      \[𝒮^{αβ}(𝐪, ω) = \frac{1}{V} ⟨ŝ^α(𝐪, ω)^\ast ŝ^β(𝐪, ω) ⟩,\]

      with $V$ the system volume. We will restrict attention to lattice systems with periodic boundaries.

      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 $𝐫_{j,k}$,

      \[𝒮^{αβ}(𝐪, ω) = ∑_{j,k} e^{i 𝐫_{j,k} ⋅ 𝐪} 𝒮̃^{αβ}_{j,k}(𝐪, ω) ⟩,\]

      From a theoretical perspective, the quantity

      \[𝒮̃^{αβ}_{j,k}(𝐪, ω) = \frac{1}{V} ⟨ŝ_j^α(𝐪, ω)^\ast ŝ_k^β(𝐪, ω)⟩\]

      is fundamental. For each sublattice $j$, the data $ŝ_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 $𝒮̃^{αβ}_{j,k}(𝐪, ω)$ correlation data, and use this to construct $𝒮^{αβ}(𝐪,ω)$ intensities that can be compared with experiment.

      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.

      Basic Usage

      The basic data type for calculating, storing and retrieving structure factor data is StructureFactor. Rather than creating a StructureFactor directly, one should call either DynamicStructureFactor, for $𝒮^{αβ}(𝐪,ω)$, or InstantStructureFactor, for $𝒮^{αβ}(𝐪)$. These functions will configure and return an appropriate StructureFactor.

      Calculating a dynamical stucture factor: $𝒮(𝐪,ω)$

      Calling DynamicStructureFactor(sys; Δt, ωmax, nω) will create a StructureFactor for the user and calculate an initial sample. There are three keywords that must be specified. These keywords will determine the dynamics used to calculate the sample and, consequently, the $ω$ information that will be available after the calculation has completed.

      1. Δ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).
      2. ω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.
      3. : Determines the number of energy bins to resolve. A larger number will require more calculation time.

      Upon constructing DynamicStructureFactor, classical spin dynamics will be performed, and spin correlation data will be accumulated into $𝒮^{αβ}(𝐪,ω)$. 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 generating a decorrelated spin configuration in sys, and then calling add_sample!.

      The outline of typical use case might look like this:

      # Make a `StructureFactor` and calculate an initial sample
      -sf = DynamicStructureFactor(sys; Δt=0.05, ωmax=10.0, nω=100) 
      +Structure Factor Calculations · Sunny documentation

      Structure Factor Calculations

      Overview

      The dynamical structure factor is of fundamental importance for characterizing a magnetic system, and facilitates quantitative comparison between theory and experimental scattering data.

      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,

      \[𝒮^{αβ}(𝐪, ω) = \frac{1}{V} ⟨ŝ^α(𝐪, ω)^\ast ŝ^β(𝐪, ω) ⟩,\]

      with $V$ the system volume. We will restrict attention to lattice systems with periodic boundaries.

      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 $𝐫_{j,k}$,

      \[𝒮^{αβ}(𝐪, ω) = ∑_{j,k} e^{i 𝐫_{j,k} ⋅ 𝐪} 𝒮̃^{αβ}_{j,k}(𝐪, ω) ⟩,\]

      From a theoretical perspective, the quantity

      \[𝒮̃^{αβ}_{j,k}(𝐪, ω) = \frac{1}{V} ⟨ŝ_j^α(𝐪, ω)^\ast ŝ_k^β(𝐪, ω)⟩\]

      is fundamental. For each sublattice $j$, the data $ŝ_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 $𝒮̃^{αβ}_{j,k}(𝐪, ω)$ correlation data, and use this to construct $𝒮^{αβ}(𝐪,ω)$ intensities that can be compared with experiment.

      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.

      Estimating stucture factors with classical dynamics

      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.

      Estimating a dynamical structure factor: $𝒮(𝐪,ω)$

      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.

      1. Δ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).
      2. ω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.
      3. : Determines the number of energy bins to resolve. A larger number will require more calculation time.

      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.

      The outline of typical use case might look like this:

      # Make a `SampledCorrelations`
      +sc = dynamical_correlations(sys; Δt=0.05, ωmax=10.0, nω=100) 
       
      -# Add additional samples
      +# Add samples
       for _ in 1:nsamples
          decorrelate_system(sys) # Perform some type of Monte Carlo simulation
      -   add_sample!(sf, sys)    # Use spins to calculate and accumulate new sample of 𝒮(𝐪,ω)
      -end

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

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

      Sunny provides two methods for calculating instantaneous, or static, structure factors: $𝒮^{αβ}(𝐪)$. The first involves calculating spin-spin correlations at single instances of time. 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 fixed spin configurations. Information about calculating instantaneous data from a dynamic structure factor can be found in the following section.

      The basic usage for the instantaneous case is very similar to the dynamic case, except one calls InstantStructureFactor instead of DynamicStructureFactor. Note that there are no required keywords as there is no need to specify any dynamics. InstantStructureFactor will immediately calculate a sample of $𝒮(𝐪)$ using the spin configuration contained in sys. It is therefore important that sys be properly thermalized before calling this function. Additional samples may be added with add_sample!(sf, sys), just as was done in the dynamic case. As was true there, it is important to ensure that the spins in sys represents a new equilibrium sample before calling add_sample!.

      Extracting information from structure factors

      The basic function for extracting information from a dynamic StructureFactor at a particular wave vector, $𝐪$, is intensities_interpolated. It takes a StructureFactor, a list of wave vectors, and a contraction mode. For example, intensities_interpolated(sf, [[0.0, 0.5, 0.5]]) will calculate intensities for the wavevector $𝐪 = (𝐛_2 + 𝐛_3)/2$. The keyword argument formula can be used to specify an intensity_formula for greater control over the intensity calculation. The default formula performs a contraction of $𝒮^{αβ}(𝐪,ω)$ that includes polarization corrections. intensities_interpolated returns a list of elements at each wavevector. The corresponding $ω$ values can be retrieved by calling ωs on sf.

      Since Sunny currently only calculates the structure factor on a finite lattice, 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 all_exact_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 connected_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, spherical_shell will provide a list of wave vectors on a sphere of a specified 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 structure factor. 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.

      + 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 correlation data

      The basic function for extracting information from a SampledCorrelations at a particular wave vector, $𝐪$, is intensities_interpolated. It takes a SampledCorrelations and a list of wave vectors. For example, intensities_interpolated(sf, [[0.0, 0.5, 0.5]]) will calculate intensities for the wavevector $𝐪 = (𝐛_2 + 𝐛_3)/2$. The keyword argument formula can be used to specify an intensity_formula for greater control over the intensity calculation. The default formula performs a contraction of $𝒮^{αβ}(𝐪,ω)$ that includes polarization corrections. intensities_interpolated returns a list of elements at each wavevector. The corresponding $ω$ values can be retrieved by calling ωs on sf.

      Since Sunny currently only calculates the structure factor on a finite lattice, 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 all_exact_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 connected_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, spherical_shell will provide a list of wave vectors on a sphere of a specified 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 structure factor, 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 34509bf01..ad7412038 100644 --- a/dev/versions/index.html +++ b/dev/versions/index.html @@ -1,2 +1,2 @@ -Version History · Sunny documentation

      Version 0.5.0

      This version includes many breaking changes.

      Added support for Dipole-mode Linear Spin Wave Theory. (Thanks Hao Zhang!)

      Split intensities into calculation (intensity_formula) and presentation (intensities_interpolated, intensities_binned). This is a breaking change, see the docs to migrate your code.

      Broadened support for custom observables in StructureFactor for use in intensity_formula.

      Added function load_nxs to load experimental neutron scattering data to compare with intensities_binned.

      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.

      Replace set_biquadratic! with an optional keyword argument biquad to set_exchange!.

      Symbolic representations of operators are now hidden unless the package DynamicPolynomials is explicitly loaded by the user. The functionality of print_anisotropy_as_stevens has been replaced with print_classical_stevens_expansion, while print_anisotropy_as_classical_spins has become print_classical_spin_polynomial.

      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.0

      This version includes many breaking changes.

      Added support for Dipole-mode Linear Spin Wave Theory. (Thanks Hao Zhang!)

      Split intensities into calculation (intensity_formula) and presentation (intensities_interpolated, intensities_binned). This is a breaking change, see the docs to migrate your code.

      StructureFactor type renamed SampledCorrelations. An appropriate SampledCorrelations is created by calling either dynamical_correlations or instant_correlations(@ref) instead of DynamicStructureFactor or InstantStructureFactor.

      Broadened support for custom observables in SampledCorrelations for use in intensity_formula.

      Added function load_nxs to load experimental neutron scattering data to compare with intensities_binned.

      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.

      Replace set_biquadratic! with an optional keyword argument biquad to set_exchange!.

      Symbolic representations of operators are now hidden unless the package DynamicPolynomials is explicitly loaded by the user. The functionality of print_anisotropy_as_stevens has been replaced with print_classical_stevens_expansion, while print_anisotropy_as_classical_spins has become print_classical_spin_polynomial.

      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 de93018f6..56259259e 100644 --- a/dev/writevtk/index.html +++ b/dev/writevtk/index.html @@ -1,5 +1,5 @@ -Volumetric Rendering with ParaView · Sunny documentation

      Volumetric Rendering with ParaView

      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:

      Simulation data

      First, generate some correlation data in Sunny. We will use a 2D lattice, since the correlation data $S(Q_x,Q_y,\omega)$ 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 DynamicalStructureFactor called dsf.

      using Sunny
      +Volumetric Rendering with ParaView · Sunny documentation

      Volumetric Rendering with ParaView

      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:

      Simulation data

      First, generate some correlation data in Sunny. We will use a 2D lattice, since the correlation data $S(Q_x,Q_y,\omega)$ 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.

      using Sunny
       
       # Single layer 12x12 periodic square lattice
       latsize = (12,12,1);
      @@ -26,11 +26,11 @@
       
       ωmax=10.
       
      -dsf = DynamicStructureFactor(sys
      -                            ;Δt=Δt
      -                            ,nω=48
      -                            ,ωmax=ωmax
      -                            ,process_trajectory=:symmetrize)
      +dsf = dynamical_correlations(sys
      +                             ;Δt=Δt
      +                             ,nω=48
      +                             ,ωmax=ωmax
      +                             ,process_trajectory=:symmetrize)
       
       nsamples = 10
       for _ in 1:nsamples
      @@ -46,7 +46,7 @@
       params.binend[4] /= scale_factor
       params.binstart[4] /= scale_factor
       params.binwidth[4] /= scale_factor
      -params.covectors[4,:] ./= scale_factor

      Doing this changes the last axis of the histogram to fit in [0,1]:

      ⊡    49 bins from -0.011 to +1.013 along [+0.10 dE] (Δ = 0.213)

      Now that our histogram is a cube, we compute the intensity in the histogram bins using the usual intensities_binned:

      formula = intensity_formula(dsf,:trace)
      +params.covectors[4,:] ./= scale_factor

      Doing this changes the last axis of the histogram to fit in [0,1]:

      ⊡    49 bins from -0.011 to +1.013 along [+0.10 dE] (Δ = 0.213)

      Now that our histogram is a cube, we compute the intensity in the histogram bins using the usual intensities_binned:

      formula = intensity_formula(dsf,:trace)
       signal, counts = intensities_binned(dsf, params; formula)
       intensity = signal ./ counts

      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.

      # Importing WriteVTK enables Sunny's export-to-VTK functions
       import WriteVTK
      @@ -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)