Skip to content

Commit 45abfc7

Browse files
committed
Cleanup
1 parent ab8ba97 commit 45abfc7

File tree

4 files changed

+31
-305
lines changed

4 files changed

+31
-305
lines changed

src/response/chi0.jl

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ precondprep!(P::FunctionPreconditioner, ::Any) = P
108108
# /!\ It is assumed (and not checked) that ψk'Hk*ψk = Diagonal(εk) (extra states
109109
# included).
110110
function sternheimer_solver(Hk, ψk, ε, rhs;
111-
callback=identity, cg_callback=identity,
111+
callback=identity,
112112
ψk_extra=zeros_like(ψk, size(ψk, 1), 0), εk_extra=zeros(0),
113113
Hψk_extra=zeros_like(ψk, size(ψk, 1), 0), tol=1e-9,
114114
miniter=1, maxiter=100)
@@ -179,10 +179,9 @@ function sternheimer_solver(Hk, ψk, ε, rhs;
179179
end
180180
J = LinearMap{eltype(ψk)}(RAR, size(Hk, 1))
181181
cg_res = cg(J, bb; precon=FunctionPreconditioner(R_ldiv!), tol, proj=R,
182-
callback=cg_callback, miniter, maxiter)
182+
callback=info -> callback(merge(info, (; basis, kpoint))),
183+
miniter, maxiter)
183184
δψknᴿ = cg_res.x
184-
info = (; basis, kpoint, cg_res)
185-
callback(info)
186185

