Skip to content

Commit 4be3fde

Browse files
committed
Implement k-point grid
1 parent f429eb0 commit 4be3fde

27 files changed

+499
-111
lines changed

app/quoll.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,16 @@ for idir in my_idirs
6868

6969
if Quoll.Parser.requires_kpoint_grid(params)
7070
@info "Initialising k-point grid"
71+
72+
# Assuming all operators in the directory are related to the same atoms
73+
atoms = Quoll.get_atoms(first(operators))
74+
kgrid = get_kgrid(atoms, params)
7175
end
7276

7377
if !isnothing(params.output)
7478
@info "Converting operators into $(params.output.format) format"
7579

76-
operators = convert_operators(operators, params.output.format; hermitian = params.output.hermitian)
80+
operators = convert_operators(operators, params.output.format, hermitian = params.output.hermitian)
7781

7882
@info "Writing operators"
7983

examples/SiC/input_file.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ directory = "SiC_DeepH_converted"
1111
# Should also allow different types,
1212
# i.e. Monkhorst-Pack and even possibly different shifts
1313
[kpoint_grid]
14-
grid = [10, 10, 10]
14+
mesh = [10, 10, 10]
1515
density = 8.0
1616

1717
[basis_projection]

src/Parser.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ using ..Quoll
1212
using ..Quoll:
1313
AbstractOperator,
1414
OperatorKind,
15+
allows_symmetry,
1516
get_avail_operatorkinds,
1617
get_operatorkinds,
1718
get_readformat,
1819
get_writeformat
19-
import ..Quoll: find_operatorkinds
20+
import ..Quoll: find_operatorkinds, get_kgrid
2021
using ..Projections
2122
using ..Projections: AbstractBasisProjection, get_basis_projection
2223
using ..Postprocessing
@@ -63,12 +64,17 @@ include("parser/symmetry.jl")
6364
postprocessing,
6465
error_metrics,
6566
)
67+
# Check if supplied symmetry options are appropriate
68+
validate_symmetry(input, basis_projection, symmetry)
69+
70+
# Look if there are any unresolvable clashes
6671
search_clashes(basis_projection, error_metrics)
72+
6773
new(input, output, basis_projection, kpoint_grid, postprocessing, error_metrics, symmetry)
6874
end
6975
end
7076

71-
# Methods that either require all subparameter types or QuollParams itself
77+
# Methods that either require subparameter types or QuollParams itself
7278
include("parser/methods.jl")
7379

7480
end

src/Quoll.jl

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,20 @@ using JSON
1414
using AtomsBase
1515
using AtomsIOPython
1616
using NeighbourLists
17+
using Spglib
1718
using MPI
1819

19-
# Common tools
20+
# Constants
21+
22+
include("constants.jl")
23+
24+
# Methods
2025

2126
export recentre
22-
include("common/constants.jl")
23-
include("common/mpitools.jl")
24-
include("common/atomtools.jl")
25-
include("common/fastlookup.jl")
27+
include("methods/mpitools.jl")
28+
include("methods/atomtools.jl")
29+
include("methods/fastlookup.jl")
30+
include("methods/symmetry.jl")
2631

2732
# Core types and their methods
2833

@@ -37,6 +42,9 @@ include("spin.jl")
3742
include("sparsity.jl")
3843
include("shconversion.jl")
3944

45+
export get_kgrid
46+
include("kgrid.jl")
47+
4048
# Operator formats and their IO routines
4149
# (Assuming no dependencies between different format types in each file)
4250

src/common/atomtools.jl

