Skip to content

Add DMC #34

Description

@ohno

This is a Julia implementation of the pure diffusion Monte Carlo method. The code is inefficient and messy, so please use it only as a reference.

# 概要:拡散モンテカルロ法
# 環境:Windows 10 Pro x64 (i7-4650U, 8.00GB)
# 言語:Julia (Version 1.5.0)
# 作成:2020-05-19 (yyyy-mm-dd)
# 更新:2020-08-05 (yyyy-mm-dd)
# 更新:2020-12-10 (yyyy-mm-dd)
# 文献:https://doi.org/10.1119/1.18168
# 文献:https://doi.org/10.1063/1.4822960


# 共通関数:
function Reset()
	println(Name," Run")
	global BIN_WIDTH = 0.001
	global histogram = [[1.4,1.4+BIN_WIDTH,0,0]] # 左端, 右端, num, num^2
	global S              .= 1
	global S[N_ini+1:end] .= 0
	global E_ref           = Averaged_Potential_Energy()
	global N_rep           = count(S.==1)
	global Info_File       = open( PROGRAM_FILE[1:end-3] *"_"* Name * "_Info.csv", "w" )
	global Stat_File       = open( PROGRAM_FILE[1:end-3] *"_"* Name * "_Stat.csv", "w" )
	write( Info_File, "#Parameter,Value" )
	write( Info_File, "\nNumber of Time Steps,"         * string(h_max)                  )
	write( Info_File, "\nNumber of Dimension,"          * string(i_max)                  )
	write( Info_File, "\nNumber of Replicas (Maximum)," * string(j_max)                  )
	write( Info_File, "\nNumber of Particles,"          * string(k_max)                  )
	write( Info_File, "\nTime Step Width,"              * string(dt)                     )
	write( Info_File, "\nInitial Number of Replicas,"   * string(N_rep)                  )
	write( Info_File, "\nInitial Reference Energy,"     * string(E_ref)                  )
	write( Info_File, "\nBin Width of Histgram,"        * string(bin_w)                  )
	write( Info_File, "\nIndex for Exports,"            * replace(string(Out), ","=>" ") )
	write( Info_File, "\nStandard Deviation of Rand,"   * replace(string(D), ","=>" ")   )
	write( Info_File, "\nCharge of Particles,"          * replace(string(Q), ","=>" ")   )
	write( Info_File, "\nInitial Status,"               * replace(string(S), ","=>" ")   )
	write( Info_File, "\nInitial Displacement,"         * replace(string(R), ","=>" ")   )
	close( Info_File )
	Label_Line = "#i,t,N_rep,E_ref"
	for k1 in 1:k_max-1 # n(n-1)/2通り
		for k2 in k1+1:k_max
			Label_Line *= ",r" * string(k1) * string(k2)
		end
	end
	write( Stat_File, Label_Line )
end	

function List_Export(data_number)
	List_File  = open( string( PROGRAM_FILE[1:end-3], "_", Name, "_List_", lpad(data_number,5,"0"), ".csv" ) , "w" )
	Label_Line = "#i"
	for k in 1:k_max
		Label_Line *= string(",x", k, ",y", k, ",z", k)
	end
	write( List_File, Label_Line)
	for j in findall(S.==1)
		Data_Line = string("\n", j)
		for k in 1:k_max
			Data_Line *= string(",", R[1,j,k], ",", R[2,j,k], ",", R[3,j,k])
		end
		write( List_File, Data_Line )
	end
	close( List_File )
end

function Hist_Update()
	Alive = findall(S.==1)
	Dist = Distance(1,2)
	for x in Dist[Alive]
		while !(histogram[1][1] <= x && x < histogram[end][2])
			if histogram[1][1] > x
				pushfirst!(histogram, [histogram[1][1]-BIN_WIDTH, histogram[1][1], 0, 0])
			end
			if histogram[end][2] <= x
				push!(histogram, [histogram[end][2], histogram[end][2]+BIN_WIDTH, 0, 0])
			end
		end
		# histogram[Int(floor((x - histogram[1][1])/BIN_WIDTH))+1][3] += 1
		# histogram[Int(floor((x - histogram[1][1])/BIN_WIDTH))+1][4] += histogram[Int(floor((x - histogram[1][1])/BIN_WIDTH))+1][3]^2
		for interval in histogram
			if interval[1] <= x && x < interval[2]
				interval[3] += 1
				interval[4] = interval[3]^2
			end
		end
	end
end

function Hist_Export()
	open(string( PROGRAM_FILE[1:end-3], "_", Name, "_Hist.csv" ), "w") do file
		println(file, "#left,right,num,num^2")
		for i in 1:length(histogram)
			println(file, histogram[i][1], ",", histogram[i][2], ",", histogram[i][3], ",", histogram[i][4])
		end
	end
	X = [(interval[1]+interval[2])/2 for interval in histogram]
	P = [interval[4] for interval in histogram]
	println("DMC   : <R>   = ", sum(X.*P/sum(P)))
end

function Stat_Export(countdown)
	Data_Line = string("\n", countdown, ",", t, ",", N_rep, ",", E_ref)
	for k1 in 1:k_max-1 # n(n-1)/2通り
		for k2 in k1+1:k_max
			Data_Line *= "," * string( sum(Distance(k1,k2)[findall(S.==1)]) / count(S.==1) )
		end
	end
	write( Stat_File, Data_Line )
