首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Metropolis monte carlo理想气体模拟量为零

Metropolis monte carlo理想气体模拟量为零
EN

Stack Overflow用户
提问于 2019-06-25 21:43:57
回答 1查看 295关注 0票数 0

我试着根据Clapeyron方程,对理想气体做一个简单的模拟,使用Metropolis蒙特卡罗,algorithm.This是一个非常简单的例子,我考虑二维分子,分子之间没有相互作用,能量等于E=pV,其中V是包含所有分子的圆的面积。

我的问题是,在很少的蒙特卡罗步骤之后,我的气体体积总是几乎为零,无论我施加多少分子或压力,我不能确定我的代码中是否有bug,或者是因为我没有任何分子相互作用。所有的帮助都是有用的,下面是我的代码

我的结果如下图所示,x轴是蒙特卡罗步数,y轴是体积,因此我希望在步数较大后,体积会有一些非零常数值。

代码语言:javascript
复制
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()
EN

回答 1

Stack Overflow用户

发布于 2019-06-25 23:02:13

只有当新的半径小于旧的半径时,才允许分子移动:

代码语言:javascript
复制
if energy_new - energy_old <= 0.0:

等同于:

代码语言:javascript
复制
np.pi * self.pressure * new_radius**2 <= np.pi * self.pressure * old_radius**2

这就是:

代码语言:javascript
复制
abs(new_radius) <= abs(old_radius)

所以所有的分子都会去中心区。

对我来说,你的假设太强了:你决定了温度、压力和分子的数量。根据理想气体方程,体积v=nRT/p也是常数。如果体积可以改变,那么压力或温度也必须改变。在您的模拟中,允许压力变化意味着压力和体积的乘积是恒定的,因此能量是恒定的,因此分子可以在任意大体积中自由运动。

顺便说一句,我认为分子应该初始化为:

代码语言:javascript
复制
(random.random() - 0.5) * full_radius

所以在零点附近占据所有的平面。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56755528

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档