Lines changed: 0 additions & 43 deletions
This file was deleted.
Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@ const AbstractAnyDict{K, V} = Union{<:AbstractDict{K, V}, <:AbstractDictionary{K
44

55
const SpeciesPairAnyDict{V} = AbstractAnyDict{NTuple{2, ChemicalSpecies}, V}
66
const SpeciesAnyDict{V} = AbstractAnyDict{ChemicalSpecies, V}
7-
# const SpeciesDict{V} = AbstractDict{ChemicalSpecies, V}
8-
# const SpeciesDictionary{V} = AbstractDictionary{ChemicalSpecies, V}
97

108
const AtomPairAnyDict{V} = AbstractAnyDict{NTuple{2, Int}, V}
11-
# const AtomPairKeyedArray{T, N, AT, KT} = AbstractArray{<:KeyedArray{T, N, AT, KT}, 2}
129

1310
const ThreeDimSliceView{T} = SubArray{
1411
T, 3, Array{T, 3},

src/kgrid.jl

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
2+
# TODO: move some of the functions from here to atomtools.jl
3+
# and some file containing symmetry operations like obtaining rotations
4+
# and checking if the system has inversion symmetry or not (relevant for Brillouin.jl)
5+
6+
# TODO:
7+
# - Would be useful to know whether it contains symmetries or not, and which ones
8+
# - There needs to be a way to distribute k-points to MPI tasks
9+
# (to achieve this could have an outer constructor which would take full KGrid
10+
# plus my_indices and would return a smaller KGrid)
11+
struct KGrid{T, W}
12+
kpoints::T
13+
weights::W
14+
time_reversal::Union{Missing, Bool}
15+
crystal_symmetry::Union{Missing, Bool}
16+
end
17+
18+
function get_kgrid(atoms::AbstractSystem; density = nothing, mesh = nothing,
19+
shift = falses(3), time_reversal = false, crystal_symmetry = false, symprec = 1e-5)
20+
21+
# Get symmetry rotations
22+
spglib_cell = get_spglib_cell(atoms)
23+
rotations = get_symmetry_rotations(spglib_cell, crystal_symmetry = crystal_symmetry, symprec = symprec)
24+
25+
# Get k-point grid
26+
mesh = get_recip_mesh(atoms, density, mesh)
27+
kgrid_spglib = get_stabilized_reciprocal_mesh(rotations, mesh, is_shift = shift, is_time_reversal = time_reversal)
28+
29+
# Add the shift and wrap irreducible k-points to [-0.5, 0.5)
30+
kirreds = map(Spglib.eachpoint(kgrid_spglib)) do kcoord
31+
normalize_kpoint_coordinate(SVector{3}(kcoord))
32+
end
33+
34+
# Get groups of reducible k-points
35+
ir_mapping = kgrid_spglib.ir_mapping_table
36+
k_all_reducible = [findall(isequal(elem), ir_mapping) for elem in unique(ir_mapping)]
37+
38+
# Get k-point weights
39+
n_equivalent_k = length.(k_all_reducible)
40+
weights = n_equivalent_k / sum(n_equivalent_k)
41+
42+
# Test if all reducible k-points can be reproduced with symmetry rotations
43+
grid_address = kgrid_spglib.grid_address
44+
symmetries_valid = check_kpoint_reduction(rotations, time_reversal, shift, mesh, grid_address, k_all_reducible, kirreds)
45+
46+
if !symmetries_valid
47+
@warn "Reducible k-points could not be generated from the irreducible kpoints. " *
48+
"This points to a bug in spglib. Defaulting to no symmetries."
49+
return get_kgrid(
50+
atoms, density = density, mesh = mesh, shift = shift,
51+
time_reversal = false, crystal_symmetry = false, symprec = symprec
52+
)
53+
else
54+
return KGrid(collect(eachpoint(kgrid_spglib)), weights, time_reversal, crystal_symmetry)
55+
end
56+
end
57+
58+
"""Bring ``k``-point coordinates into the range [-0.5, 0.5)"""
59+
function normalize_kpoint_coordinate(x::Real)
60+
x = x - round(Int, x, RoundNearestTiesUp)
61+
@assert -0.5 x < 0.5
62+
x
63+
end
64+
normalize_kpoint_coordinate(k::AbstractVector) = normalize_kpoint_coordinate.(k)
65+
66+
function check_kpoint_reduction(rotations, time_reversal, is_shift, mesh, grid_address, k_all_reducible, kirreds)
67+
all_rotations = time_reversal ? rotations [SMatrix{3, 3}(-I(3))] : rotations
68+
shift = is_shift .// 2
69+
70+
for (iks_reducible, k) in zip(k_all_reducible, kirreds), ikred in iks_reducible
71+
kred = (shift .+ grid_address[ikred]) .// mesh
72+
found_mapping = any(all_rotations) do W
73+
# If the difference between kred and W' * k == W^{-1} * k
74+
# is only integer in fractional reciprocal-space coordinates, then
75+
# kred and S' * k are equivalent k-points
76+
all(isinteger, kred - (W * k))
77+
end
78+
if !found_mapping
79+
return false
80+
end
81+
end
82+
return true
83+
end
84+
85+
function get_recip_mesh(atoms::FlexibleSystem, density, mesh)
86+
if isnothing(mesh)
87+
real_lattice = ustrip.(stack(cell_vectors(atoms)))
88+
return get_recip_mesh(real_lattice, density)
89+
else
90+
return mesh
91+
end
92+
end
93+
94+
function get_recip_mesh(real_lattice, density)
95+
recip_basis_lengths = norm.(eachcol(get_recip_lattice(real_lattice)))
96+
return ceil(Int, recip_basis_lengths .* density)
97+
end

src/methods/atomtools.jl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
function recentre(atoms::AbstractSystem)
2+
# Currently the following function does not support recentering
3+
# for systems with open boundary conditions
4+
@argcheck all(periodicity(atoms))
5+
6+
# Convert atom positions to fractional coordinates.
7+
atom_frac_pos = get_frac_positions(atoms)
8+
9+
# Wrap fractional coordinates to [-0.5, 0.5) unit cell
10+
# and shift back to [0.0, 1.0)
11+
wrapped_atom_frac_pos = atom_frac_pos .- 1e-8
12+
wrapped_atom_frac_pos = wrapped_atom_frac_pos .- round.(wrapped_atom_frac_pos) .+ 1e-8
13+
center = SA[0.5, 0.5, 0.5]
14+
wrapped_atom_frac_pos .+= center
15+
16+
# Remap fractional coordinates to atom positions
17+
wrapped_atom_pos = get_real_lattice(atoms) * wrapped_atom_frac_pos
18+
19+
# Construct new atoms
20+
recentered_atoms = periodic_system(
21+
[Atom(atom, position = wrapped_atom_pos[:, iat]) for (iat, atom) in enumerate(atoms)],
22+
cell_vectors(atoms),
23+
)
24+
return recentered_atoms
25+
end
26+
27+
function get_real_lattice(atoms::AbstractSystem)
28+
return stack(cell_vectors(atoms))
29+
end
30+
31+
function get_recip_lattice(atoms::AbstractSystem)
32+
real_lattice = get_real_lattice(atoms)
33+
return get_recip_lattice(real_lattice)
34+
end
35+
36+
# A^T B = 2πI
37+
# where both matrices contain basis vectors as columns
38+
function get_recip_lattice(real_lattice)
39+
return transpose(ustrip.(real_lattice)) \ (2π * I(3))
40+
end
41+
42+
# Strip units for matrix division because it doesn't always work with units.
43+
# Resulting fractional coordinates do not have units which is correct
44+
function get_frac_positions(atoms::AbstractSystem)
45+
real_lattice = get_real_lattice(atoms)
46+
real_positions = ustrip.(stack(position(atoms, :)))
47+
return ustrip.(real_lattice) \ ustrip.(real_positions)
48+
end

0 commit comments

Comments
 (0)