Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename :dipole_large_S to :dipole_uncorrected #321

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 17 additions & 16 deletions docs/src/renormalization.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,11 @@ same form, but now applied to the expected dipole. Classical Stevens functions
are constructed as homogeneous polynomials of order $k$, because lower-order
terms would vanish in the limit $s \to \infty$.

In a real magnetic compound, however, the spin magnitude $s$ is not necessarily
large. To obtain a better approximation, one should avoid the formal limit $s
\to \infty$. Our approach is to start with the full dynamics of SU(_N_) coherent
states, and then constrain it to the space of pure dipole states
$|\boldsymbol{\Omega}\rangle$. The latter are defined as any states where the
expected dipole 3-vector,
For real compounds with finite quantum spin-$s$, one can obtain a better
approximation by avoiding the formal $s \to \infty$ limit. Corrections can be
derived by starting from the full dynamics of SU(_N_) coherent states and then
constraining to the space of pure dipole states $|\boldsymbol{\Omega}\rangle$.
The latter are defined as any states where the expected dipole 3-vector,
```math
\boldsymbol{\Omega} ≡ \langle \boldsymbol{\Omega}| \hat{\mathbf{S}} | \boldsymbol{\Omega}\rangle,
```
Expand Down Expand Up @@ -128,8 +127,8 @@ interpreted as a correction to the traditional large-$s$ classical limit.

Renormalization also applies to the coupling between different sites. In Sunny,
couplings will often be expressed as a polynomial of spin operators using
[`set_pair_coupling!`](@ref), but any such coupling can be decomposed as sum of
tensor products of Stevens operators. Without loss of generality, consider a
[`set_pair_coupling!`](@ref), but any such coupling can be decomposed as a sum
of tensor products of Stevens operators. Without loss of generality, consider a
single coupling between two Stevens operators
$\hat{\mathcal{H}}_\mathrm{coupling} = \hat{\mathcal{O}}_{k,q} \otimes
\hat{\mathcal{O}}_{k',q'}$ along a bond connecting sites $i$ and $j$. Upon
Expand All @@ -139,16 +138,18 @@ $E_\mathrm{coupling} = c_k c_k' \mathcal{O}_{k,q}(\boldsymbol{\Omega}_i)
\mathcal{O}_{k',q'}(\boldsymbol{\Omega}_j)$, which now involves a product of
renormalized Stevens functions.

## Use `:dipole_large_s` mode to disable renormalization
## Use `:dipole_uncorrected` mode to disable renormalization

Although we generally recommend the above renormalization procedure, there are
circumstances where it is not desirable. Examples include reproducing a
model-system study, or describing a micromagnetic system for which the
$s\to\infty$ limit is a good approximation. To simulate dipoles without
interaction strength renormalization, construct a [`System`](@ref) using the
mode `:dipole_large_s` instead of `:dipole`. Symbolic operators in the large-$s$
limit can be constructed by passing `Inf` to either [`spin_matrices`](@ref) or
[`stevens_matrices`](@ref).
cases where it is not desirable. Examples include reproducing a legacy study, or
modeling a micromagnetic system for which the $s\to\infty$ limit is a good
approximation. To simulate dipoles without interaction strength renormalization,
construct a [`System`](@ref) using the mode `:dipole_uncorrected` instead of
`:dipole`. The fundamental difference between the two modes is the type of
operator expected by [`set_onsite_coupling!`](@ref). The mode
`:dipole_uncorrected` expects infinite-dimensional operators in the $s → ∞$
limit. These can be obtained by passing `Inf` to either [`spin_matrices`](@ref)
or [`stevens_matrices`](@ref).

## Definition of Stevens operators

Expand Down
4 changes: 3 additions & 1 deletion docs/src/versions.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#317](https://github.com/SunnySuite/Sunny.jl/pull/317)).
* Stabilize [`SpinWaveTheoryKPM`](@ref). It now automatically selects the
polynomial order according to an error tolerance.
* Rename mode `:dipole_large_S` to `:dipole_uncorrected` to emphasize that
corrections are missing.

