relax_geometry_cg.lua

--[[
Example on how to relax a geometry using the CG
algorithm.

This example can take any geometry and will relax it
according to the siesta input options:

 - MD.MaxForceTol
 - MD.MaxCGDispl

One should note that the CG algorithm first converges
when the total force (norm) on the atoms are below the
tolerance. This is contrary to the SIESTA default which
is a force tolerance for the individual directions,
i.e. max-direction force.

This example is prepared to easily create
a combined relaxation of several CG algorithms
simultaneously. In some cases this is shown to
speed up the convergence because an average is taken
over several optimizations.

This example defaults to two simultaneous CG algorithms
which seems adequate in most situations.

--]]

-- Load the FLOS module
local flos = require "flos"

-- Create the two CG algorithms with
-- initial Hessians 1/75 and 1/50
local CG = {}
CG[1] = flos.CG{beta='PR', line=flos.Line{optimizer = flos.LBFGS{H0 = 1. / 75.} } }
CG[2] = flos.CG{beta='PR', line=flos.Line{optimizer = flos.LBFGS{H0 = 1. / 50.} } }
-- To use more simultaneously simply add a
-- new line... with a separate CG algorithm.

-- Grab the unit table of siesta (it is already created
-- by SIESTA)
local Unit = siesta.Units


function siesta_comm()

   -- This routine does exchange of data with SIESTA
   local ret_tbl = {}

   -- Do the actual communication with SIESTA
   if siesta.state == siesta.INITIALIZE then

      -- In the initialization step we request the
      -- convergence criteria
      --  MD.MaxDispl
      --  MD.MaxForceTol
      siesta.receive({"MD.MaxDispl",
		      "MD.MaxForceTol"})


      -- Print information
      IOprint("\nLUA convergence information for the LBFGS algorithms:")

      -- Ensure we update the convergence criteria
      -- from SIESTA (in this way one can ensure siesta options)
      for i = 1, #CG do

	 CG[i].tolerance = siesta.MD.MaxForceTol * Unit.Ang / Unit.eV
	 CG[i].max_dF = siesta.MD.MaxDispl / Unit.Ang
	 -- Propagate the tolerances down to the line-search for reducing
	 -- amount of line-searches
	 CG[i].line.tolerance = CG[i].tolerance
	 CG[i].line.max_dF = CG[i].max_dF -- this is not used
	 CG[i].line.optimizer.tolerance = CG[i].tolerance -- this is not used
	 CG[i].line.optimizer.max_dF = CG[i].max_dF -- this is used

	 -- Print information
	 if siesta.IONode then
	    CG[i]:info()
	 end
      end

   end

   if siesta.state == siesta.MOVE then

      -- Here we are doing the actual CG algorithm.
      -- We retrieve the current coordinates, the forces
      -- and whether the geometry has relaxed
      siesta.receive({"geom.xa",
		      "geom.fa",
		      "MD.Relaxed"})
      ret_tbl = siesta_move(siesta)

   end

   siesta.send(ret_tbl)
end

function siesta_move(siesta)

   -- Retrieve the atomic coordinates and the forces
   local xa = flos.Array.from(siesta.geom.xa) / Unit.Ang
   local fa = flos.Array.from(siesta.geom.fa) * Unit.Ang / Unit.eV

   -- Perform step (initialize arrays to do averaging if more
   -- CG algorithms are in use).
   local all_xa = {}
   local weight = flos.Array.empty(#CG)
   for i = 1, #CG do

      -- Calculate the next optimized structure (that
      -- minimizes the Hessian)
      all_xa[i] = CG[i]:optimize(xa, fa)

      -- Get the optimization length for calculating
      -- the best average.
      weight[i] = CG[i].weight

   end

   -- Normalize weights
   weight = weight / weight:sum()
   if #CG > 1 then
      IOprint("\nCG weighted average: ", weight)
   end

   -- Calculate the new coordinates and figure out
   -- if the algorithms has been optimized.
   local out_xa = all_xa[1] * weight[1]
   local relaxed = CG[1]:optimized()
   for i = 2, #CG do

      out_xa = out_xa + all_xa[i] * weight[i]
      relaxed = relaxed and CG[i]:optimized()

   end
   -- Immediately clean-up to reduce memory overhead (force GC)
   all_xa = nil

   -- Send back new coordinates (convert to Bohr)
   siesta.geom.xa = out_xa * Unit.Ang
   siesta.MD.Relaxed = relaxed

   return {"geom.xa",
	   "MD.Relaxed"}
end
generated by LDoc 1.4.6 Last updated 2019-05-23 08:36:38