コード例7: 総合プロジェクト
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
class ComprehensiveProject:
"""総合演習プロジェクト: モンテカルロ法の基礎の実践応用"""
def __init__(self, Nx=150, Ny=150):
self.Nx = Nx
self.Ny = Ny
self.x = np.linspace(0, 10, Nx)
self.y = np.linspace(0, 10, Ny)
self.X, self.Y = np.meshgrid(self.x, self.y)
self.dx = self.x[1] - self.x[0]
self.dy = self.y[1] - self.y[0]
# 状態変数
self.field = np.zeros((Nx, Ny))
self.auxiliary = np.zeros((Nx, Ny))
def initialize_complex_condition(self):
"""複雑な初期条件"""
# 複数のガウス分布の重ね合わせ
centers = [(2, 2), (5, 5), (8, 8), (2, 8), (8, 2)]
for (cx, cy) in centers:
self.field += np.exp(-((self.X - cx)**2 + (self.Y - cy)**2) / 0.3)
# ノイズの付加
self.field += 0.1 * np.random.randn(self.Nx, self.Ny)
def coupled_evolution(self, dt):
"""結合した発展方程式"""
# Laplacian計算
lap_field = np.zeros_like(self.field)
lap_field[1:-1, 1:-1] = (
(self.field[2:, 1:-1] - 2*self.field[1:-1, 1:-1] +
self.field[:-2, 1:-1]) / self.dx**2 +
(self.field[1:-1, 2:] - 2*self.field[1:-1, 1:-1] +
self.field[1:-1, :-2]) / self.dy**2
)
# 非線形項
nonlinear_term = self.field**2 - self.field**3
# 時間発展
self.field += dt * (lap_field + nonlinear_term)
# 境界条件(Neumann)
self.field[0, :] = self.field[1, :]
self.field[-1, :] = self.field[-2, :]
self.field[:, 0] = self.field[:, 1]
self.field[:, -1] = self.field[:, -2]
def compute_statistics(self):
"""統計量の計算"""
mean = np.mean(self.field)
std = np.std(self.field)
total_energy = np.sum(self.field**2) * self.dx * self.dy
return {
'mean': mean,
'std': std,
'energy': total_energy,
'min': np.min(self.field),
'max': np.max(self.field)
}
def run_simulation(self, T=5.0, dt=0.01):
"""シミュレーション実行"""
steps = int(T / dt)
# 統計情報の記録
stats_history = []
for n in range(steps):
self.coupled_evolution(dt)
if n % 10 == 0:
stats = self.compute_statistics()
stats['time'] = n * dt
stats_history.append(stats)
print(f"ステップ {n}/{steps}: エネルギー={stats['energy']:.4f}")
return stats_history
def plot_final_results(self, stats_history):
"""最終結果の総合プロット"""
fig = plt.figure(figsize=(16, 12))
gs = fig.add_gridspec(3, 3, hspace=0.3, wspace=0.3)
# 最終フィールド(コンター)
ax1 = fig.add_subplot(gs[0, :2])
im1 = ax1.contourf(self.X, self.Y, self.field, levels=30, cmap='RdBu_r')
ax1.set_xlabel('x', fontsize=12)
ax1.set_ylabel('y', fontsize=12)
ax1.set_title('最終フィールド分布', fontsize=14, fontweight='bold')
plt.colorbar(im1, ax=ax1)
# 3Dサーフェス
ax2 = fig.add_subplot(gs[0, 2], projection='3d')
surf = ax2.plot_surface(self.X[::3, ::3], self.Y[::3, ::3],
self.field[::3, ::3], cmap='viridis')
ax2.set_xlabel('x')
ax2.set_ylabel('y')
ax2.set_zlabel('field')
ax2.set_title('3D視覚化', fontsize=12, fontweight='bold')
# エネルギー時間発展
ax3 = fig.add_subplot(gs[1, 0])
times = [s['time'] for s in stats_history]
energies = [s['energy'] for s in stats_history]
ax3.plot(times, energies, 'b-', linewidth=2)
ax3.set_xlabel('時間 t', fontsize=12)
ax3.set_ylabel('全エネルギー', fontsize=12)
ax3.set_title('エネルギー保存', fontsize=12, fontweight='bold')
ax3.grid(True, alpha=0.3)
# 統計量の時間発展
ax4 = fig.add_subplot(gs[1, 1])
means = [s['mean'] for s in stats_history]
stds = [s['std'] for s in stats_history]
ax4.plot(times, means, 'r-', linewidth=2, label='平均値')
ax4.plot(times, stds, 'g-', linewidth=2, label='標準偏差')
ax4.set_xlabel('時間 t', fontsize=12)
ax4.set_ylabel('統計量', fontsize=12)
ax4.set_title('統計的性質', fontsize=12, fontweight='bold')
ax4.legend()
ax4.grid(True, alpha=0.3)
# 最小・最大値
ax5 = fig.add_subplot(gs[1, 2])
mins = [s['min'] for s in stats_history]
maxs = [s['max'] for s in stats_history]
ax5.plot(times, mins, 'b-', linewidth=2, label='最小値')
ax5.plot(times, maxs, 'r-', linewidth=2, label='最大値')
ax5.set_xlabel('時間 t', fontsize=12)
ax5.set_ylabel('値', fontsize=12)
ax5.set_title('最小・最大値', fontsize=12, fontweight='bold')
ax5.legend()
ax5.grid(True, alpha=0.3)
# ヒストグラム
ax6 = fig.add_subplot(gs[2, 0])
ax6.hist(self.field.flatten(), bins=50, alpha=0.7, color='blue')
ax6.set_xlabel('フィールド値', fontsize=12)
ax6.set_ylabel('頻度', fontsize=12)
ax6.set_title('値の分布', fontsize=12, fontweight='bold')
ax6.grid(True, alpha=0.3, axis='y')
# 断面プロファイル
ax7 = fig.add_subplot(gs[2, 1])
mid_y = self.Ny // 2
ax7.plot(self.x, self.field[:, mid_y], 'b-', linewidth=2)
ax7.set_xlabel('x', fontsize=12)
ax7.set_ylabel('field(x, y=5)', fontsize=12)
ax7.set_title('中央断面', fontsize=12, fontweight='bold')
ax7.grid(True, alpha=0.3)
# パワースペクトル
ax8 = fig.add_subplot(gs[2, 2])
fft_field = np.fft.fft2(self.field)
power_spectrum = np.abs(fft_field)**2
power_spectrum_1d = np.mean(power_spectrum, axis=0)
freq = np.fft.fftfreq(self.Nx, self.dx)
ax8.loglog(freq[1:self.Nx//2], power_spectrum_1d[1:self.Nx//2], 'b-')
ax8.set_xlabel('波数', fontsize=12)
ax8.set_ylabel('パワー', fontsize=12)
ax8.set_title('パワースペクトル', fontsize=12, fontweight='bold')
ax8.grid(True, alpha=0.3)
return fig
# メイン実行
project = ComprehensiveProject(Nx=150, Ny=150)
project.initialize_complex_condition()
print("総合シミュレーション開始...")
stats_history = project.run_simulation(T=5.0, dt=0.01)
fig = project.plot_final_results(stats_history)
plt.show()
print("\n=== シミュレーション完了 ===")
print(f"最終エネルギー: {stats_history[-1]['energy']:.4f}")
print(f"最終平均値: {stats_history[-1]['mean']:.4f}")
print(f"最終標準偏差: {stats_history[-1]['std']:.4f}")