ولگرد دو بعدی#

ویدئوی جلسه

در ولگرد دو بعدی می‌توان نشان داد که، میانگین فاصله‌ی ذره از مبدأ پس از \( N \) قدم به صورت زیر است:

\[ \langle r \rangle \propto \sqrt{N} \]

این رابطه نشان می‌دهد که علی رغم اینکه متوسط مولفه‌های مکان ذره همواره صفر باقی می‌ماند، میانگین فاصله‌ی ذره از مبدأ با جذر تعداد قدم‌ها افزایش می‌یابد.

در کد زیر یک شبیه‌سازی از ولگشت تصادفی دو بعدی انجام می‌شود. در هر قدم، ذره به صورت تصادفی در یک جهت حرکت می‌کند و مسیر حرکت آن رسم می‌شود. همچنین، میانگین فاصله‌ی ذره از مبدأ به عنوان تابعی از تعداد قدم‌ها محاسبه و رسم می‌شود.


۱. توضیحات کد#

الف) تابع produce1randomWalker#

این تابع یک ولگشت تصادفی دو بعدی با \( N \) قدم و طول قدم \( r \) تولید می‌کند. مراحل کار به شرح زیر است:

  1. تولید زوایای تصادفی: زوایای حرکت ذره به صورت تصادفی از توزیع یکنواخت بین \( 0 \) تا \( 2\pi \) انتخاب می‌شوند.

  2. محاسبه‌ی تغییرات مختصات: تغییرات مختصات \( x \) و \( y \) با استفاده از توابع مثلثاتی محاسبه می‌شوند.

  3. محاسبه‌ی مسیر حرکت: با استفاده از np.cumsum، مسیر حرکت ذره به صورت تجمعی محاسبه می‌شود.

  4. تنظیم نقطه‌ی شروع: نقطه‌ی شروع مسیر به \( (0, 0) \) تنظیم می‌شود.

ب) رسم مسیرهای حرکت#

  • پنج مسیر حرکت مختلف با رنگ‌های متفاوت رسم می‌شوند.

  • محدوده‌ی محورها بر اساس میانگین فاصله‌ی ذره از مبدأ تنظیم می‌شود.

  • یک دایره به عنوان مرجع برای میانگین فاصله‌ی ذره از مبدأ رسم می‌شود.

ج) محاسبه‌ی میانگین فاصله‌ی ذره از مبدأ#

  • میانگین فاصله‌ی ذره از مبدأ به عنوان تابعی از تعداد قدم‌ها محاسبه و رسم می‌شود.


import numpy as np
import matplotlib.pyplot as plt
def polar2drandom_walk( N , r=1 , trials = 10000 ):
    random_angles = np.random.uniform( 0, 2*np.pi , ( trials , N ) )
    
    x_values = np.sum( r*np.cos( random_angles ) , 1 )
    y_values = np.sum( r*np.sin( random_angles ) , 1 )
    
    r2_values = x_values*x_values + y_values*y_values 
    
    r2_avg = np.average( r2_values )
    return np.sqrt(r2_avg)
from tqdm import tqdm

#Define the range of N values
NVals = range(50, 1000, 50)
results = []

for N in tqdm(NVals):
    results.append( polar2drandom_walk(N) )

# Plot the results
plt.plot(NVals, results, 'bo' , label='random walk distance')
plt.plot(NVals , np.sqrt(NVals), 'r--' , label='y=$\sqrt{x}$')
plt.grid()
plt.xlabel("Number of steps")
plt.ylabel("r_avg")
plt.title("2D Random Walk")
plt.legend()
plt.show()
../../_images/e1899764841ac59c9a48a1fca1a435dc4b89c4ce30e197a26af836141ea37121.png
import matplotlib.pyplot as plt
import numpy as np

N = 100
r = 1

def produce1randomWalker(N, r):
    random_angles = np.random.uniform(0, 2 * np.pi, N)
    
    x_values = r * np.cos(random_angles)
    y_values = r * np.sin(random_angles)

    steps_x = np.cumsum(x_values)
    steps_y = np.cumsum(y_values)

    steps_x[0] = 0
    steps_y[0] = 0
    return steps_x, steps_y

# Create subplots: 2 rows, 1 column
fig = plt.figure(figsize=(12, 10))  # Larger figure size for better visualization

# Top row: 2D random walk plot
ax1 = plt.subplot2grid((2, 1), (0, 0))  # Top row
avg_r = (np.average(r) + np.std(r)) * np.sqrt(N)
ax1.set_xlim(-2 * avg_r, 2 * avg_r)
ax1.set_ylim(-2 * avg_r, 2 * avg_r)

all_x = []
all_y = []
all_r = []
for i in range(200):
    x, y = produce1randomWalker(N, r)
    if i%10 == 0 :
        ax1.plot(x, y, color=plt.cm.hsv(i * 20 % 255), alpha=0.6)
    all_x.append(x[-1])
    all_y.append(y[-1])
    all_r.append( np.sqrt(x[-1]**2 + y[-1]**2) )

