Моделирование двумерной модели Изинга на языке C++ (с применением графического пакета OpenGL)

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Модель Изинга


Модель Изинга была введена для понимания природы ферромагнетизма и повлияла на изучение фазовых переходов и критических явлений. Ферромагнетизм описывает появление самопроизвольной намагниченности у ферромагнетиков ниже определенной температуры — точки Кюри. В точке Кюри (узкой области температур) происходит упорядочение, в данном случае, выстраивание магнитных моментов, которое влечет фазовый переход, то есть свойства вещества меняются скачком.

Изначально модель была предложена В. Ленцем в 1920 году, и исследована Изингом для одномерного случая, в честь чего и получила свое название. В данной модели, каждая вершина кристаллической решетки принимает число: +1 или -1, — поле «вверх» или «вниз». Число, которое ставится в соответствие вершинам, называется спин. Таким образом, решетка из N числа спинов может находиться в 2N состояниях. Каждому состоянию соответствует энергия, которая получается из попарного взаимодействия спинов соседних атомов:



Где J — энергия взаимодействия соседних спинов (константа обменного взаимодействия одна и та же для всех пар), si и sj — спины.

При этом J > 0 описывает поведение ферромагнетика, J < 0 антиферромагнетика.

Если поместить модель во внешнее магнитное поле H, то полная энергия примет вид:



Суммарный магнитный момент или намагниченность определяется по следующей формуле:



Метод Монте-Карло


Как упоминалось ранее, всего возможно 2N состояний и при достаточно большом числе спинов N трудно получить численные результаты. Например при N=10 получим 210 состояний, которые напрямую смоделировать не так просто, поэтому для моделирования используется статистический подход.

В этом подходе система рассматривается в состоянии термодинамического равновесия при определенной температуре T. В ходе обмена энергией с окружающей средой, энергия будет изменяться около равновесного состояния, а средняя энергия одной частицы пропорциональна T. Реализация постоянного случайного изменения вокруг состояния равновесия использует метод Монте-Карло и моделирование можно разделить на этапы:

  1. Разыгрывать состояния αi системы (например, случайным образом) при фиксированном T;
  2. Считать для этих состояний термодинамические характеристики вблизи равновесия (энергию E, намагниченность M);
  3. Усреднять полученные значения


Алгоритм Метрополиса.


В задачах статистической механики выражения «метод Монте-Карло» и «метод выборки Метрополиса» — почти синонимы. Приведем наиболее общую форму алгоритма Метрополиса на примере системы спинов или частиц:

  1. Формируем начальную конфигурацию.
  2. Производим случайное пробное изменение в начальной конфигурации. Например, выбираем случайным образом какой-нибудь спин и пробуем его опрокинуть. Или выбираем случайную частицу и пробуем переместить ее на случайное расстояние.
  3. Вычисляем ∆Е, то есть изменение энергии системы, обусловленное произведенным пробным изменением конфигурации.
  4. Если ∆Е меньше или равно нулю, то принимаем новую конфигурацию и переходим к шагу 8.
  5. Если ∆Е положительно, вычисляем «вероятность перехода»:

  6. Генерируем случайное число rnd в интервале (0, 1)
  7. Если rnd≤W, то новую конфигурацию принимаем, в противном случае сохраняем предыдущую конфигурацию.
  8. Определяем значения требуемых физических величин.
  9. Повторяем шаги 2–8 для получения достаточного числа конфигураций или «испытаний».
  10. Вычисляем средние по конфигурациям, которые статистически независимы друг от друга.

Двумерная модель Изинга на языке C++


Напишем собственную программу, реализующую двумерную модель Изинга с помощью метода Монте-Карло и алгоритма Метрополиса. Реализуем следующий функционал:

  • Пользователь задает размер стороны решетки SIZE, максимально допустимую температуру T_MAX.
  • В окне ISING будет находиться вся решетка размером SIZE×SIZE, в решетке спины, которые будут направлены вверх (0), будут являться ячейками белого цвета, тогда как спины, направленные вниз (1), будут являться ячейками черного цвета.
  • Пользователь может изменять температуру T с помощью красной шкалы справа в окне ISING. Пользователь может изменять температуру, используя нажатие мыши или кнопки W и S на клавиатуре (соответственно повышение и понижение температуры). Максимально допустимая температура определяется пользователем, минимально допустимая – 0,01℃.
  • Белая черта на красной шкале – температура Кюри ферромагнетика Изинга. В двумерной модели Изинга при критической температуре T=2,269℃ происходит фазовый переход из неупорядоченного в упорядоченное ферромагнитное состояние.
  • Изменение конфигурации будет происходить непосредственно на экране каждые 10 мс (миллисекунд); с каждым изменением конфигурации будет увеличиваться число шагов Монте-Карло.
  • Пользователь может изменять температуру перед каждым новым изменением конфигурации решетки спинов.
  • Каждые 10 с (секунд) будет происходить вывод данных в консоль (коэффициент принятия, средняя энергия на спин, средний квадрат энергии на спин, средняя намагниченность, средний квадрат намагниченности).

