Skip to content
This repository was archived by the owner on Oct 6, 2022. It is now read-only.

Commit 9aecdae

Browse files
authored
Merge pull request #9 from mfherbst/dev-ediis
EDIIS implementation
2 parents f2f4db1 + c191a2f commit 9aecdae

File tree

10 files changed

+298
-146
lines changed

10 files changed

+298
-146
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.0.0"
77
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
88
HDF5 = "f67ccb44-e63f-5c2f-98bd-6dc0ccc4ba2f"
99
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
10+
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
1011
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
1112
TensorOperations = "6aa20fa7-93e2-5fca-9bc0-fbd0db3c71a2"
1213
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

src/SelfConsistentField.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module SelfConsistentField
33
using LinearAlgebra
44
using TensorOperations
55
using DataStructures
6+
using Optim
67

78
# Types
89
export ScfProblem, TwoElectronBuilder, JKBuilderFromTensor
@@ -19,6 +20,7 @@ export break_spin_symmetry
1920
include("types/ScfIterState.jl")
2021
include("types/ScfProblem.jl")
2122
include("types/Accelerator.jl")
23+
include("types/DiisState.jl")
2224

2325
include("parts/compute_density.jl")
2426
include("parts/compute_orbitals.jl")
@@ -32,12 +34,15 @@ include("algorithms/JKBuilderFromTensor.jl")
3234
include("algorithms/Roothaan.jl")
3335
include("algorithms/FixedDamping.jl")
3436
include("algorithms/cDIIS.jl")
37+
include("algorithms/EDIIS.jl")
3538

3639
include("util/guess.jl")
3740
include("util/dump_molsturm_hdf5.jl")
3841
include("util/load_integral_hdf5.jl")
3942
include("util/break_spin_symmetry.jl")
4043

44+
include("parts/diis.jl")
45+
4146
include("run_scf.jl")
4247

4348
end # module

src/algorithms/EDIIS.jl

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"""
2+
EDIIS
3+
"""
4+
mutable struct EDIIS <: Accelerator
5+
state::Tuple{DiisState, DiisState}
6+
sync_spins::Bool
7+
conditioning_threshold::Float64
8+
coefficient_threshold::Float64
9+
10+
function EDIIS(problem::ScfProblem; n_diis_size = 5, sync_spins = true, conditioning_threshold = 1e-14, coefficient_threshold = 1e-6, kwargs...)
11+
stateα = DiisState(n_diis_size)
12+
stateβ = DiisState(n_diis_size)
13+
new((stateα, stateβ), sync_spins, conditioning_threshold, coefficient_threshold)
14+
end
15+
end
16+
17+
"""
18+
Calculates coefficients
19+
"""
20+
function diis_solve_coefficients(::EDIIS, B::AbstractArray; energybuffer::AbstractArray, kwargs...)
21+
m = size(B,1)
22+
E = map(energies -> energies["total"], energybuffer)
23+
24+
function f(x)
25+
c = x.^2/sum(x.^2)
26+
E'*c - 1/2 * c'*B*c
27+
end
28+
29+
guess = ones(m) / m
30+
guess[1] = 1
31+
32+
options = Optim.Options(x_tol = 10e-5)
33+
res = optimize(f, guess, BFGS(), options; inplace = false, autodiff = :forward)
34+
x = Optim.minimizer(res)
35+
c = x.^2/sum(x.^2)
36+
37+
# If number of iterations in optimization is zero, reuse old matrix
38+
if Optim.iterations(res) == 0
39+
c = zeros(m)
40+
c[1] = 1
41+
end
42+
43+
return c, 0
44+
end
45+
46+
"""
47+
Linear System Matrix for the EDIIS accelerator.
48+
"""
49+
function diis_build_matrix(::EDIIS, state::DiisState)
50+
@assert state.n_diis_size > 0
51+
@assert state.iterate.length > 0
52+
53+
# B has dimension m <= state.n_diis_size, since in the
54+
# beginning of the iteration we do not have the full number of
55+
# previous iterates yet.
56+
57+
m = min(state.n_diis_size, length(state.iterate))
58+
59+
B = zeros(m,m)
60+
61+
# Since the Matrix B is symmetric, we only have to calculate
62+
# the upper triagonal and can use the Julia object 'Symmetric'
63+
# to fill the lower triagonal of the matrix. This also allows
64+
# Julia to use optimized algorithems for symmetric matrices.
65+
#
66+
# The matrix B is filled in the following form:
67+
#
68+
# B[1,1] B[1,2] B[1,3] … B[1,m]
69+
# 0 B[2,2] B[2,3] … B[2,m]
70+
# 0 0 B[3,3] … B[3,m]
71+
# ⋮ ⋮ ⋮ … ⋮
72+
# 0 0 0 … B[m,m]
73+
#
74+
# Note, that the values B[1,1] … B[1,m-1] will become the values
75+
# of B[2,2] … B[2,m] in the next iteration. This means, that we effectively
76+
# only have to calculate the first row and can reuse all consecutive ones.
77+
#
78+
# We would like to store the rows in such a way, that the storage variable
79+
# can be mapped to a row immediately. Since the values are shifted to the
80+
# right in each iteration and the last element is discarded it makes sense
81+
# to use a Circular Buffer to hold each row.
82+
#
83+
# Since the last row is also discarded after the new row is calculated we
84+
# use a Circular Buffer again to store the rows.
85+
86+
# Definition of matrix elements
87+
b(i,j) = tr((state.iterate[i] - state.iterate[j]) * (state.density[i] - state.density[j]))
88+
89+
# Fill the first row with newly calculated values and cache them
90+
# in a newly created Circular Buffer
91+
newValues = CircularBuffer{Any}(state.n_diis_size)
92+
map(j -> push!(newValues, b(1,j)), 1:m)
93+
fill!(newValues, 0)
94+
95+
# Push newly calculated row to the row buffer. We use the iterationstate to
96+
# store these.
97+
pushfirst!(state.iterationstate, newValues)
98+
99+
# Now fill all rows with cached values,
100+
# push a '0' on each buffer to prepare it for the next iteration
101+
for i in 1:m
102+
B[i,1:m] = state.iterationstate[i][1:m]
103+
104+
# Since we want to use this buffer as the 2nd row of A in the next
105+
# iteration we need the following layout of the buffer
106+
# 0 A[1,1] A[1,2] … A[1,m-1]
107+
# so we need to push a 0 to the beginning
108+
pushfirst!(state.iterationstate[i], 0)
109+
end
110+
111+
return Symmetric(B)
112+
end
113+
114+
function needs_error(::EDIIS)
115+
false
116+
end
117+
118+
function needs_density(::EDIIS)
119+
true
120+
end
121+
122+
"""
123+
When synchronizing spins the resulting DIIS matrices have to be added
124+
together but the constraint must be kept as is.
125+
"""
126+
function merge_diis_matrices_spin_blocks(::EDIIS, B1::AbstractArray, B2::AbstractArray)
127+
B1 + B2
128+
end

src/algorithms/Roothaan.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ function roothan_step(problem::ScfProblem, iterate::FockIterState; kwargs...)
55
orben, orbcoeff = compute_orbitals(problem, iterate.fock; kwargs...)
66
density = compute_density(problem, orbcoeff)
77
fock, error_pulay, energies = compute_fock_matrix(problem, density; kwargs...)
8-
return FockIterState(fock, error_pulay, energies, orbcoeff, orben)
8+
return FockIterState(fock, error_pulay, energies, orbcoeff, orben, density)
99
end

0 commit comments

Comments
 (0)