ax1.set_aspect(1)
ax1.add_artist(plt.Circle((0, 0), avg_r, color='black', fill=False, alpha=1))
ax1.set_title("2D Random Walk")
ax1.set_xlabel("X Position")
ax1.set_ylabel("Y Position")

# Bottom row: 1D distributions
ax2 = plt.subplot2grid((2, 3), (1, 0))  # Bottom left: X distribution
ax3 = plt.subplot2grid((2, 3), (1, 1))  # Bottom right: Y distribution
ax4 = plt.subplot2grid((2, 3), (1, 2))  # Bottom right: Y distribution

# Plot the x distribution
ax2.hist(all_x, bins=30, color='blue', alpha=0.7, label="X Distribution")
ax2.axvline(np.mean(all_x), color='red', linestyle='--', label=f"Mean = {np.mean(all_x):.2f}")
ax2.set_title("X Distribution")
ax2.set_xlabel("X Values")
ax2.set_ylabel("Frequency")
ax2.legend()

# Plot the y distribution
ax3.hist(all_y, bins=30, color='green', alpha=0.7, label="Y Distribution")
ax3.axvline(np.mean(all_y), color='red', linestyle='--', label=f"Mean = {np.mean(all_y):.2f}")
ax3.set_title("Y Distribution")
ax3.set_xlabel("Y Values")
ax3.set_ylabel("Frequency")
ax3.legend()

# Plot the r distribution
ax4.hist(all_r, bins=30, color='orange', alpha=0.7, label="R Distribution")
ax4.axvline(np.mean(all_r), color='red', linestyle='--', label=f"Mean = {np.mean(all_r):.2f}")
ax4.set_title("R Distribution")
ax4.set_xlabel("R Values")
ax4.set_ylabel("Frequency")
ax4.legend()

# Adjust layout and show the plots
plt.tight_layout()
plt.show()
../../_images/8ea7711aa737e9ce9804940fee3359dd531cb464c8e0be506078abc7dc98c5e1.png

جمع بندی#

از شکل های بالا پیداست که در ولگرد دو بعدی، علی رغم اینکه متوسط مولفه های x و y صفر می‌ماند، اما متوسط فاصله متناسب با تعداد قدم ها افزایش می‌یابد.

تکلیف#

تکلیف ولگشت

شبیه‌سازی ولگشت دو بعدی و حل معادله‌ی پخش

در این تمرین، از شما خواسته می‌شود تا با استفاده از شبیه‌سازی ولگشت دو بعدی، معادله‌ی پخش را حل کنید. این تمرین به شما کمک می‌کند تا درک بهتری از مفاهیم پخش و ارتباط آن با ولگشت تصادفی داشته باشید.


۱. معادله‌ی پخش

معادله‌ی پخش در دو بعد به صورت زیر تعریف می‌شود:

\[ \frac{\partial u(x, y, t)}{\partial t} = D \left( \frac{\partial^2 u}{\partial x^2} + \frac{\partial^2 u}{\partial y^2} \right) \]

که در آن:

  • \( u(x, y, t) \): غلظت ماده در موقعیت \( (x, y) \) و زمان \( t \).

  • \( D \): ضریب پخش.

حل تحلیلی معادله‌ی پخش

حل تحلیلی معادله‌ی پخش در دو بعد به صورت زیر است:

\[ u(x, y, t) = \frac{1}{4\pi D t} \exp\left( -\frac{x^2 + y^2}{4 D t} \right) \]

۲. ولگشت دو بعدی و ارتباط آن با معادله‌ی پخش

ولگشت دو بعدی مدلی است که حرکت تصادفی ذرات را توصیف می‌کند. در هر قدم، ذره به صورت تصادفی در یکی از چهار جهت (بالا، پایین، چپ، راست) حرکت می‌کند. اگر تعداد ذرات زیاد باشد، توزیع موقعیت آن‌ها با معادله‌ی پخش توصیف می‌شود.


۳. مراحل انجام تمرین

الف) شبیه‌سازی ولگشت دو بعدی

  1. تعداد \( N \) ذره را در مبدأ \( (0, 0) \) قرار دهید.

  2. در هر قدم، هر ذره به صورت تصادفی در یکی از چهار جهت حرکت کند.

  3. موقعیت ذرات را پس از \( M \) قدم ثبت کنید.

ب) محاسبه‌ی توزیع ذرات

  1. فضای دوبعدی را به یک شبکه‌ی مربعی تقسیم کنید.

  2. تعداد ذرات در هر سلول شبکه را شمارش کنید.

  3. توزیع ذرات را به صورت یک تابع \( u(x, y, t) \) در نظر بگیرید.

ج) مقایسه با حل تحلیلی معادله‌ی پخش

۱. توزیع ذرات حاصل از شبیه‌سازی را با حل تحلیلی مقایسه کنید.


