mirosh111000

Мірошниченко_КМЗПМ_ЛР№6

Dec 23rd, 2025
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.20 KB | None | 0 0
  1. import math
  2. import numpy as np
  3. import matplotlib.pyplot as plt
  4. from numba import njit
  5.  
  6. @njit(cache=True, fastmath=True)
  7. def step_f(
  8.     phi,
  9.     x,
  10.     phi0,
  11.     new_phi,
  12.     new_x,
  13.     dt,
  14.     dx,
  15.     eps,
  16.     omega,
  17.     lam,
  18.     F,
  19. ):
  20.     n = phi.shape[0]
  21.     inv_dx2 = 1.0 / (dx * dx)
  22.  
  23.     for i in range(n):
  24.         im = (i - 1) % n
  25.         ip = (i + 1) % n
  26.         for j in range(n):
  27.             jm = (j - 1) % n
  28.             jp = (j + 1) % n
  29.  
  30.             lap_phi = (
  31.                 phi[ip, j] + phi[im, j] + phi[i, jp] + phi[i, jm] - 4.0 * phi[i, j]
  32.             ) * inv_dx2
  33.  
  34.             phase = math.pi * (phi[i, j] - phi0[i, j])
  35.             new_phi[i, j] = phi[i, j] + dt * (
  36.                 (omega * omega) * lap_phi
  37.                 + math.sin(phase)
  38.                 + lam * x[i, j] * (1.0 + math.cos(phase))
  39.             )
  40.  
  41.     for i in range(n):
  42.         im = (i - 1) % n
  43.         ip = (i + 1) % n
  44.         for j in range(n):
  45.             jm = (j - 1) % n
  46.             jp = (j + 1) % n
  47.  
  48.             lap_x = (
  49.                 x[ip, j] + x[im, j] + x[i, jp] + x[i, jm] - 4.0 * x[i, j]
  50.             ) * inv_dx2
  51.  
  52.             valx = x[i, j]
  53.  
  54.             reaction = valx * math.exp(-eps * valx)
  55.  
  56.             diff_factor = 1.0 - eps * valx * (1.0 - valx)
  57.             diffusion = diff_factor * lap_x
  58.  
  59.             new_x[i, j] = (
  60.                 x[i, j]
  61.                 + dt * (F - reaction + diffusion)
  62.                 - 0.5 * (new_phi[i, j] - phi[i, j])
  63.             )
  64.  
  65. def simulate_numba(
  66.     N=256,
  67.     dx=1.0,
  68.     dt=0.01,
  69.     t_end=500.0,
  70.     eps=4.0,
  71.     D0=1.0,
  72.     omega=2.0,
  73.     lam=10.0,
  74.     F=2.0,
  75.     x0=0.40,
  76.     phi0_level=0.0,
  77.     noise_amp_x=0.01,
  78.     noise_amp_phi=0.01,
  79.     seed=0,
  80.     snapshot_times=(0.0, 20.0, 40.0, 60.0, 100.0, 500.0),
  81. ):
  82.     rng = np.random.default_rng(seed)
  83.     x = (x0 + noise_amp_x * rng.standard_normal((N, N))).astype(np.float64)
  84.     phi = (phi0_level + noise_amp_phi * rng.standard_normal((N, N))).astype(np.float64)
  85.  
  86.     Phi0 = phi.copy()
  87.  
  88.     new_phi = np.empty_like(phi)
  89.     new_x = np.empty_like(x)
  90.  
  91.     n_steps = int(round(t_end / dt))
  92.     snap_steps = {int(round(t / dt)): float(t) for t in snapshot_times}
  93.     snaps = {0.0: phi.copy()}
  94.  
  95.     progress_every = max(1, n_steps // 10)
  96.  
  97.     for step in range(1, n_steps + 1):
  98.         t = step * dt
  99.  
  100.         step_f(
  101.             phi, x, Phi0, new_phi, new_x,
  102.             dt, dx, eps, omega, lam, F,
  103.         )
  104.  
  105.         phi, new_phi = new_phi, phi
  106.         x, new_x = new_x, x
  107.  
  108.         if step in snap_steps:
  109.             snaps[snap_steps[step]] = phi.copy()
  110.  
  111.         if step % progress_every == 0:
  112.             print(
  113.                 f"t={t:7.2f} | min/max phi={phi.min(): .4f}/{phi.max(): .4f} | "
  114.                 f"min/max x={x.min(): .4f}/{x.max(): .4f}"
  115.             )
  116.  
  117.         if not (np.isfinite(phi).all() and np.isfinite(x).all()):
  118.             raise FloatingPointError("NaN/Inf detected")
  119.  
  120.     for tt in snapshot_times:
  121.         if float(tt) not in snaps:
  122.             raise RuntimeError(f"Snapshot at t={tt} not recorded (check dt).")
  123.  
  124.     return snaps
  125.  
  126. def plot_snapshots(phi_snaps, dx):
  127.     times = sorted(phi_snaps.keys())
  128.     cols = 2
  129.     rows = int(math.ceil(len(times) / cols))
  130.  
  131.     N = next(iter(phi_snaps.values())).shape[0]
  132.     xs = np.arange(N) * dx
  133.     ys = np.arange(N) * dx
  134.     X, Y = np.meshgrid(xs, ys)
  135.  
  136.     fig = plt.figure(figsize=(10, 12))
  137.     for i, tt in enumerate(times, start=1):
  138.         ax = fig.add_subplot(rows, cols, i, projection="3d")
  139.         Z = phi_snaps[tt]
  140.         surf = ax.plot_surface(
  141.             X, Y, Z, rstride=2, cstride=2,
  142.             cmap="coolwarm", linewidth=0, antialiased=True
  143.         )
  144.         ax.set_title(f"t = {int(tt)}")
  145.         ax.set_xlabel("x")
  146.         ax.set_ylabel("y")
  147.         ax.set_zlabel("ϕ")
  148.         ax.view_init(elev=25, azim=-60)
  149.         fig.colorbar(surf, ax=ax, shrink=0.55, pad=0.05)
  150.  
  151.     fig.suptitle("ϕ(x,y,t)", fontsize=14)
  152.     plt.tight_layout()
  153.     plt.show()
  154.  
  155. def main():
  156.     snaps = simulate_numba(
  157.         N=256, dx=1.0, dt=0.001, t_end=500.0,
  158.         eps=4.0, omega=2.0, lam=10.0, F=2.0
  159.     )
  160.     plot_snapshots(snaps, dx=1.0)
  161.  
  162. if __name__ == "__main__":
  163.     main()
  164.  
Advertisement
Add Comment
Please, Sign In to add comment