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

Entangled units #312

Merged
merged 38 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
6ac7a7d
Initial dump (broken)
ddahlbom Sep 2, 2024
9750013
Basic LSWT for entangled units
ddahlbom Sep 2, 2024
0151715
Progress on LSWT tests
ddahlbom Sep 2, 2024
0b8f2dc
Sync
ddahlbom Sep 2, 2024
89e0595
Progress on SampledCorrelations
ddahlbom Sep 2, 2024
a4b3bcb
Update thermal_prefactor in duplicated SWT code
ddahlbom Sep 2, 2024
f99befa
Fix crystals
ddahlbom Sep 2, 2024
48e750b
Draft of position/operator separation, functional entangled SC intens…
ddahlbom Sep 2, 2024
ea57a99
Sync
ddahlbom Sep 2, 2024
62e5eb5
Fix test
ddahlbom Sep 2, 2024
7324b47
Function for setting dipoles of sys_origin
ddahlbom Sep 2, 2024
292bf24
Progress
ddahlbom Sep 2, 2024
9afe01f
Various cleanups
ddahlbom Sep 2, 2024
b80722f
Static sampled correlations
ddahlbom Sep 2, 2024
9f98860
Fixes, sync
ddahlbom Sep 2, 2024
3ae693b
Sync
ddahlbom Sep 2, 2024
0e7e683
Remove type parameter from SampledCorrelations
ddahlbom Sep 2, 2024
3716ae9
na -> npos
ddahlbom Sep 2, 2024
175feaf
Fix compilation, rebase fixes
ddahlbom Sep 2, 2024
1b423d5
Fix Base.show functions
ddahlbom Sep 2, 2024
cf52750
Misc small fixes (sparse arrays aborted)
ddahlbom Sep 2, 2024
a134836
Fix duplicated intensities_bands for new form factors
ddahlbom Sep 2, 2024
921db71
Unexport entangled units functions
ddahlbom Sep 2, 2024
c31ed10
Mutable external field for EntangledSystems
ddahlbom Sep 2, 2024
61e4a3b
More function aliasing
ddahlbom Sep 2, 2024
262a0e2
Sync
ddahlbom Sep 2, 2024
5633cd4
Add positions to regular SWT
ddahlbom Sep 2, 2024
db29378
positions -> offsets and various fixes
ddahlbom Sep 2, 2024
ca6ba03
Cleanup
ddahlbom Sep 2, 2024
0576bd3
Temporary (unexported) doc string
ddahlbom Sep 2, 2024
bee105a
Eliminate refs to intensities_instant
ddahlbom Sep 3, 2024
1479e81
Doc tweak
ddahlbom Sep 3, 2024
2b2de72
Use zeros when constructing offsets
kbarros Sep 3, 2024
47da980
Use num_observables where possible
kbarros Sep 3, 2024
f8e98c7
Tweaks
kbarros Sep 3, 2024
4b15a39
Group includes and avoid deprecation
kbarros Sep 3, 2024
b6a704e
Remove comment
kbarros Sep 3, 2024
c2b6cab
Make MeasureSpec offsets defaultable
kbarros Sep 3, 2024
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
89 changes: 89 additions & 0 deletions src/EntangledUnits/EntangledReshaping.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#TODO: Test this rigorously -- this is key to reshaping EntangledSystems and
# making EntangledSpinWaveTheorys.

# An entangled system can be specified with a list of
# tuples, e.g. [(1,2), (3,4)], which will group the original sites 1 and 2 into
# one unit and 3 and 4 into another. Given an EntangledSystem constructed from a
# sys_origin and and a reshaped sys_origin, this function returns a list of
# tuples for specifying the corresponding entanglement of the reshaped system.
function units_for_reshaped_system(reshaped_sys_origin, esys)
(; sys_origin) = esys
units = original_unit_spec(esys)
new_crystal = reshaped_sys_origin.crystal
new_atoms = collect(1:natoms(new_crystal))
new_units = []

