diff --git a/as5013-test/sim/CMD b/as5013-test/sim/CMD new file mode 100644 index 0000000000000000000000000000000000000000..7390fc96192caceb79f522e9b05aa4bfed6f686f --- /dev/null +++ b/as5013-test/sim/CMD @@ -0,0 +1,2 @@ +python bfield_fd.py --mode single_magnet -nt 40000 -mu 100 -nx 200 -ny 200 +python bfield_fd.py --mode double_magnet -nt 40000 -mu 100 -nx 200 -ny 200 diff --git a/as5013-test/sim/bfield_fd.py b/as5013-test/sim/bfield_fd.py new file mode 100644 index 0000000000000000000000000000000000000000..9086061fe1d52d53c521e5c9e0881c48484bc47f --- /dev/null +++ b/as5013-test/sim/bfield_fd.py @@ -0,0 +1,199 @@ +#! /usr/bin/env python +from __future__ import division +from numpy import * +import argparse +from matplotlib import pyplot as plt +from matplotlib import animation +plt.style.use('bmh') +from matplotlib.patches import Rectangle +import matplotlib.colors as colors + +#using sor to solve for electric fields +eps_0 = 8.85e-12 #permittivity of free space +mu_0 = 1.25663706e-6 #permittivity of free space (m*kg/s^2/A^2) + +fn_ind = 0 +contours = None + +def compute_a(mu): + #compute square contour integrals for permeability mu + a0 = mu[1:,1:] + mu[:-1,1:] + mu[1:,:-1] + mu[:-1,:-1] + a1 = .5*(mu[1:,1:] + mu[1:,:-1]) + a2 = .5*(mu[1:,1:] + mu[:-1,1:]) + a3 = .5*(mu[:-1,:-1] + mu[:-1,1:]) + a4 = .5*(mu[:-1,:-1] + mu[1:,:-1]) + return a0,a1,a2,a3,a4 +def solve_poisson(args,V,rho,a,neuman_bcs=[None,None,None,None]): + for ti in range(0,args.nt): + V[0] = V[1] + if neuman_bcs[0] is not None: + V[1,0,:] = V[1,1,:] - neuman_bcs[0] + if neuman_bcs[1] is not None: + V[1,-1,:] = V[1,-2,:] + neuman_bcs[1] + if neuman_bcs[2] is not None: + V[1,:,0] = V[1,:,1] - neuman_bcs[2] + if neuman_bcs[3] is not None: + V[1,:,-1] = V[1,:,-2] + neuman_bcs[3] + V[1,1:-1,1:-1] = (1-args.alpha)*V[0,1:-1,1:-1] + \ + args.alpha*( a[1]*V[0,2:,1:-1] + a[2]*V[0,1:-1,2:] + a[3]*V[0,:-2,1:-1] + a[4]*V[0,1:-1,:-2] )/a[0] + \ + args.alpha*rho[1:-1,1:-1]/mu_0/a[0] + + R = absolute(V[0,1:-1,1:-1] - V[1,1:-1,1:-1]) + if amax(R) < 1e-6: + print "broke after %d iterations"%ti + break + return V +def compute_H(V,dx,dy): + #take derivatives of V and shift indices + Hx = -.5*(V[-1,1:,1:] - V[-1,1:,:-1])/dx - .5*(V[-1,:-1,1:] - V[-1,:-1,:-1])/dx + Hy = -.5*(V[-1,1:,1:] - V[-1,:-1,1:])/dy - .5*(V[-1,1:,:-1] - V[-1,:-1,:-1])/dy + Hmag = sqrt(Hx*Hx + Hy*Hy) + return Hx,Hy,Hmag + + +def run_single_magnet(args): + nx = args.nx; dx = args.xs/nx + ny = args.ny; dy = args.ys/ny + py1 = int(args.ny/2 - int(args.l/2/dy)) #index for plate location + py2 = int(args.ny/2 + int(args.l/2/dy)) #index for plate location + py_sep1 = int(args.ny/2 - int(args.l/2/dy) - int(args.sep/dy)) + px1 = int(args.nx/2 - int(args.w/2/dx)) #index for plate edge + px2 = int(args.nx/2 + int(args.w/2/dx)) + V = zeros((2,ny,nx)) #use twice time steps for half-stepping + V[:,:,0] = zeros(ny) + V[:,0,:] = zeros(nx) + V[:,:,-1] = zeros(ny) + V[:,-1,:] = zeros(nx) + + mu = ones((ny-1,nx-1)) + mu[ py1:py2, px1:px2+1 ] = args.mu + #mu[ 0:py1, px1:px2+1 ] = args.mu + + divM = zeros_like(V[0]) #divergence of magnetic dipole moment density M = B_r / mu_0 + vol = args.w*args.w*args.l + divM[py1,px1:px2+1] = -args.Br/mu_0/(px2-px1)*vol + divM[py2,px1:px2+1] = args.Br/mu_0/(px2-px1)*vol + + V = solve_poisson(args,V,divM,compute_a(mu),neuman_bcs=[0,0,0,0]) + Hx,Hy,Hmag = compute_H(V,dx,dy) + + + fig, axs = plt.subplots(2, 1, gridspec_kw = {'height_ratios':[2.5, 1]}) + axs[0].set_aspect(1.) + x = linspace(-.5*args.xs, .5*args.xs, nx); y = linspace(-.5*args.ys, .5*args.ys, ny); + CS = axs[0].contourf(x[1:], y[1:], Hmag, cmag = plt.cm.autumn) + #cbar = fig.colorbar(CS, ax=axs[0]) + #cbar.ax.set_ylabel('field strength A/m') + #plt.contourf(x, y, V[-1]) + X,Y = meshgrid(x[1:],y[1:]) + axs[0].set_xlim([x[0],x[-1]]) + axs[0].set_ylim([args.pf*y[0],args.pf*y[-1]]) + strm = axs[0].streamplot(X,Y, Hx,Hy,color=Hmag, minlength=args.w/2,linewidth=1, cmap=plt.cm.summer) + axs[0].add_patch(Rectangle( (-args.w/2, -args.l/2), args.w, args.l, facecolor="grey", alpha=.4 )) + axs[0].plot([-args.xs/2,args.xs/2],[-args.l/2-args.sep,-args.l/2-args.sep],c='k',lw=2,ls='--') + + axs[1].plot(x[:-1],Hy[py_sep1]) + axs[1].set_xlabel('x (m)') + axs[1].set_ylabel('B_z') + axs[1].set_yticks([0.]) + axs[1].set_xlim([-2*args.w,2*args.w]) #set x range based on magnet width + + plt.savefig('run_single_magnet.png', bbox_inches='tight', pad_inches=0) + plt.show() + + +def run_double_magnet(args): + nx = args.nx; dx = args.xs/nx + ny = args.ny; dy = args.ys/ny + py1 = int(args.ny/2 - int(args.l/2/dy)) #index for plate location + py2 = int(args.ny/2 + int(args.l/2/dy)) #index for plate location + py_sep1 = int(args.ny/2 - int(args.l/2/dy) - int(args.sep/dy)) + px1 = int(args.nx/2 - int(args.w/dx)) #index for plate edge + pxm = int(args.nx/2) + px2 = int(args.nx/2 + int(args.w/dx)) + V = zeros((2,ny,nx)) #use twice time steps for half-stepping + V[:,:,0] = zeros(ny) + V[:,0,:] = zeros(nx) + V[:,:,-1] = zeros(ny) + V[:,-1,:] = zeros(nx) + + mu = ones((ny-1,nx-1)) + mu[ py1:py2, px1:px2+1 ] = args.mu + #mu[ 0:py1, px1:px2+1 ] = args.mu + + divM = zeros_like(V[0]) #divergence of magnetic dipole moment density M = B_r / mu_0 + vol = args.w*args.w*args.l + divM[py1,px1:pxm] = -args.Br/mu_0/(px2-px1)*vol + divM[py1,pxm:px2] = args.Br/mu_0/(px2-px1)*vol + divM[py2,px1:pxm] = args.Br/mu_0/(px2-px1)*vol + divM[py2,pxm:px2] = -args.Br/mu_0/(px2-px1)*vol + + V = solve_poisson(args,V,divM,compute_a(mu),neuman_bcs=[0,0,0,0]) + Hx,Hy,Hmag = compute_H(V,dx,dy) + + + fig, axs = plt.subplots(2, 1, gridspec_kw = {'height_ratios':[2.5, 1]}) + axs[0].set_aspect(1.) + x = linspace(-.5*args.xs, .5*args.xs, nx); y = linspace(-.5*args.ys, .5*args.ys, ny); + CS = axs[0].contourf(x[1:], y[1:], Hmag, cmag = plt.cm.autumn) + #cbar = fig.colorbar(CS, ax=axs[0]) + #cbar.ax.set_ylabel('field strength A/m') + #plt.contourf(x, y, V[-1]) + X,Y = meshgrid(x[1:],y[1:]) + axs[0].set_xlim([x[0],x[-1]]) + axs[0].set_ylim([args.pf*y[0],args.pf*y[-1]]) + strm = axs[0].streamplot(X,Y, Hx,Hy,color=Hmag, minlength=args.w/2,linewidth=1, cmap=plt.cm.summer) + axs[0].add_patch(Rectangle( (-args.w, -args.l/2), .99*args.w, args.l, facecolor="grey", alpha=.4 )) + axs[0].add_patch(Rectangle( (0.01*args.w, -args.l/2), args.w, args.l, facecolor="grey", alpha=.4 )) + axs[0].plot([-args.xs/2,args.xs/2],[-args.l/2-args.sep,-args.l/2-args.sep],c='k',lw=2,ls='--') + + axs[1].plot(x[:-1],Hy[py_sep1]) + #axs[1].plot(x[:-1],Hy[py_sep2]) + #axs[1].plot(x[:-1],Hy[py_sep3]) + axs[1].set_xlabel('x (m)') + axs[1].set_ylabel('B_z') + axs[1].set_yticks([0.]) + axs[1].set_xlim([-2*args.w,2*args.w]) #set x range based on magnet width + + plt.savefig('run_double_magnet.png', bbox_inches='tight', pad_inches=0) + plt.show() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('-M','--mode',choices=('single_magnet','double_magnet')) + parser.add_argument("-nx","--nx", type=int, default=200, help="grid size") + parser.add_argument("-ny","--ny", type=int, default=200, help="grid size") + parser.add_argument("-xs","--xs", type=float, default=.05, help="space extent x") + parser.add_argument("-ys","--ys", type=float, default=.04, help="space extent y") + parser.add_argument("-pf","--pf", type=float, default=.75, help="plot fraction (how much of simulated space to plot)") + parser.add_argument("-l","--l", type=float, default=.01, help="magnet length") + parser.add_argument("-w","--w", type=float, default=.002, help="magnet width") + parser.add_argument("-sep","--sep", type=float, default=.001, help="separation between magnet bottom and graphing plane") + parser.add_argument("-mu","--mu", type=float, default=1., help="relative permeability of magnet") + parser.add_argument("-Br","--Br", type=float, default=1., help="residual flux density of magnet (Teslas)") + parser.add_argument("-nt","--nt", type=int, default=50, help="num time steps") + parser.add_argument("-alpha","--alpha", type=float, default=1., help="alpha, relaxation parameter") + args = parser.parse_args() + if args.mode == 'single_magnet': + run_single_magnet(args) + if args.mode == 'double_magnet': + run_double_magnet(args) + '''elif args.mode == 'moving_dialectric_sweep': + Cs = [] + seps = [(args.ys/args.ny)*i for i in range(3,15)] + for sep in seps: + args.sep = sep + Cs.append(run_moving_dialectric(args)) + fn_ind += 1 + print "capacitances: ",list(Cs) + print "seps",list(seps) + plt.figure() + plt.plot(1e3*asarray(seps),1e12*asarray(Cs)) + plt.title('Adjacent trace Capacitance vs. separation') + plt.xlabel('separation distance (mm)') + plt.ylabel('capacitance (pF)') + plt.ylim([0,1.1*amax(1e12*asarray(Cs))]) + plt.show() + ''' + diff --git a/as5013-test/sim/run_double_magnet.png b/as5013-test/sim/run_double_magnet.png new file mode 100644 index 0000000000000000000000000000000000000000..afc422fd0d22af85a64aba1fc2f19cd68eb98a85 Binary files /dev/null and b/as5013-test/sim/run_double_magnet.png differ diff --git a/as5013-test/sim/run_single_magnet.png b/as5013-test/sim/run_single_magnet.png new file mode 100644 index 0000000000000000000000000000000000000000..f6d3e85b73ebd2e1b02624f1b6382c665e417007 Binary files /dev/null and b/as5013-test/sim/run_single_magnet.png differ