۴. رسم نتایج

الف) رسم توزیع ذرات

  • توزیع ذرات را پس از \( M \) قدم به صورت یک نمودار دو بعدی رسم کنید.

  • از رنگ‌های مختلف برای نشان‌دادن غلظت ذرات در هر سلول استفاده کنید.

ب) رسم حل تحلیلی

  • حل تحلیلی معادله‌ی پخش را برای زمان‌های مختلف رسم کنید.

  • نتایج شبیه‌سازی و حل تحلیلی را با هم مقایسه کنید.


۵. حالت غیر متقارن

در این بخش می‌خواهیم احتمال انتخاب یک جهت (مثلا جهت بالا) را افزاییش دهیم. می‌توانید اگر قرار بود حرکت در راستای عمودی باشد، در ۴۰ درصد موارد حرکت پایین و در ۶۰ درصد موارد حرکت به سمت بالا را انتخاب کنید.

تمرین بالا را تکرار کنید و توزیع ذرات بر حسب زمان را به دست بیاورید.

برای اینکه معادله ی پخش شبیه به نتایج به دست امده باشد، باید چه تغییری در آن ایجاد کنید؟


واپاشی#

در واپاشی ذرات، می‌دانیم که اگر N ذره داشته باشیم که هر کدام با احتمال p بتواند واپاشی کند، تعداد ذرات باقی‌مانده بعد از زمان t از رابطه ی نمائي تبعیت می‌کند.

یادآوری: اثبات فرمول واپاشی نمایی#

فرض کنید \( N(t) \) تعداد ذرات یا مقدار ماده‌ی موجود در زمان \( t \) باشد. واپاشی نمایی به این معناست که نرخ کاهش \( N(t) \) متناسب با مقدار فعلی \( N(t) \) است. این رابطه به صورت زیر بیان می‌شود:

\[ \frac{dN}{dt} = -\lambda N \]

که در آن:

  • \( \lambda \): ثابت واپاشی (Decay Constant).

  • علامت منفی نشان‌دهنده‌ی کاهش مقدار \( N(t) \) با زمان است.


۱. حل معادله‌ی دیفرانسیل#

برای حل معادله‌ی دیفرانسیل بالا، مراحل زیر را دنبال می‌کنیم:

الف) جدا کردن متغیرها#

معادله‌ی دیفرانسیل را به صورت زیر بازنویسی می‌کنیم:

\[ \frac{dN}{N} = -\lambda \, dt \]

ب) انتگرال‌گیری از دو طرف#

از دو طرف معادله انتگرال می‌گیریم:

\[ \int \frac{1}{N} \, dN = -\lambda \int dt \]
\[ \ln N = -\lambda t + C \]

که در آن \( C \) ثابت انتگرال‌گیری است.

ج) حل برای \( N(t) \)#

با نمایی کردن دو طرف معادله، داریم:

\[ N(t) = e^{-\lambda t + C} = e^C \cdot e^{-\lambda t} \]

اگر مقدار اولیه‌ی \( N \) در زمان \( t = 0 \) را \( N_0 \) در نظر بگیریم، داریم:

\[ N(0) = e^C \cdot e^{0} = e^C = N_0 \]

بنابراین، فرمول واپاشی نمایی به صورت زیر به دست می‌آید:

\[ N(t) = N_0 e^{-\lambda t} \]

شبیه سازی#

برای شبیه سازی، کافی است تصور کنیم در هر بازه ی زمانی هر ذره به طور تصادفی و با احتمال p تصمیم به واپاشی می‌گیرد. برای پیاده سازی این کار، در هر مرحله به تعداد ذرات واپاشی نکرده باید عدد تصادفی تولید کنیم و بر اساس آن ببینیم تعداد ذراتی که در این مرحله قرار است واپاشی کنند چند است.

سپس تعداد ذرات باقی مانده در هر مرحله را رسم کنیم. از آنجا که می‌دانیم شکل باید نمائي باشد، محور عمودی را به صورت لگاریتمی رسم می‌کنیم.

def decay(N0 , lambda0=0.1 ):
    steps , ns = [] , []
    i = 0
    while N0 > 0:
        steps.append(i)
        ns.append(N0)
        N0 -= np.sum( np.random.uniform(0,1, N0) < lambda0 )
        i += 1

    return steps , ns 

plt.yscale( 'log' )
iii = 1
for N0 in range( 1001000 , 0 , -190100 ):
    steps , ns = decay( N0 )
    plt.plot( steps , ns , color=plt.colormaps['hsv'](iii) )
    iii+=20
../../_images/06eefca8a9cd9c369cd767a69b934ef0e8ba52fddf154dd82a878568c9e2c1e7.png

نتیجه گیری#

از شکل بالا می‌توان افت و خیزهای غیر نمائی برای حالتی که تعداد ذرات باقی‌مانده کم می‌شوند را نیز به خوبی مشاهد کرد.