end

# function GaussianRand(n,m) # 平均0分散1の正規分布に従う乱数をn,m個並べた配列を返す
# 	return sqrt.(-2.0*log.(1 .-rand(n,m))).*sin.(2.0*pi*rand(n,m)) 
# end

function Diffusion_Process()
	global t += dt
	for k in 1:k_max
		global R[:,:,k] += D[k] * randn(Float64,i_max,j_max)
		# global R[:,:,k] += D[k] * GaussianRand(i_max,j_max)
	end
end

#本当に合ってるのか?
function Distance(num1,num2) # 粒子間距離の配列
	dX = R[1,:,num1] - R[1,:,num2]
	dY = R[2,:,num1] - R[2,:,num2]
	dZ = R[3,:,num1] - R[3,:,num2]
	return sqrt.(dX .* dX + dY .* dY + dZ .* dZ)
end

function Potential_Energy() # 死んだレプリカも含まれるので注意
	U = zeros(Float64,j_max)
	for k1 in 1:k_max-1 #findall([k for k in 1:k_max] .!== k1)
		for k2 in k1+1:k_max # n(n-1)/2通りの相互作用 
			U += Q[k1]*Q[k2] ./ Distance(k1,k2)
		end
	end
	return U
end

function Averaged_Potential_Energy()
	return sum( Potential_Energy()[findall(S.==1)] ) / count(S.==1)
end

function Birth_Replica(parent_replica)
	first_dead = findfirst(S.==0)
	# println(parent_replica, "->",first_dead)
	global S[first_dead] = 2
	for k in 1:k_max
		global R[:,first_dead,k] = R[:,parent_replica,k]
	end
end

function Branch_Process()
	Weight = exp.(-(Potential_Energy().-E_ref)*dt)
	mn = floor.(Weight+rand(j_max))
	Alive = findall(S.==1)
	for j in intersect( findall(mn.==0) , Alive )
		global S[j] = 0 # death
	end
	for j in intersect( findall(mn.==2) , Alive )
		Birth_Replica(j)
	end
	for j in intersect( findall(mn.==3) , Alive )
		Birth_Replica(j)
		Birth_Replica(j)
	end
	for j in findall(S.==2) # birth mark
		global S[j] = 1
	end
end

function Energy_Calculation()
	local  N_old = N_rep
	global N_rep = count(S.==1)
	global E_ref += 1.0/dt*(1.0-(N_rep+1.0)/(N_old+1.0)*(N_old+10.0*j_max)/(N_ini+10.0*j_max))
	# global E_ave = (1.0-F_ave)*E_ave + F_ave*E_ref
	# 参照エネルギーの時間平均が系のエネルギーを表すので移動平均を取れば良い.
end

function Finish()
	close( Stat_File )
	println(Name," Finish")
end

function Run()
	Reset()
	Stat_Export(0)
	for h in 1:h_max
		Diffusion_Process()
		Branch_Process()
		Energy_Calculation()
		Stat_Export(h)
		if h > 5000
			Hist_Update()
		end
	end
	List_Export(h_max)
	Hist_Export()
	Finish()
end

# 宣言:
# Out   = union([0],[10^i for i in 0:7],5*[10^i for i in 0:6],[100*i for i in 1:10],[1000*i for i in 1:10],[10000*i for i in 1:10]) # Index for Exports e.g. [1 5 50 100 500 1000 5000 10000]
Out   = [1 10 100 1000 5000 15000 25000 35000 45000]
const h_max = 25000                        # Number of Time Steps
const i_max = 3                            # Number of Dimension
const j_max = 8800                         # Number of Replicas (Maximum)
const N_ini = 8000                         # Initial Number of Replicas
const dt    = 0.1                          # Time Step Width
const bin_w = 0.2                          # Bin Width of Histgram

# 原子:
Names=["Ps","Mu","H","D","T"]
Diffs=[sqrt(dt/1.0000000),sqrt(dt/206.7682830),sqrt(dt/1836.15267343),sqrt(dt/3670.48296788),sqrt(dt/5496.92153573)]
for system in 1:5
global Name  = Names[system]                            # Name of System
global k_max = 2                                        # Number of Particles (Nuclear & Electron)
global E_ref = 0.0                                      # Reference Energy
global t     = 0.0                                      # Time
global N_rep = N_ini                                    # Current Number of Replicas
global Q     = ones(Float64,k_max)                      # Charge of Particles
global D     = ones(Float64,k_max)                      # Diffusion Coefficient of Particles
global S     = ones(Int64,j_max)                        # Status of Replicas / 0-not alive, 1-alive, 2-birth mark
global R     = (rand(Float64,i_max,j_max,k_max).-0.5)*2 # Displacement of Replicas
global Q[1]  = +1.0                                     # Nuclear
global Q[2]  = -1.0                                     # Electron
global D[1]  = Diffs[system]                            # Positron(1) Muon(206.7682830), Proton(1836.15267343), Deutron(3670.48296788), Triton(5496.92153573)
global D[2]  = sqrt(dt)                                 # Electron(1)
global R[:,:,1] .= 0                                    # Initial Displacement
@time Run()
end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions