Criticality and hysteresis in the 2-D Ising model

The two dimensional Ising model possesses all of the features that we expect of a true ferromagnetic system: spontaneous magnetization, critical behavior, and hysteresis.

A Monte Carlo simulation illustrates all of this quite graphically. I use common lisp in this coding example, and the SDL graphics library (which is great for coding games and real-time graphics). The lispbuilder-sdl package can be installed on your computer system with quicklisp . I recommend using sbcl, which is the fastest lisp available.

Let’s get to the fun first. I am running the simulation on a Rockpro64, which is a 79.00 SBC computer with 4Gb of ram and a 64-bit ARM processor, so a very modest machine. It is run in real time, and I use vokoscreen to capture the running simulation as an mp4 stream, which we are able to embed below.

I will slowly ramp up the temperature, and you can see the scale-invariant macrostate with domains of all sizes form at around the critical temperature T=2.4 k_B J.

I will increase the temperature well past this, then very rapidly drop it back down to nearly zero. When the simulation began at very low-T, we had one large domain of spins-down, with a few fluctuations of spin-up sites. Now you  will see hysteresis: we will rapidly drop to the original low temperature but the large domains that form will be of a totally different nature from the initial.

play-sharp-fill

Notice that near the critical temperature the simulation slows down a lot, because we use the accept-reject algorithm for the Boltzmann distribution, and there are many rejects.

For those of you that may wish to try it out, the code is below.

#| Jeff Schmidt 2015, 
First we create some classes for handling the lattice and its measurements
then we set up the graphics. This requires lispbuilder-sdl, and should be
run under sbcl, clisp or ccl ;
(load \"sdl-Ising2D.lisp\")  remove the slashes!
(sdl-Ising2D) |#

(defclass lattice ()
  ((size  :accessor size :initarg :size)
   (spins :accessor spins :initarg :spins)
   (energy :accessor energy :initarg :energy)
   (magnetization :accessor magnetization :initarg :magnetization)))

(defun environ (m i j n)
"Local environment of a nxn matrix PBC"
(+ (aref m (mod (+ i 1) n) j) (aref m (mod (- i 1) n) j)
   (aref m i (mod (+ j 1) n)) (aref m i (mod (- j 1) n))))

(defgeneric find-mag (obj))
(defmethod find-mag ((lat lattice))
"Compute by hand the average magnetic moment"
(let* ((n (size lat)))
(/ (loop for i from 0 to (- n 1) sum
    (loop for j from 0 to (- n 1) sum (aref (spins lat) i j))) (* 1.0d0 n n))))

(defgeneric find-energy (obj))
(defmethod find-energy ((lat lattice))
"Compute by hand the total energy"
(let* ((n (size lat)))
(loop for i from 0 to (- n 1) sum
    (loop for j from 0 to (- n 1) sum 
	 (* (aref (spins lat) i j) (environ (spins lat) i j n) -0.5d0)))))

(defmethod initialize-instance :after 
           ((lat lattice) &rest args)
"Initialize the energy/magnetization slots after the spin-state is loaded"
  (setf (energy lat) (find-energy lat))
  (setf (magnetization lat) (find-mag lat)))

(defgeneric update-lattice (obj tee))
(defmethod update-lattice ((lat lattice) (temp number))
"Update-washout of the lattice, run to erase its memory"
(let* ((n (size lat)) (i (random n)) (j (random n))
       (de (* 2.0d0 (aref (spins lat) i j) (environ (spins lat) i j n))))
(if (< de 0.0d0)
       (progn (setf (aref (spins lat) i j) (* -1 (aref (spins lat) i j)))
	   (setf (energy lat) (+ (energy lat) de))
	   (setf (magnetization lat) (+ (magnetization lat) 
					(* 2 (aref (spins lat) i j)))))
      (progn
       (if (<= (random 1.0d0) (exp (/ (* -1.0d0 de) temp)))
	   (progn (setf (aref (spins lat) i j) (* -1 (aref (spins lat) i j)))
	   (setf (energy lat) (+ (energy lat) de))
	   (setf (magnetization lat) (+ (magnetization lat) 
					(* 2 (aref (spins lat) i j))))))))
))

(defgeneric measure-lattice (obj tee en))
(defmethod measure-lattice ((lat lattice) (temp number) (M number))
"Data collection, finds average M,E at T=temp, averaging over M updates"
(loop for trials from 1 to M do (update-lattice lat temp) 
   summing (energy lat) into Esum 
   summing (magnetization lat) into Msum 
   finally (return (/ Esum M 10000))))

;;That's it for classes, let's get busy!

(require 'lispbuilder-sdl)
(defvar ell (make-instance 'lattice :size 100 :spins 
			   (make-array (list 100 100) :initial-element -1)))
(defvar dT 0.05)
(defvar Temp 1.0)

(defun sdl-Ising2D ()
"Two-dimensional Ising model, the video game (Jeff Schmidt 2015)"
  (sdl:with-init ()
    (sdl:window 600 405 :title-caption "2D-Ising")
    (sdl:initialise-default-font sdl:*font-10x20*)
    (setf (sdl:frame-rate) 20)
    (sdl:with-events (:poll)
      (:quit-event () t)
      (:key-down-event 
      (:key key)
      (case key
	(:sdl-key-up (incf Temp dT))
	(:sdl-key-down (decf Temp dT))
	(:sdl-key-p (sleep 2))
	(:sdl-key-q (sdl:push-quit-event))))  
      (:idle ()
	     (sdl:clear-display sdl:*black*)
	     (loop for i from 0 to 10000 do (update-lattice ell Temp))
	     (loop for i from 0 to 99 do 
		  (loop for j from 0 to 99 do (if (= 1 (aref (spins ell) i j))
		  (sdl:draw-filled-circle (sdl:point :x (+ (* i 4) 3)  
						     :y (+ (* j 4) 3))
						     2
						     :color sdl:*yellow*
						     :stroke-color sdl:*white*))))
      (sdl:draw-string-solid-* (format nil "10^4 spins" )
				420 20
				:color sdl:*red* :justify :left)
      (sdl:draw-string-solid-* (format nil "Showing \"up\"" )
				420 40
				:color sdl:*red* :justify :left)
      (sdl:draw-string-solid-* (format nil "spins only" )
				420 60
				:color sdl:*red* :justify :left)	     
      (sdl:draw-string-solid-* (format nil "kT/J=~,3F" Temp)
				420 100
				:color sdl:*red* :justify :left)
      (sdl:draw-string-solid-* (format nil "E/N=~,3F" (measure-lattice ell Temp 1000))
				420 120
				:color sdl:*red* :justify :left)
      (sdl:draw-string-solid-* (format nil "up increases T")
				420 200
				:color sdl:*blue* :justify :left)
      (sdl:draw-string-solid-* (format nil "down decreases T")
				420 220
				:color sdl:*blue* :justify :left)
      (sdl:draw-string-solid-* (format nil "p pauses")
				420 240
				:color sdl:*blue* :justify :left)
      (sdl:draw-string-solid-* (format nil "q quits")
				420 260
				:color sdl:*blue* :justify :left)
	     (sdl:update-display)
	     )
	    )
      )
    )
Home 2.0
error: Content is protected !!