Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from __future__ import annotations
- import numpy as np
- import matplotlib.pyplot as plt
- from matplotlib.patches import ConnectionPatch
- BETA = 0.9
- EPS = 4.0
- RHO = 0.25
- CROSSES = [
- (0.1, 0.75), (0.1, 1.3), (0.1, 1.8),
- (0.2, 0.75), (0.2, 1.3), (0.2, 1.8),
- ]
- P_MIN, P_MAX, P_POINTS = 0.0, 0.5, 220
- T_MIN, T_MAX, T_POINTS = 0.05, 2.00, 150
- K_MAX, K_POINTS = 3.0, 400
- def mu_of(c: np.ndarray | float) -> np.ndarray | float:
- return c * (1.0 - c)
- def f_c(c: np.ndarray | float, P: float, T: float, beta: float = BETA, eps: float = EPS, Dpar: float = 0.1) -> np.ndarray | float:
- return (
- P * (1.0 - c) * (1.0 - beta * c)
- - c * (1.0 - beta * c) * np.exp(-2.0 * eps * c / T)
- - Dpar * c * (1.0 - beta)
- )
- def df_dc(c: float, P: float, T: float, beta: float = BETA, eps: float = EPS, Dpar: float = 0.1) -> float:
- term1 = P * (-(1.0 + beta) + 2.0 * beta * c)
- g = c - beta * c * c
- gp = 1.0 - 2.0 * beta * c
- h = np.exp(-2.0 * eps * c / T)
- hp = (-2.0 * eps / T) * h
- term2 = -gp * h + (2.0 * eps / T) * g * h
- term3 = -Dpar * (1.0 - beta)
- return float(term1 + term2 + term3)
- def find_c_st(P: float, T: float, beta: float = BETA, eps: float = EPS, Dpar: float = 0.1,
- tol: float = 1e-10, maxit: int = 200) -> float:
- a, b = 0.0, 1.0
- fa = f_c(a, P, T, beta, eps, Dpar)
- fb = f_c(b, P, T, beta, eps, Dpar)
- if fa * fb > 0:
- xs = np.linspace(0.0, 1.0, 2001)
- vals = f_c(xs, P, T, beta, eps, Dpar)
- s = np.sign(vals)
- idx = np.where(s[:-1] * s[1:] <= 0)[0]
- if len(idx) == 0:
- return float(xs[np.argmin(np.abs(vals))])
- a, b = float(xs[idx[0]]), float(xs[idx[0] + 1])
- fa, fb = float(vals[idx[0]]), float(vals[idx[0] + 1])
- for _ in range(maxit):
- m = 0.5 * (a + b)
- fm = f_c(m, P, T, beta, eps, Dpar)
- if abs(fm) < tol or (b - a) < tol:
- return float(m)
- if fa * fm <= 0:
- b, fb = m, fm
- else:
- a, fa = m, fm
- return float(0.5 * (a + b))
- def lambda_k(k: np.ndarray, P: float, T: float, Dpar: float = 0.1,
- beta: float = BETA, eps: float = EPS, rho: float = RHO) -> np.ndarray:
- T_eff = max(T, 1e-9)
- cst = find_c_st(P, T_eff, beta=beta, eps=eps, Dpar=Dpar)
- lam0 = df_dc(cst, P, T_eff, beta=beta, eps=eps, Dpar=Dpar)
- mu = mu_of(cst)
- return lam0 - k**2 * (1.0 - 2.0 * (eps / T_eff) * mu * (1.0 - (rho**2) * k**2))
- def max_lambda_over_k(P: float, T: float, Dpar: float) -> float:
- ks = np.linspace(0.0, K_MAX, K_POINTS)
- lams = lambda_k(ks, P, T, Dpar=Dpar)
- return float(np.max(lams))
- def Tcrit_numeric_for_P(P: float, Dpar: float, t_min: float = T_MIN, t_max: float = T_MAX,
- nT: int = T_POINTS) -> float | float('nan'):
- Ts = np.linspace(t_min, t_max, nT)
- phi = np.array([max_lambda_over_k(P, T, Dpar) for T in Ts])
- sgn = np.sign(phi)
- roots = []
- for i in range(len(Ts) - 1):
- if sgn[i] == 0:
- roots.append(Ts[i]); continue
- if sgn[i] * sgn[i + 1] < 0:
- a, b = Ts[i], Ts[i + 1]
- fa, fb = phi[i], phi[i + 1]
- for _ in range(40):
- m = 0.5 * (a + b)
- fm = max_lambda_over_k(P, m, Dpar)
- if abs(fm) < 1e-6 or (b - a) < 1e-3:
- roots.append(m); break
- if fa * fm <= 0:
- b, fb = m, fm
- else:
- a, fa = m, fm
- if len(roots) == 0:
- return float('nan')
- return float(np.max(roots))
- def Tcrit_curve(P_grid: np.ndarray, Dpar: float) -> tuple[np.ndarray, np.ndarray]:
- T_vals = np.array([Tcrit_numeric_for_P(P, Dpar) for P in P_grid])
- mask = np.isfinite(T_vals)
- return P_grid[mask], T_vals[mask]
- def plot_PT_main():
- P_grid = np.linspace(P_MIN, P_MAX, P_POINTS)
- P_b, T_b = Tcrit_curve(P_grid, Dpar=0.1)
- P_r, T_r = Tcrit_curve(P_grid, Dpar=0.5)
- fig, ax = plt.subplots(figsize=(9.5, 5.5), dpi=130)
- ax.plot(P_b, T_b, 'k-', lw=2.2, label=r'$D_\parallel=0.1$')
- ax.plot(P_r, T_r, 'r--', lw=2.2, label=r'$D_\parallel=0.5$')
- for (p, t) in CROSSES:
- ax.plot(p, t, 'kx', ms=8, mew=1.8)
- ax.set_xlim(P_MIN, P_MAX)
- ax.set_ylim(0.0, T_MAX)
- ax.set_xlabel('P'); ax.set_ylabel('T')
- ax.text(0.04, 1.72, 'B', fontsize=12)
- ax.text(0.44, 0.32, 'A', fontsize=12)
- ax.legend(loc='upper right', frameon=False)
- ax.set_title('Умови формування просторових структур')
- plt.tight_layout(); plt.show()
- def plot_lambda_small(P_val: float, T_val: float):
- ks = np.linspace(0.0, K_MAX, K_POINTS)
- lam_b = lambda_k(ks, P_val, T_val, Dpar=0.1)
- lam_r = lambda_k(ks, P_val, T_val, Dpar=0.5)
- fig, ax = plt.subplots(figsize=(5.3, 4.0), dpi=130)
- ax.plot(ks, lam_b, 'k-', lw=2, label=r'$D_\parallel=0.1$')
- ax.plot(ks, lam_r, 'r--', lw=2, label=r'$D_\parallel=0.5$')
- ax.axhline(0.0, color='gray', lw=1)
- ax.set_xlim(0.0, K_MAX)
- ax.set_xlabel('k'); ax.set_ylabel(r'$\lambda(k)$')
- ax.set_title(f'λ(k): P={P_val:.3f}, T={T_val:.3f}')
- ax.legend(loc='upper right', frameon=False, fontsize=9)
- plt.tight_layout(); plt.show()
- def lambda_max_point(P_val: float, T_val: float, Dpar: float) -> tuple[float, float]:
- ks = np.linspace(0.0, K_MAX, K_POINTS)
- lam = lambda_k(ks, P_val, T_val, Dpar=Dpar)
- i = int(np.argmax(lam))
- return float(ks[i]), float(lam[i])
- def plot_composite():
- P_grid = np.linspace(P_MIN, P_MAX, P_POINTS)
- P_b, T_b = Tcrit_curve(P_grid, Dpar=0.1)
- P_r, T_r = Tcrit_curve(P_grid, Dpar=0.5)
- fig = plt.figure(figsize=(13.5, 8.4), dpi=120)
- gs = fig.add_gridspec(3, 3, width_ratios=[1.3, 2.2, 1.3], wspace=0.35, hspace=0.35)
- axC = fig.add_subplot(gs[:, 1])
- axC.plot(P_b, T_b, 'k-', lw=2.2, label=r'$D_\parallel=0.1$')
- axC.plot(P_r, T_r, 'r--', lw=2.2, label=r'$D_\parallel=0.5$')
- for (p, t) in CROSSES:
- axC.plot(p, t, 'k*', ms=9)
- axC.set_xlim(P_MIN, P_MAX); axC.set_ylim(0.0, T_MAX)
- axC.set_xlabel('P'); axC.set_ylabel('T')
- axC.legend(loc='upper right', frameon=False)
- axC.set_title('Умови формування просторових структур')
- left_points = CROSSES[2::-1] # (1.8, 1.3, 0.75) при P=0.1
- right_points = CROSSES[5:2:-1] # (1.8, 1.3, 0.75) при P=0.2
- def add_lambda_panel(ax, P_val, T_val):
- ks = np.linspace(0.0, K_MAX, K_POINTS)
- lam_b = lambda_k(ks, P_val, T_val, Dpar=0.1)
- lam_r = lambda_k(ks, P_val, T_val, Dpar=0.5)
- ax.plot(ks, lam_b, 'k-', lw=2, label=r'$D_\parallel=0.1$')
- ax.plot(ks, lam_r, 'r--', lw=2, label=r'$D_\parallel=0.5$')
- ax.axhline(0.0, color='gray', lw=1)
- ax.set_xlim(0.0, K_MAX)
- ax.set_title(f'P={P_val:.3f}, T={T_val:.3f}', fontsize=10)
- ax.set_xlabel('k'); ax.set_ylabel(r'$\lambda(k)$')
- km, lm = lambda_max_point(P_val, T_val, Dpar=0.5)
- ax.plot(km, lm, 'o', color='#2b6fff', ms=5)
- return km, lm
- left_axes = [fig.add_subplot(gs[i, 0]) for i in range(3)]
- for ax, (p, t) in zip(left_axes, left_points):
- km, lm = add_lambda_panel(ax, p, t)
- con = ConnectionPatch(xyA=(km, lm), coordsA=ax.transData,
- xyB=(p, t), coordsB=axC.transData,
- arrowstyle='->', lw=1.6, color='#2b6fff')
- fig.add_artist(con)
- right_axes = [fig.add_subplot(gs[i, 2]) for i in range(3)]
- for ax, (p, t) in zip(right_axes, right_points):
- km, lm = add_lambda_panel(ax, p, t)
- con = ConnectionPatch(xyA=(km, lm), coordsA=ax.transData,
- xyB=(p, t), coordsB=axC.transData,
- arrowstyle='->', lw=1.6, color='#2b6fff')
- fig.add_artist(con)
- plt.show()
- plt.close(fig)
- if __name__ == '__main__':
- plot_PT_main()
- for i, (p, t) in enumerate(CROSSES, start=1):
- plot_lambda_small(p, t)
- plot_composite()
Advertisement
Add Comment
Please, Sign In to add comment