"""Plot slope field, exact solution, Euler's method, and Asymptote."""

# eulers_method.py
#
# With help from Copilot for the script and ChatGPT for setting the fonts
# Re-import necessary libraries after execution state reset
import numpy as np
import matplotlib.pyplot as plt

from font_select import set_font_style

set_font_style("sans-serif")


def dv_dt(v):
    """Define the differential equation dv/dt = 10 - 0.001*v**2."""
    return 10 - 0.001 * v**2


def exact_solution(t):
    """Exact solution using separation of variables."""
    return 100 * np.tanh(0.1 * t)


def euler_approximation(t, dt):
    """Euler approximation for the differential equation."""
    v = np.zeros_like(t)
    for i in range(1, len(t)):
        v[i] = v[i - 1] + dt * dv_dt(v[i - 1])
    return v


# Parameters
t_start, t_end, dt = 0, 500, 1.0  # Time domain in seconds, with step size of 1.0 s
v_min, v_max = 0, 125  # Velocity domain in m/s
t = np.arange(t_start, t_end + dt, dt)

# Compute exact solution and Euler approximation
v_exact = exact_solution(t)
v_euler = euler_approximation(t, dt)

# Generate the slope field
t_grid, v_grid = np.meshgrid(
    np.linspace(t_start, t_end, 20), np.linspace(v_min, v_max, 20)
)
dv = dv_dt(v_grid)
dt_field = np.ones_like(dv)  # Time step for slope field
magnitude = np.sqrt(dt_field**2 + dv**2)  # Normalize vectors
dt_field /= magnitude
dv /= magnitude

# Create the figure and plot the elements
plt.figure(figsize=(8, 6))

# Plot the slope field as quiver
plt.quiver(
    t_grid, v_grid, dt_field, dv, color="gray", alpha=0.6, scale=30, label="Slope Field"
)

# Plot the asymptote v = 100
plt.axhline(
    y=100,
    color="green",
    linestyle="dashdot",
    linewidth=2,
    label=r"Asymptote $v = 100$",
)

# Plot the exact solution
plt.plot(
    t, v_exact, label="Exact Solution", color="#4682B4", linewidth=1.5
)  # SteelBlue

# Plot the Euler approximation
plt.plot(
    t,
    v_euler,
    label="Euler Approximation",
    color="#800000",  # Maroon
    alpha=0.5,
    linestyle="dotted",
    linewidth=2,
)

# Add labels, legend, and title
plt.xlabel(r"Time $t$ (s)")
plt.ylabel(r"Velocity $v$ (m/s)")
plt.title("Slope Field, Asymptote, Exact Solution, and Euler Approximation")
plt.legend(loc="lower right")
plt.xlim(t_start, t_end)
plt.ylim(v_min, v_max)
plt.grid()

# Show the plot
plt.tight_layout()
plt.savefig("../images/eulers-method.svg", transparent=True)
plt.show()
