Vector Fields and Streamlines¶

Derive vector fields from symbolic potentials and visualize them with ax_vector_field and ax_streamline.

This notebook highlights the symbolic-numeric bridge: we use Maxima's symbolic differentiation to compute gradient fields from scalar potentials, then feed those expressions directly to ax-plots for numerical sampling and rendering.

In [89]:
load("numerics")$
load("ax-plots")$

Gradient Fields from a Scalar Potential¶

Given a scalar potential $V(x,y)$, the associated conservative field is $\mathbf{F} = -\nabla V$.

We start with the simplest case: a quadratic potential well $V = x^2 + y^2$, whose gradient field points radially inward.

In [90]:
/* Define scalar potential and compute gradient symbolically */
V : x^2 + y^2$
Fx : -diff(V, x)$
Fy : -diff(V, y)$
print("F =", [Fx, Fy])$
F = [-(2*x),-(2*y)]
In [91]:
/* Visualize the gradient field — arrows point toward the origin */
ax_draw2d(
  ngrid=12,
  ax_vector_field(Fx, Fy, x, -3, 3, y, -3, 3),
  title="Gradient of V = x^2 + y^2",
  aspect_ratio=true
)$
No description has been provided for this image

Electromagnetic Field: Point Charge¶

The electric field of a point charge is $\mathbf{E} = -\nabla V$ where $V = \frac{1}{\sqrt{x^2+y^2}}$.

We add a small regularization term (0.1) to avoid the singularity at the origin, then let Maxima differentiate symbolically.

In [92]:
/* Point charge potential (regularized) */
V_charge : 1/sqrt(x^2 + y^2 + 0.1)$
Ex : -diff(V_charge, x)$
Ey : -diff(V_charge, y)$
print("E =", [Ex, Ey])$
E = [x/(y^2+x^2+0.1)^(3/2),y/(y^2+x^2+0.1)^(3/2)]
In [93]:
/* Electric field radiates outward from the charge */
ax_draw2d(
  normalize=true, name="E", ngrid=12,
  ax_vector_field(Ex, Ey, x, -3, 3, y, -3, 3),
  title="Electric Field: Point Charge",
  aspect_ratio=true
)$
No description has been provided for this image

Dipole Field¶

A dipole has two charges of opposite sign separated by a distance. The potential is the superposition:

$$V = \frac{1}{\sqrt{(x-1)^2 + y^2 + 0.1}} - \frac{1}{\sqrt{(x+1)^2 + y^2 + 0.1}}$$

Again we derive the field symbolically and plot.

In [94]:
/* Dipole potential: positive charge at (1,0), negative at (-1,0) */
V_dipole : 1/sqrt((x-1)^2 + y^2 + 0.1) - 1/sqrt((x+1)^2 + y^2 + 0.1)$
Dx : -diff(V_dipole, x)$
Dy : -diff(V_dipole, y)$

ax_draw2d(
  normalize=true, ngrid=12, name="E",
  ax_vector_field(Dx, Dy, x, -4, 4, y, -4, 4),
  title="Electric Field: Dipole",
  aspect_ratio=true
)$
No description has been provided for this image

Fluid Flow: Rotational Field¶

The field $\mathbf{F} = (-y, x)$ describes rigid-body rotation. The vector field and streamlines together form a classic phase portrait.

In [95]:
/* Rotational flow: vector field */
ax_draw2d(
  ngrid=12,
  ax_vector_field(-y, x, x, -3, 3, y, -3, 3),
  title="Rotational Flow: Vector Field",
  aspect_ratio=true
)$
No description has been provided for this image
In [96]:
/* Rotational flow: streamlines trace circular orbits */
ax_draw2d(
  color="#cccccc", ngrid=12, ax_vector_field(-y, x, x, -3, 3, y, -3, 3),
  color="red", ax_streamline(-y, x, x, -3, 3, y, -3, 3),
  aspect_ratio=true, title="Rotational Flow: Phase Portrait"
)$
No description has been provided for this image

Source and Sink Flow¶

A radial source field $\mathbf{F} = \frac{(x, y)}{x^2+y^2+\epsilon}$ points outward from the origin. Streamlines radiate outward like spokes.

In [97]:
/* Source flow: vector field + streamlines */
Sx : x/(x^2 + y^2 + 0.1)$
Sy : y/(x^2 + y^2 + 0.1)$

ax_draw2d(
  color="#cccccc", name="F", ngrid=12, ax_vector_field(Sx, Sy, x, -3, 3, y, -3, 3),
  color="blue", name="streamline", ax_streamline(Sx, Sy, x, -3, 3, y, -3, 3),
  aspect_ratio=true, title="Source Flow"
)$
No description has been provided for this image

Curl and Divergence Analysis¶

For a 2D vector field $\mathbf{F} = (P(x,y),\; Q(x,y))$:

  • Divergence: $\nabla \cdot \mathbf{F} = \frac{\partial P}{\partial x} + \frac{\partial Q}{\partial y}$ (measures local expansion/compression)
  • Curl (scalar in 2D): $(\nabla \times \mathbf{F})_z = \frac{\partial Q}{\partial x} - \frac{\partial P}{\partial y}$ (measures local rotation)

We apply these to our rotational and source flows, computing everything symbolically.

In [98]:
/* Define divergence and curl for 2D fields */
div2d(P, Q) := diff(P, x) + diff(Q, y)$
curl2d(P, Q) := diff(Q, x) - diff(P, y)$

/* Rotational flow: F = (-y, x) */
print("=== Rotational flow F = (-y, x) ===")$
print("div  =", div2d(-y, x))$
print("curl =", curl2d(-y, x))$
=== Rotational flow F = (-y, x) ===
div  = 0
curl = 2
In [99]:
/* Source flow: F = (x, y)/(x^2+y^2+0.1) */
print("=== Source flow ===")$
div_source : ratsimp(div2d(Sx, Sy))$
curl_source : ratsimp(curl2d(Sx, Sy))$
print("div  =", div_source)$
print("curl =", curl_source)$
=== Source flow ===
rat: replaced 0.1 by 1/10 = 0.1
rat: replaced 0.1 by 1/10 = 0.1
rat: replaced 0.1 by 1/10 = 0.1
div  = 20/(100*y^4+(200*x^2+20)*y^2+100*x^4+20*x^2+1)
curl = 0