mirosh111000

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

Oct 16th, 2025
279
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.01 KB | None | 0 0
  1. from dataclasses import dataclass
  2. from typing import Dict, List, Tuple
  3. import numpy as np
  4. import matplotlib.pyplot as plt
  5.  
  6.  
  7.  
  8. @dataclass(frozen=True)
  9. class SimulationConfig:
  10.     n_nodes: int = 140
  11.     dt: float = 0.01
  12.     dy: float = 1.0
  13.     amplitude: float = 4.0
  14.     omega: float = 1.0
  15.     wave_speed: float = 2.0
  16.     t_max: float = 100.0
  17.     target_times: Tuple[float, ...] = (
  18.         5.85, 7.05, 12.36, 19.15, 21.25, 24.25, 28.35, 100.00
  19.     )
  20.     front_threshold_ratio: float = 0.1
  21.     ignore_edge_points: int = 5
  22.     drive_periods: float = 2.0
  23.  
  24.     @property
  25.     def drive_stop_time(self) -> float:
  26.         return self.drive_periods * (2.0 * np.pi / self.omega)
  27.  
  28.  
  29.  
  30. def simulate(cfg: SimulationConfig) -> Dict[str, np.ndarray]:
  31.  
  32.     n = cfg.n_nodes
  33.     dt, dy = cfg.dt, cfg.dy
  34.     A, w, c = cfg.amplitude, cfg.omega, cfg.wave_speed
  35.  
  36.  
  37.     y = np.arange(n, dtype=float) * dy
  38.  
  39.  
  40.     x = np.zeros(n, dtype=float)
  41.     v = np.zeros(n, dtype=float)
  42.  
  43.  
  44.     frame_times = np.asarray(cfg.target_times, dtype=float)
  45.     frame_steps = np.clip(np.rint(frame_times / dt).astype(int), 0, int(np.rint(cfg.t_max / dt)))
  46.     frame_map = {int(s): i for i, s in enumerate(frame_steps)}
  47.     snapshots = np.zeros((len(frame_times), n), dtype=float)
  48.  
  49.  
  50.     threshold = cfg.front_threshold_ratio * A
  51.     arrival_times = np.full(n, np.nan, dtype=float)
  52.  
  53.     n_steps = int(np.rint(cfg.t_max / dt))
  54.     c2_dt = (c * c) * dt / (dy * dy)
  55.  
  56.  
  57.     for step in range(n_steps + 1):
  58.         t = step * dt
  59.  
  60.  
  61.         if step in frame_map:
  62.             snapshots[frame_map[step]] = x
  63.  
  64.  
  65.         if t <= cfg.drive_stop_time:
  66.             x[0] = A * np.sin(w * t)
  67.         else:
  68.             x[0] = 0.0
  69.         v[0] = 0.0
  70.  
  71.  
  72.         x[-1] = 0.0
  73.         v[-1] = 0.0
  74.  
  75.  
  76.         lap = x[2:] - 2.0 * x[1:-1] + x[:-2]
  77.         v[1:-1] += c2_dt * lap
  78.         x[1:-1] += dt * v[1:-1]
  79.  
  80.  
  81.         need = np.isnan(arrival_times)
  82.         crossed = np.abs(x) >= threshold
  83.         newly = need & crossed
  84.         if np.any(newly):
  85.             arrival_times[newly] = t
  86.  
  87.  
  88.     L = cfg.ignore_edge_points
  89.     core = arrival_times[L:n - L]
  90.     avg_arrival = float(np.nanmean(core)) if np.any(~np.isnan(core)) else np.nan
  91.  
  92.     return {
  93.         "y": y,
  94.         "snapshots": snapshots,
  95.         "arrival_times": arrival_times,
  96.         "avg_arrival": np.array(avg_arrival),
  97.     }
  98.  
  99.  
  100.  
  101. def plot_results(cfg: SimulationConfig, data: Dict[str, np.ndarray]) -> None:
  102.     y = data["y"]
  103.     Xs = data["snapshots"]
  104.     arrival_times = data["arrival_times"]
  105.     avg_arrival = float(data["avg_arrival"]) if np.ndim(data["avg_arrival"]) else float(data["avg_arrival"])
  106.  
  107.     n_frames = Xs.shape[0]
  108.     rows, cols = 2, 4
  109.  
  110.     fig, axes = plt.subplots(rows, cols, figsize=(14, 6), sharey=True)
  111.     axes = np.asarray(axes).reshape(-1)
  112.  
  113.  
  114.     y_min = -cfg.amplitude * 1.05
  115.     y_max = cfg.amplitude * 1.05
  116.  
  117.     for i, ax in enumerate(axes):
  118.         t_show = cfg.target_times[i]
  119.         ax.plot(y, Xs[i], linewidth=1.5)
  120.         ax.set_title(f"t = {t_show:.2f} с", fontsize=10)
  121.         ax.set_xlim(y[0], y[-1])
  122.         ax.set_ylim(y_min, y_max)
  123.         ax.grid(True, linewidth=0.6, alpha=0.4)
  124.         ax.tick_params(labelsize=9)
  125.         for spine in ax.spines.values():
  126.             spine.set_linewidth(0.8)
  127.  
  128.  
  129.     ax_last = axes[-1]
  130.     L = cfg.ignore_edge_points
  131.     for i in range(L, cfg.n_nodes - L):
  132.         t_a = arrival_times[i]
  133.         if not np.isnan(t_a):
  134.             ax_last.axvline(i * cfg.dy, ymin=0.02, ymax=0.12, linewidth=0.6, linestyle=":", alpha=0.5)
  135.  
  136.     fig.suptitle("Розповсюдження одновимірної хвилі (кадри) і час приходу фронту", fontsize=12)
  137.     fig.tight_layout(rect=(0, 0, 1, 0.95))
  138.     plt.show()
  139.  
  140.     print(f"З рисунка бачимо, що середнiй час поширення фронту хвилi становить t ≈ {avg_arrival:.0f}.")
  141.  
  142.  
  143.  
  144. if __name__ == "__main__":
  145.     cfg = SimulationConfig()
  146.     results = simulate(cfg)
  147.     plot_results(cfg, results)
  148.  
Advertisement
Add Comment
Please, Sign In to add comment