A simple framework for setting up electrostatic problems and solving them using the finite difference method.
In order to set up an electrostatic problem, the grid values of ρ, ε and the boundary conditions can be set.
drawing_ops
contains functions for drawing basic geometric objects onto a grid. When an input argument is passed to the function, the specified object is drawn onto it.
import drawing_ops as ops
N = 256
U = np.zeros((N, N))
U = ops.plate_capacitor(U, center=(N/2, N/2),
length=N/2,
distance=N/8,
rotation=90)
Alternatively, if only geometric properties are specified, the function returns another function that can draw the object onto an input.
N = 256
capacitor = ops.plate_capacitor(center=(N/2, N/2),
length=N/2,
distance=N/8,
rotation=90)
U = capacitor(np.zeros((N, N)))
The function solve_poisson
receives the grid values as input and returns the finite-difference solution of φ.
phi = solve_poisson(U)
capacitor = ops.plate_capacitor(center=(N/2, N/2),
length=N/2,
distance=N/8,
rotation=90)
U = capacitor(np.zeros((N, N)))
phi = solve_poisson(U)
plot_images([U, phi], ['U', 'φ'], cmap='afmhot')
Ey, Ex = np.gradient(phi)
Ex, Ey = -Ex, -Ey
E = np.sqrt(Ex**2 + Ey**2)
capacitor = ops.plate_capacitor(center=(N/2-1, N/2-1),
length=N/1.5,
distance=N/8,
rotation=90,
values=[-10, 10])
U = capacitor(np.zeros((N, N)))
Eps = np.ones((N, N))
Eps = ops.rectangle(Eps, center=(N/2-1, N/2-1),
wh=(N//16, N//16),
filled=True,
value=5)
phi = solve_poisson(U=U, Eps=Eps)
charges = ops.composition(
ops.circle(center=(N/2-N/5, N/2), radius=N/16, filled=True, value=1),
ops.circle(center=(N/2+N/5, N/2), radius=N/16, filled=True, value=-1)
)
Rho = charges(np.zeros((N, N)))
phi = solve_poisson(U=np.zeros((N, N)), Rho=Rho)
Rho = ops.circle(np.zeros((N, N)), center=(N/2+N/8, N/2),
radius=N/32,
filled=True)
U = ops.line(np.zeros((N, N)), center=(N/2-N/8, N/2),
length=N/2,
rotation=90,
value=1)
phi = solve_poisson(U=U, Rho=Rho)
Eps = np.ones((N, N))
Eps[:,:N//2-N//8] = 3
Rho = ops.circle(np.zeros((N, N)), center=(N/2+N/16, N/2),
radius=N/32,
filled=True)
phi = solve_poisson(Eps=Eps, Rho=Rho)
frames = make_frames(ts, U, stars)
frames_c = colorize_frames(frames['E'], num_levels=30)
plt.figure(figsize=(10, 10))
plot_frames(frames_c, num=10, nrow=5)
make_video('data/E_stars_512_fps20_l30_m15.mp4', frames_c, fps=20, fourcc='h264')
distance = lambda t: N/5 + N/10*np.sin(2*np.pi*t)
cap = lambda t: ops.plate_capacitor(center=(N/2, N/2),
length=N/2,
distance=distance(t),
values=[-10, 10],
plate_width=N//50,
rotation=90)
E_cap_512_fps20_lN_m15.mp4
theta = lambda t: 360*t
arcs2 = lambda t: ops.composition(
ops.arc(center=(N/2, N/2), radius=N/3, start=0, end=250, rotation=theta(t), value=10),
ops.arc(center=(N/2, N/2), radius=N/3-N/10, start=0, end=250, rotation=45-theta(t), value=-10),
ops.arc(center=(N/2, N/2), radius=N/3-2*N/10, start=0, end=250, rotation=90+theta(t), value=10),
ops.arc(center=(N/2, N/2), radius=N/3-3*N/10, start=0, end=250, rotation=135-theta(t), value=-10)
)
E_arcs2_512_20_N.mp4
voltage = lambda t, phase: 10*np.sin(2*np.pi*t + phase/180*np.pi)
stars = lambda t: ops.composition(
ops.star(center=(N/2-N/5, N/2+N/5), N_angles=6, ro=N/10, value=voltage(t, phase=0)),
ops.star(center=(N/2+N/5, N/2+N/5), N_angles=6, ro=N/10, value=voltage(t, phase=120)),
ops.star(center=(N/2, N/2-N/5), N_angles=6, ro=N/10, value=voltage(t, phase=-120)))
E_stars_512_fps20_l30_m15.mp4
Nagel 2012 - Solving the Generalized Poisson Equation Using the Finite-Difference Method (FDM)