mirosh111000

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

Oct 16th, 2025 (edited)
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.58 KB | None | 0 0
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from dataclasses import dataclass
  4. from typing import Optional
  5.  
  6.  
  7.  
  8.  
  9. @dataclass
  10. class Params:
  11.     N: int = 77
  12.     m: float = 0.01
  13.     r: float = 0.005
  14.     q_val: float = 100.0
  15.     k_val: float = 0.0
  16.  
  17.     A: float = 50.0
  18.     T_period: float = 0.3
  19.  
  20.     T_max: float = 1.0
  21.     dt: float = 1e-4
  22.  
  23.     n_snapshots: int = 14
  24.     front_eps: float = 1e-4
  25.  
  26.  
  27. def build_q_array(N: int, q_val: float | np.ndarray) -> np.ndarray:
  28.     if np.isscalar(q_val):
  29.         q = np.full(N + 1, float(q_val), dtype=float)
  30.     else:
  31.         q = np.asarray(q_val, dtype=float)
  32.         if q.shape != (N + 1,):
  33.             raise ValueError("q array must have shape (N+1,)")
  34.     return q
  35.  
  36.  
  37. def compute_link_forces(x: np.ndarray, q: np.ndarray) -> np.ndarray:
  38.     N = x.size
  39.     x_pad = np.empty(N + 2, dtype=float)
  40.     x_pad[0] = 0.0
  41.     x_pad[1:-1] = x
  42.     x_pad[-1] = 0.0
  43.  
  44.     left = x_pad[0:N]
  45.     cen = x_pad[1:N+1]
  46.     right = x_pad[2:N+2]
  47.  
  48.     qL = q[0:N]
  49.     qR = q[1:N+1]
  50.  
  51.     F = qL * (left - cen) + qR * (right - cen)
  52.     return F
  53.  
  54.  
  55. def external_force(t: float, p: Params) -> np.ndarray:
  56.     f = np.zeros(p.N, dtype=float)
  57.     omega = 2.0 * np.pi / p.T_period
  58.     if t <= 0.5 * p.T_period:
  59.         f[0] = p.A * np.sin(omega * t)
  60.     return f
  61.  
  62.  
  63. def total_energy(x: np.ndarray, v: np.ndarray, p: Params, q: np.ndarray) -> float:
  64.     T = 0.5 * p.m * float(np.dot(v, v))
  65.     x_pad = np.empty(p.N + 2, dtype=float)
  66.     x_pad[0] = 0.0
  67.     x_pad[1:-1] = x
  68.     x_pad[-1] = 0.0
  69.     diffs = x_pad[1:] - x_pad[:-1]
  70.     V_links = 0.5 * float(np.dot(q, diffs * diffs))
  71.     V_self = 0.5 * p.k_val * float(np.dot(x, x))
  72.     return T + V_links + V_self
  73.  
  74.  
  75.  
  76.  
  77. def simulate(p: Params):
  78.     N = p.N
  79.     q = build_q_array(N, p.q_val)
  80.  
  81.     steps = int(np.floor(p.T_max / p.dt + 1e-15))
  82.     t_grid = np.arange(steps + 1, dtype=float) * p.dt
  83.  
  84.     x = np.zeros(N, dtype=float)
  85.     v = np.zeros(N, dtype=float)
  86.  
  87.     E_log = np.empty(steps + 1, dtype=float)
  88.     E_log[0] = total_energy(x, v, p, q)
  89.  
  90.     t_front: Optional[float] = None
  91.  
  92.  
  93.  
  94.     snap_times = np.linspace(0.0, p.T_max, p.n_snapshots + 1)[1:]
  95.     snap_dict: dict[float, np.ndarray] = {}
  96.  
  97.     for n in range(steps):
  98.         t = t_grid[n]
  99.         F = compute_link_forces(x, q)
  100.         f_ext = external_force(t, p)
  101.         a = (F - p.r * v - p.k_val * x + f_ext) / p.m
  102.  
  103.         v += a * p.dt
  104.         x += v * p.dt
  105.  
  106.         E_log[n + 1] = total_energy(x, v, p, q)
  107.  
  108.         if t_front is None and abs(x[-1]) > p.front_eps:
  109.             t_front = t
  110.  
  111.  
  112.         for ts in snap_times:
  113.             if ts not in snap_dict and (t <= ts < t + p.dt):
  114.                 snap_dict[ts] = x.copy()
  115.  
  116.  
  117.     if p.T_max not in snap_dict:
  118.         snap_dict[p.T_max] = x.copy()
  119.  
  120.     print(f"T_max={p.T_max:g} с, dt={p.dt:g}, кроків={steps}")
  121.     print(f"N={p.N}, m={p.m}, r={p.r}, q={p.q_val}, k={p.k_val}, A={p.A}, T={p.T_period}")
  122.     if t_front is not None:
  123.         print(f"Час проходження фронту до останнього вузла: ≈ {t_front:.4f} с")
  124.     else:
  125.         print("Фронт не досяг правого краю за відведений час.")
  126.  
  127.  
  128.     fig1, ax1 = plt.subplots(figsize=(7.6, 4.6))
  129.     ax1.plot(t_grid, E_log)
  130.     ax1.set_xlabel('Час, с')
  131.     ax1.set_ylabel('Повна енергія E(t)')
  132.     ax1.set_title('Зміна повної енергії системи у часі')
  133.     ax1.grid(True, ls=':')
  134.     fig1.tight_layout()
  135.  
  136.  
  137.     if snap_dict:
  138.         snaps_sorted = sorted(snap_dict.items(), key=lambda kv: kv[0])
  139.         n = len(snaps_sorted)
  140.         cols = 4 if n >= 13 else 3
  141.         rows = int(np.ceil(n / cols))
  142.         fig2, axes = plt.subplots(rows, cols, figsize=(4.9 * cols, 3.4 * rows), sharey=True)
  143.         axes = np.atleast_1d(axes).ravel()
  144.         xi = np.arange(1, N + 1)
  145.         for ax, (ts, xs) in zip(axes, snaps_sorted):
  146.             ax.plot(xi, xs, marker='o', lw=1)
  147.             ax.axhline(0.0, color='0.6', ls='--', lw=0.8)
  148.             ax.set_xlim(1, N)
  149.             ax.set_title(f"t = {ts:.3f} с")
  150.             ax.set_xlabel('Номер осцилятора')
  151.             ax.set_ylabel('Зсув')
  152.             ax.grid(True, ls=':')
  153.             ax.set_xticks(np.arange(1, N + 1, 5))
  154.         for ax in axes[n:]:
  155.             ax.axis('off')
  156.         fig2.suptitle('Знімки профілю зсувів уздовж ланцюжка')
  157.         fig2.tight_layout(rect=[0, 0, 1, 0.96])
  158.  
  159.     plt.show()
  160.  
  161.  
  162. if __name__ == '__main__':
  163.     params = Params()
  164.     simulate(params)
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
Advertisement
Add Comment
Please, Sign In to add comment