Метрополис Монте-Карло объем идеального газа идеал стремится к нулю - PullRequest
0 голосов
/ 25 июня 2019

Я пытаюсь провести простое моделирование идеального газа в соответствии с уравнением Клапейрона `pv = nkbT ', используя алгоритм Метрополиса Монте-Карло. Это очень простой пример, где я рассматриваю молекулы в 2D без взаимодействия друг с другом, и энергия равно E = pV, где V - область круга, содержащая все молекулы.

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

Мои результаты показаны на графике ниже, ось X - это шаги Монте-Карло, а ось Y - это объем, я ожидаю, что в результате не будет нулевого значения константы объема после большего числа шагов. plot of volume vs monte carlo steps

import numpy as np
import random
import matplotlib.pyplot as plt


def centroid(arr):
    length = arr.shape[0]
    sum_x = sum([i.x for i in arr])
    sum_y = sum([i.y for i in arr])
    return sum_x/length, sum_y/length


class Molecule:
    def __init__(self, xpos, ypos):
        self.pos = (xpos, ypos)
        self.x = xpos
        self.y = ypos


class IdealGas:
    # CONSTANTS
    def __init__(self, n,full_radius, pressure, T, number_of_runs):
        gas = []
        for i in range(0, n):
            gas.append(Molecule(random.random() * full_radius,
                                random.random() * full_radius))
        self.gas = np.array(gas)
        self.center = centroid(self.gas)
        self.small_radius = full_radius/4.
        self.pressure = pressure
        self.kbT = 9.36E-18 * T

        self.n = n
        self.number_of_runs = number_of_runs

    def update_pos(self):
        random_molecule = np.random.choice(self.gas)
        old_state_x = random_molecule.x
        old_state_y = random_molecule.y
        old_radius = np.linalg.norm(np.array([old_state_x,old_state_y])-np.array([self.center[0],self.center[1]]))
        energy_old = np.pi * self.pressure * old_radius**2
        random_molecule.x = old_state_x + (random.random() * self.small_radius) * np.random.choice([-1, 1])
        random_molecule.y = old_state_y + (random.random() * self.small_radius) * np.random.choice([-1, 1])
        new_radius =  np.linalg.norm(np.array([random_molecule.x,random_molecule.y])-np.array([self.center[0],self.center[1]]))
        energy_new = np.pi * self.pressure * new_radius**2
        if energy_new - energy_old <= 0.0:
            return random_molecule
        elif np.exp((-1.0 * (energy_new - energy_old)) / self.kbT) > random.random():
            return random_molecule
        else:
            random_molecule.x = old_state_x
            random_molecule.y = old_state_y
            return random_molecule

    def monte_carlo_step(self):
        gas = []
        for molecule in range(0, self.n):
            gas.append(self.update_pos())
        self.gas = np.array(gas)
        #self.center = centroid(self.gas)
        return self.gas

    def simulation(self):
        volume = []
        for run in range(self.number_of_runs):
            step_gas = self.monte_carlo_step()
            step_centroid = centroid(step_gas)
            step_radius = max([np.linalg.norm(np.array([gas.x,gas.y])-np.array([step_centroid[0],step_centroid[1]]))
                               for gas in step_gas])
            step_volume = np.pi * step_radius**2
            volume.append(step_volume)
        return volume


Gas = IdealGas(500, 50, 1000, 300, 100)
vol = Gas.simulation()
plt.plot(vol)
plt.show()


1 Ответ

1 голос
/ 25 июня 2019

Вы позволяете своим молекулам двигаться только в том случае, если новый радиус уступает старому радиусу:

if energy_new - energy_old <= 0.0:

эквивалентен:

np.pi * self.pressure * new_radius**2 <= np.pi * self.pressure * old_radius**2

, то есть:

abs(new_radius) <= abs(old_radius)

Итак, все молекулы уходят в центр.

Для меня ваша гипотеза слишком сильна: вы фиксируете температуру, давление и количество молекул.Согласно уравнению идеального газа это означает, что объем v = nRT / p также постоянен.Если объем может измениться, то давление или температура должны измениться.В вашей имитации изменение давления будет означать, что произведение давления на объем является постоянным, так что энергия постоянна, поэтому молекулы могут свободно перемещаться в произвольном большом объеме.

Кстати, я думаю, что молекулы должныбыть инициализирован с помощью:

(random.random() - 0.5) * full_radius

, чтобы занять всю плоскость вокруг нуля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...