import numpy as np
import matplotlib.pyplot as plt
import time
class ReactionDiffusionModel:
def __init__(self, Nx=128, Ny=128, P=0.06):
self.Nx = Nx
self.Ny = Ny
self.dx = 1.0
self.dy = 1.0
self.epsilon = 4.0
self.beta = 0.9
self.rho = 0.25
self.T = 1.0
self.D_par = 0.1
self.P = P
self.dt = 0.01
self.t_max = 2000
self.steps = int(self.t_max / self.dt)
np.random.seed(42)
self.x = 0.5 + 0.1 * (np.random.rand(self.Nx, self.Ny) - 0.5)
self.time_points = []
self.mean_history = []
self.variance_history = []
self.snapshots = {}
if abs(self.P - 0.12) < 1e-5:
self.snapshot_times = [20, 40, 60, 80, 100, 500, 1000, 2000]
else:
self.snapshot_times = [20, 100, 120, 160, 200, 500, 1000, 2000]
def laplacian(self, field):
top = np.roll(field, 1, axis=0)
bottom = np.roll(field, -1, axis=0)
left = np.roll(field, 1, axis=1)
right = np.roll(field, -1, axis=1)
return (top + bottom + left + right - 4 * field) / (self.dx ** 2)
def nonlinear_flux_divergence(self, M, field):
M_ip1 = np.roll(M, -1, axis=0)
M_im1 = np.roll(M, 1, axis=0)
M_jp1 = np.roll(M, -1, axis=1)
M_jm1 = np.roll(M, 1, axis=1)
f_ip1 = np.roll(field, -1, axis=0)
f_im1 = np.roll(field, 1, axis=0)
f_jp1 = np.roll(field, -1, axis=1)
f_jm1 = np.roll(field, 1, axis=1)
term_x = ( (M_ip1 + M)/2.0 * (f_ip1 - field) -
(M + M_im1)/2.0 * (field - f_im1) ) / (self.dx**2)
term_y = ( (M_jp1 + M)/2.0 * (f_jp1 - field) -
(M + M_jm1)/2.0 * (field - f_jm1) ) / (self.dy**2)
return term_x + term_y
def reaction_term(self, x):
term1 = self.P * (1 - x) * (1 - self.beta * x)
term2 = x * (1 - self.beta * x) * np.exp(- (2 * self.epsilon / self.T) * x)
term3 = self.D_par * x * (1 - self.beta)
return term1 - term2 - term3
def run(self):
print(f"Початок симуляції для P={self.P}...")
print(f" Цільові знімки на t: {self.snapshot_times}")
start_time = time.time()
for step in range(self.steps + 1):
t = step * self.dt
if step % 100 == 0:
mean_val = np.mean(self.x)
sq_mean = np.mean(self.x**2)
variance = sq_mean - mean_val**2
self.time_points.append(t)
self.mean_history.append(mean_val)
self.variance_history.append(variance)
for st in self.snapshot_times:
if abs(t - st) < self.dt / 1.5:
if st not in self.snapshots:
self.snapshots[st] = self.x.copy()
M = self.x * (1 - self.x)
lap_x = self.laplacian(self.x)
factor = 2 * self.epsilon / self.T
term_nabla_M_nabla_x = self.nonlinear_flux_divergence(M, self.x)
term_nabla_M_nabla_lapX = self.nonlinear_flux_divergence(M, lap_x)
Diffusion_total = lap_x - factor * term_nabla_M_nabla_x - factor * (self.rho**2) * term_nabla_M_nabla_lapX
Reaction = self.reaction_term(self.x)
self.x += self.dt * (Reaction + Diffusion_total)
self.x = np.clip(self.x, 0, 1)
if step % 50000 == 0 and step > 0:
print(f" Прогрес: {t:.0f}/{self.t_max} a.u.")
print(f"Симуляцію завершено за {time.time() - start_time:.2f} с.")
def main():
sim1 = ReactionDiffusionModel(P=0.06)
sim1.run()
sim2 = ReactionDiffusionModel(P=0.12)
sim2.run()
print("Виведення графіків...")
plt.figure(figsize=(8, 6))
plt.plot(sim1.time_points, sim1.mean_history, 'k-', label='P = 0.06')
plt.plot(sim2.time_points, sim2.mean_history, 'r-', label='P = 0.12')
plt.xlabel('time [a.u.]')
plt.ylabel('')
plt.title('Середня концентрація')
plt.legend()
plt.grid(True, linestyle=':', alpha=0.6)
plt.figure(figsize=(8, 6))
plt.plot(sim1.time_points, sim1.variance_history, 'k-', label='P = 0.06')
plt.plot(sim2.time_points, sim2.variance_history, 'r-', label='P = 0.12')
plt.xlabel('time [a.u.]')
plt.ylabel('<($\delta$x)$^2$>')
plt.title('Дисперсія')
plt.legend()
plt.grid(True, linestyle=':', alpha=0.6)
def show_8_snapshots(sim_obj, title):
times = sorted(sim_obj.snapshots.keys())
fig, axes = plt.subplots(2, 4, figsize=(16, 8))
fig.suptitle(title, fontsize=16)
ax_flat = axes.flatten()
last_im = None
for i, ax in enumerate(ax_flat):
if i < len(times):
t = times[i]
last_im = ax.imshow(sim_obj.snapshots[t], cmap='hot', origin='lower', interpolation='bilinear', vmin=0, vmax=1)
ax.set_title(f"t = {t}")
ax.axis('off')
else:
ax.axis('off')
if last_im:
cbar = fig.colorbar(last_im, ax=axes, orientation='vertical', fraction=0.025, pad=0.04)
cbar.set_label('x(r)', fontsize=12)
show_8_snapshots(sim2, f"Еволюція для P=0.12")
show_8_snapshots(sim1, f"Еволюція для P=0.06")
plt.show()
if __name__ == "__main__":
main()