Skip to content

Commit 3e88c9d

Browse files
committed
Update conversion with shconv and manual sparsity
1 parent 9dc393b commit 3e88c9d

File tree

7 files changed

+107
-39
lines changed

7 files changed

+107
-39
lines changed

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@ HDF5 = "0.17"
4040
LoggingExtras = "1.1"
4141
MPI = "0.20"
4242
NeighbourLists = "0.5"
43+
OffsetArrays = "1.17"
4344
Reexport = "1.2"
4445
SafeTestsets = "0.1"
4546
StaticArrays = "1.9"
47+
StructArrays = "0.7"
4648
Unitful = "1.25"
4749
UnitfulAtomic = "1"
4850
julia = "1.9"

bin/quoll.jl

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,24 @@ for idir in my_idirs
6262

6363
# TODO: in the future could allow for <other canonical formats/shortcut conversions>
6464
@info "Converting operators into canonical format"
65-
# operators = Dict(Quoll.RealBSparseOperator, operators)
66-
67-
end
65+
66+
operators = Dict([
67+
operatorkind => Quoll.RealBSparseOperator(operator, params.input.radii)
68+
for (operatorkind, operator) in operators
69+
])
70+
71+
# TODO: include a function here which would initialise the k-point grid if its required
72+
# so that we don't have to do logic everywhere else multiple times
73+
74+
# Basis projection
75+
# - requires k-point grid
76+
# - incompatible with error metrics (TODO: probably should throw an error but I could do that at parse time)
77+
78+
# Postprocessing
79+
# - most of them require k-point grid (except band structure)
80+
# - should store eigenvalues, fermi level and pass them to error metrics if required
81+
82+
# Error metrics
83+
# - some require k-point grid and eigenvalues (e.g. eigenvalue error)
84+
85+
end

examples/SiC/input_file.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
format = "FHI-aims"
66
directories = ["SiC_FHIaims"]
77
operators = ["H", "S"]
8-
radii = [
9-
"C 12.0 ang",
10-
"Si 12.0 ang",
11-
]
8+
# radii = [
9+
# "C 12.0 ang",
10+
# "Si 12.0 ang",
11+
# ]
1212

1313
# Convert
1414
# - Output format

src/conversions/fhiaims/fhiaims_csc.jl

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11

22
# TODO: might need to write a more specialized function which doesn't do conversions for
33
# each operator separately assuming the metadata is the same
4-
function RealBSparseOperator(in_operator::FHIaimsCSCOperator)
5-
## Metadata
6-
# Convert sparsity
7-
out_sparsity = RealBlockSparsity(in_operator.metadata.sparsity, in_operator.metadata.basisset)
4+
# TODO: Allow to compute sparsity from radii
5+
function RealBSparseOperator(in_operator::FHIaimsCSCOperator, radii)
6+
7+
# Obtain sparsity
8+
if isnothing(radii)
9+
out_sparsity = RealBlockSparsity(in_operator.metadata.sparsity, in_operator.metadata.basisset)
10+
else
11+
@info "Computing sparsity manually from radii"
12+
out_sparsity = RealBlockSparsity(in_operator.metadata.atoms, radii, hermitian = true)
13+
end
814

915
# Compute z1z2_ij2interval
1016
z1z2_ij2interval = compute_z1z2_ij2interval(in_operator.metadata.atoms, out_sparsity)
1117

18+
# Construct metadata
1219
out_metadata = RealBSparseMetadata(
1320
in_operator.metadata.atoms, out_sparsity, in_operator.metadata.basisset, in_operator.metadata.spins, z1z2_ij2interval
1421
)
1522

16-
## Data
1723
# Initialize out_operator with zeros
1824
out_operator = RealBSparseOperator(in_operator.kind, out_metadata)
1925