187186
# 2) solve for αkn now that we know δψknᴿ
188187
# Note that αkn is an empty array if there is no extra bands.
@@ -618,10 +617,10 @@ end
618617
Set the convergence tolerance for each Sternheimer solver to be a fixed factor
619618
times the desired density tolerance.
620619
"""
621-
struct SternheimerFactor{T}
620+
struct BandtolFactor{T}
622621
factor::T
623622
end
624-
SternheimerFactor() = SternheimerFactor(1)
625-
function determine_band_tolerances(alg::SternheimerFactor, tol_density)
623+
BandtolFactor() = BandtolFactor(1)
624+
function determine_band_tolerances(alg::BandtolFactor, tol_density)
626625
alg.factor * tol_density
627626
end

src/response/gmres.jl

Lines changed: 0 additions & 261 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ function inexact_gmres!(x, A, b::AbstractVector{T};
7777
residual_norm=β, maxiter, tol, s, residual=r,
7878
restart_history, stage=:restart, krylovdim, k, Axinfo)
7979

80-
8180
while (n_iter < maxiter && k < m) # Arnoldi loop
8281
n_iter += 1
8382

@@ -145,263 +144,3 @@ end
145144
function inexact_gmres(A, b; kwargs...)
146145
inexact_gmres!(zeros_like(b, eltype(b), size(A, 2)), A, b; kwargs...)
147146
end
148-
149-
150-
151-
152-
153-
154-
155-
156-
157-
158-
function gmres(operators::Function, b::AbstractVector{T};
159-
x₀=nothing,
160-
maxiter=min(100, size(operators(0), 1)),
161-
restart=min(20, size(operators(0), 1)),
162-
tol=1e-6, s_guess=0.8, verbose=1, debug=false) where {T}
163-
# pass s/3m 1/\|r_tilde\| tol to operators()
164-
normb = norm(b)
165-
b = b ./ normb
166-
tol = tol / normb
167-
if tol < 0.5*eps(T)
168-
#throw a warning
169-
@warn "The effective tolerance is smaller than half of the machine epsilon, the requested accuracy may not be achieved."
170-
end
171-
172-
n_size = length(b)
173-
174-
# counters
175-
numrestarts::Int64 = 0
176-
restart_inds = Int64[]
177-
MvTime = Float64[]
178-
179-
# initialization: Arnoldi basis and Hessenberg matrix
180-
V = zeros(n_size, restart + 1)
181-
H = zeros(restart + 1, restart)
182-
183-
# residual history
184-
residuals = zeros(maxiter)
185-
denominatorvec = zeros(restart)
186-
denominator2 = 1.0
187-
# record min singular values
188-
minsvdvals = zeros(maxiter)
189-
190-
# solution history
191-
if debug
192-
X = zeros(n_size, maxiter)
193-
end
194-
195-
# if x0 is zero, set r0 = b
196-
x0iszero = isnothing(x₀)
197-
if x0iszero
198-
β₀ = 1.0
199-
V[:, 1] = b #/ β₀
200-
tol_new = tol / 2
201-
lm = s_guess / restart / 2 * tol
202-
else
203-
# assert x₀ is a vector of the right size
204-
@assert length(x₀) == n_size
205-
x₀ ./= normb
206-
x0iszero = false
207-
tol_new = tol / 3
208-
A0_tol = tol / 3
209-
lm = s_guess / restart / 3 * tol
210-
push!(MvTime, @elapsed r₀ = operators(A0_tol) * x₀)
211-
r₀ = b - r₀
212-
β₀ = norm(r₀)
213-
V[:, 1] = r₀ / β₀
214-
end
215-
216-
Ai_tol = lm / β₀
217-
i = 0 # iteration counter, set to 0 when restarted
218-
for j = 1:maxiter
219-
i += 1
220-
221-
# Arnoldi iteration using MGS
222-
push!(MvTime, @elapsed w = operators(Ai_tol) * V[:, i])
223-
for j = 1:i
224-
H[j, i] = dot(V[:, j], w)
225-
w .-= H[j, i] * V[:, j]
226-
end
227-
H[i+1, i] = norm(w)
228-
V[:, i+1] = w / H[i+1, i]
229-
230-
# compute the min singular value of the upper Hessenberg matrix
231-
minsvdvals[j] = svdvals(H[1:i+1, 1:i])[end]
232-
233-
# update residual history
234-
if i == 1
235-
denominatorvec[1] = conj(-H[1, 1] / H[2, 1])
236-
else
237-
denominatorvec[i] = conj(-(H[1, i] + dot(denominatorvec[1:i-1], H[2:i, i])) / H[i+1, i])
238-
end
239-
denominator2 += abs2(denominatorvec[i])
240-
residuals[j] = β₀ / sqrt(denominator2)
241-
Ai_tol = lm / residuals[j]
242-
243-
(verbose > 0) && println("restart = ", numrestarts + 1, ", iteration = ", i, ", res = ", residuals[j]*normb, "\n")
244-
245-
# when converged without updating the s_guess, restart once
246-
converged = residuals[j] < tol_new
247-
happy = converged && ((numrestarts > 0) || (s_guess <= minsvdvals[j]))
248-
needrestart = (i == restart) || (converged && !happy) # equal to converged && (numrestarts == 0) && (s_guess > minsvdvals[j])
249-
reachmaxiter = (j == maxiter)
250-
exitloop = (happy || reachmaxiter)
251-
252-
solvels = (exitloop || needrestart || debug)
253-
if solvels
254-
# solve the Hessenberg least squares problem
255-
rhs = (UpperTriangular(H[2:i+1, 1:i]) \ denominatorvec[1:i]) * (-β₀ / denominator2)
256-
if x0iszero
257-
xᵢ = V[:, 1:i] * rhs
258-
else
259-
xᵢ = x₀ + V[:, 1:i] * rhs
260-
end
261-
262-
debug && (X[:, j] = xᵢ)
263-
264-
if exitloop
265-
if debug
266-
return (; x=X[:, 1:j].*normb, residuals=residuals[1:j].*normb, MvTime=MvTime, restart_inds=restart_inds, minsvdvals=minsvdvals[1:j])
267-
else
268-
return (; x=xᵢ.*normb, residuals=residuals[1:j].*normb, MvTime=MvTime, restart_inds=restart_inds)
269-
end
270-
end
271-
272-
if needrestart
273-
i = 0
274-
x0iszero = false
275-
# whenever restart, update the guess of the smallest singular value
276-
min_s = minimum(minsvdvals[1:j])
277-
if s_guess > min_s
278-
verbose > 0 && println("current s_guess = ", s_guess, "> minsvdval = ", min_s, ", restart with s_guess = minsvdval")
279-
else
280-
verbose > 0 && println("current s_guess = ", s_guess, "≤ minsvdval = ", min_s, ", restart with s_guess = minsvdval")
281-
end
282-
s_guess = min_s
283-
lm = s_guess / restart / 3 * tol
284-
tol_new = tol / 3
285-
A0_tol = tol / 3
286-
287-
x₀ = xᵢ
288-
push!(MvTime, @elapsed r₀ = operators(A0_tol) * x₀)
289-
r₀ = b - r₀
290-
β₀ = norm(r₀)
291-
V[:, 1] = r₀ / β₀
292-
numrestarts += 1
293-
denominatorvec = zeros(maxiter)
294-
denominator2 = 1.0
295-
push!(restart_inds, j)
296-
(verbose > -1) && println("restarting: ", "iteration = ", j, ", r₀ = ", β₀, "\n")
297-
Ai_tol = lm / β₀
298-
end
299-
end
300-
end
301-
end
302-
303-
304-
function gmres(operator::LinearMap{T}, b::AbstractVector{T};
305-
x₀ = nothing,
306-
maxiter=min(100, size(operator, 1)),
307-
restart=min(20, size(operator, 1)),
308-
tol=1e-6, verbose=0, debug=false) where {T}
309-
310-
n_size = length(b)
311-
312-
# counters
313-
numrestarts::Int64 = 0
314-
restart_inds = Int64[]
315-
MvTime = Float64[]
316-
317-
# initialization: Arnoldi basis and Hessenberg matrix
318-
V = zeros(n_size, restart + 1)
319-
H = zeros(restart + 1, restart)
320-
321-
# residual history
322-
residuals = zeros(maxiter)
323-
denominatorvec = zeros(restart)
324-
denominator2 = 1.0
325-
326-
# solution history
327-
if debug
328-
X = zeros(n_size, maxiter)
329-
end
330-
331-
# if x0 is zero, set r0 = b
332-
if isnothing(x₀)
333-
β₀ = norm(b)
334-
V[:, 1] = b / β₀
335-
else
336-
# assert x₀ is a vector of the right size
337-
@assert length(x₀) == n_size
338-
push!(MvTime, @elapsed r₀ = operator * x₀)
339-
r₀ = b - r₀
340-
β₀ = norm(r₀)
341-
V[:, 1] = r₀ / β₀
342-
end
343-
344-
i = 0 # iteration counter, set to 0 when restarted
345-
for j = 1:maxiter
346-
i += 1
347-
# Arnoldi iteration using MGS
348-
push!(MvTime, @elapsed w = operator * V[:, i])
349-
for j = 1:i
350-
H[j, i] = dot(V[:, j], w)
351-
w .-= H[j, i] * V[:, j]
352-
end
353-
H[i+1, i] = norm(w)
354-
V[:, i+1] = w / H[i+1, i]
355-
356-
# update residual history
357-
if i == 1
358-
denominatorvec[1] = conj(-H[1, 1] / H[2, 1])
359-
else
360-
denominatorvec[i] = conj(-(H[1, i] + dot(denominatorvec[1:i-1], H[2:i, i])) / H[i+1, i])
361-
end
362-
denominator2 += abs2(denominatorvec[i])
363-
residuals[j] = β₀ / sqrt(denominator2)
364-
365-
(verbose > 0) && println("restart = ", numrestarts + 1, ", iteration = ", i, ", res = ", residuals[j], "\n")
366-
367-
happy = residuals[j] < tol
368-
needrestart = (i == restart)
369-
reachmaxiter = (j == maxiter)
370-
exitloop = (happy || reachmaxiter)
371-
372-
solvels = (exitloop || needrestart || debug)
373-
if solvels
374-
# solve the Hessenberg least squares problem
375-
rhs = (UpperTriangular(H[2:i+1, 1:i]) \ denominatorvec[1:i]) * (-β₀ / denominator2)
376-
if isnothing(x₀)
377-
xᵢ = V[:, 1:i] * rhs
378-
else
379-
xᵢ = x₀ + V[:, 1:i] * rhs
380-
end
381-
382-
debug && (X[:, j] = xᵢ)
383-
384-
if exitloop
385-
if debug
386-
return (; x=X[:, 1:j], residuals=residuals[1:j], MvTime=MvTime, restart_inds=restart_inds)
387-
else
388-
return (; x=xᵢ, residuals=residuals[1:j], MvTime=MvTime, restart_inds=restart_inds)
389-
end
390-
end
391-
392-
if needrestart
393-
i = 0
394-
x₀ = xᵢ
395-
push!(MvTime, @elapsed r₀ = operator * x₀)
396-
r₀ = b - r₀
397-
β₀ = norm(r₀)
398-
V[:, 1] = r₀ / β₀
399-
numrestarts += 1
400-
denominatorvec = zeros(maxiter)
401-
denominator2 = 1.0
402-
push!(restart_inds, j)
403-
(verbose > 0) && println("restarting: ", "iteration = ", j, ", r₀ = ", β₀, "\n")
404-
end
405-
end
406-
end
407-
end

src/response/hessian.jl

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ Input parameters:
247247
eigenvalues; occupation_threshold),
248248
q=zero(Vec3{real(T)}),
249249
maxiter_sternheimer=100,
250-
maxiter=100, krylovdim=10, s=1.0, debug_use_old_solver=true,
250+
maxiter=100, krylovdim=10, s=10.0,
251251
callback=verbose ? OmegaPlusKDefaultCallback() : identity,
252252
kwargs...) where {T}
253253
# Using χ04P = -Ω^-1, E extension operator (2P->4P) and R restriction operator:
@@ -280,35 +280,18 @@ Input parameters:
280280
occupation_threshold, q)
281281
end
282282

283-
if debug_use_old_solver
284-
# compute total δρ
285-
function dielectric_adjoint(δρ)
286-
δV = apply_kernel(basis, δρ; ρ, q)
287-
# TODO
288-
# Would be nice to play with abstol / reltol etc. to avoid over-solving
289-
# for the initial GMRES steps.
290-
χ0δV = apply_χ0(ham, ψ, occupation, εF, eigenvalues, δV; miniter=1,
291-
occupation_threshold, tol, bandtolalg, q, kwargs...).δρ
292-
δρ - χ0δV
293-
end
294-
δρ, info_gmres = linsolve(dielectric_adjoint, δρ0;
295-
ishermitian=false, krylovdim,
296-
tol, verbosity=(verbose ? 3 : 0))
297-
info_gmres.converged == 0 && @warn "Solve_ΩplusK_split solver not converged"
298-
else
299-
# compute total δρ
300-
# TODO Can be smarter here, e.g. use mixing to come up with initial guess.
301-
ε = DielectricAdjoint(ham, ρ, ψ, occupation, εF, eigenvalues, occupation_threshold,
302-
bandtolalg, maxiter_sternheimer, q)
303-
precon = I # TODO Use mixing
304-
callback_inner(info) = callback(merge(info, (; runtime_ns=time_ns() - start_ns)))
305-
info_gmres = inexact_gmres(ε, vec(δρ0);
306-
tol, precon, krylovdim, maxiter, s,
307-
callback=callback_inner, kwargs...)
308-
δρ = reshape(info_gmres.x, size(ρ))
309-
if !info_gmres.converged
310-
@warn "Solve_ΩplusK_split solver not converged"
311-
end
283+
# compute total δρ
284+
# TODO Can be smarter here, e.g. use mixing to come up with initial guess.
285+
ε = DielectricAdjoint(ham, ρ, ψ, occupation, εF, eigenvalues, occupation_threshold,
286+
bandtolalg, maxiter_sternheimer, q)
287+
precon = I # TODO Use mixing
288+
callback_inner(info) = callback(merge(info, (; runtime_ns=time_ns() - start_ns)))
289+
info_gmres = inexact_gmres(ε, vec(δρ0);
290+
tol, precon, krylovdim, maxiter, s,
291+
callback=callback_inner, kwargs...)
292+
δρ = reshape(info_gmres.x, size(ρ))
293+
if !info_gmres.converged
294+
@warn "Solve_ΩplusK_split solver not converged"
312295
end
313296

314297
# Compute total change in Hamiltonian applied to ψ
@@ -335,7 +318,8 @@ Input parameters:
335318
callback((; stage=:final, runtime_ns=time_ns() - start_ns,
336319
Axinfo=(; basis, tol=tol*factor_final, resfinal...)))
337320

338-
(; resfinal.δψ, δρ, δHψ, δVind, δeigenvalues, resfinal.δoccupation, resfinal.δεF, info_gmres)
321+
(; resfinal.δψ, δρ, δHψ, δVind, δρ0, δeigenvalues, resfinal.δoccupation, resfinal.δεF,
322+
ε, info_gmres)
339323
end
340324

341325
function solve_ΩplusK_split(scfres::NamedTuple, rhs; kwargs...)
@@ -360,13 +344,17 @@ struct DielectricAdjoint{Tρ, Tψ, Toccupation, TεF, Teigenvalues, Tq}
360344
maxiter::Int # CG maximum number of iterations
361345
q::Tq
362346
end
363-
function inexact_mul::DielectricAdjoint, δρ; tol=0.0)
347+
function DielectricAdjoint(scfres; bandtolalg=BandtolBalanced(scfres), q=zero(Vec3{Float64}), maxiter=100)
348+
DielectricAdjoint(scfres.ham, scfres.ρ, scfres.ψ, scfres.occupation, scfres.εF,
349+
scfres.eigenvalues, scfres.occupation_threshold, bandtolalg, maxiter, q)
350+
end
351+
function inexact_mul::DielectricAdjoint, δρ; tol=0.0, kwargs...)
364352
δρ = reshape(δρ, size.ρ))
365353
basis = ε.ham.basis
366354
δV = apply_kernel(basis, δρ; ε.ρ, ε.q)
367355
res = apply_χ0.ham, ε.ψ, ε.occupation, ε.εF, ε.eigenvalues, δV;
368356
miniter=1, ε.occupation_threshold, tol,
369-
ε.bandtolalg, ε.q, ε.maxiter)
357+
ε.bandtolalg, ε.q, ε.maxiter, kwargs...)
370358
χ0δV = res.δρ
371359
Ax = vec(δρ - χ0δV) # (1 - χ0 K δρ)
372360
(; Ax, info=(; tol, basis, res...))

0 commit comments

Comments
 (0)