I normally write my Monte Carlo codes in Fortran for speed, but I was doing some quick and dirty work and wrote one in Mathematica for the XY model on a square lattice (see Kosterlitz-Thouless Transition).
Monte Carlo is normally all about speed, since we are usually interested in very large systems (i.e. the "thermodynamic limit"). I usually use Mathematica for quick and dirty calculations and for its graphical capabilities, and rarely have considered too carefully the performance of my code. I'm curious if anyone can point out any major shortfalls in this code.
(*parameters*)
L = 20;
T = 1.0;
\[Alpha] = 1.;
pi = N@\[Pi];
(*acceptance rate array*)
accepts = ConstantArray[1, L^2];
(*mod for periodic boundaries*)
mod[n_] := 1 + Mod[n - 1, L]
(*lists of all lattice indexes *)
pos = Flatten[Table[{i, j}, {i, L}, {j, L}], 1];
(*list of neighbors of site (i,j)*)
neighbors = Table[{{i, mod[j + 1]}, {mod[i + 1], j}, {i, mod[j - 1]}, {mod[i - 1], j}}, {i, 1, L}, {j, 1, L}];
(*initialized lattice of 2d spins*)
XY = Map[Normalize, RandomReal[{-1., 1.}, {L, L, 2}], {-2}];
(*metropolis update for site (i,j)*)
MCUpdate[{i_, j_}] := (
v = XY[[i, j]]; (*current vector*)
u = RotationMatrix[\[Alpha] RandomReal[{-pi,pi}]].v; (*new proposed vector*)
dE = (Total@Extract[XY, neighbors[[i, j]]]).(u - v); (*change in energy by changing to new vector*)
n = j + (i - 1) L;
If[RandomReal[] < Min[1, Quiet@Exp[-dE/T]],
(*update vector if Metropolis condition is satisfied*)
XY[[i, j]] = u;
accepts[[n]] = 1
,
(*reject update*)
accepts[[n]] = 0
]
)
(*performs n sweeps of the lattice*)
Sweep[n_] := Do[
MCUpdate /@ pos;
(*make sure everything is normalized*)
Map[Normalize, XY, {-2}];
If[Mean[accepts] < 0.45, \[Alpha] *= .95,
If[Mean[accepts] > 0.55, \[Alpha] *= 1.05]];
, n]
Some basic explanations:
accepts
tracks the lastL^2
attempts to update one of the variables, so that the magnitude of the proposed changes,\[Alpha]
, can be adjusted such that the acceptance rate stays around0.5
.MCUpdate
proposes a rotation to the vector at site(i,j)
, computes the change in energydE
due to this change, and then applies the Metropolis condition to determine whether to accept or reject with probabilitymin(1,exp(-dE/T))
whereT
is the temperature
If you'd like to play with this, the following function will find all the vortices and color them:
(* list of indexes for each plaquette*)
plaq = Flatten[Table[{{i, j}, {i, mod[j + 1]}, {mod[i + 1], mod[j + 1]}, {mod[i + 1], j}}, {i, L}, {j, L}], 1]; (*find vortices and color them*)
vortexcolors = {Blue, Transparent, Red};
vortex := Table[
p = plaq[[i]];
spins = Extract[XY, plaq[[i]]];
\[CapitalDelta] = Round@Sum[
s1 = spins[[j]]~Append~0; s2 = spins[[1 + Mod[j, 4]]]~Append~0;
Sign[Cross[s1, s2].{0, 0, 1}] ArcCos[s1.s2]/(2 \[Pi])
,
{j, 4}];
Graphics[{vortexcolors[[\[CapitalDelta] + 2]], Disk[p[[1]] - {.5, .5}, 0.25]}], {i, L^2}]
and this will allow you to plot all the spins, starting from a random configuration and "sweeping" the lattice some times to come to thermal equilibrium:
(*random starting configuration*)
XY = Map[Normalize, RandomReal[{-1., 1.}, {L, L, 2}], {-2}];
(*arrows to represent vectors*)
plotXY[col_] := (
Map[(p = First@Position[XY, #] - {1, 1}; Graphics[{col, Arrow[{p, p + #/1.5}]}]) &, XY, {-2}]
)
(*100 monte carlo sweeps*)
Sweep[100];
(*plot the configuration with vortices and square lattice grid*)
p1 = {plotXY[Black], vortex};
grid = Graphics[{Lighter@Red, Line[#]}] & /@ (Table[{{i, 0}, {i, L}}, {i, 0, L - 1}]~Join~Table[{{0, i}, {L, i}}, {i, 0, L - 1}]);
Show[{grid, p1}, PlotRange -> {{-1, L}, {-1, L}}]
Edit: As a bonus, is there a better way than Quiet@Exp[-dE/T]
to deal with the error that Exp[-large number]
cannot be represented by machine precision numbers? I would expect it to simply output zero.
Compile
? $\endgroup$Exp[Clip[x, {-700., ∞}]]
. The approximation should have a negligible effect on the simulation and at the same time, it avoids underflow, according to his answer. $\endgroup$Exp[Min[Max[-700., -dE/T], 0.]]
in the compiled code sinceClip
is not compilable. However,Clip
is usually nicer to use because it has attributeListable
. $\endgroup$