# Take a list of all the new atoms in the reshaped system. Pick the first.
# Map it back to the original system to determine what unit it belongs to.
# Then map all members of the unit forward to define the unit in terms of
# the atoms of the reshaped system. Remove these atoms from the list of
# sites left to be "entangled" and repeat until list of new atoms is
# exhausted.
while length(new_atoms) > 0
# Pick any site from list of new sites
new_atom = new_atoms[1]
new_site = CartesianIndex(1, 1, 1, new_atom) # Only need to define for a single unit cell, may as well be the first
new_position = position(reshaped_sys_origin, new_site)

# Find corresponding original atom number.
site = position_to_site(sys_origin, position(reshaped_sys_origin, new_site))
original_atom = site[4]
position_of_corresponding_atom = position(sys_origin, (1, 1, 1, original_atom))
offset = new_position - position_of_corresponding_atom

# Find the unit to which this original atom belongs.
unit = units[findfirst(unit -> original_atom in unit, units)]

# Find positions of all atoms in the unit, find corresponding sites in reshape system, and define unit for reshaped system.
unit_positions = [position(sys_origin, CartesianIndex(1, 1, 1, atom)) for atom in unit]
new_unit_sites = [position_to_site(reshaped_sys_origin, position + offset) for position in unit_positions]
new_unit = Int64[]
for new_site in new_unit_sites
i, j, k, a = new_site.I
if !(i == j == k == 1)
error("Specified reshaping incompatible with specified entangled units. (Unit split between crystalographic unit cells.)")
end
push!(new_unit, a)
end
push!(new_units, Tuple(new_unit))

# Delete members of newly defined unit from list of all atoms in the
# reshaped system.
idcs = findall(atom -> atom in new_unit, new_atoms)
deleteat!(new_atoms, idcs)
end

return new_units
end

function reshape_supercell(esys::EntangledSystem, shape)
(; sys, sys_origin) = esys

# Reshape the origin System.
sys_origin_new = reshape_supercell(sys_origin, shape)

# Reshape the the underlying "entangled" System.
units_new = units_for_reshaped_system(sys_origin_new, esys)
_, contraction_info = contract_crystal(sys_origin_new.crystal, units_new)
sys_new = reshape_supercell(sys, shape)

# Construct dipole operator field for reshaped EntangledSystem
dipole_operators_origin = all_dipole_observables(sys_origin_new; apply_g=false)
(; observables, source_idcs) = observables_to_product_space(dipole_operators_origin, sys_origin_new, contraction_info)

return EntangledSystem(sys_new, sys_origin_new, contraction_info, observables, source_idcs)
end

function repeat_periodically(esys, counts)
(; sys, sys_origin, contraction_info) = esys

# Repeat both entangled and original system periodically
sys_new = repeat_periodically(sys, counts)
sys_origin_new = repeat_periodically(sys_origin, counts)

# Construct dipole operator field for reshaped EntangledSystem
dipole_operators_origin = all_dipole_observables(sys_origin_new; apply_g=false)
(; observables, source_idcs) = observables_to_product_space(dipole_operators_origin, sys_origin_new, contraction_info)

return EntangledSystem(sys_new, sys_origin_new, contraction_info, observables, source_idcs)
end
170 changes: 170 additions & 0 deletions src/EntangledUnits/EntangledSampledCorrelations.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
struct EntangledSampledCorrelations
sc::SampledCorrelations # Parent SampledCorrelations
esys::EntangledSystem # Probably don't need to carry around the whole thing -- defeats spirit of original design for SC
end

struct EntangledSampledCorrelationsStatic
sc::SampledCorrelationsStatic # Parent SampledCorrelations
esys::EntangledSystem # Probably don't need to carry around the whole thing -- defeats spirit of original design for SC
end

function Base.setproperty!(sc::T, sym::Symbol, val) where {T<:Union{EntangledSampledCorrelations, EntangledSampledCorrelationsStatic}}
sc = sc.sc
if sym == :measure
@assert sc.measure.observables ≈ val.observables "New MeasureSpec must contain identical observables."
@assert all(x -> x == 1, sc.measure.corr_pairs .== val.corr_pairs) "New MeasureSpec must contain identical correlation pairs."
setfield!(sc, :measure, val)
else
setfield!(sc, sym, val)
end
end

function Base.show(io::IO, ::EntangledSampledCorrelations)
print(io, "EntangledSampledCorrelations")
end

function Base.show(io::IO, ::EntangledSampledCorrelationsStatic)
print(io, "EntangledSampledCorrelationsStatic")
end

function Base.show(io::IO, ::MIME"text/plain", esc::EntangledSampledCorrelations)
(; crystal, sys_dims, nsamples) = esc.sc
printstyled(io, "EntangledSampledCorrelations"; bold=true, color=:underline)
println(io," ($(Base.format_bytes(Base.summarysize(esc))))")
print(io,"[")
printstyled(io,"S(q,ω)"; bold=true)
print(io," | nω = $(round(Int, size(esc.sc.data)[7]/2 + 1)), Δω = $(round(esc.sc.Δω, digits=4))")
println(io," | $nsamples $(nsamples > 1 ? "samples" : "sample")]")
println(io,"Lattice: $sys_dims × $(natoms(crystal))")
end

function Base.show(io::IO, ::MIME"text/plain", esc::EntangledSampledCorrelationsStatic)
(; crystal, sys_dims, nsamples) = esc.sc.parent
printstyled(io, "SampledCorrelationsStatic"; bold=true, color=:underline)
println(io," ($(Base.format_bytes(Base.summarysize(esc))))")
print(io,"[")
printstyled(io,"S(q)"; bold=true)
println(io," | $nsamples $(nsamples > 1 ? "samples" : "sample")]")
println(io,"Lattice: $sys_dims × $(natoms(crystal))")
end

function Base.setproperty!(esc::EntangledSampledCorrelations, sym::Symbol, val)
if sym == :measure
measure = val
(; observables) = observables_to_product_space(measure.observables, esc.esys.sys_origin, esc.esys.contraction_info)
@assert esc.sc.measure.observables ≈ observables "New MeasureSpec must contain identical observables."
@assert all(x -> x == 1, esc.sc.measure.corr_pairs .== measure.corr_pairs) "New MeasureSpec must contain identical correlation pairs."
setfield!(esc.sc, :measure, val) # Sets new combiner
else
setfield!(sc, sym, val)
end
end

Base.setproperty!(esc::EntangledSampledCorrelationsStatic, sym::Symbol, val) = setproperty!(esc.parent, sym, val)


# Take observables specified in terms or original system and transform them into
# a field of observables in the tensor product space, together with mapping
# information for populating the expectation values of these operators with
# respect to the entangled system.
function observables_to_product_space(observables, sys_origin, contraction_info)
Ns_per_unit = Ns_in_units(sys_origin, contraction_info)
Ns_all = [prod(Ns) for Ns in Ns_per_unit]
N = Ns_all[1]
@assert all(==(N), Ns_all) "All entangled units must have the same dimension Hilbert space."

observables_new = fill(zeros(ComplexF64, N, N), size(observables))
positions = zeros(Vec3, size(observables)[2:end])
source_idcs = zeros(Int64, size(observables)[2:end])

for site in eachsite(sys_origin)
atom = site.I[4]
positions[site] = sys_origin.crystal.positions[atom]
source_idcs[site] = contraction_info.forward[atom][1]
for μ in axes(observables, 1)
obs = observables[μ, site]
unit, unitsub = contraction_info.forward[atom]
Ns = Ns_per_unit[unit]
observables_new[μ, site] = local_op_to_product_space(obs, unitsub, Ns)
end
end
observables = observables_new

return (; observables, positions, source_idcs)
end


# Configures an ordinary SampledCorrelations for an entangled system. The
# measure is assumed to correspond to the sites of the original "unentangled"
# system.
function SampledCorrelations(esys::EntangledSystem; measure, energies, dt, calculate_errors=false)
# Convert observables on different sites to "multiposition" observables in
# tensor product spaces. With entangled units, the position of an operator
# cannot be uniquely determined from the `atom` index of a `Site`. Instead,
# the position is recorded independently, and the index of the relevant
# coherent state (which may now be used for operators corresponding to
# multiple positions) is recorded in `source_idcs`.
(; observables, positions, source_idcs) = observables_to_product_space(measure.observables, esys.sys_origin, esys.contraction_info)

# Make a sampled correlations for the esys.
sc = SampledCorrelations(esys.sys; measure, energies, dt, calculate_errors, positions)

# Replace relevant fields or the resulting SampledCorrelations. Note use of
# undocumented `positions` keyword. This can be eliminated if positions are
# migrated into the MeasureSpec.
crystal = esys.sys_origin.crystal
origin_crystal = orig_crystal(esys.sys_origin)
sc_new = SampledCorrelations(sc.data, sc.M, crystal, origin_crystal, sc.Δω, measure, observables, positions, source_idcs, measure.corr_pairs,
sc.measperiod, sc.dt, sc.nsamples, sc.samplebuf, sc.corrbuf, sc.space_fft!, sc.time_fft!, sc.corr_fft!, sc.corr_ifft!)

return EntangledSampledCorrelations(sc_new, esys)
end

function SampledCorrelationsStatic(esys::EntangledSystem; measure, calculate_errors=false)
(; observables, positions, source_idcs) = observables_to_product_space(measure.observables, esys.sys_origin, esys.contraction_info)
sc = SampledCorrelations(esys.sys; measure, energies=nothing, dt=NaN, calculate_errors, positions)

# Replace relevant fields
crystal = esys.sys_origin.crystal
origin_crystal = orig_crystal(esys.sys_origin)
parent = SampledCorrelations(sc.data, sc.M, crystal, origin_crystal, sc.Δω, measure, observables, positions, source_idcs, measure.corr_pairs,
sc.measperiod, sc.dt, sc.nsamples, sc.samplebuf, sc.corrbuf, sc.space_fft!, sc.time_fft!, sc.corr_fft!, sc.corr_ifft!)

ssc = SampledCorrelationsStatic(parent)
return EntangledSampledCorrelationsStatic(ssc, esys)
end


function add_sample!(esc::EntangledSampledCorrelations, esys::EntangledSystem; window=:cosine)
new_sample!(esc.sc, esys.sys)
accum_sample!(esc.sc; window)
end

function add_sample!(esc::EntangledSampledCorrelationsStatic, esys::EntangledSystem; window=:cosine)
add_sample!(esc.sc, esys.sys)
end

available_energies(esc::EntangledSampledCorrelations) = available_energies(esc.sc)
available_wave_vectors(esc::EntangledSampledCorrelations) = available_wave_vectors(esc.sc)

function clone_correlations(esc::EntangledSampledCorrelations; kwargs...)
sc = clone_correlations(esc.sc)
EntangledSampledCorrelations(sc, esc.esys)
end

function merge_correlations(escs::Vector{EntangledSampledCorrelations}; kwargs...)
sc_merged = merge_correlations([esc.sc for esc in escs])
EntangledSampledCorrelations(sc_merged, escs[1].esys)
end

function intensities(esc::EntangledSampledCorrelations, qpts; kwargs...)
intensities(esc.sc, qpts; kwargs...)
end

function intensities_static(esc::EntangledSampledCorrelations, qpts; kwargs...)
intensities_static(esc.sc, qpts; kwargs...)
end

function intensities_static(esc::EntangledSampledCorrelationsStatic, qpts; kwargs...)
intensities_static(esc.sc, qpts; kwargs...)
end
Loading
Loading