## v0.7.2
(Sep 11, 2024)
Expand Down Expand Up @@ -49,7 +51,7 @@ This **major release** introduces breaking interface changes.
[`domain_average`](@ref), which wrap [`intensities`](@ref).
* [`System`](@ref) now expects supercell dimensions as a `dims` keyword
argument. [`Moment`](@ref) replaces `SpinInfo`. Lower-case `s` now labels
quantum spin. For example, use `:dipole_large_s` instead of `:dipole_large_S`.
quantum spin.
* In [`view_crystal`](@ref) and [`plot_spins`](@ref) use `ndims` instead of
`dims` for the number of spatial dimensions.
* Binning features have been removed. Some functionality may be added back in a
Expand Down
2 changes: 1 addition & 1 deletion examples/spinw_tutorials/SW12_Triangular_easy_plane.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ set_exchange!(sys, J1, Bond(1, 1, [1, 0, 0]))
# interaction strength as ``D → (1 - 1/2s) D``. We must "undo" Sunny's
# classical-to-quantum rescaling factor to reproduce the SpinW calculation.
# Alternatively, renormalization can be disabled by selecting the system mode
# `:dipole_large_s` instead of `:dipole`.
# `:dipole_uncorrected` instead of `:dipole`.

undo_classical_to_quantum_rescaling = 1 / (1 - 1/2s)
D = 0.2 * undo_classical_to_quantum_rescaling
Expand Down
4 changes: 2 additions & 2 deletions examples/spinw_tutorials/SW13_LiNiPO4.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ view_crystal(cryst)
# Create a system with exchange parameters taken from [T. Jensen, et al., PRB
# **79**, 092413 (2009)](https://doi.org/10.1103/PhysRevB.79.092413). The
# corrected anisotropy values are taken from the thesis of T. Jensen. The mode
# `:dipole_large_s` avoids a [classical-to-quantum rescaling factor](@ref
# `:dipole_uncorrected` avoids a [classical-to-quantum rescaling factor](@ref
# "Interaction Renormalization") of anisotropy strengths, as needed for
# consistency with the original fits.

sys = System(cryst, [1 => Moment(s=1, g=2)], :dipole_large_s)
sys = System(cryst, [1 => Moment(s=1, g=2)], :dipole_uncorrected)
Jbc = 1.036
Jb = 0.6701
Jc = -0.0469
Expand Down
5 changes: 3 additions & 2 deletions examples/spinw_tutorials/SW14_YVO3.jl
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ cryst = Crystal(latvecs, positions, 1; types)

# Create a system following the model of [C. Ulrich, et al. PRL **91**, 257202
# (2003)](https://doi.org/10.1103/PhysRevLett.91.257202). The mode
# `:dipole_large_s` avoids a [classical-to-quantum rescaling factor](@ref
# `:dipole_uncorrected` avoids a [classical-to-quantum rescaling factor](@ref
# "Interaction Renormalization") of anisotropy strengths, as needed for
# consistency with the original fits.

