A system for variational Monte Carlo calculations spring 2009

advertisement
A system for variational Monte Carlo calculations
Project 1, FYS4410, Computational Physics 2,
spring 2009
Kyrre Ness Sjøbæk
April 14, 2009
Abstract
In this document I will describe a program for calculating the energy of various atoms using Metropolis-Hastings Monte-Carlo, given
an electron many-body wavefunction. I will further describe how it
may be easily generalized it to any quantum system where the Hamiltonian is only acting in position space, and we have an even number
of fermions.
I will also describe methods to find the wavefunction describing the
ground state of the system. Given this, we can calculate properties such
as ground state energy to a high accuracy, as well as the onebody- or
charge density.
I will also describe a technique for estimating the calculation error
(blocking), as well as how to automate this calculation.
1
Contents
1 Introduction
1.1 Many-body quantum mechanics . . . . . . . . . . . . . . . .
1.1.1 Choice of test wavefunctions . . . . . . . . . . . . . .
1.1.2 Onebody- and charge density . . . . . . . . . . . . .
1.2 Monte-Carlo integration . . . . . . . . . . . . . . . . . . . .
1.2.1 Importance sampling . . . . . . . . . . . . . . . . . .
1.2.2 Metropolis algorithm . . . . . . . . . . . . . . . . . .
1.2.3 Metropolis-Hastings algorithm . . . . . . . . . . . .
1.2.4 Use of Monte Carlo integration in Quantum physics
1.2.5 Error estimation through blocking . . . . . . . . . .
1.3 Variation of parameters . . . . . . . . . . . . . . . . . . . .
1.3.1 Sample and plot . . . . . . . . . . . . . . . . . . . .
1.3.2 Outline of the Conjugate Gradient Method (CGM) .
.
.
.
.
.
.
.
.
.
.
.
.
4
5
6
8
9
10
11
12
14
15
16
16
17
2 Program
2.1 Basic structure . . . . . . . . . . . . . . . . . .
2.2 Wavefunctions . . . . . . . . . . . . . . . . . . .
2.2.1 Stateless . . . . . . . . . . . . . . . . . .
2.2.2 Statefull . . . . . . . . . . . . . . . . . .
2.2.3 Support for Conjugate Gradient Method
2.2.4 Other features . . . . . . . . . . . . . .
2.3 Algorithms . . . . . . . . . . . . . . . . . . . .
2.3.1 Brute-force Metropolis . . . . . . . . . .
2.3.2 Importance sampling Metropolis . . . .
2.3.3 Blocking . . . . . . . . . . . . . . . . . .
2.3.4 CGM . . . . . . . . . . . . . . . . . . .
2.4 Runner scripts . . . . . . . . . . . . . . . . . .
2.4.1 Grid sampling programs (vmc_*.cpp) . .
2.4.2 CGM (paramsearch_conjgrad.cpp) . .
2.4.3 Misc. . . . . . . . . . . . . . . . . . . . .
2.5 Parallelization . . . . . . . . . . . . . . . . . . .
2.6 Ideas for improvement . . . . . . . . . . . . . .
2.6.1 Performance improvements . . . . . . .
2.6.2 Better program structure . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
19
19
19
19
21
23
23
23
24
25
25
26
27
27
28
29
29
30
30
31
.
.
.
.
.
.
32
32
32
34
36
36
38
3 Results
3.1 Minimum of Ē[~
α] .
3.1.1 Helium . . .
3.1.2 Beryllium .
3.1.3 Neon . . . .
3.2 Value of the energy
3.2.1 Blocking . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
at the minimum
. . . . . . . . . .
2
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3.3
3.2.2 Helium . . . . .
3.2.3 Beryllium . . .
3.2.4 Neon . . . . . .
Charge density profiles
3.3.1 Helium . . . . .
3.3.2 Beryllium . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4 Appendix A: Header files
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
38
39
40
42
42
43
43
3
1
Introduction
The goal of our calculation is to find an approximation to the exact solution
of Schrödinger’s equation (1). We are going to work in the position basis,
so the vector ψ is represented by a wavefunction. The Hamiltonian Ĥ is
therefore also written in a position basis.
Ĥψ = Eψ
(1)
Equation (1) is an eigenvalue equation. We may identify the eigenvalue E
of the Hamiltonian and eigenfunction ψ as the energy of the system, given
that it is in the state ψ.
The solution we are after is what is called the ground state, ψgs , which
has the energy Egs . This is the solution of (1) with the lowest possible
eigenvalue E, and thus the lowest possible energy. This is an interesting
state as the dynamics of the quantum system will probably take it toward
this state via interaction (emission of photons etc.).
We will not try to solve (1) exactly, but instead try to find an as good as
possible estimate for the wavefunction ψgs . In order to do this will make an
ansatz wavefunction with tunable parameters, which we will vary in order
to find an as low as possible energy. This is called the variational method1 .
The method is then to calculate the energy at different sets of variational
parameters, in order to find the set of parameters that yields the lowest
energy. This is equivalent to sampling different points in the Hilbert space, as
our parameter space is a subset of the full Hilbert space. It also means that by
varying the set of parameters, we will pick up different energy eigenfunctions,
as our test wavefunction2 ψT ({~r}; α
~ ) may be written as a weighted sum over
energy eigenstates ψi :
∞
X
ψT =
Ci ψi
i=gs
As our «convergence criteria» is that we find a minima in the energy as a
function of the parameters3 , this will quite reliably give us the ground state
energy (given that we have a good ansatz wavefunction), but the wavefunction might not be as well described. This is due to that several wavefunctions will contribute (unless we have the true ground state WF), which could
make an impact for example the shape of the the onebody density (see section 1.1.2)) and other observables. This will be especially bad if we have a
degenerate or close to degenerate ground state.
1
See for example D.J.Griffiths, ’Introduction to quantum mechanics’ (Pearson 2005,
2ed, international edition), Chapter 7 ’The variational principle’
2
I have defined {~r} as the set of single-particle positions, and α
~ is the set of variational
parameters.
3
In other words, δE = E(δ~
α) → 0
4
1.1
Many-body quantum mechanics
As most interesting physical systems are composed of several interacting
particles, we need a formalism that accommodates it. Further, quantum
particles have non-classical properties, such as being indistinguishable, as
well as being either fermions or bosons.
If we specialize to fermions, as electrons are of this type (being spin 1/2),
they are characterized by not being able to share the same quantum state,
and also fulfilling the anti-symmetrisation requirement
P̂ ψ(~r1 , s1 ; ~r2 , s2 ; . . . , ~ri , si ; . . . ; ~rj , sj ; . . . ; ~rn , sn )
= −ψ(~r1 , ~r2 , . . . , ~rj , . . . , ~ri , . . . , ~rn )
(2)
, where P̂ is an exchange operator interchanging ~ri , si and rj , sj , or more
generally interchanging the quantum numbers of single-particle wavefunction
i with single-particle wavefunction j 4 .
A way of writing a manybody wavefunction fulfilling (2), is by using a
Slater determinant, such as shown in (3).
ϕ1 (~r1 , s1 ) ϕ2 (~r1 , s1 ) · · · ϕn (~r1 , s1 ) ..
ϕ1 (~r2 , s2 ) ϕ2 (~r2 , s2 )
.
(3)
ψ(~r1 , s1 ; r2 , s2 ; · · · ) = |φ| = ..
.
.
.
.
.
.
.
ϕ1 (~rn , sn ) ϕ2 (~rn , sn ) · · · ϕn (~rn , sn )
Exchange of any two coordinates is equivalent to interchanging two rows in
(3), and exchange of any two quantum numbers is equivalent to interchange
of two columns. This yields a sign change in the determinant (and thus the
wavefunction), which is exactly what we want for fermions.
However, this means that for an N -body wavefunctions, we have to keep
track of an N × N slater matrix, which is quite heavy for a big system.
Luckily, if the Hamiltonian is spin-independent, and N is even, the slater
determinant of the wavefunction used as input to this operator may be split
into two N2 × N2 matrices.
We may see this by a simple example – Helium. The ground-state of
Helium is two electrons in the 1s orbital, which means the spins have to be
anti-symmetric. This means we may write the slater matrix as
ϕ1s (~r1 )χ↑ (s1 ) ϕ1s (~r1 )χ↓ (s1 )
|φ| = ϕ1s (~r2 )χ↑ (s2 ) ϕ1s (~r2 )χ↓ (s2 )
=ϕ1s (~r1 )χ↑ (s1 )ϕ1s (~r2 )χ↓ (s2 ) − ϕ1s (~r2 )χ↑ (s2 )ϕ1s (~r1 )χ↓ (s1 )
4
We might write ψ(~r1 , s1 ; ~r2 , s2 ; · · · ) as h~r1 , s1 ; ~r2 , s2 ; · · · |ϕ1 , ϕ2 , ϕ3 , · · ·i, where ~ri , si are
single particle positions in position- and spin-space, while ϕj are single-particle wavefunctions. This means that if whether choose to interchange the positions or the single-particle
wavefunctions is irrelevant. We also see that the space the particles are described in (here:
position and spin) does not matter.
5
which means that
Ĥϕ1s (~r1 )χ↑ (s1 )ϕ1s (~r2 )χ↓ (s2 ) − ϕ1s (~r2 )χ↑ (s2 )ϕ1s (~r1 )χ↓ (s1 )
= (χ↑ (s1 )χ↓ (s2 ) − χ↑ (s2 )χ↓ (s1 )) Ĥϕ1s (~r1 )ϕ1s (~r2 )
, where ϕ1s (~r1 )ϕ1s (~r1 ) is the product of two (1 × 1) slater matrices with
identical space-only quantum numbers. This results generalizes to higher
number of particles – for example for beryllium (Z = 4) we get
ϕ1s (~r1 )χ↑ (s1 ) ϕ1s (~r1 )χ↓ (s1 ) ϕ2s (~r1 )χ↑ (s1 ) ϕ2s (~r1 )χ↓ (s1 )
ϕ (~r )χ (s ) ϕ1s (~r2 )χ↓ (s2 ) ϕ2s (~r2 )χ↑ (s2 ) ϕ2s (~r2 )χ↓ (s2 )
|φ| = 1s 2 ↑ 2
ϕ1s (~r3 )χ↑ (s3 ) ϕ1s (~r3 )χ↓ (s3 ) ϕ2s (~r3 )χ↑ (s3 ) ϕ2s (~r3 )χ↓ (s3 )
ϕ1s (~r4 )χ↑ (s4 ) ϕ1s (~r4 )χ↓ (s4 ) ϕ2s (~r4 )χ↑ (s4 ) ϕ2s (~r4 )χ↓ (s4 )
which may be written as the product of two 2 × 2 matrices
ϕ1s (r~1 ) ϕ2s (r~1 ) ϕ1s (r~3 ) ϕ2s (r~3 )
·
|φ1 | · |φ2 | = ϕ1s (r~2 ) ϕ2s (r~2 ) ϕ1s (r~4 ) ϕ2s (r~4 )
when calculating the energy with a spin-independent Hamiltonian. Similar
is the case for Neon (Z = 10), where we instead get 5 × 5 matrices when the
Hamiltonian does not act on spin.
Unfortunately5 , Slater matrices are not all there is to manybody quantum
mechanics. A quantum system is fundamentally different from a classical
system in that it is more than the sum of its parts – there are multi-particle
correlations that needs to be taken care of. In order to do this, we will use a
Jastrow factor which takes into account two-particle correlations, as we only
have two-particle interactions. This may schematically be written as
Y
J=
g(rij )
(4)
i<j
, where g(rij ) is some function of the separation distance rij , and we are
taking the product of g(rij ) between the all possible sets two states.
1.1.1
Choice of test wavefunctions
In order to have an as good as possible convergence to the ground state, it is
necessary that our parametrized test wavefunction span the part of Hilbert
space containing the true ground state, or at least get close to it. Further,
we need to avoid infinities in the integrals.
In order to satisfy the last condition, we need to obey the so-called cusp
condition6 . This is in order to avoid the infinities when we have an Hamiltonian which includes terms on the form rZi and/or r1ij . This may be done by
5
If this was true, we would rather use Hartree-Fock methods, which are much faster,
but can only handle systems described by a Slater determinant
6
M. Hjorth-Jensen, ’computational physics’, university of Oslo, 2009, unpublished.
6
demanding that the radial part of the wave function should be on the form
α
RT ∝ e− l+1 r
, where α ≈ Z.7 Similarly for the jastrow factors g(rij )
rij
g(rij ) ∝ exp
2(l + 1)
.
Since we here are interested in atomic systems, a good choice of trial
wavefunctions is probably to use the Hydrogen wavefunctions, as they are
exact solutions to a similar problem, and are quite easy to handle (at least
for low quantum numbers) both numerically and analytically. We have used
the (non-normalized) single-particle wavefunctions listed below. I have also
listed the gradients and the laplacians, as they are needed for the kinetic
energy, and also for the Metropolis-Hastings algorithm described in sections
1.2.3 and 1.2.4.
ϕ1s (r) = e−αr
~ 1s (~r) = − α~r e−αr
∇ϕ
r
α
2
∇ ϕ1s (r) =
(αr − 2) e−αr
r
αr − α r
ϕ2s (r) =
1−
e 2
2
~ 2s (~r) = − α~r 2 − αr e− α2 r
∇ϕ
2r 2
αr αr 2 α
α
2
4−5
+
e− 2 r
∇ ϕ2s (r) = −
2r
2
2
α
ϕx2p (~r) = αxe− 2 r
αxy αxz α
αx2
x
~
k̂ e− 2 r
∇ϕ2p (~r) = α
1−
î −
ĵ −
2r
2r
2r
α2 x αr −α r
4−
e 2
∇2 ϕx2p (~r) = −
2r
2
For the 2p state, we actually have four states, corresponding to the magnetic
quantum numbers m = {0, ±1}. For our observables we may use so-called
real solid harmonics instead. Thus ϕx2p in the table actually represents three
wavefunctions – one for x (the one listed), one for y, and one for z.
For our Jastrow factor, we choose
arij
g(rij ) = exp
(1 + βrij )
7
Approximately due to charge-screening effects, making the effective charge seen by
electrons smaller than the real Z
7
, where a = 1/2 for opposite spins, and a = 1/4 for equal spins. The gradient
and Lapla|cian of the Jastrow factor is then:
~ i g(rij ) =
∇
∇2i g(rij ) =
1.1.2
a(~ri − ~rj )
rij (1 + βrij )2
2a
rij (1 + βrij )3
Onebody- and charge density
Another experimental8 quantity we are interested in (in addition to the
ground state energy), is the charge density of the atom. For single particle wavefunctions, this is simply given by equation (5), while it is generally
(for N-particle systems) given by equation (6).
ρ(~r) = Z · |ψ(~r)|2
Z
|ψ({~r})|2 d3~r2 . . . d3~rn
ρ(~r) = Z ·
(5)
(6)
V
We see that eq. (5) is just a special case of eq. (6).
Further, we define the onebody density as
f (~r) =
ρ(~r)
Z
(7)
. The variational calculation may be used to get an estimate the groundstate wavefunction, which may then be plugged into (6) to get the charge
density. However we are still bound by that the variational calculation may
not give a good estimate for the ground-state wavefunction, as discussed in
section 1.
We also see that the onebody density has a normalization criteria
Z
Z Z
3
f (~r)d ~r =
|ψ({~r})|2 d3~rd3~r2 · · · d3~rn
V
V
V
Z
(8)
2 3
3
=
|ψ({~r})| d ~r1 · · · d ~rn = 1
V
as the last integral is identical to the normalization integral for the wavefunction.
8
When doing scattering experiments, we often get a «form factor» F (~
q 2 ) (where ~
q2
is the square of the momentum transfer) that modifies the main part of the differential
crossection. This form factor is in turn given by the fourier transform of the charge
distribution, e.g.
Z
F (~
q2 ) =
ei~q·~x/~ f (~
x)d3 ~
x
where f (~
x) is the onebody density. See for example Povh, Rith, Scholz and Zetshe,
’Particles and Nuclei’, 5th ed, Springer 2006, chapter 5.4.
8
It is often useful (especially for wavefunctions where f (~r) is spherically
symetric) not to plot the onebody density, but instead use the radial density,
which for a spherically symmetrical wavefunction is defined as
(9)
R(r) = f (r) · r2
. This is proportional to «how much» of f (r) is found at the distance r from
the center, as it takes into account that the volume of the infinitely thin
spherical shell the PDF f (r) lives on is ∝ r2 . The radial density (if assumed
to be spherically symmetric) then has the normalization condition
Z ∞
Z ∞Z
Z
2
3
R(r)dr
f (r)r drd = 4π
f (r)d ~r =
1=
0
V
0
ω
Z
∞
⇒
R(r)dr =
0
1.2
1
4π
(10)
Monte-Carlo integration
When integrating multidimensional functions as we are doing when calculation the energy of a manybody quantum system
Z
E = hψ| Ĥ |ψi = ψ ∗ ({~r})Ĥψ({~r})d3~r1 · · · d3~rn
, the most efficient method is Monte-Carlo (MC) integration, where the error
in the results scales approximatly9 as N −1/2 , while for quadrature-based
methods the error scales as N −k/d where k is the order of the method, and
d is the dimension of the hypercube we are integrating.
This method is based on statistics, where the expectation value of an
observable O depending on a stochastic variable x defined in an interval
x ∈ [b, a] is given as
Z b
hOi =
O(x)X(x)dx
a
, where X(x) is the probability distribution function (PDF) of x. This may
be approximated (for example when doing an experiment, where you have a
finite sample size) as
1 X
Ō =
O(x)
N
N
, where x (and thus O(x)) are picked according to the underlying probability
distribution X(x).
9
Se M.H. Jensen, ’Computational Physics’, chapter 8 ’Outline of the Monte-Carlo
strategy’ (as of 20/11 2007)
9
The simplest form of MC integration of a function f (x) is simply to force
1
f (x) = O(x), and X(x) = a−b
, where a, b are the limits of integration. This
yields a brute-force approach, where
Z a
1 X
f (x)dx ≈
f (x)
(11)
N
b
N
1
, and x is picked according to the flat PDF X(x) = a−b
.
This might work well if f (x) is approximately flat within the limits of
integration. However, if the limits are very large (such as ±∞ or [0, ∞i. . . ),
or the function is not at all flat, we will need very many cycles to achieve a
reasonable accuracy. What we then may do is to sample according to another
PDF than the simple flat one, preferably one that follows the function we
are trying to integrate quite closely. This may be seen as factorizing the
function we are trying to integrate f (x) into a PDF and an observable
f (x) = X(x)O(x)
(12)
.
1.2.1
Importance sampling
The most direct way of doing the factorization (12), is if we have an analytical
expression for the PDF X(x) contained in f (x). For example, this may be
an exponential distribution X(x) = e−x , x ∈ [0, ∞), as is the case with the
integrals we have to solve to get the one-body densities.
As a practical example, we may take a function f (x) = e−ax g(x). If we
now take X(x) = ne−ax to be our PDF, where n is an normalization constant
which can be shown to be n = a.
However, we cannot sample directly from an exponential distribution,
as our random generators only gives us numbers from the uniform distribution. Thus we make a switch of variables x → y, where y is an uniformly
distributed random variable on the interval y ∈ [0, 1]. Conservation of probability yields that
ae−ax dx = 1dy
, and integrating this yields the cumulative probability distributions
Z x
Z y
−1
ae−ax dx = a (e−ax − a0 ) =
dy = y
a
0
0
. Using this we can finally arrive at the change of variables we need:
x=
−1
ln(1 − y)
a
10
(13)
This means our integral may be written as
Z ∞
Z ∞
g(x)
ae−ax
f (x)dx =
f (x) =
dx
a
0
0
Z 1
g −1
a ln(1 − y)
=
dy
a
0
(14)
, which may then be approximated using (11). If our new function g(y) then
is quite flat, we may then need vastly fewer cycles to achieve the same level
of accuracy, and we may sample x ∈ [0, ∞] without making a cutoff.
1.2.2
Metropolis algorithm
If we cannot get an analytical expression for the inverse of the PDF, such
as (13), we may still do importance sampling. One way of doing this is by
simulating the probability distribution using the metropolis algorithm.
In the metropolis algorithm, one simulates the diffusion equation to move
the sampling point around in the space of integration points. The PDF we
are simulating from is then taken to be the the steady-state distribution from
a diffusion process. The sampling point then moves about according to this
PDF.
This leads to10 the algorithm shown in figure 1, given the factorization
(12). In the metropolis algorithm the ratio
R=
X(xi+1 )
X(xi )
(15)
plays a vital role, as it decides whether the jump is made or not. As the
random number r ∈ [0, 1], we see that a move to a more probable position
will always be accepted, as this yields R > 1. However, there is a nonzero
probability R for accepting a move to a less probable position. This means
that we will reach the most likely state of the system (equilibrium), while all
points in space may be sampled (ergodic).
We therefore run the algorithm for many cycles while collecting statistics of functions distributed according to the PDF (there may be several),
basically using eq. (11). But before we start collecting statistics, we should
do a small (O(104 )) number of cycles in order to reach the most likely state
of the system. This is called thermalization.
When choosing the stepsize h of the algorithm, we must be a bit careful,
and not choose a to large stepsize, as this will lead to large fluctuations in the
value of the wavefunction between one step and the next. This will in turn
mean that the probability for accepting (especially for a PDF approximatly
shaped as a Gaussian or an exponential function, which are much larger at
the center, and then tapers of into nothing when we leave this area) a move
10
Read (for example) M.H. Jensen ’Computational physics’ for more details
11
Start at a point x0
Propose a move to
a new point x1 = x0±h
Calculate the ratio
R = X(x1)/X(x0)
Generate an
uniformly distributed
random variable r
Compare R and r
Repeat many times
(number of MC cycles)
If R < r:
Go back to x=x0
If R > r:
accept move, x=x1
Collect statistics
(add up sum of functions to
be integrated , which are distributed
according to X(x) )
Store
of stats
Figure 1: Schematic overview of the Metropolis algorithm
is very low. This will in turn lead to highly biased statistics, as we will
barely move at all. A good rule of thumb for efficient calculation is to set
the stepsize so we get about 50% of our moves accepted.
1.2.3
Metropolis-Hastings algorithm
The Metropolis-Hastings algorithm also utilizes a variety of the diffusion
equation called the Fokker-Planck equation, which reads
X
∂
∂
∂P
=
D
− Fi (xi ) P
(16)
∂t
∂xi ∂xi
i
12
. This is different from the usual diffusion equation in that it incorporates a
drift term Fi (xi ). The Fokker-Planck equation may be simulated using the
Langevin equation
d~x
= DF (x(t)) + η
(17)
dt
, which describes the time-evolution of the position of a single particle doing
Brownian motion. Here η is a Gauss-distributed random variable. Integrating using Euler’s method yields
√
~x(ti + ∆t) = DF (x(ti ))∆t + η 0 ∆t
(18)
where η 0 is a normal distributed random variable, and ∆t is the finite timestep
from Euler’s method.
When we have moved our «sampler particle», we must check if we accept
the move or not. The condition on the movement of the sampler is then that
we are in equilibrium (which again necessitates thermalization steps), which
yields11
P (x(t) → x(t + ∆t)) = P (x(t + ∆t) → x(t))
⇒ W (x(t + ∆t)|x(t)) X(x(t)) = W (x(t)|x(t + ∆t)) X(x(t + ∆t))
, where W (x(t + ∆t)|x(t)) is the Green’s function for moving from (x, t) to
(x(t + ∆t), t + ∆t). This yields (in style with the «brute-force» metropolis
algorithm, where W = 1) that the probability for making a move is
R0 =
A(x(t + ∆t)|x(t))
W̃ (x(t + ∆t|x(t)))X(t + ∆t)
=
=
A(x(t)|x(t + ∆t))
W̃ (x(t)|x(t + ∆t))X(t)
W̃ (x(t + ∆t|x(t)))
·R
=
W̃ (x(t)|x(t + ∆t))
(19)
, where A(x(t + ∆t)|x(t)) is the (a priori unknown) acceptance probability of
accepting a move from x(t + ∆t) to x(t), and W̃ (x(t + ∆t|x(t)) the transition
probability for making a move from (x(t), t) to (x(t + ∆t), t + ∆t). R is the
ratio defined in (15), same as in the «brute force» metropolis method.
This transition probability can be calculated to be
h
i
1
0
~ (~x))2
W̃ (~x0 , ~x, δt) =
exp
−(~
x
−
~
x
−
Dδt
F
(4πDδt)3N/2
, where N is the number of particles12 , and we have assumed that the change
in F (~x) is small for a small timestep δt. If we know the diffusion constant D
and the external force F~ (~x), which depend on the PDF, we now know enough
to calculate the new position, and decide whether to accept the move or not.
11
12
For 1-dimensional motion – the generalization to more dimensions is straightforward
The vectors ~
x, ~
x0 are thus vectors in 3N dimensions
13
Thus, the PDF we are simulating from here enters in both the determination of R from eq. (15) (as in the brute-force Metropolis algorithm), and
in the external force F~ (~x), which yields better jumps.
Ideally the timestep ∆t should be as small as possible, so what we might
do is to make several calculations with different ∆t, and then making a fit
of O[∆t], finding the limit O[∆t] → 0, where O is the observable following
the PDF we are simulating.
1.2.4
Use of Monte Carlo integration in Quantum physics
In writing this program, we are interested in simulating from a quantum
PDF, which is the absolute value of the wavefunction squared, which for a
non-normalized wavefunction ψT means
X({~x}) = R
|ψT |2
|ψT |2 d~r1 · · · d~rn
(20)
, where the integral in the denominator is simply the normalization integral.
The main observable of interest for us is the energy, which normally is
calculated as (for a normalized wavefunction ψ)
Z
Ē = hHi = ψ ∗ Ĥψd~r1 · · · d~rn
. However, we want the function under integration, ψ ∗ Ĥψ, on the form of
equation (12), where X(x) should be the quantum PDF (20). This can be
done through a simple rewrite of the equation for Ē,
Z
Z
ψ
∗
Ē = ψ Ĥψd~r1 · · · d~rn = ψ ∗ Ĥψd~r1 · · · d~rn
ψ
(21)
Z
Z
2 Ĥψ
d~r1 · · · d~rn = P ({~r}) · EL ({~r})d~r1 · · · d~rn
= |ψ|
ψ
, where the «local energy» EL is our new observable, following the wanted
PDF (20). We might also define more observables, such as the distance
2 i = hE 2 i − hEi2 , etc.
r12 = |~r1 − ~r2 |, the variance in energy hσE
A good thing about the Metropolis- and Metropolis-Hastings algorithms,
is that the PDF in use do not need to be normalized. To understand this,
we observe that the PDF’s enter in a ratio R, defined in (15). This means
that any normalization constants will removed, as they are constants.
For the Metropolis-Hastings algorithm, it may be shown that the force
F~ is the quantum force13
~
2∇ψ
F~ =
(22)
ψ
13
Assumed that we are in a stationary state, ⇒
14
∂|ψ|2
∂t
=0
, where the vectors are in 3N dimensions14 . The diffusion constant D is in
this case D = 12 .
We may show that in this case, the ratio R0 (defined in eq. (19)) needed
in the metropolis algorithm, may be calculated as
i 1 ~
1 h~ 0
0
0
0
~
~
F (~x ) − F (~x) · ~x − ~x +
F (~x) − F (~x ) D∆t R
P (accept) = R =
2
2
, where we are considering making a move from ~x to ~x0 .
1.2.5
Error estimation through blocking
When we have calculated observables using some Monte-Carlo method, it
is important to be able to say something about the errors of our estimates.
In order to do this, we note that we might view each observation of the
observable as an experiment, and calculate the variance of the observations.
However, this has a couple of problems – the observable might carry its
own intrinsic variance, and the experiments are not independent. This is
explicitly true when we are using Metropolis Monte-Carlo aka Markow chain
Monte-Carlo, but also when using pseudorandom numbers in «normal» importance/brute sampling.
If we instead of calculating the variance of repeated single observations,
we repeat the whole experiment several times, and calculate the estimator
each time. If we have set this up correctly, we will then have several independent observations of the observable we are trying to estimate the error
in. This then yields an distribution of the estimator. If we assume that each
of the estimators are Gauss-distributed around the real expectation value,
we get that the variance in the estimator is given by
2
σ̄ =
2
σ̄hOi
N −1
2
, where N is the number of measurements of the estimator Ō, and σhOi
is
the variance of these measurements. We define the error in the estimator as
s
s
2
σhOi
√
O2 − (Ō)2
errŌ = σ 2 =
=
(23)
N −1
N −1
However, we do not want to actually perform many experiments, and
even our separate Monte-Carlo «experiments» are not guaranteed to be uncorrelated. But what we do know, is that as the Markow chain moves the
sampling walker about, the amount of correlations decrease. Further, if we
14
It may be shown that equation (22) factorizes into N independent 3-vectors if and
only if the wavefunction ψ factorizes into N independent single-particle wavefunctions
15
make a number of moves comparable to the correlation time15 τ , the sampled
values may be taken to be uncorrelated.
Thus, we may divide the experiment into «blocks» of sizes on the order
of τ . Each of these blocks may then be taken to be a separate, uncorrelated
experiment, and we may then use equation (23) to estimate the error in the
total average.
Now we need at method to estimate the optimal block size. This must
be larger than τ in order to have truly uncorrelated blocks, but not to large,
as this will lead to fewer blocks and thus worse statistics when calculating
(23). One way to do this, is to plot errŌ as a function of the blocksize b. We
will then see that as b increases, errŌ does as well. This continues until one
reaches some value of b where errŌ plateaus for a while, before just becoming
noise. This happens when b ≈ τ , so the correct value of errŌ is then the
value at the plateau. I did develop an automatic method for finding the
position of the plateau, and thus automatically calculating the error of the
estimator – see section 2.3.3.
1.3
Variation of parameters
As discussed in the introduction, we need to vary the parameters for of our
wavefunction in order to find the set of parameters witch yields the lowest
energy E[~
α]. I have used a combination of two strategies to do this – «sample
and plot», and the conjugate gradient method. Typically, I have used sample
and plot first in order to approximately bracket the minima, and then used
the conjugate gradient method to find the exact minima.
1.3.1
Sample and plot
In this quite straight-forward method, one defines a set of points in parameter
space that is hoped to surround and include the minima in E[~
α]. One then
calculates the energy of these points, and plots the energy as a function of
the parameters. This plot is then used to eyeball the position of the minima.
An analytical example is if we have a hydrogen 1s test wavefunction with
a single parameter α
ψT = e−αr
, which yields the normalization and local energy
Z
π
ψT∗ ψT d3~r =
α3
α−1
− 0.5α2
EL [α] =
r
15
Se for example H. Flyvbjerg and H.G. Petersen, ’Error estimates on averages of correlated data’, Journal of Chemical Physics, 1989
16
(with Ĥ = − 12 ∇2 − 1r ). We might from this calculate E[α] using eq. (21),
which yields
1
hE[α]i = α2 − α
2
, which has the analytical minima at α = 1, hE[α = 1]i = −0.5, which is the
analytical solution. This yields a plot as shown in figure 2. We can easily
see where the minima is (at least approximately), as well as how deep it is.
Hydrogen, analytical solution
0
−0.05
−0.1
−0.15
E[α]
−0.2
−0.25
−0.3
−0.35
−0.4
−0.45
−0.5
0
0.2
0.4
0.6
0.8
1
α
1.2
1.4
1.6
1.8
2
Figure 2: Analytic solution of E[α] for hydrogen, ψT = e−αr
If we where to do this in a case where calculating E[~
α] was quite expensive
(For Neon, it takes something like 3 minutes with 60 quite modern CPU’s),
we would calculate and plot a few points, look at the plot, chose some new
points etc. all the time trying to use our computational resources as close as
possible to the minimum. However, I did use hydrogen as a test case when
developing my codes.
1.3.2
Outline of the Conjugate Gradient Method (CGM)
If we are able to get not only the value of the function we are trying to
minimize (in our case E[~
α]), but also the partial derivatives, this could lead
to a quicker convergence than sampling and plotting. We might then approximate the function as a quadratic form
1
f (~x) ≈ c − ~b · ~x + ~xT A~x
2
, as shown in figure 3.
17
(24)
Figure 3: The steepest decent method often have to make a lot of extra
evaluations. (Figure from ’Numercal Recipes’ by William H. Press, Saul A.
Teukolsky, William T. Vetterling, Brian P. Flannery, 3rd edition, Cambridge
university press 2007, figure 10.8.1)
A naive way of exploiting the partial derivative (aka the gradient) information, is to always move in the direction of steepest decent. However, this
turns out not to always be effective, as we might end up jumping a lot «back
and forth», as shown in figure 3. What the CGM method does, is trying
to construct the next vector so it is conjugate to the previous (with respect
to the quadratic form.16 A reference to CGM is ’Numerical Recipes’, 3rd
ed. (detailed citing in caption of figure 3), chapter 10.8 ’Conjugate Gradient
Methods in Multidimensions’.
This is exploitable in our MC method, as we may sample the gradients
the same way we are sampling the local energy etc. It may be shown that17
∂E
ψi
ψi
=2
EL − hEL i
(25)
∂αi
ψ
ψ
, where ψi is defined as:
∂ψ
(26)
∂αi
I use this to sample the partial derivatives at each point. This is quite
cheap when we get analytic expressions for ψi (Helium, Hydrogen), but beψi ≡
16
Ideally it should be conjugate to all previous jumps, at least until the assumption of a
quadratic form break down. At this point the Fletcher-Reeves version of CGM effectively
resets, going down the steepest gradient again. I do not know what version of CGM is
implemented in the library we have used.
17
See for example M. Hjorth-Jensen, computational physics
(Lecture notes), university of Oslo, 2009, unpublished:
http://www.uio.no/studier/emner/matnat/fys/FYS4410/v09/
undervisningsmateriale/Slides%20from%20Lectures/slides2009.pdf
18
comes more expensive when we have to evaluate the partial derivatives of
the slater matrices and the Jastrow factor numerically.
2
Program
This is a short description on how the program is built, and how to use
it. It is not a detailed description of the algorithms used – for that look
into to section 1, and the slides from the lectures, which may be found at
http://www.uio.no/studier/emner/matnat/fys/FYS4410/v09/
undervisningsmateriale/Slides%20from%20Lectures/slides2009.pdf
. I will also describe the structure of the program and how to use it in a talk
which will be put on my webpage, http://folk.uio.no/kyrrens.
2.1
Basic structure
The main part of this program is the classes Wavefunction (described in
section 2.2, header file found in listing 2), and MontecarloAlgo (described
in section 2.2, header file found in listing 3).
2.2
Wavefunctions
The class Wavefunction is an interface – it does not provide a complete
implementation. In order to have a complete implementation, a class you
can actually have an object of, you need to define another class that inherits
from Wavefunction.
These objects are the actual physical description of the system, and defines the test wavefunction, the Hamiltonian (expressed as the local energy)
and more.
The point of doing this, is so that you may pass around pointers to
general wavefunctions, use them in MonteCarlo integrations (see section 2.3)
etc. without needing to rewrite this code every time you want to treat a new
system – which is represented as a new implementation of the Wavefunction
interface/baseclass. The tree of classes belonging to the Wavefunction family
may be seen in figure 4.
Note that there are actually two interfaces – Wavefunction and
Wavefunction_Slater. The first is the most general, and is used directly by
the «stateless» wavefunctions (described in section 2.2.1), while the second
is used for larger many-body systems using slater determinants (described
in section 2.2.2).
2.2.1
Stateless
The simpler systems are implemented using the Wavefunction interface directly, and includes hydrogen_1s, helium1_nocor, and helium1. These
19
Figure 4: Class diagram for the wavefunctions
20
classes then have to provide implementations of the methods
• double getWf(double** r)
• double local_energy(double** r)
• void print_params()
• double* get_partPsi_over_psi(double** r)
. These wavefunctions are called stateless as they do not keep a state on
position – you specify the position with each call to getWf, local_energy
etc.
In addition helper functions that simplifies definition of the Hamiltonian
is provided. Also, all the implementing wavefunctions I have written provides
functions double getAlpha() etc. in order to make it possible to retrieve
the variational parameters, which was set in the constructor.
2.2.2
Statefull
The statefull wavefunctions are implemented using the interface Wavefunction_Slater,
and includes the atomic systems beryllium_nocor, beryllium, and neon.
These classes only have to provide an constructor to configure Wavefunction_Slater.
The reason these wavefunctions are called statefull, is because they keep
a set of particle positions stored internally, and the local energy etc. is then
only defined for this position. If you want to get these values for another set
of positions, you have to move your particles, one at a time – as in done in
the metropolis algorithm. This is done in order to save many calculations
within the Slater determinant and the Jastrow factor, as not all needs to be
recalculated when moving one particle.
There are two modes of movement – one adapted to the Brute-force MC
algorithm (described in section 2.3.1), and one for the importance sampling
MC algorithm (described in section 2.3.2).
When brute-force sampling, all you need to decide whether you accept
or not, is the ratio R which is defined in equation (15). In order to get this,
call the function double getRatio(double* r_new, int particle). This
will return the ratio, which you may then compare to a random number
in the Metropolis algorithm. If you decide to accept, you then call void
acceptMove(), which will update the internal state of the wavefunction.
You may now call double local_energy() etc. to get the local energy at
the current position.
However, when importance-sampling, we need more information in order to compute the ratio R0 defined in equation (19). Especially, we need
the quantum force defined in equation (22), which involves the gradient
of the wavefunction. In order to calculate this, we need to update the
Slater determinant and the Jastrow factor. This is done by calling void
21
tryMove(double* r_new, int particle). When this has been called, the
internal state is updated, and it is possible to get the new quantum force
etc. at the new position. In order to make it easy and fast to rollback if the
move was rejected, the method void rollback() moves back to the position
before the move was made.
As the test wavefunction may be written as
(27)
ψT = φ1 ~r1 , · · · , ~rN/2 · φ2 ~rN/2+1 , · · · , ~rN · J(rij )
, this wavefunction holds pointers to two Slater and one Jastrow class.
Slater determinant The Slater class18 implements a single Slater determinant in a statefull way. It keeps an updated version of the Slater matrix,
the inverse slater matrix, etc. By use of these, it makes it possible to get the
ratio R, the gradient and Laplacian of the matrix etc.
As a Slater matrix is defined by the single-particle orbitals it contains
(as described in section 1.1 and particularly 1.1.1), a N -dimensional Slater
matrix class holds pointers to N objects implementing the Orbital interface.
These are in turn stateless19 , and provides the value of the single-particle
wavefunction at a given position in 3-space. In addition they also provides
the gradient and the Laplacian of the orbital they are representing at a
given position. This may be implemented analytically or numerically, but in
the current implementations of Orbital (orb1s, orb2s, and orb2p) it is all
analytical, which provides both better accuracy and higher execution speed.
The algorithms used for updating the matrix is described in M.H.Jensen,
’Slides from FYS4410 Lectures’, unpublished, http://www.uio.no/studier/
emner/matnat/fys/FYS4410/v09/undervisningsmateriale/Slides%20from%
20Lectures/slides2009.pdf
Jastrow factor The Jastrow class20 implements a Jastrow factor as discussed in section 1.1. The pure Jastrow class is actually an interface, for
which two implementations are provided – the JastrowDummy and JastrowExp
classes.
The JastrowDummy class is used to provide a Jastrow function pointer
to Wavefunction_Slater in cases where we want to deactivate the Jastrow
factor. This is equivalent to setting J = 1, see equation (27).
The JastrowExp class is used to provide a Jastrow factor on the form
Y
J=
exp(g(rij ))
i<j
18
Header file of Slater class and related classes shown in listing 4.
They do contain a fixed variational parameter set in its constructor
20
Header file of Jastrow class and related classes shown in listning 5.
19
22
, which is what is demanded of the cusp condition (see section 1.1.1). It therefore holds a pointer to another object, which is implementing g(rij ). This
object should be an implementation of the jasFuncExp interface. There exist
one such implementation today, which is jasFuncExp1, which implements a
g(rij )-function on the form
g(rij ) =
arij
1 + βrij
. Here a is 1/2 if the spins of particle i and j are opposite, and 1/4 if the
spins of the particles are equal, and β a variational parameter.
Setting up a statefull wavefunction When setting up a statefull wavefunction, one must setup two Slater objects and one Jastrow object, in
addition to configuring parameters such as the central charge Z etc. You
may also make a setup for the conjugate gradient method, see section 2.2.3
This is done in the class constructor, and I refer you to read the constructors
of the implemented wavefunctions for example.
2.2.3
Support for Conjugate Gradient Method
In order to be able to use the Conjugate Gradient Method, as discussed in
section 1.3.2, we need to be able to sample ψi , as defined in equation (26).
This is implemented through the method double* get_partPsi_over_psi(double**)
which is defined in the Wavefunction interface.
Different implementations provide this differently – hydrogen_1s and
helium1 provides analytical expressions, while classes implementing Wavefunction_Slater
can use helper functions in this interface to setup a numerical derivative.
This method returns an array of length equal to the number of variational
parameters, which contains the different ψi as [ψ1 , ψ2 , · · · ].
2.2.4
Other features
There are support for density calculation support through a stateless implementation of getWf(double** r) present in both in the direct implementations of Wavefunction, as well as in Wavefunction_Slater.
All the wavefunctions also implement a function void print_params(),
which prints the variational parameters as well as some other stats. As this
calls into the Slater and Jastrow objects, this means that any implementation of the underlying classes jasFuncExp and Orbital also have to provide
such a printing function.
2.3
Algorithms
There are basically two algorithms implemented: brute-force metropolis, as
described in section 1.2.2, and importance-sampling Metropolis, also known
23
as Metropolis-Hastings, described in section 1.2.3. This results in four classes,
as there are two different kinds of algorithms, which should be able to work
with two different kinds of wavefunctions (stateless and statefull). The class
diagram for these can be seen in figure 5, and the header file in listing 3.
Figure 5: Class diagram for the algorithms
Generally, an algorithm needs a wavefunction to work with, and a number of MC cycles and thermalization steps. Once setup, you may run the
algorithm by calling void run_algo(). This will take some time, and when
it has returned, you may get the results by calling double getEnergy() etc.
2.3.1
Brute-force Metropolis
The classes metropolis_brute and metropolis_brute_slater implements
a brute force Metropolis method, as discussed in section 1.2.2. The difference
between them is that the first is adapted to a stateless wavefunction, while
24
the second is adapted to a statefull one. This results in the adaptations
discussed in 2.2.1 and 2.2.1. The brute-force metropolis algorithm needs, in
addition to what is mentioned in section 2.3, the step length as a parameter,
which is supplied to the constructor.
2.3.2
Importance sampling Metropolis
In parallel to to the brute-force metropolis algorithms, the classes
metropolis_importance_sampler and metropolis_importance_sampler_slater
implements support for the Metropolis-Hastings algorithm, as discussed in
section 1.2.3, for stateless- and statefull wavefunctions.
This algorithm needs, in addition to what is mentioned in sections 2.3,
the timestep ∆t as a parameter. As is discussed in section 3.2, this parameter
should ideally ∆t → 0, which is obviously not practical. What may be done,
is to calculate the energy (with errorbars) for several ∆t, and make a fit to
what happens when ∆t → 0. We may also run it with a quite small step size
and many steps, as this will also give us a good accuracy.
2.3.3
Blocking
Error estimation through blocking, as discussed in section 1.2.5, is supported
by a set of methods in the MontecarloAlgo interface:
• void activateBlocking()
• double block(long blocksize)
• double getIdealBlockSize()
• double getError(int blocksize)
As it is needed to store all sampled values of the blocked observable21 ,
it we do not want to turn this function on by default. This does not mean
that storing this data is a big problem to do on todays computers – the size
of the blocking array will be equal to sizeof(double)*mc_cycles, where
sizeof(double) = 8 bytes.22 This means that a blocking array of 106
elements would take 8 MB of memory. However, it also means for a really
long run of 109 cycles, it would take 8 Gb, which is a problem. Thus it has
to be activated before you make a run in order to be created.
The method double block(long blocksize) does blocking on the array
with the set blocksize, and returns the estimator O2 of the array. Ō2 does
not need to be calculated for the blocking array, as it equals Ō2 for the entire
set of measurements (in our case, use the square of the return value from
21
22
Only support for the local energy EL is implemented
Tested using GCC as well as mpicxx (Intel icc 10.1) on 64-bit RHEL5 installations
25
double getEnergy()) as long as the blocksize is a factor in the length of
the blocking array, ie. blocksize MOD len(block_array) = 0.
As the error in the estimate of the observable is found by applying eq.
(23) with a blocksize just above the «edge» in errŌ (blocksize), as discussed
in section 1.2.5, it would be nice to have an automatic way of finding this
edge. It turned out (see section 3.2.1) that the derivative of errŌ (blocksize)
was not only relatively noise-free, but also followed the expression
derrŌ (b.s.)
≈ axb
d(b.s.)
, where a and b are constants, quite closely. Thus i could get a quite good estimate of the position of the edge by doing blocking for some reasonable set of
block-sizes23 , calculating the derivative, and fitting to the above expression.
I chose24 to demand that derivative of the error as a function of the block
1
size should at the ideal block-size fall to 1000
of the derivative with block
size 1, in other words
1
1
err0 (b.s. = 1)
=
=
C
1000
err0 (b.s. = ideal)
(28)
. This demand is implemented as a constant in the said function.
In order to make the fit, I implemented a linear least squares method
double* leastsquares(double* x, double* y, double* variance, int
N), which is based on the normal equations25 . This is found in the general
utilities file util.cpp, for which the header file is found in listing 6.
Using this estimate for the ideal block size, you can then call double
getError(int blocksize), which searches for the next matching blocksize,
does blocking using this blocksize, and returns the error.
2.3.4
CGM
As sampling for CGM might be expensive (especially when using Wavefunction_Slater,
as discussed in section 2.2.3), this is turned off by default. If you want to
use it, call void activateDerivatives() before calling void runAlgo().
The results of
∂E
∂αi
may then be fetched using the method double* get_partial_energy() .
You may also call the methods double* get_psiP_over_psi() and double*
23
The implementation is to use the first 30 matching blocksizes
in double getIdealBlockSize()
25
Se David C. Lay, ’Linear Algebra’, 3rd edition, Pearson 2006, and Are Strandlie,
Slides from lectures in FYS4550 (autumn 2008), part I Probability and statistics, http:
//folk.uio.no/ares/FYS4550/Lectures_H08_1.pdf
24
26
get_el_times_psiP_over_psi() to get
ψi
ψ
and
ψi
EL
ψ
, which might be useful if you are running several MC sampling algorithms
in parallel on the same parameter set.
2.4
Runner scripts
As I said, the main parts of this program are kept in the classes described
in sections 2.2 and 2.3. However, some code is needed to setup and run
these algorithms, which is the runner scripts. They are written in C++,
but I choose to call them scripts – they are simple, replaceable, and ugly.
And you frequently need to edit them when you want to test another set of
parameters.
2.4.1
Grid sampling programs (vmc_*.cpp)
The simplest minimization method, described in section 1.3.1, is to calculate
the values at a set of points, plot it, and eyeball the plot for the minima. It
is brutal, but it is also robust and easy to use, and the plots gives a good
feeling for how the wavefunction depends on the parameters. I have used
these methods first, before bringing in the CGM method to find the exact
minima – using the eyeballed minima from this method as a starting point.
vmc_serial, vmc_MPI_brute, and vmc_MPI_importance are all grid samplers. They take input on grid type, number of cycles etc. from the command
line, but wavefunction and/or sampler must be selected by editing a few lines
in the script. Their output is (in addition to what is written directly to the
screen for progress monitoring) tab-separated files where each line represents
a point on the format
α β
E
2
σE
r12
σr212
When sampling many-particle wavefunctions, I have often chosen to disable
the last two output points, as they are zero anyway.
vmc_slatertest is a simple program for test-running the algorithms with
a wavefunction. It only outputs to screen, and any setup is done within the
program. I choose to print this in listing 1, as it is a good starting point if
you want to make your own runner script.
Listing 1: vmc_slatertest.cpp
1
2
3
4
5
6
7
#include <i o s t r e a m >
#include " w a v e f u n c . hpp "
#include " a l g o s . hpp "
#include < s t d l i b . h>
using namespace s t d ;
i n t main ( i n t a r g c , char ∗ a r g v [ ] )
{
27
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// l o n g mc_steps (1 e7 ) , therm_steps (1 e5 ) ;
long mc_steps ( 1 e 6 ) , t h e r m _ s t e p s ( 2 e 4 ) ;
// B e r y l l i u m
double a l p h a = 3 . 8 5 ;
// d o u b l e b e t a = 0 . 1 5 ;
//Neon
// d o u b l e a l p h a = 9 . 8 ;
// d o u b l e b e t a = 0 . 1 2 ;
W a v e f u n c t i o n _ S l a t e r ∗ wf = new b e r y l l i u m _ n o c o r ( a l p h a ) ;
// Wavefunction_Slater ∗ wf = new b e r y l l i u m ( alpha , b e t a ) ;
// Wavefunction_Slater ∗ wf = new neon ( alpha , b e t a ) ;
// MontecarloAlgo ∗ a l g o = new m e t r o p o l i s _ b r u t e _ s l a t e r ( wf , mc_steps , therm_steps , 0 . 5 , −1);
M o n t e c a r l o A l g o ∗ a l g o = new m e t r o p o l i s _ i m p o r t a n c e _ s a m p l e r _ s l a t e r ( wf , mc_steps , therm_steps , 0 . 0 5 , − 1 ) ;
wf−>p r i n t _ p a r a m s ( ) ;
c o u t << e n d l ;
a l g o −>p r i n t _ p a r a m s ( ) ;
c o u t << e n d l ;
a l g o −>r u n _ a l g o ( ) ;
}
a l g o −>p r i n t _ r e s u l t s ( ) ;
2.4.2
CGM (paramsearch_conjgrad.cpp)
The CGM method, described in section 1.3.2, finds the minima more or less
automatically. However, it does need a fairly good starting point, else it will
easily go «astray».
This is implemented in paramsearch_conjgrad.cpp, which calls void
dfpmin(...) as provided from conjgrad.h, shown in listing 7. The code is
from Numerical Recipes, provided by M.H. Jensen.
dpfmin then calls the functions double E_function(double p[]) and
void dE_function(double p[], double ret[]) in order to get the values
and the gradient at point p[]. Note that dfpmin is using fortran convention
in array numbering – it only looks at elements 1 . . . N of an array of length
N + 1.
As the CGM method is dependent of approximating the function as a
quadratic form, it should be started reasonably close to the minima. If this is
not done, it will lead to long convergence times, poor convergence, or crashes
when it tries to sample negative β.26
The program also writes a file as-it-goes, with the format
α β
E
2
σE
∂E
∂α
∂E
∂β
where the last column is set to zero if num_params = 1
26
«Crashes» here means that the algorithms behaviour is undefined, not that the program exits abruptly. Some have implemented methods for leading it back to the area
where the energy is defined like returning ∂E/∂β = −1, E = 0 if β < 0, but this will
probably make the estimate of the Hessian matrix A in equation (24) horribly wrong, and
thus lead to poor results.
28
2.4.3
Misc.
In addition to the minimum finders described above, there are a couple of
other runner scripts. The most significant ones are blocking_test and
deltat_test, which has been used to produce the plots in section 3.2.
blocking_test runs an algorithm, does blocking on the output, and
produces datafiles on the form
blocksize err(blocksize) err0 (blocksize)
. It also outputs an estimate of the ideal blocksize and the error at the next
legal blocksize after this.
deltat_test runs an algorithm for several ∆t, and tries to estimate the
error using the same method as blocking_test. It outputs files on the form
∆t Ē[∆t] err(estimated ideal blocksize, ∆t)
.
There is also the the charge-density calculators chargeDensity and
chargeDensity_importance, which performs the integral defined in eq. (6)
with the «first» particle placed at increasing distances from origo. They use
respectively brute-force and exponential importance sampling, as discussed
in sections 1.2 and 1.2.1. However, they do not utilize parallelization, which
would have been a big help when calculating the charge density of beryllium.
Using metropolis or metropolis-hastings to simulate the PDF may also have
provided a good speedup, however I am not shure about how to define the
factorization of eq. (12) in this case.
The output is files in the format
r
R(r) = f (r)r2
f (r)
, and are by default named chargeDensity.out.
2.5
Parallelization
There are two obvious ways of parallelization of the grid sampling programs –
either run all nodes in sync on one set of parameters at a time, or make a stack
of sets of parameters on a master node, and hand them out to calculation
«slave» nodes as they finish the previous set.
I did implement the second option in 2007 during the VMC/MPI-project
in Computational Physics 1, which made a very big difference as it was able
to fully utilize a quite hetrogenous cluster. The biggest advantage was that
you avoided blocking the entire calculation while waiting for one or two slow
nodes. This scheme is somewhat more complicated to setup, as it needs to
do explicit message passing, as well as writing (and debugging!) of semiadvanced «handler» code.
29
However, this time I had access to two quite homogenous clusters – Titan,
and the local cluster, which has been upgraded since last time to stable
machines sporting quad-core 2.66 Ghz CPU’s. Thus I this time went with
the first approach, which made it possible to produce statistics faster (about
60 times faster – 15 quad-core machines). This meant I could get higher
precision on a single point in parameter space in shorter calculation time.
It is also possible to implement a CGM method utilizing the cluster to get
higher accuracy faster, but as this requires a bit of message passing etc. I
did not implement it at this time, instead utilizing a single CPU for these
calculations.
2.6
Ideas for improvement
There are several things that could be improved in my program, both related
to efficiency, and to have an as smart and flexible as possible implementation,
that I did not have time to implement. I will here describe my ideas for
improvement briefly.
2.6.1
Performance improvements
Implementation of real rollback support As discussed in section 2.2.2,
it is necessary to update quite a lot in the Slater and Jastrow objects
contained within the Wavefunction_Slater in order to get the Quantum
force. However, most often a large proportion of moves will be rejected,
which mean that one has to redo this calculation in order to get back the
old state.
There is a method void rollback() in Wavefunction_Slater that is
called when a move is rejected by the Metropolis-Hastings algorithm. Today
this makes a whole complete calculation for making a step – back to the
previous position. This is quite wastefull, and should be replaced with an
implementation (with corresponding support in Slater and Jastrow) that
simply fetches the previous data instead of recalculating.
Smarter calculation of determinants of Slater matrices Today the
determinants for matrices larger than 2 × 2 is calculated using a recursive
cofactor expansion (2 × 2 is evaluated using explicit formula). This is wastefull, especially for large matrices, as it scales as n!. However, methods based
3
on tridiagonalizing the matrix, such as LU-decomposition, is of order 2n3 .27
Thus implementation of a better method of calculating this determinant
would boost calculation speed of CGM and charge density for large systems.
27
David C. Lay, ’Linear Algebra and its applications’
30
2.6.2
Better program structure
Sampler classes Today what observables to sample is hard-coded into the
algorithms. This could be replaced by an interface for sampling classes (and
a collection of implementing classes). The sampling algorithm would then
call a function in the sampling class each time it wanted to take a sample,
which would then make the sampling of the desired observables. Which
sampler class to use would then be an input to the algorithm the same way
which wavefunction to use is today.
There should be several implementations – simple implementations for
sampling the local energy and its variance, implementations implementing
support for CGM, blocking etc.
This would clean up the MontecarloAlgo code, and make the code easier
to use and more adaptable.
Generalization of double getAlpha(), double getBeta() Today all the
wavefunctions implement functions double getAlpha(), double getBeta()
that returns their defining parameters. This is at least used from the CGM
running script.
However, this causes a problem, as they are defined within each implementing wavefunction, instead of in the Wavefunction interface – as they
have to be, as the names of parameters change from wavefunction to wavefunction. This means that casting to the correct is necessary for getting
them. Cast to the wrong type, and something undefined happens.
This could be solved by defining a function double* getParams() in
the Wavefunction interface, which would then return an array (of length
num_params, which is gettable from every Wavefunction).
Generalization of Wavefunction_Slater to include other Hamiltonians Today, Wavefunction_Slater explicitly implements the Hamiltonian
X
N 1X
Z
1
2
Ĥ = −
∇i −
+
2
ri
rij
i=1
i<j
. This should be moved28 into each implementing class, making it possible
to treat systems such as quantum dots etc.
It is semi-possible to do this today as well by overriding the interfacedefined double local_energy(), but this it is ugly.
28
Probably, the implementation in Wavefunction_Slater should be kept, but renamed
and made a protected function that implementations may utilize.
31
3
Results
Minimum of Ē[~
α]
3.1
In this section I will present results of minimum-finding using sample-andplot (section 1.3.1) together with CGM (section 1.3.2). The value of α
~ =
(α, β) at the minimum will be quoted, as well as the approximate energy. I
have used the Metropolis-Hastings to calculate the energy in all cases.
3.1.1
Helium
For helium, I found the minimum at α = 1.8436, β = 0.347083, with
2 = 0.140302, all in atomic units. The inter-electron
Ē = −2.89095 and σE
separation was r12 = 1.3550753 at a quite close point α = 1.85, β = 3.85.
Graphs of E[~
α] around the minimum can be seen in figures 6, 7, and 8.
Helium
−2.88
−2.882
−2.884
−2.886
<E>
−2.888
−2.89
−2.892
−2.894
−2.896
run01
run02
run03
run04
conjgrad (vector length log10 scale)
−2.898
−2.9
0.5
0.45
0.4
0.35
0.3
0.25
0.2
0.15
0.1
1.85
1.8
1.75
β
1.9
1.95
α
Figure 6: Helium, 3D-plot around minimum
All simulations where run with ∆t = 0.01529 , with 107 cycles + 2 · 104
thermalization steps pr. CPU. Sample-and plot calculations where run with
60 CPU’s in parallel, CGM with a single CPU.
I have no good explanation why of why the CGM data points are systematically a bit lower (about 0.0005 atomic energy units) than what was found
29
This results in a very high acceptance ratio, but is OK as long as we are doing enough
steps to actually sample the entire space
32
Helium
run01
run02
run03
run04
conjgrad
−2.8895
<E>
−2.89
−2.8905
−2.891
1.8
1.81
1.82
1.83
1.84
α
1.85
1.86
1.87
1.88
1.89
Figure 7: Helium, α around the minimum
Helium
−2.888
run01
run02
run03
run04
conjgrad
−2.8885
−2.889
<E>
−2.8895
−2.89
−2.8905
−2.891
−2.8915
−2.892
0.25
0.3
0.35
β
0.4
Figure 8: Helium, β around the minimum
33
0.45
with from the sample and plot points. This only happens for Helium. However, we can probably thrust the quality of the minima, as the two methods
2 30 is in good compatibility
are in good agreement. The further, the small σE
with finding a point in Hilbert space close to a true eigenstate of Ĥ, which
is important as these parameters will be used as input to calculations of the
charge density profile.
3.1.2
Beryllium
For beryllium, I found the minimum at α = 3.96, β = 0.105, with Ē =
2 = 1.70707, all in atomic (Hartree) units.
−14.5003 and σE
Graphs of E[~
α] around the minimum can be seen in figures 9, 10, and
11.
Beryllium
<E>
−14.2
−14.4
run01
run02
run03
run04
conjgrad (vector length log10 scale)
1
0.8
0.6
−14.6
3
0.4
3.5
0.2
4
4.5
0
β
α
Figure 9: Beryllium, 3D-plot around minimum
All simulations where again run with ∆t = 0.015, with 107 cycles + 2·104
thermalization steps pr. CPU. Sample-and-plot calculations where run with
60 CPU’s in parallel, CGM with a single CPU. Again we find a quite small
2 31 , which is good.
σE
√
2
σE
≈
Ē√
2
σE
31
Beryllium: Ē
30
Helium:
12%
≈ 12%
34
Beryllium
run01
run02
run03
run04
conjgrad
−14.43
−14.44
−14.45
<E>
−14.46
−14.47
−14.48
−14.49
−14.5
−14.51
3.7
3.8
3.9
α
4
4.1
4.2
Figure 10: Beryllium, α around the minimum
Beryllium
−14.42
run01
run02
run03
run04
conjgrad
−14.43
−14.44
−14.45
<E>
−14.46
−14.47
−14.48
−14.49
−14.5
−14.51
0.05
0.1
β
0.15
0.2
Figure 11: Beryllium, β around the minimum
35
0.25
3.1.3
Neon
For neon, I found the minimum at α = 10.2068, β = 0.0911634, with Ē =
2 = 35.1335, all in atomic (Hartree) units.
−127.765 and σE
Neon
−126.4
run01
run02
run03
run04
run05
run06
run07
run08
run09
conjgrad
−126.6
−126.8
<E>
−127
−127.2
−127.4
−127.6
−127.8
0.2
0.15
0.1
0.05
9.7
β
9.8
10
9.9
10.1
10.2
10.3
10.4
10.5
α
Figure 12: Neon, 3D-plot around minimum
These simulations where again done with ∆t = 0.015, 60 · 106 cycles +
2 · 104 thermalization steps pr. CPU. Sample-and-plot calculations where
done with 60 CPU’s in parallel, CGM on a single CPU.
2 32 was greater, but so was the energy. We notice espeThis time the σE
cially that α > Z, which is opposite to the screening effect that happened
with Helium and Beryllium. We also notice that β is even smaller than it
was Beryllium. If I was to give a physical interpretation of this, we would
have to take into account that this is the first atom under study with an
l = 1 orbital (2p).
3.2
Value of the energy at the minimum
In order to calculate the value of the energy of the minimum, I will take the
parameter set found in section 3.1, and use it as input to several MetropolisHastings calculations of the energy. I will thus assume that the position of
√
32
Neon:
2
σE
Ē
≈ 4%
36
Neon
run01
run02
run03
run04
run05
run06
run07
run08
run09
conjgrad
−127.64
−127.66
−127.68
<E>
−127.7
−127.72
−127.74
−127.76
−127.78
9.9
10
10.1
α
10.2
10.3
10.4
Figure 13: Neon, α around the minimum
Neon
run01
run02
run03
run04
run05
run06
run07
run08
run09
conjgrad
−127.58
−127.6
−127.62
−127.64
<E>
−127.66
−127.68
−127.7
−127.72
−127.74
−127.76
−127.78
0.05
0.06
0.07
0.08
0.09
0.1
β
0.11
0.12
0.13
Figure 14: Neon, β around the minimum
37
0.14
0.15
the minimum is independent of the choice of ∆t.33
3.2.1
Blocking
As discussed in section 1.2.5 and 2.3.3, the error may be estimated via use
of blocking. We get plots such as shown in figures 15, 18, and 21 which we
may then use to estimate the error of the calculation.
As also discussed, this is possible to estimate by doing a curve fit of the
derivative, as is shown in figures 16, 19 and 22.
These fits, with the parameter C = 1000 as defined in equation (28), I
get the estimates shown in the marked points in figures. From this it seems
that C might be set a bit low, but it is OK for making errorbars.
3.2.2
Helium
Blocking-plots for helium can be seen in figures 15 and fit to derivative in
16. We see that the machinery works very well.
−4
4.5
Helium
x 10
dt=0.1
dt=0.015
X: 200
Y: 0.0003861
4
Error estimate
3.5
3
2.5
X: 50
Y: 0.0002322
2
1.5
1
0
10
1
2
10
10
Blocksize
Figure 15: Blocking on helium. Automatically found errors are indicated
The final energy can be seen from figure 17. It is here evident that at
very large ∆t the algorithm gives large systematic errors (to large energy),
while for very small ∆t, we get fluctuations. The problem at small ∆t can
probably be remedied by increasing the number of steps, in order to have
several independent datasets within each sampling run. I have done a fit of
the energy as a function of ∆t (ignoring the errorbars), which yielded the
rest energy −2.892 Hartree. This corresponds to −78.69 eV, which is close
to the experimental value of −2.903724375 Hartree34 .
33
From figures 17, 20, and 23, this seems like a good assumption, as long as we have
enough cycles to be able to assume ergodicity, and enough thermalization steps to be able
to assume equilibrium.
34
S.A.Alexander, R.L.Coldwell, ’Atomic Wave Function Forms’, 1997
38
Helium
−3
10
dt=0.1
fit to dt=0.1
dt=0.015
fit to dt=0.015
−4
10
−5
10
d(err) / d(blocksize)
−6
10
−7
10
−8
10
−9
10
−10
10
−11
10
−12
10
0
10
1
2
10
10
Blocksize
Figure 16: Fitting the derivative of err(b.s.) for beryllium
Helium
−2.889
data 1
−2.89
<E>
−2.891
−2.892
−2.88
y = 0.013*x − 2.892
<E>
−2.885
−2.893
−2.89
data 2
linear
−2.895
−2.894
0
0
0.05
0.1
∆t
0.2
0.15
0.4
∆t
0.6
0.8
1
0.2
Figure 17: Calculated energy (with errorbars from autoblocking) as a function of ∆t for helium, with linear fit (not using the errorbars)
3.2.3
Beryllium
Blocking-plots for Beryllium can be seen in figures 18 and fit to derivative
in 19. We again see that the machinery works very well, however yielding a
bit low ideal blocksize for dt = 0.015. This is probably fixable by tweaking
of the constant C, defined in equation (28).
The final energy is from the fit in figure 20 −14.52 Hartree, which close
39
−4
14
Beryllium
x 10
dt=0.015
dt=0.1
13
X: 125
Y: 0.001225
12
11
Error estimate
10
9
8
X: 64
Y: 0.0007653
7
6
5
4
0
10
1
2
10
10
Blocksize
Figure 18: Blocking on beryllium. Automatically found errors are indicated
Beryllium
−3
10
dt=0.015
fit to dt=0.015
dt=0.15
fit to dt=0.1
−4
10
−5
10
d(err) / d(blocksize)
−6
10
−7
10
−8
10
−9
10
−10
10
−11
10
−12
10
0
10
1
2
10
10
Blocksize
Figure 19: Fitting the derivative of err(b.s.) for beryllium
to the experimental value of −14.66737 Hartree. However, we note from
the blowup in figure 20 that it seems to converge to a slightly higher value,
around −14.505 ± 0.005. This wavefunction yields another behaviour when
increasing ∆t than Neon, as E[∆t] seems to be a lot closer than to a linear
function than what was the case with Helium.
3.2.4
Neon
Blocking-plots for beryllium can be seen in figures 21, and fit to derivative
in 22. We here see that for ∆t = 0.015 the machinery works very well, but
not so much for ∆t = 0.1. Exactly what happens here I am not shure of,
but the plot indicates we are not able to get a large enough blocksize to get
uncorrelated samples. The acceptance ratio was at 52%, which is rather low
for this kind of calculation, but not so low as that I would expect this to
happen. The accepted moves should also be longer, which should provide a
correlation time of approximately the same order, as is seen with helium and
beryllium. However, I therefore chose to terminate the dtWalk-calculation
40
Beryllium
data 1
−14.485
−14.49
−14.495
Beryllium
<E>
−13.6
−14.5
−13.7
−13.8
−13.9
−14.505
−14
−14.1
y = 0.858*x − 14.52
−14.2
−14.51
−14.3
data 2
linear
−14.4
−14.515
−14.5
0
0.1
0.2
0.3
0.4
0.5
∆t
0.6
0.7
0.8
0.9
1
−14.52
0
0.01
0.02
0.03
∆t
0.04
0.05
0.06
Figure 20: Calculated energy (with errorbars from autoblocking) as a function of ∆t for beryllium, with linear fit (not using the errorbars)
at ∆t = 0.1 instead of ∆t = 1.0.
Neon
0.055
0.05
dt=0.1
dt=0.015
0.045
X: 1250
Y: 0.04717
Error estimate
0.04
0.035
0.03
0.025
0.02
0.015
X: 125
Y: 0.01333
0.01
0.005
0
10
1
10
2
10
Blocksize
3
10
4
10
Figure 21: Blocking on neon. Automatically found errors are indicated
The final energy is from the fit in figure 23 −127.9 Hartree, which again
seems to be a bit lower than the −127.85 ± 0.025 indicated in the blowup.
I did not find any direct experimental data for the ground state energy
of the electrons in neon, but I was able to make an estimate by summing up
41
Neon
−2
10
dt=0.1
fit to dt=0.1
dt=0.015
fit to dt=0.015
−3
10
−4
d(err) / d(blocksize)
10
−5
10
−6
10
−7
10
−8
10
−9
10
0
10
1
2
10
10
Blocksize
Figure 22: Fitting the derivative of err(b.s.) for neon
the ionization enthalpies35 . This is not completely accurate, as enthalpy is
defined to include work done on the enviroment by the system. If we then
assume that the volume of the atoms decrease when they are ionized, these
enthalpies are a bit lower than the actual ionization energies. I got a value
of 129.05 Hartree/atom, which is close to my calculation.
3.3
Charge density profiles
In this section I have calculated and displayed charge density profiles for Helium and Beryllium, calculated with different parameter sets. Charge density is explained in 1.1.2. The plots displayed in this section are for onebody
density R(r) = r2 · f (r), charge density is obtained by multiplying by Z. All
normalization performed numerically after the calculation of the onebody
density, by use of equation (10) and numerical integration in Matlab.
3.3.1
Helium
In figure 24 we see plots for the radial density of Helium, calculated for a case
of no correlations in the wavefunction with the «Analytic» minima α = Z,
no correlations with α at the value found in section 3.1.1, and the case with
correlations and parameters α, β at the value found in section 3.1.1.
We see that the correlations tend to push the positions of the electrons
a bit outwards. We see that both the charge-screening effect and the correlation part of the wavefunction contribute to this.
42
Neon
data 1
−127.7
−127.75
−127.8
−125.5
<E>
y = 17.54*x − 127.9
−126
−127.85
<E>
−126.5
−127.9
−127
data 2
linear
−127.5
−127.95
−128
0
0.005
0.01
0
0.02
0.015
∆t
0.04
0.02
0.06
∆t
0.08
0.1
0.12
0.025
Figure 23: Calculated energy (with errorbars from autoblocking) as a function of ∆t for neon, with linear fit (not using the errorbars)
3.3.2
Beryllium
The results for beryllium are shown in figure 25. Unfortunately, I did not
have time to complete this calculation (which would also have yielded correct
normalizations), but at least the inner part is shown.
We see that the correlations make the integral harder to solve 36 , and
with the data at hand it is hard to say anything about the effect of the
correlations.
4
Appendix A: Header files
Listing 2: wavefunc.hpp
1
2
3
4
#i f n d e f WAVEFUNC_HPP
#d e f i n e WAVEFUNC_HPP
#include " s l a t e r . hpp "
35
Ionization enthalpies for Neon found at
http://202.114.88.54/g/web18/wangluo/webelements/webelements/elements/text/
ne/ionz.html
36
the curve with no correlations are nice and smooth, the curve with are much more
«jagged», probably because of numerical errors. Both calculations where made with 101 0
MC cycles, importance sampling from PDF αe−αr
43
Helium
0.09
No correlation, α = Z
No correlation, α = 1.8436
With correlations, α = 1.8436, β = 0.347083
0.08
0.07
2
R(r) = r f(r)
0.06
0.05
0.04
0.03
0.02
0.01
0
0
1
2
3
r
4
5
Figure 24: Radial density, Helium
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include " j a s t r o w . hpp "
/∗
∗ General c l a s s d e f i n i n g a w a v e f u n c t i o n .
∗ O b j e c t s o f d e r i v e d c l a s s e s h o l d s t h e c u r r e n t v a r i a t i o n a l parameters ,
∗ and have f u n c t i o n s which can compute t h e l o c a l energy .
∗
∗ Note : This i s an a b s t r a c t c l a s s ( an i n t e r f a c e ) −
∗ you have t o i n h e r i t i t , and d e f i n e some o f t h e f u n c t i o n s y o u r s e l f !
∗/
c l a s s Wavefunction {
public :
/∗
∗ I n i t i a l i z e s base c l a s s
∗/
Wavefunction ( ) ;
/∗
∗ Returns t h e v a l u e o f t h e w a v e f u n c t i o n a t p o s i t i o n ( s ) r
∗/
v i r t u a l double getWf ( double ∗∗ r ) = 0 ;
/∗
∗ Returns t h e l o c a l energy computed a t r
∗/
v i r t u a l double l o c a l _ e n e r g y ( double ∗∗ r ) = 0 ;
/∗
∗ P r i n t v a r i a t i o n a l parameters t o s t d o u t
∗/
v i r t u a l void p r i n t _ p a r a m s ( ) = 0 ;
/∗
∗ Returns t h e number o f p a r t i c l e s e x p e c t e d by t h i s
∗ wavefunction , w i t h t h e c u r r e n t c o n f i g u r a t i o n
∗/
int get_num_particles ( ) ;
/∗
∗ Returns t h e number o f parameters i n
this
44
wavefunction
6
Beryllium
0.9
No correlations
With correlations
0.8
0.7
R(r) = r2 f(r)
0.6
0.5
0.4
0.3
0.2
0.1
0
0
0.05
0.1
0.15
0.2
0.25
r
0.3
0.35
0.4
0.45
0.5
Figure 25: Radial density, beryllium (aborted calculation)
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
∗/
i n t get_num_params ( ) ;
/∗
∗ Returns ( d ( p s i )/ d ( param [ i ] ) ) / p s i ,
∗ used f o r e s t i m a t i n g d e r i v a t i v e s o f l o c a l energy
∗ by t h e c o n j u g a t e g r a d i e n t method .
∗
∗ Returns a new array
∗/
v i r t u a l double ∗ g e t _ p a r t P s i _ o v e r _ p s i ( double ∗∗ r ) = 0 ;
protected :
/∗
∗ Function t o n u m e r i c a l l y compute t h e k i n e t i c p a r t
∗ o f t h e l o c a l energy
∗/
double l o c a l _ e n e r g y _ k i n e t i c _ n u m e r i c ( double ∗∗ r ) ;
/∗
∗ Returns t h e e l e c t r o n −e l e c t r o n r e p u l s i o n p a r t o f t h e
∗ l o c a l energy as a p o s i t i v e q u a n t i t y
∗/
double l o c a l _ e n e r g y _ e l e c t r o n ( double ∗∗ r ) ;
/∗
∗ Returns t h e e l e c t r o n −n u c l e u s a t t r a c t i o n p a r t o f t h e
∗ l o c a l energy ( d i v i d e d by Z) as a p o s i t i v e q u a n t i t y
∗/
double l o c a l _ e n e r g y _ c e n t r a l ( double ∗∗ r ) ;
int num_particles ;
i n t num_params ;
private :
// Step l e n g t h and i t s squared i n v e r s e
s t a t i c const double h = 0 . 0 0 1 ;
double h 2 i ; // 1/h∗∗2
};
f o r t h e secound d e r i v a t i v e
/∗
∗ Wavefunction used i n t a s k 1
∗/
c l a s s h e l i u m 1 : public W a v e f u n c t i o n {
45
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
public :
h e l i u m 1 ( double a l p h a , double b e t a ) ;
double getWf ( double ∗∗ r ) ;
double l o c a l _ e n e r g y ( double ∗∗ r ) ;
void p r i n t _ p a r a m s ( ) ;
double g e t A l p h a ( ) ;
double g e t B e t a ( ) ;
double ∗ g e t _ p a r t P s i _ o v e r _ p s i ( double ∗∗ r ) ;
private :
double a l p h a ;
double b e t a ;
s t a t i c const i n t Z = 2 ;
};
/∗
∗ Helium , o n l y s l a t e r .
∗ Used t o t e s t onebody d e n s i t y ( has a n a l y t i c
∗/
c l a s s h e l i u m 1 _ n o c o r : public W a v e f u n c t i o n {
public :
h e l i u m 1 _ n o c o r ( double a l p h a ) ;
double getWf ( double ∗∗ r ) ;
double l o c a l _ e n e r g y ( double ∗∗ r ) ;
void p r i n t _ p a r a m s ( ) ;
double g e t A l p h a ( ) ;
double ∗ g e t _ p a r t P s i _ o v e r _ p s i ( double ∗∗ r ) ;
private :
double a l p h a ;
s t a t i c const i n t Z = 2 ;
};
solution )
/∗
∗ Wavefunction used t o t e s t t h a t t h e machinery works
∗/
c l a s s hydrogen_1s : public W a v e f u n c t i o n {
public :
hydrogen_1s ( double a l p h a , bool n u m e r i c ) ;
double getWf ( double ∗∗ r ) ;
double l o c a l _ e n e r g y ( double ∗∗ r ) ;
void p r i n t _ p a r a m s ( ) ;
double ∗ g e t _ p a r t P s i _ o v e r _ p s i ( double ∗∗ r ) ;
private :
double a l p h a ;
bool n u m e r i c ;
s t a t i c const i n t Z = 1 ;
};
/∗
∗ C l a s s f o r a s i n g l e −s l a t e r d e t e r m i n a n t w a v e f u n c t i o n
∗
∗/
c l a s s W a v e f u n c t i o n _ S l a t e r : public W a v e f u n c t i o n {
public :
Wavefunction_Slater ( ) ;
/∗
∗ Set the i n i t i a l p o s i t i o n before
∗/
void i n i t i a l S e t ( double ∗∗ r ) ;
s t a r t i n g a montecarlo run
/∗
∗ This r e t u r n s t h e v a l u e o f t h e w a v e f u n c t i o n a t p o i n t r [ p a r t i c l e ] [ d ]
∗ Don ’ t use t h i s t o c a l c u l a t e t h e r a t i o , use g e t R a t i o .
∗ Only t h e r e f o r c o m p a t i b i l i t y w i t h s t a n d a r d Wavefunction ,
∗ and f o r c a l c u l a t i o n o f one−body / charge d e n s i t y .
∗/
double getWf ( double ∗∗ r ) ;
/∗
∗ Get t h e l o c a l energy f o r t h e s t o r e d p o s i t i o n s e t .
∗ This implements a g e n e r i c atomic h a m i l t o n i a n .
∗/
double l o c a l _ e n e r g y ( ) ;
/∗
∗ Maintained f o r backwards c o m p a t i b i l i t y − DO NOT USE.
∗ Returns 0 . 0 i f t h e r s e n t t o i t i s not e q u a l t h e r s t o r e d .
∗ Use l o c a l _ e n e r g y ( ) d i r e c t l y i n s t e a d .
∗/
double l o c a l _ e n e r g y ( double ∗∗ r ) ;
void p r i n t _ p a r a m s ( ) ;
46
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/∗
∗ Returns partPsi_over_psi a t r_now .
∗ See Wavefunction : : get_partPsi_over_psi ( d o u b l e ∗∗ r )
∗ for explanation
∗/
double ∗ g e t _ p a r t P s i _ o v e r _ p s i ( ) ;
/∗
∗ Maintained f o r backwards c o m p a t i b i l i t y − DO NOT USE.
∗ Returns NULL i f t h e r s e n t t o i t i s not e q u a l t h e r s t o r e d .
∗ Use get_partPsi_over_psi ( ) d i r e c t l y i n s t e a d !
∗ ( s t i l l u s e f u l l f o r d e b u g g i n g your a l g o )
∗/
double ∗ g e t _ p a r t P s i _ o v e r _ p s i ( double ∗∗ r ) ;
/∗
∗ Get t h e r a t i o f o r t h e m e t r o p o l i s t e s t , and update t h e array .
∗
∗/
double g e t R a t i o ( double ∗ r_new , i n t p a r t i c l e ) ;
/∗
∗ Get t h e l a s t c a l c u l a t e d r a t i o ( l a s t tryMove ( ) or g e t R a t i o ( d o u b l e ∗ , i n t )
∗ Updated on c a l l s t o tryMove and g e t R a t i o ( d o u b l e ∗ , i n t )
∗/
double g e t R a t i o ( ) ;
/∗
∗ Try t o make a move , which makes i t
∗ p o s s i b l e t o g e t t h e quantum f o r c e .
∗
∗ Note : Dummy implementation , c a l l s
∗ g e t R a t i o (r_new , i n t p a r t i c l e )
∗ and acceptMove ( ) b eh in d t h e s c e n e s
∗
∗/
void tryMove ( double ∗ r_new , i n t p a r t i c l e ) ;
/∗
∗ Rollback to position
∗/
void r o l l b a c k ( ) ;
before
l a s t tryMove c a l l
/∗
∗ Accept a move − update s l a t e r matrix
∗
∗ Not n e c c e s s a r y i f tryMove i s used :
∗ E i t h e r use g e t R a t i o ( d o u b l e ∗ , i n t ) and acceptMove ( ) ( m e t r o p o l i s _ b r u t e )
∗ OR use tryMove ( d o u b l e ∗ , i n t ) , g e t R a t i o ( ) , and ( i f n e c c e s s a r y ) r o l l b a c k ( )
∗/
void acceptMove ( ) ;
/∗
∗ Get t h e quantum f o r c e
∗ at the currently stored
∗ p o s i t i o n r_now .
∗
∗ Returns a new array
∗/
double ∗∗ getQuantumForce ( ) ;
protected :
/∗
∗ C a l c u l a t e t h e g r a d i e n t ( d i v i d e d by t h e d e t e r m i n a n t s )
∗ o f t h e d o u b l e s l a t e r determinant ,
∗ with respect to a given p a r t i c l e
∗ ( used i n l o c a l energy c a l c u l a t i o n , quantum f o r c e )
∗
∗ Returns a new array
∗/
double ∗ g e t D e r i v _ s l a t e r ( i n t p ) ;
/∗
∗ Returns t h e l o c a l k i n e t i c energy from S l a t e r & Jastrow
∗ a t r_now
∗/
double l o c a l _ e n e r g y _ k i n e t i c ( ) ;
// S l a t e r d e t e r m i n a n t s
Slater ∗ slater1 ;
Slater ∗ slater2 ;
// Jastrow f a c t o r
Jastrow ∗ jastrow ;
47
call )
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
// Which p a r t i c l e was l a s t moved? ( used when a c c e p t i n g a move , u p d a t i n g s l a t e r
int particle_lastmoved ;
//Where are we c o n s i d e r i n g t o move t o ( used t o update r_now i n acceptMove )
double ∗ r_new ;
// Previous p o s i t i o n o f p a r t i c l e _ t r i e d ( used i n r o l l b a c k )
double ∗ r_prev ;
int p a r t i c l e _ t r i e d ;
// Where are t h e l a s t a c c e p t e d p o s i t i o n ( used t o g e t l o c a l energy e t c . )
double ∗∗ r_now ;
double R ; // l a s t
calculated
ratio
// num_particles /2 − Assumed : num_particles ALWAYS even . Used f o r
i n t p2 ;
// Charge o f n u c l e u s .
int Z ;
};
//Name o f w a v e f u n c t i o n ( used i n print_params t o
// p r i n t i d e n t i f y which WF we are u s i n g )
char ∗ WFname ;
/∗
∗ B e r y l l i u m w a v e f u n c t i o n (No j a s t r o w f a c t o r )
∗
∗/
c l a s s b e r y l l i u m _ n o c o r : public W a v e f u n c t i o n _ S l a t e r {
public :
b e r y l l i u m _ n o c o r ( double a l p h a ) ;
double g e t A l p h a ( ) ;
private :
double a l p h a ;
};
/∗
∗ Beryllium wavefunction ( with jastrow f a c t o r )
∗/
c l a s s b e r y l l i u m : public W a v e f u n c t i o n _ S l a t e r {
public :
b e r y l l i u m ( double a l p h a , double b e t a ) ;
double g e t A l p h a ( ) ;
double g e t B e t a ( ) ;
private :
double a l p h a ;
double b e t a ;
};
/∗
∗ Neon w a v e f u n c t i o n ( w i t h j a s t r o w f a c t o r )
∗/
c l a s s neon : public W a v e f u n c t i o n _ S l a t e r {
public :
neon ( double a l p h a , double b e t a ) ;
double g e t A l p h a ( ) ;
double g e t B e t a ( ) ;
private :
double a l p h a ;
double b e t a ;
};
#e n d i f
Listing 3: algos.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
matrices )
#i f n d e f ALGOS_HPP
#d e f i n e ALGOS_HPP
#include " w a v e f u n c . hpp "
//#import " wavefunc . hpp" //Use import t o a v o i d double−i n c l u s i o n
/∗
∗ General c l a s s d e f i n i n g a MonteCarlo a l g o r i t m .
∗ Objects of derived c l a s s e s contains the actual
∗ algoritms
∗/
class MontecarloAlgo {
public :
/∗
∗ S e t b a s i c parameters . V a r i a t i o n a l parameters s h o u l d be
∗ s e t i n t h e Wavefunction .
48
slater
product
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
∗/
M o n t e c a r l o A l g o ( W a v e f u n c t i o n ∗ wf , long mc_steps ,
i n t therm_steps , long randomseed ) ;
/∗
∗ Run t h e a c c t u a l a l g o r i m
∗/
v i r t u a l void r u n _ a l g o ( ) = 0 ;
/∗
∗ P r i n t r e s u l t s o f montecarlo a l g o t o s t d o u t
∗/
v i r t u a l void p r i n t _ r e s u l t s ( ) = 0 ;
/∗
∗ P r i n t montecarlo parameters t o s t d o u t
∗ ( d e f a u l t implementation p r o v i d e d )
∗/
v i r t u a l void p r i n t _ p a r a m s ( ) ;
/∗
∗ Returns a p o i n t e r t o t h e w a v e f u n c t i o n o b j e c t used
∗/
Wavefunction ∗ getWfPointer ( ) ;
/∗
∗ Functions t o g e t t h e r e s u l t s
∗/
double g e t E n e r g y ( ) ;
double g e t E n e r g y 2 ( ) ;
double g e t V a r i a n c e ( ) ;
double getR12 ( ) ;
//Only m e a n i n g f u l l
double getR12_2 ( ) ;
double g e t R 1 2 V a r i a n c e ( ) ;
/∗
∗ Call t h i s to a c t i v a t e
∗/
void a c t i v a t e B l o c k i n g ( ) ;
storing
if
num_particles = 2
o f data f o r
blocking
/∗
∗ Do b l o c k i n g on t h e array w i t h t h e s e t b l o c k s i z e .
∗
∗ I f N = number o f b l o c k s = number o f samples /b
∗ ( i n t e g e r d i v i s i o n , may waste some samples ) ,
∗ t h i s method f i r s t c r e a t e s an array o f l e n g t h N
∗ c o n t a i n i n g t h e mean o f each b l o c k , g i v e n by ( b l o c k s i z e = b )
∗ X_i = 1/ b ∗ \sum_{k=b∗ i }^{k=b ∗( i +1)−1} x_k
∗ ( Note : This array a c t u a l l y i s n ’ t c r e a t e d . . . )
∗
∗ I t then c a l c u l a t e s and r e t u r n s
∗ t h e mean o f t h e s q u a r e s o f t h i s b l o c k e d array .
∗ Note t h a t t h e mean o f t h i s b l o c k e d array i s t h e same
∗ as t h e mean o f t h e l o c a l energy .
∗
∗ The u s e r may then use t h e s e t o c a l c u l a t e an e r r o r e s t i m a t e ,
∗ g i v e n by e r r = \ s q r t ( (<M^2> − <M>^2)/(N−1.0)
∗/
double b l o c k ( long b l o c k s i z e ) ;
/∗
∗ Do b l o c k i n g w i t h many b l o c k s i z e s , and f i n d t h e e r r o r
∗ and d e r i v a t i v e o f t h e e r r o r . F i t t h e d e r i v a t i v e t o an
∗ a n a l y t i c f u n t i o n , and use t h i s t o e s t i m a t e an " i d e a l " b l o c k −s i z e ,
∗ which i s r e t u r n e d
∗/
double g e t I d e a l B l o c k S i z e ( ) ;
/∗
∗ Use b l o c k i n g t o e s t i m a t e t h e e r r o r a t t h e
∗ b l o c k s i z e >= i n p u t b l o c k s i z e
∗/
double g e t E r r o r ( i n t b l o c k s i z e ) ;
first
good
/∗
∗ A c t i v a t e sampling o f <p s i ’/ p s i > and <E_l∗ p s i ’/ p s i >,
∗ used f o r c o n j u g a t e g r a d i e n t minima f i n d i n g ,
∗ which needs d<E_l [ a l p h a ]>/d ( alpha_i )
∗/
void a c t i v a t e D e r i v a t i v e s ( ) ;
/∗
∗ Get <p s i ’/ p s i >
∗ Returns an array , as t h e r e might be s e v e r a l
∗/
double ∗ g e t _ p s i P _ o v e r _ p s i ( ) ;
/∗
49
v a r i a t i o n a l params
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
∗ Get <E_l ∗ p s i ’/ p s i >
∗ Returns an array , as t h e r e might be s e v e r a l
∗/
double ∗ g e t _ e l _ t i m e s _ p s i P _ o v e r _ p s i ( ) ;
v a r i a t i o n a l params
/∗
∗ Get e s t i m a t o r f o r p a r t i a l d e r i v a t i v e o f t h e energy ,
∗ d e r i v e d by t h e parameters ( alpha , b e t a , e t c . ) :
∗ d<E_l [ a l p h a ]>/d alpha_i , used f o r minima f i n d i n g i n
∗ c o n j u g a t e g r a d i e n t method .
∗ Returns an array , as t h e r e might be s e v e r a l v a r i a t i o n a l params .
∗/
double ∗ g e t _ p a r t i a l _ e n e r g y ( ) ;
/∗
∗ Destructor , d e l e t e s
∗/
~MontecarloAlgo ( ) ;
the blockArray
if
created .
protected :
Wavefunction ∗ wavefunction ;
long mc_steps ;
int therm_steps ;
long randomseed ;
bool b l o c k i n g ;
double ∗ b l o c k A r r a y ; // Array f o r
storing
a l l E_l v a l u e s
bool d e r i v a t i v e s ;
// R e s u l t s
double e n e r g y ;
double e n e r g y 2 ;
double v a r i a n c e ;
double r 1 2 ; //Only m e a n i n g f u l l i f num_particles = 2 . . .
double r12_2 ; //sum o f s q u a r e s o f r12 v a l u e s
double r 1 2 _ v a r i a n c e ;
double ∗ p s i P _ o v e r _ p s i ; //Used f o r
double ∗ e l _ t i m e s _ p s i P _ o v e r _ p s i ;
partial
derivaties
of
l o c a l energy
};
/∗
∗ Brute−f o r c e m e t r o p o l i s monte−c a r l o
∗
∗/
c l a s s m e t r o p o l i s _ b r u t e : public M o n t e c a r l o A l g o {
public :
m e t r o p o l i s _ b r u t e ( W a v e f u n c t i o n ∗ wf , long mc_steps , i n t therm_steps ,
double s t e p _ l e n g t h , long randomseed ) :
M o n t e c a r l o A l g o ( wf , mc_steps , therm_steps , randomseed ) , s t e p _ l e n g t h ( s t e p _ l e n g t h )
void r u n _ a l g o ( ) ;
void p r i n t _ r e s u l t s ( ) ;
void p r i n t _ p a r a m s ( ) ;
private :
double s t e p _ l e n g t h ;
int accepted ;
};
/∗
∗ M e t r o p o l i s−h a s t i n g s importance sampling montecarlo
∗
∗/
c l a s s m e t r o p o l i s _ i m p o r t a n c e _ s a m p l e r : public M o n t e c a r l o A l g o {
public :
m e t r o p o l i s _ i m p o r t a n c e _ s a m p l e r ( W a v e f u n c t i o n ∗ wf , long mc_steps , i n t therm_steps ,
double dt , long randomseed ) :
M o n t e c a r l o A l g o ( wf , mc_steps , therm_steps , randomseed ) , d t ( d t ) { } ;
void r u n _ a l g o ( ) ;
void p r i n t _ r e s u l t s ( ) ;
void p r i n t _ p a r a m s ( ) ;
private :
/∗
∗ C a l c u l a t e t h e quantuum f o r c e , \ vec F_i = 2∗\ Del \ p s i / \ p s i
∗/
void quantum_force ( double ∗∗ r , double ∗∗ q f o r c e ) ;
double d t ;
int accepted ;
i n t n u m _ p a r t i c l e s ; // I n i t i a l i z e d i n run_algo ( )
s t a t i c const double h = 0 . 0 0 1 ;
};
50
{};
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/∗
∗ Brute−f o r c e m e t r o p o l i s monte−c a r l o
∗
∗/
for
slater
determinant w a v e f u n c t i o n s
c l a s s m e t r o p o l i s _ b r u t e _ s l a t e r : public M o n t e c a r l o A l g o {
public :
m e t r o p o l i s _ b r u t e _ s l a t e r ( W a v e f u n c t i o n _ S l a t e r ∗ wf , long mc_steps ,
double s t e p _ l e n g t h , long randomseed ) :
M o n t e c a r l o A l g o ( wf , mc_steps , therm_steps , randomseed ) ,
w a v e f u n c t i o n _ s l a t e r ( wf ) , s t e p _ l e n g t h ( s t e p _ l e n g t h ) { } ;
void r u n _ a l g o ( ) ;
void p r i n t _ r e s u l t s ( ) ;
void p r i n t _ p a r a m s ( ) ;
protected :
// C a l l t h i s something e l s e t o minimize c o n f u s i o n . . .
//The same o b j e c t as wavefunction , b u t o t h e r t y p i n g
Wavefunction_Slater ∗ wavefunction_slater ;
private :
double s t e p _ l e n g t h ;
int accepted ;
};
/∗
∗ M e t r o p o l i s−h a s t i n g s importance sampling montecarlo f o r
∗
∗/
slater
determinant w a v e f u n c t i o n s
c l a s s m e t r o p o l i s _ i m p o r t a n c e _ s a m p l e r _ s l a t e r : public M o n t e c a r l o A l g o {
public :
m e t r o p o l i s _ i m p o r t a n c e _ s a m p l e r _ s l a t e r ( W a v e f u n c t i o n _ S l a t e r ∗ wf , long mc_steps , i n t therm_steps ,
double dt , long randomseed ) :
M o n t e c a r l o A l g o ( wf , mc_steps , therm_steps , randomseed ) , w a v e f u n c t i o n _ s l a t e r ( wf ) , d t ( d t ) { } ;
void r u n _ a l g o ( ) ;
void p r i n t _ r e s u l t s ( ) ;
void p r i n t _ p a r a m s ( ) ;
protected :
// C a l l t h i s something e l s e t o minimize c o n f u s i o n . . .
//The same o b j e c t as wavefunction , b u t o t h e r t y p i n g
Wavefunction_Slater ∗ wavefunction_slater ;
private :
// v o i d quantum_force ( d o u b l e ∗∗ r , d o u b l e ∗∗ q f o r c e ) ; //Moved i n t o Wavefunction_Slater
double d t ;
int accepted ;
i n t n u m _ p a r t i c l e s ; // I n i t i a l i z e d i n run_algo ( )
// s t a t i c c o n s t d o u b l e h = 0 . 0 0 1 ;
};
#e n d i f
Listing 4: slater.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
i n t therm_steps ,
#i f n d e f SLATER_HPP
#d e f i n e SLATER_HPP
/∗
∗ General c l a s s h o l d i n g s i n g l e −p a r t i c l e w a v e f u n c t i o n s
∗ and t h e i r d e r i v a t i v e s
∗
∗/
class Orbital {
public :
/∗
∗ Get t h e v a l u e o f t h e w a v e f u n c t i o n a t p o s i t i o n r
∗/
v i r t u a l double
getWf
( double ∗ r ) = 0 ;
/∗
∗ Get t h e p a r t i a l d e r i v a t i v e s o f t h e wf . a t pos . r
∗/
v i r t u a l double ∗ g e t D e r i v
( double ∗ r ) = 0 ;
/∗
∗ Get t h e l a p l a c i a n o f t h e wf a t pos r
∗/
v i r t u a l double
g e t L a p l a c e ( double ∗ r ) = 0 ;
/∗
∗ P r i n t name o f s i n g l e p a r t i c l e wavefunction ,
51
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
∗ and parameters
∗/
v i r t u a l void p r i n t _ p a r a m s ( ) = 0 ;
protected :
/∗
∗ U t i l i t y function to c a l c u l a t e
∗/
double c a l c R ( double ∗ r ) ;
};
t h e a b s o l u t e v a l u e o f r−v e c t o r
/∗
∗ 1S o r b i t a l , wf ( r ) = exp(−a l p h a ∗ r )
∗/
c l a s s o r b 1 s : public O r b i t a l {
public :
o r b 1 s ( double a l p h a ) ;
double getWf
( double ∗ r ) ;
double ∗ g e t D e r i v
( double ∗ r ) ;
double g e t L a p l a c e ( double ∗ r ) ;
void p r i n t _ p a r a m s ( ) ;
private :
double a l p h a ;
};
/∗
∗ 2S o r b i t a l , wf ( r ) = (1− a l p h a ∗ r /2) exp(−a l p h a ∗ r /2)
∗/
c l a s s o r b 2 s : public O r b i t a l {
public :
o r b 2 s ( double a l p h a ) ;
double getWf
( double ∗ r ) ;
double ∗ g e t D e r i v
( double ∗ r ) ;
double g e t L a p l a c e ( double ∗ r ) ;
void p r i n t _ p a r a m s ( ) ;
private :
double a l p h a ;
};
/∗
∗ 2P o r b i t a l , wf ( r , i ) = a l p h a ∗r_i∗ exp(−a l p h a ∗ r / 2 ) ,
∗ where r_i = r [ d i r ] = { x=r [ 0 ] i f i = 0 , y=r [ 1 ] i f
∗/
c l a s s o r b 2 p : public O r b i t a l {
public :
o r b 2 p ( double a l p h a , i n t d i r ) ;
double getWf
( double ∗ r ) ;
double ∗ g e t D e r i v
( double ∗ r ) ;
double g e t L a p l a c e ( double ∗ r ) ;
void p r i n t _ p a r a m s ( ) ;
private :
double a l p h a ;
int d i r ;
};
/∗
∗ C l a s s f o r h o l d i n g a s l a t e r determinant ,
∗ u p d a t i n g i t , and g e t t i n g i n f o out i t
∗/
class Slater {
public :
/∗
∗ I n i t i a l i z e t h e s l a t e r determinant w i t h a l i s t o f
∗ and i n i t i a l p o s i t i o n ( dim = number o f p a r t i c l e s )
∗/
S l a t e r ( i n t dim , O r b i t a l ∗∗ o r b i t a l s , double ∗∗ r ) ;
/∗
∗ R e c a l c u l a t e t h e e n t i r e matrix
∗ Makes a copy o f i n p u t ∗∗ r ( so
∗ i n c a l l i n g code )
∗
∗/
void i n i t i a l U p d a t e ( double ∗∗ r ) ;
it
is
safe to
i =1, z=r [ 2 ]
if
i=2 }
orbitals
d e l e t e / change l a t e r
/∗
∗ New p o s i t i o n accepted , update t h e s l a t e r matrix and i t s i n v e r s e .
∗ Always c a l l g e t R a t i o f i r s t , e l s e i t won ’ t work
∗ ( t h i s method u s e s t h e c a l c u l a t e d new r a t i o and t h e r_new , p a r t i c l e R was c a l c u l a t e d
∗/
void u p d a t e ( ) ;
/∗
∗ C a l c u l a t e r a t i o R = | p s i (new ) | / | p s i ( o l d ) | ,
∗ used f o r m e t r o p o l i s t e s t , and a l s o f o r matrix update .
∗ Note t h a t t h i s s e t s t h e r a t i o t h a t i s l a t e r used i n update !
52
for
last )
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
∗/
double g e t R a t i o ( double ∗ r_new ,
int
particle );
/∗
∗ C a l c u l a t e t h e determinant a t p o s i t i o n s r
∗ Used t o c a l c u l a t e t h e onebody/ charge d e n s i t y .
∗
∗ Independent o f r_now e t c .
∗/
double g e t D e t ( double ∗∗ r ) ;
/∗
∗ Get g r a d i e n t ( d i v i d e d by d e t (D) ) f o r one p a r t i c l e ( used i n quantum f o r c e c a l c ) .
∗ Returns a new array .
∗/
double ∗ g e t D e r i v
( int p a r t i c l e ) ;
/∗
∗ Get l a p l a c i a n ( d i v i d e d by d e t (D) ) f o r one p a r t i c l e ( used i n l o c a l energy c a l c )
∗/
double
getLaplace ( int p a r t i c l e ) ;
/∗
∗ Get p a r t i a l d e r i v a t i v e o f s l a t e r w i t h r e s p e c t t o parameter alpha ,
∗ d i v i d e d by t h e s l a t e r .
∗ E v a l u a t e d a t r_now .
∗ Assumption : Only one s i n g l e parameter a l p h a !
∗
∗ You have t o s e t u p o r b i t a l s _ p and orbitals_m u s i n g CGMsetup ( ) !
∗/
double g e t _ p a r t P s i _ o v e r _ p s i ( ) ;
/∗
∗ Setup o r b i t a l s f o r use i n get_partPsi_over_psi ( )
∗ f o r Conjugate Gradient Method
∗/
void CGMsetup ( O r b i t a l ∗∗ o r b i t a l s _ p , O r b i t a l ∗∗ o r b i t a l s _ m , double h_alpha ) ;
/∗
∗ P r i n t matrix and i n v e r s e , used f o r d e b u g g i n g
∗/
void p r i n t M a t r i c e s ( ) ;
/∗
∗ P r i n t parameters o f t h i s s l a t e r matrix
∗ ( dimension and parameters / t y p e s o f o r b i t a l s , CGM s t a t s )
∗/
void p r i n t _ p a r a m s ( ) ;
private :
i n t dim ;
// How many p a r t i c l e s do we have ?
O r b i t a l ∗∗ o r b i t a l s ; // L i s t o f p o i n t e r s t o o r b i t a l s
double ∗∗ m a t r i x ;
// d_ij ( i=which wf , j=which pos )
double ∗∗ i n v e r s e ;
// d^{−1}_ji ( note ! Transposed f o r ( c++) speed ! )
//Used f o r e s t i m a t i n g t h e p a r t i a l d e r i v a t i v e w i t h r e s p e c t t o
// v a r i a t i o n a l parameter ( assumption : Only 1 v a r i a t i o n a l parameter )
O r b i t a l ∗∗ o r b i t a l s _ p ;
O r b i t a l ∗∗ o r b i t a l s _ m ;
double h_alpha ; // S t e p s i z e o f a l p h a i n h , o r b i t a l s _ p = \ p h i ( x , \ a l p h a+h_alpha )
bool CGMready ; // This i s t r u e i f o r b i t a l s _ p and orbitals_m i s s e t
//Much has t o be c a l c u l a t e d a l r e a d y i n g e t R a t i o ( ) ,
// s t o r e t h i s and r e u s e i n update ( ) i f move a c c e p t e d
int p a r t i c l e ;
//Which p a r t i c l e i s moved
double ∗ r_new ; //Where has i t been moved t o
double ∗ matrix_new ; //Updated row o f s l a t e r matrix
double R ;
// Ratio f o r p o s i t i o n r_now , used i n update ( )
//What s e t o f p o s i t i o n s
double ∗∗ r_now ;
is
t h e s t o r e d / a c c e p t e d matrix c u r r e n t l y
valid
for?
/∗
∗ C a l c u l a t e t h e determinant o f a dxd matrix
∗ u s i n g r e c u r s i v e c a l l i n g o f i t s e l f , a l o n g f i r s t column .
∗
∗ 2x2 m a t r i c e s are e v a l u a t e d e x p l i c i t l y .
∗/
double d e t ( double ∗∗ mat , i n t d ) ;
/∗
∗ Setup a s l a t e r matrix a t t h e p o i n t r ,
∗ g i v e n a l i s t o f o r b i t a l s . Number o f p a r t i c l e s = dim ( c l a s s
∗ F i l l s t h e dim∗dim matrix mat
∗/
53
variable ).
193
194
195
196
};
void s e t u p _ m a t r i x ( O r b i t a l ∗∗ o r b s , double ∗∗ r , double ∗∗ mat ) ;
#e n d i f
Listing 5: jastrow.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#i f n d e f JASTROW_HPP
#d e f i n e JASTROW_HPP
/∗
∗ General c l a s s
∗/
for handling a jastrow
factor
class Jastrow {
public :
/∗
∗ I n i t i a l i z e m a t r i c e s and s e t num_particles
∗/
Jastrow ( int num_particles ) ;
/∗
∗ Delete matrices
∗/
~Jastrow ( ) ;
/∗
∗ Make t h e i n i t i a l update o f t h e m a t r i c e s
∗/
v i r t u a l void i n i t i a l U p d a t e ( double ∗∗ r ) = 0 ;
/∗
∗ Accept t h e move o f a p a r t i c l e ( from l a s t g e t R a t i o ()− c a l l )
∗/
v i r t u a l void u p d a t e ( ) = 0 ;
/∗
∗ Get t h e r a t i o o f t h e j a s t r o w s , update temp s t o r e f o r use i n update ( )
∗/
v i r t u a l double g e t R a t i o ( double ∗ r , i n t p a r t i c l e ) = 0 ;
/∗
∗ Get t h e v a l u e o f t h e j a s t r o w f a c t o r
∗
∗ Independent o f r_now e t c .
∗/
v i r t u a l double g e t V a l ( double ∗∗ r ) = 0 ;
/∗
∗ Get p a r t i a l d e r i v a t i v e o f j a s t r o w w i t h r e s p e c t t o parameter b e t a ,
∗ d i v i d e d by t h e v a l u e o f t h e j a s t r o w f a c t o r .
∗ Assumption : Only one s i n g l e parameter b e t a !
∗ E v a l u a t e d a t r_now .
∗
∗ You p r o b a b l y have t o do some e x t r a s e t u p t o use t h i s f u n c t i o n −−
∗ s e e documentation o f implementing c l a s s .
∗
∗/
v i r t u a l double g e t _ p a r t P s i _ o v e r _ p s i ( ) = 0 ;
/∗
∗ Get p a r t i a l f i r s t d e r i v a t i v e s w i t h r e s p e c t t o a g i v e n p a r t i c l e ,
∗ d i v i d e d by v a l u e o f j a s t r o w , a t t h e l a s t a c c e p t e d p o s i t i o n .
∗ Returns a new array .
∗/
v i r t u a l double ∗ g e t D e r i v ( i n t p a r t i c l e ) = 0 ;
/∗
∗ Get l a p l a c i a n , d i v i d e d by v a l u e o f j a s t r o w , a t l a s t a c c e p t e d p o s i t i o n
∗/
v i r t u a l double g e t L a p l a c e ( i n t p a r t i c l e ) = 0 ;
/∗
∗ P r i n t parameters f o r j a s t r o w f a c t o r
∗/
v i r t u a l void p r i n t _ p a r a m s ( ) = 0 ;
protected :
/∗
∗ Get r_{p1 , p2} from t h e s e n t−i n p o s i t i o n −matrix r
∗/
double r _ i n t e r ( double ∗∗ r , i n t p1 , i n t p2 ) ;
/∗
∗ Get | r1−r2 |
∗/
double r _ i n t e r ( double ∗ r1 , double ∗ r 2 ) ;
/∗
∗ Save a ( copy o f ) r_update t o r_new , and update r_inter_new , as w e l l as i n t
∗/
54
particle
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
void u p d a t e _ t e m p s t o r e ( double ∗ r_update ,
int
particle );
/∗
∗ Save r_new and r_inter_new t o r_now and r_inter_now
∗ when a c c e p t i n g a move
∗/
void f l i p _ t e m p s t o r e ( ) ;
int num_particles ;
//Number o f p a r t i c l e s ( g i v e s s i z e s o f m a t r i c e s e t c . )
double ∗∗ r_now ;
//Where where we l a s t time we a c c e p t e d a move ?
double ∗∗ r_inter_now ; //r_{ i j } ( o n l y upper−t r i a n g l e guaranteed−good , d i a g o n a l and l o w e r may be whatever )
int p a r t i c l e ;
// Last moved p a r t i c l e ( from g e t R a t i o )
double ∗ r_new ; // Last t r i e d r ( o f p a r t i c l e no = p a r t i c l e )
double ∗ r_inter_new ; //r_{ i j } ( s t o r e d " s m a r t l y " − s e e code update_tempstore ( ) )
};
/∗
∗ General c l a s s f o r p r o v i d i n g t h e f a c t o r g (r_{ i j }) t o JastrowExp
∗/
c l a s s jasFuncExp {
public :
/∗
∗ Returns t h e v a l u e o f g (r_{ i j }) = g ( r _ i n t e r ) .
∗ S e t spinEx = True i f spin_i != spin_j , f a l s e i f spin_i = spin_j
∗/
v i r t u a l double g e t V a l u e ( double r _ i n t e r , bool s p i n E x ) = 0 ;
/∗
∗ Gradient : r e t u r n s
∗ \del_1 g ( | r1−r2 | ) = − \del_2 g ( | r1−r2 | )
∗ as a new array
∗/
v i r t u a l double ∗ g e t D e r i v ( double ∗ r1 , double ∗ r2 , bool s p i n E x ) = 0 ;
/∗
∗ L a p l a c i a n : Returns t h e v a l u e o f
∗ \ d e l ^2_1 g ( | r1−r2 | ) = \ d e l ^2_2 g ( | r1−r2 | )
∗/
v i r t u a l double g e t L a p l a c e ( double r _ i n t e r , bool s p i n E x ) = 0 ;
/∗
∗ P r i n t name and parameters o f jasFuncExp
∗/
v i r t u a l void p r i n t _ p a r a m s ( ) = 0 ;
protected :
/∗
∗ Get | r1−r2 |
∗ ( copy−p a s t e o f code i n Jastrow )
∗/
double r _ i n t e r ( double ∗ r1 , double ∗ r 2 ) ;
};
/∗
∗ Implementation o f
∗ \ f r a c {a∗r_{ i j }} {1+b e t a ∗r_{ i j }}
∗/
c l a s s jasFuncExp1 : public jasFuncExp {
public :
jasFuncExp1 ( double b e t a ) ;
double g e t V a l u e ( double r _ i n t e r , bool s p i n E x ) ;
double ∗ g e t D e r i v ( double ∗ r1 , double ∗ r2 , bool s p i n E x ) ;
double g e t L a p l a c e ( double r _ i n t e r , bool s p i n E x ) ;
void p r i n t _ p a r a m s ( ) ;
private :
double b e t a ;
/∗
∗ Get t h e f a c t o r "a" i n t h e j a s t r o w f u n c t i o n
∗ ( 0 . 5 i f t r u e ( s p i n 1 != s p i n 2 ) , 0 . 2 5 i f f a l s e ( s p i n 1 == s p i n 2 ) )
∗/
double getA ( bool s p i n E x ) ;
};
/∗
∗ C l a s s f o r h a n d l i n g a j a s t r o w f a c t o r o f t h e form
∗ \prod_{ i<j }∗ exp ( g (r_{ i j } ) ) , where g (r_{ i j }) i s g i v e n as i n p u t
∗ ( a c l a s s implementing jasFuncExp )
∗/
c l a s s JastrowExp : public J a s t r o w {
public :
/∗
∗ Create m a t r i c e s and s e t u p g (r_{ i j })
∗/
JastrowExp ( i n t n u m _ p a r t i c l e s , jasFuncExp ∗ f a c t o r ) ;
/∗
∗ Destroy m a t r i c e s
55
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
∗/
~JastrowExp ( ) ;
void
i n i t i a l U p d a t e ( double ∗∗ r ) ;
void
update ( ) ;
double g e t R a t i o ( double ∗ r , i n t p a r t i c l e ) ;
double g e t V a l ( double ∗∗ r ) ;
/∗
∗ C a l c u l a t e p a r t i a l d e r i v a t i v e o f Jastrow f a c t o r w i t h
∗ r e s p e c t t o parameter b e t a , d i v i d e d by Jastrow f a c t o r .
∗ Assumption : Only one parameter b e t a .
∗ E v a l u a t e d a t r_now
∗
∗ Numerical d i f f e r e n t i a t i o n , c a l l CGMsetup b e f o r e using ,
∗ or e l s e your program w i l l c r a s h .
∗/
double
get_partPsi_over_psi ( ) ;
double ∗ g e t D e r i v ( i n t p a r t i c l e ) ;
double
getLaplace ( int p a r t i c l e ) ;
void
print_params ( ) ;
/∗
∗ Setup f a c t o r s f o r use i n CGM
∗/
void CGMsetup ( jasFuncExp ∗ f a c t o r _ p , jasFuncExp ∗ factor_m , double h_beta ) ;
protected :
/∗
∗ Used t o d e c i d e t h e spinEx f l a g s e n t t o jasFuncExp .
∗ Returns :
∗ True i f s p i n o f p1 != p2 ,
∗ F a l s e i f s p i n o f p1 == p2
∗/
bool s p i n E x _ d e c i d e ( i n t p1 , i n t p2 ) ;
i n t np2 ; // = num_particles / 2
private :
// P o i n t e r t o c l a s s c a p a b l e o f g e n e r a t i n g g (r_{ i j })
jasFuncExp ∗ f a c t o r ;
//Used f o r e s t i m a t i n g t h e p a r t i a l d e r i v a t i v e w i t h r e s p e c t t o
// v a r i a t i o n a l parameter ( assumption : Only 1 v a r i a t i o n a l parameter )
jasFuncExp ∗ f a c t o r _ p ;
jasFuncExp ∗ factor_m ;
double h_beta ;
bool CGMready ;
};
// Factor m a t r i c e s
double ∗∗ f a c t o r s _ n o w ;
double ∗ f a c t o r s _ n e w ;
/∗
∗ C l a s s f o r h a n d l i n g a "dummy" j a s t r o w −f a c t o r which i s always 1
∗ ( used by Wavefunction_Slater i n c a s e s where we don ’ t r e a l l y want any Jastrow f a c t o r )
∗/
c l a s s JastrowDummy : public J a s t r o w {
public :
//We need t o c a l l a ( t h e ) b a s e c l a s s c o n s t r u c t o r , which needs an argument .
JastrowDummy ( i n t n u m _ p a r t i c l e s ) : J a s t r o w ( n u m _ p a r t i c l e s ) { } ;
void i n i t i a l U p d a t e ( double ∗∗ r ) ;
void u p d a t e ( ) ;
double g e t R a t i o ( double ∗ r , i n t p a r t i c l e ) ;
double g e t V a l ( double ∗∗ r ) ;
double g e t _ p a r t P s i _ o v e r _ p s i ( ) ;
//Note : Returns a new array ( o f o n l y z e r o s )
double ∗ g e t D e r i v ( i n t p a r t i c l e ) ;
double g e t L a p l a c e ( i n t p a r t i c l e ) ;
void p r i n t _ p a r a m s ( ) ;
};
#e n d i f
Listing 6: util.hpp
1
2
3
4
5
6
7
8
9
#i f n d e f UTIL_HPP
#d e f i n e UTIL_HPP
/∗
∗ Function t o s e t u p NxM m a t r i c e s o f d o u b l e s
∗/
double ∗∗ c r e a t e _ m a t r i x ( i n t N, i n t M) ;
/∗
56
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
∗ Function t o d e l e t e m a t r i c e s o f d o u b l e s
∗ w i t h N rows ( no . o f columns not r e q u i r e d )
∗/
void d e l e t e _ m a t r i x ( double ∗∗ m a t r i x , i n t N ) ;
#e n d i f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/∗
∗ Function t o minimize a f u n c t i o n u s i n g t h e c o n j u g a t e g r a d i e n t method .
∗ Based on code from numerical r e c i p e s .
∗
∗ Arguments :
∗ double p [ ]
− I n i t i a l g u e s s f o r minima , l e n g t h n+1
∗ int n
− Number o f parameters
∗ d o u b l e g t o l − Tolerance i n minima f i n d i n g
∗ int∗ iter
− Return number o f i t e r a t i o n s used
∗ d o u b l e ∗ f r e t − Return f u n c t i o n v a l u e a t minima
∗ d o u b l e (∗ func ) ( d o u b l e [ ] )
− The f u n c t i o n on which minimization i s done
∗
( c a l l w i t h "&functionName" i n your program ) .
∗
Needs t o t a k e a n+1 l e n g t h array o f d o u b l e s
∗
which c o n t a i n s t h e p o s i t i o n t h a t t h e f u n c t i o n
∗
s h o u l d be c a l c u l a t e d i n .
∗ v o i d (∗ dfunc ) ( d o u b l e [ ] , d o u b l e [ ] ) − Function t h a t c a l c u l a t e s t h e g r a d i e n t .
∗
Needs t o t a k e two arguments :
∗
1) an n+1 l e n g t h array o f d o u b l e s , c o n t a i n i n g
∗
t h e p o s i t i o n you wish t o c a l c u l a t e t h e g r a d i e n t i n
∗
2) another n+1 l e n g t h array o f d o u b l e s , c o n t a i n g
∗
p a r t i a l d e r i v a t i v e s along a l l n a x i s
∗/
void dfpmin ( double p [ ] , i n t n , double g t o l , i n t ∗ i t e r , double ∗ f r e t ,
double ( ∗ f u n c ) ( double [ ] ) , void ( ∗ d f u n c ) ( double [ ] , double [ ] ) ) ;
/∗
/∗
∗ Function t o copy NxM m a t r i c e s o f d o u b l e s
∗ i n t o a new matrix
∗/
double ∗∗ copy_matrix ( double ∗∗ s o u r c e , i n t N,
/∗
∗ Function t o p r e t t y −p r i n t a matrix
∗/
void p r i n t _ m a t r i x ( double ∗∗ m a t r i x , i n t N,
i n t M) ;
i n t M) ;
/∗
∗ Least−s q u a r e s method u s i n g normal e q u a t i o n s .
∗
∗ I f v a r i a n c e=NULL, assume a l l measurements y ( x )
∗ have t h e same s t a n d a r d d e v i a t i o n .
∗
∗ Returns : Vector [ b , a ] o f s o l u t i o n y ( x ) = ax+b
∗/
double ∗ l e a s t s q u a r e s ( double ∗ x , double ∗ y , double ∗ v a r i a n c e ,
int N) ;
/∗
∗∗ The f u n c t i o n
∗∗
ran2 ( )
∗∗ i s a l o n g p e r i o d e (> 2 x 10^18) random number g e n e r a t o r o f
∗∗ L ’ Ecuyer and Bays−Durham s h u f f l e and added s a f e g u a r d s .
∗∗ C a l l w i t h idum a n e g a t i v e i n t e g e r t o i n i t i a l i z e ; t h e r e a f t e r ,
∗∗ do not a l t e r idum between s u c e s s i v e d e v i a t e s i n a
∗∗ sequence . RNMX s h o u l d approximate t h e l a r g e s t f l o a t i n g p o i n t v a l u e
∗∗ t h a t i s l e s s than 1 .
∗∗ The f u n c t i o n r e t u r n s a uniform d e v i a t e between 0 . 0 and 1 . 0
∗∗ ( e x c l u s i v e o f end−p o i n t v a l u e s ) .
∗/
double r a n 2 ( long ∗ idum ) ;
/∗
∗ Box−m u l l e r random d e v i a t e
∗ ( w i t h acceptance−r e j e c t a n c e )
∗
∗ Adapted from Numerical Recipes 3 rd e d i t i o n
∗
∗ Returns random numbers w i t h mu = sigma = 1
∗
∗/
double ran_normal ( long ∗ idum ) ;
Listing 7: conjgrad.h
57
26
27
28
29
∗ Function used by dfpmin
∗/
void l n s r c h ( i n t n , double x o l d [ ] , double f o l d , double g [ ] , double p [ ] , double x [ ] ,
double ∗ f , double stpmax , i n t ∗ c h e c k , double ( ∗ f u n c ) ( double [ ] ) ) ;
58
Download