#include <iostream>
#include <random>
#include <locale>
#include "glut.h"

using namespace std;

#define SIZE 256
#define SIZE_PX 800
#define T_MAX 4
#define CURIE_SCALE 1000. 

double quadSize = SIZE_PX / (double)SIZE;

short lattice[SIZE][SIZE];
double w[5];
double T = T_MAX, M, E;

int ratio = 0;
size_t nmcs = 0;
double ecum = 0, e2cum = 0, mcum = 0, m2cum = 0;

void display()
{
	glClear(GL_COLOR_BUFFER_BIT);
	
	glBegin(GL_QUADS);
	for (int i = 0; i < SIZE; i++)
		for (int j = 0; j < SIZE; j++)
		{
			glColor3f(lattice[i][j], lattice[i][j], lattice[i][j]);
			glVertex2d(i, j);
			glVertex2d(i, j + 1);
			glVertex2d(i + 1, j + 1);
			glVertex2d(i + 1, j);
		}
	glEnd();

	glBegin(GL_QUADS);
	{
		glColor3f(1, 0, 0);
		glVertex2d(SIZE, 0);
		glVertex2d(SIZE, SIZE * T / T_MAX);
		glVertex2d(SIZE + SIZE / 8, SIZE * T / T_MAX);
		glVertex2d(SIZE + SIZE / 8, 0);

		glColor3f(1, 1, 1);
		glVertex2d(SIZE, SIZE * 2.27 / T_MAX - SIZE / CURIE_SCALE);
		glVertex2d(SIZE, SIZE * 2.27 / T_MAX + SIZE / CURIE_SCALE);
		glVertex2d(SIZE + SIZE / 8, SIZE * 2.27 / T_MAX + SIZE / CURIE_SCALE);
		glVertex2d(SIZE + SIZE / 8, SIZE * 2.27 / T_MAX - SIZE / CURIE_SCALE);
	}
	glEnd();

	glutSwapBuffers();
	glFlush();
}

void calcW()
{
	double e4 = exp(-4 / T), e8 = e4 * e4;
	w[0] = w[4] = e8;
	w[1] = w[3] = e4;
	w[2] = 0;
}

void init()
{
	M = E = 0;
	static std::default_random_engine generator;
	std::uniform_int_distribution<int> distribution(0, RAND_MAX);
	for (int i = 0; i < SIZE; i++)
		for (int j = 0; j < SIZE; j++)
		{
			lattice[i][j] = ((distribution(generator) / (double)RAND_MAX >= 0.5) - 1) * 2 + 1;
			M += lattice[i][j];
		}

	for (int i = 0; i < SIZE; i++)
		for (int j = 0; j < SIZE; j++)
		{
			E += (i + 1 != SIZE) ? lattice[i][j] * lattice[i + 1][j] : 0;
			E += (j + 1 != SIZE) ? lattice[i][j] * lattice[i][j + 1] : 0;
		}

	calcW();
}

void metropolis()
{
	int x, y, sum;
	for (int i = 0; i < SIZE * SIZE; i++)
	{
		x = rand() % SIZE;
		y = rand() % SIZE;
		sum = lattice[(x - 1 + SIZE) % SIZE][y] +
			lattice[(x + 1 + SIZE) % SIZE][y] +
			lattice[x][(y - 1 + SIZE) % SIZE] +
			lattice[x][(y + 1 + SIZE) % SIZE];

		if (sum * lattice[x][y] <= 0 || (rand() / (double)RAND_MAX) < w[sum / 2 + 2])
		{
			lattice[x][y] = -lattice[x][y];
			::ratio++;
			M += 2 * lattice[x][y];
			E -= 2 * lattice[x][y] * sum;
		}
	}
}