sys = System(cryst, [1 => Moment(s=1/2, g=2), 2 => Moment(s=1/2, g=2)], :dipole_large_s; dims=(2,2,1))
moments = [1 => Moment(s=1/2, g=2), 2 => Moment(s=1/2, g=2)]
sys = System(cryst, moments, :dipole_uncorrected; dims=(2,2,1))
Jab = 2.6
Jc = 3.1
δ = 0.35
Expand Down
2 changes: 1 addition & 1 deletion src/EntangledUnits/EntangledSpinWaveTheory.jl
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ function dynamical_matrix!(H, swt::EntangledSpinWaveTheory, q_reshaped)
if swt.sys.mode == :SUN
swt_hamiltonian_SUN!(H, swt, q_reshaped)
else
@assert swt.sys.mode in (:dipole, :dipole_large_S)
@assert swt.sys.mode in (:dipole, :dipole_uncorrected)
swt_hamiltonian_dipole!(H, swt, q_reshaped)
end
end
Expand Down
2 changes: 1 addition & 1 deletion src/KPM/SpinWaveTheoryKPM.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ function intensities!(data, swt_kpm::SpinWaveTheoryKPM, qpts; energies, kernel::
end
end
else
@assert sys.mode in (:dipole, :dipole_large_s)
@assert sys.mode in (:dipole, :dipole_uncorrected)
(; sqrtS, observables_localized) = swt.data::SWTDataDipole
for i in 1:Na
for μ in 1:Nobs
Expand Down
2 changes: 1 addition & 1 deletion src/SpinWaveTheory/DispersionAndIntensities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ function intensities_bands(swt::SpinWaveTheory, qpts; kT=0, with_negative=false)
end
end
else
@assert sys.mode in (:dipole, :dipole_large_s)
@assert sys.mode in (:dipole, :dipole_uncorrected)
data = swt.data::SWTDataDipole
t = reshape(view(T, :, band), Na, 2)
for i in 1:Na, μ in 1:Nobs
Expand Down
4 changes: 2 additions & 2 deletions src/SpinWaveTheory/LSWTCorrections.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ end
magnetization_lswt_correction(swt::SpinWaveTheory; opts...)
Calculates the reduction in the classical dipole magnitude for all atoms in the
magnetic cell. In the case of `:dipole` and `:dipole_large_s` mode, the
magnetic cell. In the case of `:dipole` and `:dipole_uncorrected` mode, the
classical dipole magnitude is constrained to spin-`s`. While in `:SUN` mode, the
classical dipole magnitude can be smaller than `s` due to anisotropic
interactions.
Expand All @@ -113,7 +113,7 @@ function magnetization_lswt_correction(swt::SpinWaveTheory; opts...)
if sys.mode == :SUN
δS = magnetization_lswt_correction_sun(swt; opts...)
else
@assert sys.mode in (:dipole, :dipole_large_s)
@assert sys.mode in (:dipole, :dipole_uncorrected)
δS = magnetization_lswt_correction_dipole(swt; opts...)
end
return δS
Expand Down
2 changes: 1 addition & 1 deletion src/SpinWaveTheory/SpinWaveTheory.jl
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ function dynamical_matrix!(H, swt::SpinWaveTheory, q_reshaped)
if swt.sys.mode == :SUN
swt_hamiltonian_SUN!(H, swt, q_reshaped)
else
@assert swt.sys.mode in (:dipole, :dipole_large_s)
@assert swt.sys.mode in (:dipole, :dipole_uncorrected)
swt_hamiltonian_dipole!(H, swt, q_reshaped)
end
end
Expand Down
2 changes: 1 addition & 1 deletion src/Spiral/LuttingerTisza.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# wavevector k between Bravais lattice cells. This analysis ignores local
# normalization constraints for the spins within the cell.
function luttinger_tisza_exchange(sys::System; k, ϵ=0)
@assert sys.mode in (:dipole, :dipole_large_s) "SU(N) mode not supported"
@assert sys.mode in (:dipole, :dipole_uncorrected) "SU(N) mode not supported"
@assert sys.dims == (1, 1, 1) "System must have only a single cell"

Na = natoms(sys.crystal)
Expand Down
2 changes: 1 addition & 1 deletion src/Spiral/SpinWaveTheorySpiral.jl
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ function intensities_bands(sswt::SpinWaveTheorySpiral, qpts; kT=0) # TODO: branc
(; sys, data, measure) = swt
isempty(measure.observables) && error("No observables! Construct SpinWaveTheorySpiral with a `measure` argument.")
sys.mode == :SUN && error("SU(N) mode not supported for spiral calculation")
@assert sys.mode in (:dipole, :dipole_large_s)
@assert sys.mode in (:dipole, :dipole_uncorrected)

qpts = convert(AbstractQPoints, qpts)
cryst = orig_crystal(sys)
Expand Down
4 changes: 2 additions & 2 deletions src/Spiral/SpiralEnergy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ special case ``𝐤 = 0`` yields result is identical to [`energy`](@ref).
See also [`minimize_spiral_energy!`](@ref) and [`repeat_periodically_as_spiral`](@ref).
"""
function spiral_energy(sys::System{0}; k, axis)
sys.mode in (:dipole, :dipole_large_s) || error("SU(N) mode not supported")
sys.mode in (:dipole, :dipole_uncorrected) || error("SU(N) mode not supported")
sys.dims == (1, 1, 1) || error("System must have only a single cell")

check_rotational_symmetry(sys; axis, θ=0.01)
Expand Down Expand Up @@ -198,7 +198,7 @@ approximately commensurate with the returned propagation wavevector ``𝐤``.
function minimize_spiral_energy!(sys, axis; maxiters=10_000, k_guess=randn(sys.rng, 3))
axis = normalize(axis)

sys.mode in (:dipole, :dipole_large_s) || error("SU(N) mode not supported")
sys.mode in (:dipole, :dipole_uncorrected) || error("SU(N) mode not supported")
sys.dims == (1, 1, 1) || error("System must have only a single cell")
norm([S × axis for S in sys.dipoles]) > 1e-12 || error("Spins cannot be exactly aligned with polarization axis")

Expand Down
8 changes: 4 additions & 4 deletions src/System/Interactions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ function local_energy_change(sys::System{N}, site, state::SpinState) where N

# Biquadratic
if !iszero(pc.biquad)
if sys.mode in (:dipole, :dipole_large_s)
if sys.mode in (:dipole, :dipole_uncorrected)
ΔQ = quadrupole(S) - quadrupole(S₀)
Qⱼ = quadrupole(Sⱼ)
else
Expand Down Expand Up @@ -315,7 +315,7 @@ function energy_aux(ints::Interactions, sys::System{N}, i::Int, cells) where N

# Biquadratic
if !iszero(pc.biquad)
if sys.mode in (:dipole, :dipole_large_s)
if sys.mode in (:dipole, :dipole_uncorrected)
Qᵢ = quadrupole(Sᵢ)
Qⱼ = quadrupole(Sⱼ)
else
Expand Down Expand Up @@ -386,7 +386,7 @@ end
function set_energy_grad_dipoles_aux!(∇E, dipoles::Array{Vec3, 4}, ints::Interactions, sys::System{N}, i::Int, cells) where N
# Single-ion anisotropy only contributes in dipole mode. In SU(N) mode, the
# anisotropy matrix will be incorporated directly into local H matrix.
if sys.mode in (:dipole, :dipole_large_s)
if sys.mode in (:dipole, :dipole_uncorrected)
stvexp = ints.onsite :: StevensExpansion
for cell in cells
S = dipoles[cell, i]
Expand All @@ -409,7 +409,7 @@ function set_energy_grad_dipoles_aux!(∇E, dipoles::Array{Vec3, 4}, ints::Inter
∇E[cellⱼ, bond.j] += J' * Sᵢ

# Biquadratic for dipole mode only (SU(N) handled differently)
if sys.mode in (:dipole, :dipole_large_s)
if sys.mode in (:dipole, :dipole_uncorrected)
if !iszero(pc.biquad)
Qᵢ = quadrupole(Sᵢ)
Qⱼ = quadrupole(Sⱼ)
Expand Down
12 changes: 6 additions & 6 deletions src/System/OnsiteCoupling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ function onsite_coupling(sys, site, matrep::AbstractMatrix)
matrep ≈ matrep' || error("Operator is not Hermitian")

if N == 2 && isapprox(matrep, matrep[1, 1] * I; atol=1e-8)
suggest = sys.mode == :dipole ? " (use :dipole_large_s to reproduce legacy calculations)" : ""
suggest = sys.mode == :dipole ? " (use :dipole_uncorrected for legacy calculations)" : ""
@warn "Onsite coupling is always trivial for quantum spin s=1/2" * suggest
end

Expand All @@ -14,14 +14,14 @@ function onsite_coupling(sys, site, matrep::AbstractMatrix)
s = spin_label(sys, to_atom(site))
c = matrix_to_stevens_coefficients(hermitianpart(matrep))
return StevensExpansion(rcs_factors(s) .* c)
elseif sys.mode == :dipole_large_s
error("System with mode `:dipole_large_s` requires a symbolic operator.")
elseif sys.mode == :dipole_uncorrected
error("System with mode `:dipole_uncorrected` requires a symbolic operator.")
end
end

function onsite_coupling(sys, site, p::DP.AbstractPolynomialLike)
if sys.mode != :dipole_large_s
error("Symbolic operator only valid for system with mode `:dipole_large_s`.")
if sys.mode != :dipole_uncorrected
error("Symbolic operator only valid for system with mode `:dipole_uncorrected`.")
end

s = sys.κs[site]
Expand All @@ -47,7 +47,7 @@ function rcs_factors(s)
end

function empty_anisotropy(mode, N)
if mode == :dipole || mode == :dipole_large_s
if mode in (:dipole, :dipole_uncorrected)
c = map(k -> zeros(2k+1), OffsetArray(0:6, 0:6))
return StevensExpansion(c)
elseif mode == :SUN
Expand Down
22 changes: 11 additions & 11 deletions src/System/PairExchange.jl
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ end


function check_allowable_dipole_coupling(tensordec, mode)
if !isempty(tensordec.data) && mode in (:dipole, :dipole_large_s)
if !isempty(tensordec.data) && mode in (:dipole, :dipole_uncorrected)
error("""
Invalid pair coupling. In dipole mode, the most general allowed form is
(Si, Sj) -> Si'*J*Sj + [(Si'*K1*Si)*(Sj'*K2*Sj) + ...]
Expand Down Expand Up @@ -290,8 +290,8 @@ function set_pair_coupling!(sys::System{N}, op::AbstractMatrix, bond; extract_pa

op ≈ op' || error("Operator is not Hermitian")

if sys.mode == :dipole_large_s
error("Symbolic operators required for mode `:dipole_large_s`.")
if sys.mode == :dipole_uncorrected
error("Symbolic operators required for mode `:dipole_uncorrected`.")
end

Ni = Int(2spin_label(sys, bond.i)+1)
Expand All @@ -303,8 +303,8 @@ function set_pair_coupling!(sys::System{N}, op::AbstractMatrix, bond; extract_pa
end

function set_pair_coupling!(sys::System{N}, fn::Function, bond; extract_parts=true) where N
if sys.mode == :dipole_large_s
error("General couplings not yet supported for mode `:dipole_large_s`.")
if sys.mode == :dipole_uncorrected
error("General couplings not supported for mode `:dipole_uncorrected`.")
end

si = spin_label(sys, bond.i)
Expand All @@ -319,7 +319,7 @@ end
# are the five Stevens quadrupoles, and g is the `scalar_biquad_metric`. The
# parameter `biquad` is accepted as the coefficient to (Sᵢ⋅Sⱼ)², but is returned
# as the coefficient to Qᵢ⋅g Qⱼ. This is achieved via a shift of the bilinear
# and scalar parts. In the special case of :dipole_large_s, the limiting
# and scalar parts. In the special case of :dipole_uncorrected, the limiting
# behavior is Sᵢ²Sⱼ² → sᵢ²sⱼ² (just the spin labels squared), and 𝒪(s²) → 0
# (homogeneous in quartic order of spin).
function adapt_for_biquad(scalar, bilin, biquad, sys, site1, site2)
Expand All @@ -333,7 +333,7 @@ function adapt_for_biquad(scalar, bilin, biquad, sys, site1, site2)
bilin -= (bilin isa Number) ? biquad/2 : (biquad/2)*I
scalar += biquad * s1*(s1+1) * s2*(s2+1) / 3
else
@assert sys.mode == :dipole_large_s
@assert sys.mode == :dipole_uncorrected
s1 = sys.κs[to_cartesian(site1)]
s2 = sys.κs[to_cartesian(site2)]
scalar += biquad * s1^2 * s2^2 / 3
Expand Down Expand Up @@ -491,8 +491,8 @@ two sites. The documentation for [`set_pair_coupling!`](@ref) provides examples
constructing `op`.
"""
function set_pair_coupling_at!(sys::System{N}, op::AbstractMatrix, site1::Site, site2::Site; offset=nothing) where N
if sys.mode == :dipole_large_s
error("Symbolic operators required for mode `:dipole_large_s`.")
if sys.mode == :dipole_uncorrected
error("Symbolic operators required for mode `:dipole_uncorrected`.")
end

N1 = Int(2spin_label(sys, to_atom(site1))+1)
Expand All @@ -504,8 +504,8 @@ function set_pair_coupling_at!(sys::System{N}, op::AbstractMatrix, site1::Site,
end

function set_pair_coupling_at!(sys::System{N}, fn::Function, site1::Site, site2::Site; offset=nothing) where N
if sys.mode == :dipole_large_s
error("General couplings not yet supported for mode `:dipole_large_s`.")
if sys.mode == :dipole_uncorrected
error("General couplings not yet supported for mode `:dipole_uncorrected`.")
end

s1 = spin_label(sys, to_atom(site1))
Expand Down
Loading
Loading