11# ##############################################################################
22# basis_forge.jl #
3- # --------- #
3+ # ------------------------------------------------------------------------ #
44# Build custom Gaussian‑format basis sets via automatic least‑squares fits #
55# to Slater targets. #
66# #
99# ##############################################################################
1010
1111using LinearAlgebra
12- using QuadGK # ∫₀^∞ … r² dr integrals
13- using Optim # derivative‑free optimisation
12+ using QuadGK # ∫₀^∞ … r² dr integrals
13+ using Optim # derivative‑free optimisation
1414
1515# ---------- numerical settings ----------------------------------------------
16- const ATOL = 1e-12 # quadrature accuracy
16+ const ATOL = 1e-12 # quadrature accuracy
1717
1818# ---------- Slater target ----------------------------------------------------
1919χ_STO (r, ζ; n, l) = r^ (n - 1 ) * exp (- ζ * r) * r^ l
20-
2120sto_norm (ζ; n, l) = sqrt ((2 ζ)^ (2 n + 2 l + 1 ) / factorial (2 n + 2 l))
2221
2322# ---------- primitive Gaussian ----------------------------------------------
2423χ_G (r, α; l) = r^ l * exp (- α * r^ 2 )
25-
2624radial_integral (f) = QuadGK. quadgk (r -> f (r) * r^ 2 , 0.0 , Inf ; atol = ATOL)[1 ]
2725
2826# ---------- build A, B, C matrices ------------------------------------------
2927function build_matrices (alphas, ζ; n, l)
3028 k = length (alphas)
31- Nsto = sto_norm (ζ; n, l)
32- sto (r) = Nsto * χ_STO (r, ζ; n, l)
29+ Nsto = sto_norm (ζ; n = n, l = l)
30+ sto (r) = Nsto * χ_STO (r, ζ; n = n, l = l)
3331
34- A = 1.0 # < STO|STO>
35- B = [ radial_integral (r -> χ_G (r, α; l) * sto (r)) for α in alphas ]
36- C = [ radial_integral (r -> χ_G (r, αi; l) * χ_G (r, αj; l))
37- for αi in alphas, αj in alphas ]
32+ A = 1.0 # ⟨ STO|STO⟩
33+ B = [radial_integral (r -> χ_G (r, α; l) * sto (r)) for α in alphas]
34+ C = [radial_integral (r -> χ_G (r, αi; l) * χ_G (r, αj; l))
35+ for αi in alphas, αj in alphas]
3836 return A, B, Symmetric (reshape (C, k, k))
3937end
4038
4139# ---------- inner LSQ for coefficients + RMS --------------------------------
4240function inner_fit (alphas, ζ; n, l)
43- A, B, C = build_matrices (alphas, ζ; n, l)
41+ A, B, C = build_matrices (alphas, ζ; n = n, l = l)
4442 coeffs = C \ B
4543 coeffs ./= sqrt (dot (coeffs, C * coeffs)) # renormalise
46- RMS ² = A - 2 dot (coeffs, B) + dot (coeffs, C * coeffs)
47- return coeffs, sqrt (RMS ²)
44+ rms ² = A - 2 dot (coeffs, B) + dot (coeffs, C * coeffs)
45+ return coeffs, sqrt (rms ²)
4846end
4947
5048# ---------- outer optimisation of β, γ, ζ (even‑tempered αᵢ) ---------------
51- function optimise_basis (k; n, l; β0 = 0.15 , γ0 = 3.2 , ζ0 = 1.0 )
49+ function optimise_basis (k, n, l, β0 = 0.15 , γ0 = 3.2 , ζ0 = 1.0 )
5250 obj (p) = begin
5351 β, γ, ζ = p
54- αs = [β * γ^ (i - 1 ) for i = 1 : k]
55- _, rms = inner_fit (αs , ζ; n, l)
52+ alphas = [β * γ^ (i - 1 ) for i = 1 : k]
53+ _, rms = inner_fit (alphas , ζ; n = n, l = l)
5654 rms
5755 end
5856
59- p0 = [β0, γ0, ζ0]
60- lower = [1e-4 , 1.01 , 0.1 ] # β>0, γ>1, ζ>0
61- upper = [1e2 , 10.0 , 5.0 ]
57+ p0 = [β0, γ0, ζ0]
58+ lower = [1e-4 , 1.01 , 0.1 ] # β>0, γ>1, ζ>0
59+ upper = [1e2 , 10.0 , 5.0 ]
6260
63- res = optimize (obj, lower, upper, p0,
64- Fminbox { NelderMead} (); x_tol = 1e-10 , f_tol = 1e-12 )
61+ opts = Optim . Options (x_tol = 1e-10 , f_tol = 1e-12 )
62+ res = optimize (obj, lower, upper, p0, Fminbox ( NelderMead ()), opts )
6563
66- β, γ, ζ = Optim. minimizer (res)
67- αs = [β * γ^ (i - 1 ) for i = 1 : k]
68- coeffs, rms = inner_fit (αs , ζ; n, l)
64+ β, γ, ζ = Optim. minimizer (res)
65+ alphas = [β * γ^ (i - 1 ) for i = 1 : k]
66+ coeffs, rms = inner_fit (alphas , ζ; n = n, l = l)
6967 return β, γ, ζ, coeffs, rms
7068end
7169
@@ -76,7 +74,7 @@ function print_gaussian94(io, element, n, l, β, γ, coeffs)
7674 println (io, " $element $lchar $k " )
7775 for (i, c) in enumerate (coeffs)
7876 α = β * γ^ (i - 1 )
79- @printf (io, " %14.8f %14.8f \n " , α, c )
77+ print (io, " $α $c \n " )
8078 end
8179end
8280
@@ -88,22 +86,22 @@ shell_table = Dict(
8886 " H" => [(1 , 0 , 3 )], # 1s STO‑3G
8987 " C" => [(1 , 0 , 3 ), # 1s
9088 (2 , 0 , 3 ), # 2s
91- (2 , 1 , 3 ), # 2p (shares β,γ with 2s manually )
92- (0 , 2 , 1 )] # 3d polarisation (single prim.)
89+ (2 , 1 , 3 ), # 2p (shares β,γ with 2s)
90+ (0 , 2 , 1 )] # 3d polarisation
9391)
9492
9593open (" my-basis.gbs" , " w" ) do io
9694 for el in elements
9795 for (idx, (n, l, k)) in enumerate (shell_table[el])
9896 # share β, γ between 2s and 2p (SP trick) if consecutive in list
9997 if el == " C" && n == 2 && l == 1 && idx > 1
100- β, γ, _, _, _ = optimise_basis (k; n = 2 , l = 0 )
101- ζ = 1.0 # ζ irrelevant for pure Gaussian fit
98+ β, γ, _, _, _ = optimise_basis (k, 2 , 0 )
99+ ζ = 1.0 # ζ irrelevant for pure Gaussian fit
102100 coeffs, _ = inner_fit ([β * γ^ (i - 1 ) for i = 1 : k],
103101 ζ; n = 2 , l = 1 )
104102 print_gaussian94 (io, el, n, l, β, γ, coeffs)
105103 else
106- β, γ, ζ, coeffs, _ = optimise_basis (k; n, l)
104+ β, γ, ζ, coeffs, _ = optimise_basis (k, n, l)
107105 print_gaussian94 (io, el, n, l, β, γ, coeffs)
108106 end
109107 end
0 commit comments