void timer1(int)
{
	display();

	metropolis();

	nmcs++;

	ecum += E;
	e2cum += E * E;
	mcum += M;
	m2cum += M * M;


	glutTimerFunc(10, timer1, 0);
}

void outputData(int)
{
	double norm = 1 / (double)(nmcs * SIZE * SIZE);

	cout << "Коэффициент принятия = " << ::ratio * norm << endl;
	cout << "Средняя энергия на спин = " << ecum * norm << endl;
	cout << "Средний квадрат энергии на спин = " << e2cum * norm << endl;
	cout << "Средняя намагниченность = " << mcum * norm << endl;
	cout << "Средний квадрат намагниченности = " << m2cum * norm << endl << endl;

	glutTimerFunc(10000, outputData, 0);
}

void keyboard(unsigned char key, int x, int y)
{
	switch (key)
	{
	case 'w': case 'W':
	{
		T += 0.01;
		T = (T >= T_MAX) ? T_MAX : T;
		calcW();
		break;
	}
	case 's': case 'S':
	{
		T -= 0.01;
		T = (T <= 0.01) ? 0.01 : T;
		calcW();
		break;
	}
	}
}

void motion(int x, int y)
{
	double k = 1 - y / (double)SIZE_PX;
	T = T_MAX * k;
	T = (T >= T_MAX) ? T_MAX : T;
	T = (T <= 0.01) ? 0.01 : T;
	calcW();
}

int main()
{
	setlocale(LC_ALL, "ru");
	init();
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowSize(SIZE_PX + 100, SIZE_PX);
	glutCreateWindow("ISING");
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, SIZE + SIZE / 8, 0, SIZE);
	glutDisplayFunc(display);
	glutKeyboardFunc(keyboard);
	glutMotionFunc(motion);
	glutTimerFunc(1, timer1, 0);
	glutTimerFunc(10000, outputData, 0);

	glutMainLoop();
}

Отметим цель создания некоторых функций в данном программном продукте:

  • init() – создание начальной конфигурации;
  • display() – отрисовка решетки спинов и шкалы температуры;
  • calcW() – вычисление вероятностей перехода;
  • metropolis() – реализация алгоритма Метрополиса;
  • timer1() – обновление данных после каждого изменения конфигурации, увеличение числа шагов Монте-Карло;
  • outputData() – вычисление среднего на спин, вывод необходимых данных;
  • keyboard() и motion() – возможность изменять температуру с помощью шкалы двумя путями – кнопками на клавиатуре и нажатием мыши соответственно;

Стоит сделать пару выводов:

  • При критической температуре T=2,269℃ происходит фазовый переход из неупорядоченного в упорядоченное ферромагнитное состояние.
  • При изменении температуры в меньшую сторону следующие физические и статистические характеристики изменяются следующим образом:
    • Коэффициент принятия уменьшается;
    • Средняя энергия на спин уменьшается;
    • Средний квадрат энергии на спин увеличивается;
    • Средняя намагниченность уменьшается;
    • Средний квадрат намагниченности увеличивается.

Скриншоты работы программы при понижении и повышении температуры


Источник: https://habr.com/ru/post/506100/


Интересные статьи

Интересные статьи

Недавно на проекте интегрировал модуль CRM Битрикса c виртуальной АТС Ростелеком. Делал по стандартной инструкции, где пошагово показано, какие поля заполнять. Оказалось, следование ей не гаран...
Команда Big Data МТС активно извлекает знания из имеющихся данных и решает большое количество задач для бизнеса. Один из типов задач машинного обучения, с которыми мы сталкиваемся – это задачи ...
За долгие годы написания статей про игры я рассказал о многих удивительных глитчах, неизвестных с давних пор кодах, трюках с выполнением произвольного кода и поисках глубоко сокрытого контента ...
В данной статье будут описаны установка и применение бесплатного ПО для моделирования схем цифровой логики на языке Verilog как альтернативы коммерческих продуктов Incisve от компании Cadense и M...
Одной из «киллер-фич» 12й версии Битрикса была объявлена возможность отдавать статические файлы из CDN, тем самым увеличивая скорость работы сайта. Попробуем оценить практический выигрыш от использова...