Skip to content

Commit c855755

Browse files
committed
Add script to optmize the coefficients of the basis sets
1 parent ed881a6 commit c855755

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

basissets.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
],
8484
"metadata": {
8585
"kernelspec": {
86-
"display_name": "Julia 1.11.3",
86+
"display_name": "Julia 1.11.2",
8787
"language": "julia",
8888
"name": "julia-1.11"
8989
},

sto3g-test.jl

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
###############################################################################
2+
# STO-nG regression test (H 1s example) #
3+
# ----------------------------------------------------------------------- #
4+
# • Uses numerical quadrature (QuadGK) for all radial integrals. #
5+
# • Shows two optimisation routes #
6+
# 1. Direct normal-equation solve C*c = B (strict least-squares) #
7+
# 2. Gradient descent with automatic differentiation (Zygote) #
8+
# • Prints the RMS radial error and the fitted coefficients. #
9+
# ----------------------------------------------------------------------- #
10+
# REQUIRE: julia> ] add QuadGK Zygote #
11+
###############################################################################
12+
13+
using LinearAlgebra, QuadGK, Zygote
14+
15+
# ---------- 1. Slater-type (target) orbital --------------------------------
16+
"""
17+
χ_STO(r; ζ=1.24, n=1)
18+
19+
Unnormalised radial part r^{n-1}·exp(-ζ·r).
20+
"""
21+
χ_STO(r; ζ=1.24, n=1) = r^(n-1) * exp(-ζ * r)
22+
23+
"""
24+
normalise_STO(ζ; n=1)
25+
26+
Returns the normalisation constant N such that
27+
∫₀^∞ |N·χ_STO(r)|²·r² dr = 1
28+
"""
29+
function normalise_STO(ζ; n=1)
30+
# analytic for n = 1,2,… : N = √( (2ζ)^{2n+1} / (2n)! )
31+
return sqrt( (2ζ)^(2n+1) / factorial(2n) )
32+
end
33+
34+
# ---------- 2. Primitive Gaussian -----------------------------------------
35+
"""
36+
χ_G(r, α; l=0)
37+
38+
Primitive Gaussian r^{l}·exp(-α·r²)
39+
(Angular part is ignored because we only care about the radial fit.)
40+
"""
41+
χ_G(r, α; l=0) = r^l * exp(-α * r^2)
42+
43+
# ---------- 3. Radial integrals (numerical) -------------------------------
44+
const atol = 1e-12 # quad accuracy
45+
46+
# ∫₀^∞ f(r) r² dr (measure already contains 4π average over angles)
47+
function radial_integral(f)
48+
value, _err = QuadGK.quadgk(r -> f(r) * r^2, 0.0, Inf; atol)
49+
return value
50+
end
51+
"""
52+
build_matrices(alphas, ζ; l=0, n=1)
53+
54+
Return (A, B, C) for the quadratic error
55+
R² = A − 2 cᵀ B + cᵀ C c
56+
"""
57+
function build_matrices(alphas, ζ; l=0, n=1)
58+
k = length(alphas)
59+
# Normalised STO
60+
N = normalise_STO(ζ; n)
61+
sto = r -> N * χ_STO(r; ζ, n)
62+
# A = ⟨STO|STO⟩ = 1 by construction
63+
A = 1.0
64+
# Bᵢ = ⟨PGFᵢ|STO⟩
65+
B = [ radial_integral(r -> χ_G(r, α; l) * sto(r)) for α in alphas ]
66+
# Cᵢⱼ = ⟨PGFᵢ|PGFⱼ⟩
67+
C = [ radial_integral(r -> χ_G(r, αi; l) * χ_G(r, αj; l))
68+
for αi in alphas, αj in alphas ]
69+
return A, B, Symmetric(reshape(C, k, k))
70+
end
71+
72+
# ---------- 4. Direct least-squares solution ------------------------------
73+
function fit_direct(alphas, ζ; l=0, n=1)
74+
A, B, C = build_matrices(alphas, ζ; l, n)
75+
c = C \ B # solve normal equations
76+
# renormalise contracted Gaussian
77+
norm = sqrt(dot(c, C * c))
78+
c ./= norm
79+
# RMS error
80+
R2 = A - 2dot(c, B) + dot(c, C * c)
81+
return c, sqrt(R2)
82+
end
83+
84+
# ---------- 5. Gradient descent (AD) --------------------------------------
85+
"""
86+
fit_AD(alphas, ζ; l=0, n=1, lr=1e-2, maxiter=2000)
87+
88+
Crude gradient descent on the same quadratic loss, to illustrate that
89+
AD finds the same minimum as the linear solve.
90+
"""
91+
function fit_AD(alphas, ζ; l=0, n=1, lr=1e-2, maxiter=2000)
92+
k = length(alphas)
93+
A, B, C = build_matrices(alphas, ζ; l, n)
94+
c = fill(0.3, k) # naive start
95+
loss(c) = A - 2dot(c, B) + dot(c, C * c)
96+
for it = 1:maxiter
97+
grad = Zygote.gradient(loss, c)[1]
98+
c .-= lr * grad
99+
if norm(grad) < 1e-10
100+
break
101+
end
102+
end
103+
# renormalise and RMS
104+
c ./= sqrt(dot(c, C * c))
105+
R = sqrt(loss(c))
106+
return c, R
107+
end
108+
109+
# ---------- 6. Demo: H 1s STO-3G ------------------------------------------
110+
ζ_H = 1.24 # standard value used by STO-3G
111+
αs = [0.109818, 0.405771, 2.22766] # H 1s STO-3G exponents
112+
113+
#c = [0.9817067, 0.949464, 0.2959065]
114+
115+
#H 0
116+
#S 3 1.00
117+
# 0.3425250914D+01 0.1543289673D+00
118+
# 0.6239137298D+00 0.5353281423D+00
119+
# 0.1688554040D+00 0.4446345422D+00
120+
#****
121+
122+
c_direct, RMS_direct = fit_direct(αs, ζ_H)
123+
c_AD, RMS_AD = fit_AD(αs, ζ_H; lr=1e-1)
124+
125+
println("=== STO-3G (H 1s) fit with fixed exponents ===")
126+
println("Direct linear solve:")
127+
println(" c = ", round.(c_direct, sigdigits=7))
128+
println(" RMS = ", print("%.3e", RMS_direct))
129+
println("Automatic-diff AD gradient descent:")
130+
println(" c = ", round.(c_AD, sigdigits=7))
131+
println(" RMS = ", print("%.3e", RMS_AD))

0 commit comments

Comments
 (0)