@@ -41,9 +47,11 @@ function populate!(out_keydata, out_sparsity, out_basisset, in_data, in_sparsity
4147

4248
atom2basis_offset = get_offsets(out_basisset)
4349
iglobal2ilocal = get_iglobal2ilocal(out_sparsity)
50+
shconv = SHConversion(out_type) inv(SHConversion(in_type))
4451

45-
# shconv = SHConversion(out_type) ∘ inv(SHConversion(in_type))
46-
# shifts, phases = precompute_shiftphases(out_basisset, shconv)
52+
# Use inv(shconv) for shifts and phases because matrix is being reordered
53+
# using `type2` reordering, for more information see tests/unit/shconversion.jl
54+
shifts, phases = precompute_shiftphases(out_basisset, inv(shconv))
4755

4856
for i_cell in axes(in_sparsity.colcellptr, 2)
4957
image = in_sparsity.images[i_cell]
@@ -65,24 +73,31 @@ function populate!(out_keydata, out_sparsity, out_basisset, in_data, in_sparsity
6573
i_basis_row_local = i_basis_row - atom2basis_offset[i_atom_row]
6674
i_basis_col_local = i_basis_col - atom2basis_offset[i_atom_col]
6775

68-
out_keydata[(i_atom_row, i_atom_col)][i_basis_row_local, i_basis_col_local, i_cell_local] = in_data[i_index]
76+
out_keydata[(i_atom_row, i_atom_col)][
77+
i_basis_row_local + shifts[out_basisset.atom2species[i_atom_row]][i_basis_row_local],
78+
i_basis_col_local + shifts[out_basisset.atom2species[i_atom_col]][i_basis_col_local],
79+
i_cell_local
80+
] = (
81+
in_data[i_index]
82+
* phases[out_basisset.atom2species[i_atom_row]][i_basis_row_local]
83+
* phases[out_basisset.atom2species[i_atom_col]][i_basis_col_local]
84+
)
6985
end
7086
end
7187
end
72-
end
7388

74-
# struct FHIaimsCSCMetadata{A<:AbstractSystem, E} <: AbstractFHIaimsMetadata
75-
# atoms::A
76-
# sparsity::RealCSCSparsity
77-
# basisset::BasisSetMetadata{E}
78-
# spinset::Union{SpinsMetadata, Nothing}
79-
# # TODO: Is Union{SpinsMetadata, Nothing} best approach here?
80-
# # Making FHIaimsCSCMetadata a parametric type wrt typeof(spins)
81-
# # or making SpinsMetadata a parametric type might be an overkill
82-
# end
83-
84-
# struct FHIaimsCSCOperator{O<:AbstractOperatorKind, T<:AbstractFloat, A<:AbstractSystem, E} <: AbstractFHIaimsOperator
85-
# kind::O
86-
# data::Vector{T}
87-
# metadata::FHIaimsCSCMetadata{A, E}
88-
# end
89+
# Fill in the 'L' part of on-site blocks that, due of Hermitian CSC sparsity,
90+
# were not filled in the loop above
91+
n_atoms = length(atom2basis_offset)
92+
for i_atom in 1:n_atoms
93+
for k in axes(out_keydata[(i_atom, i_atom)], 3)
94+
for j in axes(out_keydata[(i_atom, i_atom)], 2)
95+
@inbounds for i in axes(out_keydata[(i_atom, i_atom)], 1)
96+
j > i || continue
97+
out_keydata[(i_atom, i_atom)][j, i, k] = out_keydata[(i_atom, i_atom)][i, j, k]
98+
end
99+
end
100+
end
101+
end
102+
103+
end

src/parser/input_output.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ function parse_radius(radius_string)
9595
r = parse(Float64, radius_match.captures[2])
9696
unit = radius_match.captures[3]
9797

98-
if unit === nothing
98+
if isnothing(unit)
9999
@warn "Units to radii field not supplied, assuming Å"
100100
r = r * u"Å"
101101
else

src/sparsity.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ function RealBlockSparsity(colcellptr, rowval, images, basis2atom)
104104
return RealBlockSparsity(ij2images, images, true)
105105
end
106106

107+
# A map from image indices in `images` to local image indices in `ij2images` for a given ij
107108
function get_iglobal2ilocal(sparsity::RealBlockSparsity)
108109
return Dictionary(
109110
keys(sparsity.ij2images),

test/unit/shconversion.jl

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ using AtomsBase
33

44
using Test
55

6-
function reorder_matrix(A1, basis, shconv)
6+
function reorder_matrix_type1(A1, basis, shconv)
77
A2 = zero(A1)
88

99
# Precompute shifts and phases
@@ -30,6 +30,34 @@ function reorder_matrix(A1, basis, shconv)
3030
return A2
3131
end
3232

33+
function reorder_matrix_type2(A1, basis, inv_shconv)
34+
A2 = zero(A1)
35+
36+
# Precompute shifts and phases
37+
n = size(A1, 2)
38+
shifts = Vector{Int}(undef, n)
39+
phases = Vector{Int}(undef, n)
40+
41+
for j in 1:n
42+
shifts[j], phases[j] = Quoll.get_shiftphase(basis[j], inv_shconv)
43+
end
44+
45+
for j in 1:n
46+
shift_j = shifts[j]
47+
phase_j = phases[j]
48+
49+
for i in 1:n
50+
shift_i = shifts[i]
51+
phase_i = phases[i]
52+
53+
# Note shifts on A2 instead of A1 as in type1 conversion
54+
A2[i + shift_i, j + shift_j] = A1[i, j] * phase_i * phase_j
55+
end
56+
end
57+
58+
return A2
59+
end
60+
3361

3462
@testset "SHConversion" begin
3563
orders = [[1], [3, 1, 2], [1, 4, 5, 3, 2]]
@@ -89,7 +117,7 @@ end
89117
shconv2 = Quoll.SHConversion(orders2, phases2)
90118

91119
@testset "Basic" begin
92-
A2 = reorder_matrix(A1, basis, shconv1)
120+
A2 = reorder_matrix_type1(A1, basis, shconv1)
93121
@test A2 == [
94122
0 2 -1 3;
95123
2 4 -3 5;
@@ -106,19 +134,23 @@ end
106134
2 3 5 4;
107135
]
108136

109-
A2 = reorder_matrix(A1, basis, shconv1)
110-
A3 = reorder_matrix(A2, basis, shconv2)
137+
A2 = reorder_matrix_type1(A1, basis, shconv1)
138+
A3 = reorder_matrix_type1(A2, basis, shconv2)
111139
@test A3 == ref
112140

113-
A3_direct = reorder_matrix(A1, basis, shconv2 shconv1)
141+
A3_direct = reorder_matrix_type1(A1, basis, shconv2 shconv1)
114142
@test A3_direct == ref
115143
end
116144

117145
@testset "Inverse" begin
118-
A2 = reorder_matrix(A1, basis, shconv1)
119-
A3 = reorder_matrix(A2, basis, inv(shconv1))
146+
A2 = reorder_matrix_type1(A1, basis, shconv1)
147+
A3 = reorder_matrix_type1(A2, basis, inv(shconv1))
120148
@test A1 == A3
121149

150+
A2type1 = reorder_matrix_type1(A1, basis, shconv1)
151+
A2type2 = reorder_matrix_type2(A1, basis, inv(shconv1))
152+
@test A2type1 == A2type2
153+
122154
identity_shconv = inv(shconv1) shconv1
123155

124156
l = 0

0 commit comments

Comments
 (0)