-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpropose.f90
103 lines (82 loc) · 2.61 KB
/
propose.f90
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
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
!---------------------From Antony Lewis' CosmoMC-----------------------------
!Proposal density
!Using the covariance matrix to give the proposal directions typically
!significantly increases the acceptance rate and gives faster movement
!around parameter space.
!We generate a random basis in the eigenvectors, then cycle through them
!proposing changes to each, then generate a new random basis
!The distance proposal in the random direction is given by a two-D Gaussian
!radial function mixed with an exponential, which is quite robust to wrong width estimates
!See http://cosmologist.info/notes/cosmomc.ps.gz
module propose
use random
use cosmoSetUp
implicit none
logical :: propose_rand_directions = .true.
real, allocatable, dimension(:,:), save :: Rot_slow
real(hp) :: propose_scale = 2.4
contains
subroutine RotMatrix(M,n)
integer, intent(in) :: n
real M(n,n)
integer i
if (propose_rand_directions .and. n > 1) then
call RandRotation(M, n)
else
M = 0
do i = 1, n
M(i,i) = sign(1., real(ranmar())-0.5)
end do
end if
end subroutine RotMatrix
function Propose_r(in_n) result(r_fac)
!distance proposal function (scale is 1)
integer, intent(in) :: in_n
integer i,n
real r_fac
if (ranmar() < 0.33d0) then
r_fac = randexp1()
else
n = min(in_n,2)
r_fac = 0
do i = 1, n
r_fac = r_fac + Gaussian1()**2
end do
r_fac = sqrt( r_fac / n )
end if
end function Propose_r
subroutine UpdateParamsDirection(tmp, dist, i)
!Change parameters in tmp by dist in the direction of the ith random e-vector
implicit none
real(hp), dimension(nparam) :: tmp
real vec(nparam)
integer, intent(in) :: i
real(hp), intent(in) :: dist
tmp = tmp + Rot_slow(:,i) * dist * pset%Width
end subroutine UpdateParamsDirection
subroutine GetProposalProjSlow(In, Out)
implicit none
real(hp), dimension(nparam) :: In, Out
real(hp) :: wid
integer, save :: loopix = 0
Out= In
wid = propose_scale
if (mod(loopix,nparam)==0) then
if (.not. allocated(Rot_slow)) allocate(Rot_slow(nparam,nparam))
call RotMatrix(Rot_slow, nparam)
loopix = 0
end if
loopix = loopix + 1
call UpdateParamsDirection(Out, Propose_r(nparam) * wid, loopix)
end subroutine GetProposalProjSlow
subroutine GetProposal(InPlus, OutPlus)
implicit none
real(hp), dimension(nparam+1) :: InPlus, OutPlus
real(hp), dimension(nparam) :: before, after
before=InPlus(1:nparam)
call GetProposalProjSlow(before, after)
current_param(1:nparam)=after
call getOk
OutPlus=current_param
end subroutine GetProposal
end module propose