Parameter Optimization

Selectively optimizing parameters

In the Basis Sets section, we have briefly introduced ParamBox as the parameters embedded in containers such as BasisFunc and BasisFuncs. This means how we construct the basis set using the parameters will determine the parameter space for the basis set optimization. (For more information please refer to Constructing basis sets based on ParamBox.) Sometimes, we can select parameters for optimization to achieve higher efficiency.

Here is an example of using GaussFunc and GridBox to quickly generate a grid-based basis set with only 3 independent parameters. One is the spacing $L$ of the grid points that determines all the center coordinates of the basis functions; the other two are the exponent coefficient $\alpha$ and the contraction coefficient $d$.

julia> nuc = ["H", "H"];
julia> nucCoords = [[-0.7,0.0,0.0], [0.7,0.0,0.0]];
julia> grid = GridBox(1, 3.0)GridBox{Float64, 3, 8, โ€ฆ}(spacing, nPoint, point, param)
julia> gf1 = GaussFunc(0.7, 1.0);
julia> bs = genBasisFunc.(grid.point, Ref(gf1)) |> collect;

After building the basis set, we need to use markParams! to mark all the unique parameters that can also be optimized later:

julia> pars = markParams!(bs, true)3-element Vector{ParamBox{Float64}}:
 ParamBox{Float64, :X, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[-1.5]
 ParamBox{Float64, :ฮฑ, โ€ฆ}{0}[โˆ‚][ฮฑโ‚]โŸฆ=โŸง[0.7]
 ParamBox{Float64, :d, โ€ฆ}{0}[โˆ‚][dโ‚]โŸฆ=โŸง[1.0]

When markParams!'s second argument is set to true, it will return only the ParamBoxes that have unique independent variables. Thus, the length of pars is 3 for the aforementioned three independent parameters, despite the basis set having eight basis functions with a total of 40 parameters. However, if we take a step further, we can remove the ParamBox representing $d$ since each basis function here is just one same Gaussian function. Thus, input the rest parameters (along with other necessary arguments) into optimizeParams! and we will have a more efficient optimization iteration:

julia> parsPartial = pars[1:2];
julia> isConverged, Es = optimizeParams!(parsPartial, bs, nuc, nucCoords, POconfig(maxStep=10));Step 0: ๐‘“ = 0.33268816 โˆฅvec(โˆ‡๐‘“)โˆฅโ‚‚ = 4.24093968 Step duration: 24.959378 seconds. Step 1: ๐‘“ = -0.12730324 โˆฅvec(โˆ‡๐‘“)โˆฅโ‚‚ = 3.96879286 Step duration: 0.769129 second. Step 2: ๐‘“ = -0.85913818 โˆฅvec(โˆ‡๐‘“)โˆฅโ‚‚ = 2.86813146 Step duration: 8.636303 seconds. Step 4: ๐‘“ = -1.61878993 โˆฅvec(โˆ‡๐‘“)โˆฅโ‚‚ = 0.62882932 Step duration: 1.099411 seconds. Step 6: ๐‘“ = -1.65687612 โˆฅvec(โˆ‡๐‘“)โˆฅโ‚‚ = 0.06863309 Step duration: 1.097882 seconds. The optimization of parameters ๐’™ := [:Lโ‚, :ฮฑโ‚] with respect to ๐‘“(๐’™) from the profile :HFenergy just ended at Step 10: ๐‘“ = -1.6625356874 ๐’™ = [1.0085804, 0.4097516] after 49.451672 seconds. The iteration has not converged: โˆฅฮ”๐‘“โˆฅโ‚‚ โ†’ 0.00085395, โˆฅvec(โˆ‡๐‘“)โˆฅโ‚‚ โ†’ 0.03748260.

After the optimization, you can check the original bs and find that the inside parameters are changed as well. This is because the ! in the function name indicates that optimizeParams! is a function that modifies its arguments.

julia> getParams(bs)40-element Vector{ParamBox{Float64}}:
 ParamBox{Float64, :X, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[-0.5042902069]
 ParamBox{Float64, :Y, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[-0.5042902069]
 ParamBox{Float64, :Z, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[-0.5042902069]
 ParamBox{Float64, :ฮฑ, โ€ฆ}{0}[โˆ‚][ฮฑโ‚]โŸฆ=โŸง[0.4097516014]
 ParamBox{Float64, :d, โ€ฆ}{0}[โˆ‚][dโ‚]โŸฆ=โŸง[1.0]
 ParamBox{Float64, :X, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[0.5042902069]
 ParamBox{Float64, :Y, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[-0.5042902069]
 ParamBox{Float64, :Z, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[-0.5042902069]
 ParamBox{Float64, :ฮฑ, โ€ฆ}{0}[โˆ‚][ฮฑโ‚]โŸฆ=โŸง[0.4097516014]
 ParamBox{Float64, :d, โ€ฆ}{0}[โˆ‚][dโ‚]โŸฆ=โŸง[1.0]
 โ‹ฎ
 ParamBox{Float64, :Y, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[0.5042902069]
 ParamBox{Float64, :Z, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[0.5042902069]
 ParamBox{Float64, :ฮฑ, โ€ฆ}{0}[โˆ‚][ฮฑโ‚]โŸฆ=โŸง[0.4097516014]
 ParamBox{Float64, :d, โ€ฆ}{0}[โˆ‚][dโ‚]โŸฆ=โŸง[1.0]
 ParamBox{Float64, :X, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[0.5042902069]
 ParamBox{Float64, :Y, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[0.5042902069]
 ParamBox{Float64, :Z, โ€ฆ}{2}[๐››][Lโ‚]โŸฆโ†’โŸง[0.5042902069]
 ParamBox{Float64, :ฮฑ, โ€ฆ}{0}[โˆ‚][ฮฑโ‚]โŸฆ=โŸง[0.4097516014]
 ParamBox{Float64, :d, โ€ฆ}{0}[โˆ‚][dโ‚]โŸฆ=โŸง[1.0]

If you want to go through the above example by yourself, you can find the script here.