33# We always work in cartesian coordinates.
44#
55
6- export minimize_energy!
7-
86using AtomsCalculators: Energy, Forces, calculate
97
108mutable struct GeometryOptimizationState
11- calc_state # Reference to the current calculator state
12- energy # Most recent energy value
13- forces # Most recent force value
14- virial # Most recent virial value
9+ calculator
10+ calc_state # Reference to the most recent calculator state
11+ energy # Current energy value
12+ forces # Current force value
13+ virial # Current virial value
14+ energy_change # Change in energy since previous step
15+ start_time:: UInt64 # Time when the calculation started from time_ns()
1516end
16- function GeometryOptimizationState (system, calculator)
17- GeometryOptimizationState (AC. get_state (calculator),
18- AC. zero_energy (system, calculator),
19- AC. zero_forces (system, calculator),
20- AC. zero_virial (system, calculator))
17+ function GeometryOptimizationState (system, calculator; start_time= time_ns ())
18+ GeometryOptimizationState (
19+ calculator,
20+ AC. get_state (calculator),
21+ AC. zero_energy (system, calculator),
22+ AC. zero_forces (system, calculator),
23+ AC. zero_virial (system, calculator),
24+ AC. zero_energy (system, calculator),
25+ start_time,
26+ )
2127end
2228
2329"""
@@ -48,7 +54,6 @@ function Optimization.OptimizationProblem(system, calculator, geoopt_state; kwar
4854 new_system = update_not_clamped_positions (system, x * u " bohr" )
4955 res = calculate (Energy (), new_system, calculator, ps, geoopt_state. calc_state)
5056 geoopt_state. calc_state = res. state
51- geoopt_state. energy = res. energy
5257 austrip (res. energy), geoopt_state
5358 end
5459 g! = function (G:: AbstractVector{<:Real} , x:: AbstractVector{<:Real} , ps)
@@ -89,13 +94,18 @@ can also be employed here.
8994
9095## Keyword arguments:
9196- `maxiters`: Maximal number of iterations
97+ - `maxtime`: Maximal allowed runtime (in seconds)
9298- `tol_energy`: Tolerance in the energy to stop the minimisation (all `tol_*` need to be satisfied)
93- - `tol_force `: Tolerance in the force to stop the minimisation (all `tol_*` need to be satisfied)
99+ - `tol_forces `: Tolerance in the force to stop the minimisation (all `tol_*` need to be satisfied)
94100- `tol_virial`: Tolerance in the virial to stop the minimisation (all `tol_*` need to be satisfied)
95- - `maxstep`: Maximal step size (in AU) to be taken in a single optimisation step
101+ - `maxstep`: Maximal step size (in AU or length units ) to be taken in a single optimisation step
96102 (not supported for all `solver`s)
97- - `callback`: A custom callback, which obtains the pair `(optimization_state, geoopt_state)` and is
98- expected to return `false` (continue iterating) or `true` (halt iterations).
103+ - `verbosity`: Printing level. The idea is that `0` is silent, `1` displays the optimisation
104+ progress and `≥ 2` starts displaying things from the calculator as well (e.g SCF iterations).
105+ - `callback`: A custom callback, which obtains the pair `(optimization_state, geoopt_state)`
106+ and is expected to return `false` (continue iterating) or `true` (halt iterations). Note
107+ that specifying this overwrites the default printing callback. The calculation thus becomes
108+ silent unless a [`GeoOptDefaultCallback`](@ref) is included in the callback.
99109- `kwargs`: All other keyword arguments are passed to the call to `solve`. Note, that
100110 if special `kwargs` should be passed to the `Optimization.OptimizationProblem` the user
101111 needs to setup the problem manually (e.g. `OptimizationProblem(system, calculator)`)
@@ -110,12 +120,14 @@ end
110120# do some additional calculator-specific setup (e.g. callbacks) and so on. Then
111121# by calling this function the actual minimisation is started off.
112122function _minimize_energy! (system, calculator, solver;
113- maxiters= 100 ,
123+ maxiters:: Integer = 100 ,
124+ maxtime:: Integer = 60 * 60 * 24 * 365 , # 1 year
114125 tol_energy= Inf * u " eV" ,
115- tol_force = 1e-4 u " eV/Å" , # VASP default
116- tol_virial= 1e-6 u " eV" , # TODO How reasonable ?
126+ tol_forces = 1e-4 u " eV/Å" , # VASP default
127+ tol_virial= 1e-6 u " eV" , # TODO How reasonable ?
117128 maxstep= 0.8 u " bohr" ,
118- callback= (x,y) -> false ,
129+ verbosity:: Integer = 0 ,
130+ callback= GeoOptDefaultCallback (verbosity),
119131 kwargs... )
120132 solver = setup_solver (system, calculator, solver; maxstep)
121133 system = convert_to_updatable (system)
@@ -124,23 +136,27 @@ function _minimize_energy!(system, calculator, solver;
124136 problem = OptimizationProblem (system, calculator, geoopt_state; sense= Optimization. MinSense)
125137 converged = false
126138
127- Eold = AC . zero_energy (system, calculator)
139+ Eold = 0 # Atomic units
128140 function inner_callback (optim_state, :: Any , geoopt_state)
141+ geoopt_state. energy = optim_state. objective * u " hartree"
142+ geoopt_state. energy_change = (optim_state. objective - Eold) * u " hartree"
143+
129144 halt = callback (optim_state, geoopt_state)
130145 halt && return true
131146
132- energy_converged = austrip ( abs (geoopt_state . energy - Eold)) < austrip (tol_energy)
133- force_converged = austrip (maximum (norm, geoopt_state. forces)) < austrip (tol_force )
147+ energy_converged = optim_state . objective - Eold < austrip (tol_energy)
148+ force_converged = austrip (maximum (norm, geoopt_state. forces)) < austrip (tol_forces )
134149 virial_converged = austrip (maximum (abs, geoopt_state. virial)) < austrip (tol_virial)
135150
136- Eold = geoopt_state . energy
151+ Eold = optim_state . objective
137152 converged = energy_converged && force_converged && virial_converged
138153 return converged
139154 end
140155
141- optimres = solve (problem, solver; maxiters, callback= inner_callback, kwargs... )
156+ optimres = solve (problem, solver; maxiters, maxtime, callback= inner_callback, kwargs... )
157+ converged || @warn " Geometry optimisation not converged."
142158 (; system= update_not_clamped_positions (system, optimres. u * u " bohr" ), converged,
143- energy= optimres. objective, geoopt_state. forces, geoopt_state. virial,
159+ energy= optimres. objective * u " hartree " , geoopt_state. forces, geoopt_state. virial,
144160 state= geoopt_state. calc_state, optimres. stats, optimres. alg, optimres)
145161end
146162
0 commit comments