fdfd_tools/examples/fdfd.py

230 lines
7.0 KiB
Python
Raw Normal View History

import importlib
2016-05-30 22:30:45 -07:00
import numpy
from numpy.linalg import norm
2016-05-30 22:30:45 -07:00
2019-08-04 14:13:51 -07:00
import meanas
2019-08-26 01:12:36 -07:00
from meanas import vec, unvec, fdtd
2019-08-05 00:20:06 -07:00
from meanas.fdfd import waveguide_mode, functional, scpml, operators
2019-08-04 14:13:51 -07:00
from meanas.fdfd.solvers import generic as generic_solver
2016-05-30 22:30:45 -07:00
import gridlock
from matplotlib import pyplot
2016-07-04 16:35:28 -07:00
2016-05-30 22:30:45 -07:00
__author__ = 'Jan Petykiewicz'
def test0(solver=generic_solver):
2016-05-30 22:30:45 -07:00
dx = 50 # discretization (nm/cell)
pml_thickness = 10 # (number of cells)
wl = 1550 # Excitation wavelength
omega = 2 * numpy.pi / wl
# Device design parameters
radii = (1, 0.6)
th = 220
center = [0, 0, 0]
# refractive indices
n_ring = numpy.sqrt(12.6) # ~Si
n_air = 4.0 # air
# Half-dimensions of the simulation grid
xyz_max = numpy.array([1.2, 1.2, 0.3]) * 1000 + pml_thickness * dx
# Coordinates of the edges of the cells.
half_edge_coords = [numpy.arange(dx/2, m + dx, step=dx) for m in xyz_max]
edge_coords = [numpy.hstack((-h[::-1], h)) for h in half_edge_coords]
# #### Create the grid, mask, and draw the device ####
grid = gridlock.Grid(edge_coords, initial=n_air**2, num_grids=3)
grid.draw_cylinder(surface_normal=gridlock.Direction.z,
center=center,
radius=max(radii),
thickness=th,
eps=n_ring**2,
num_points=24)
grid.draw_cylinder(surface_normal=gridlock.Direction.z,
center=center,
radius=min(radii),
thickness=th*1.1,
eps=n_air ** 2,
num_points=24)
2016-07-03 14:23:24 -07:00
dxes = [grid.dxyz, grid.autoshifted_dxyz()]
2016-05-30 22:30:45 -07:00
for a in (0, 1, 2):
for p in (-1, 1):
2019-08-05 00:20:06 -07:00
dxes = meanas.fdfd.scpml.stretch_with_scpml(dxes, axis=a, polarity=p, omega=omega,
thickness=pml_thickness)
2016-05-30 22:30:45 -07:00
J = [numpy.zeros_like(grid.grids[0], dtype=complex) for _ in range(3)]
2019-08-05 00:20:06 -07:00
J[1][15, grid.shape[1]//2, grid.shape[2]//2] = 1
2016-05-30 22:30:45 -07:00
'''
Solve!
'''
2019-08-05 00:20:06 -07:00
sim_args = {
'omega': omega,
'dxes': dxes,
'epsilon': vec(grid.grids),
}
x = solver(J=vec(J), **sim_args)
2019-08-05 00:20:06 -07:00
A = operators.e_full(omega, dxes, vec(grid.grids)).tocsr()
2016-05-30 22:30:45 -07:00
b = -1j * omega * vec(J)
print('Norm of the residual is ', norm(A @ x - b))
2016-05-30 22:30:45 -07:00
E = unvec(x, grid.shape)
'''
Plot results
'''
2016-05-30 22:30:45 -07:00
pyplot.figure()
pyplot.pcolor(numpy.real(E[1][:, :, grid.shape[2]//2]), cmap='seismic')
pyplot.axis('equal')
pyplot.show()
def test1(solver=generic_solver):
2016-05-30 22:30:45 -07:00
dx = 40 # discretization (nm/cell)
pml_thickness = 10 # (number of cells)
wl = 1550 # Excitation wavelength
omega = 2 * numpy.pi / wl
# Device design parameters
w = 600
th = 220
center = [0, 0, 0]
# refractive indices
n_wg = numpy.sqrt(12.6) # ~Si
n_air = 1.0 # air
# Half-dimensions of the simulation grid
xyz_max = numpy.array([0.8, 0.9, 0.6]) * 1000 + (pml_thickness + 2) * dx
# Coordinates of the edges of the cells.
half_edge_coords = [numpy.arange(dx/2, m + dx/2, step=dx) for m in xyz_max]
edge_coords = [numpy.hstack((-h[::-1], h)) for h in half_edge_coords]
# #### Create the grid and draw the device ####
grid = gridlock.Grid(edge_coords, initial=n_air**2, num_grids=3)
grid.draw_cuboid(center=center, dimensions=[8e3, w, th], eps=n_wg**2)
2016-07-03 14:23:24 -07:00
dxes = [grid.dxyz, grid.autoshifted_dxyz()]
2016-05-30 22:30:45 -07:00
for a in (0, 1, 2):
for p in (-1, 1):
2019-08-04 14:13:51 -07:00
dxes = scpml.stretch_with_scpml(dxes,omega=omega, axis=a, polarity=p,
thickness=pml_thickness)
2016-05-30 22:30:45 -07:00
half_dims = numpy.array([10, 20, 15]) * dx
dims = [-half_dims, half_dims]
dims[1][0] = dims[0][0]
ind_dims = (grid.pos2ind(dims[0], which_shifts=None).astype(int),
grid.pos2ind(dims[1], which_shifts=None).astype(int))
2019-08-26 01:12:36 -07:00
src_axis = 0
2016-05-30 22:30:45 -07:00
wg_args = {
'omega': omega,
'slices': [slice(i, f+1) for i, f in zip(*ind_dims)],
'dxes': dxes,
2019-08-26 01:12:36 -07:00
'axis': src_axis,
2016-05-30 22:30:45 -07:00
'polarity': +1,
2019-08-26 01:12:36 -07:00
'epsilon': grid.grids,
2016-05-30 22:30:45 -07:00
}
2019-08-26 01:12:36 -07:00
wg_results = waveguide_mode.solve_waveguide_mode(mode_number=0, **wg_args)
J = waveguide_mode.compute_source(**wg_args, E=wg_results['E'], wavenumber=wg_results['wavenumber'])
2016-05-30 22:30:45 -07:00
H_overlap = waveguide_mode.compute_overlap_e(**wg_args, **wg_results)
2016-07-03 16:45:38 -07:00
pecg = gridlock.Grid(edge_coords, initial=0.0, num_grids=3)
# pecg.draw_cuboid(center=[700, 0, 0], dimensions=[80, 1e8, 1e8], eps=1)
2016-07-03 14:23:51 -07:00
# pecg.visualize_isosurface()
2016-07-03 16:45:38 -07:00
pmcg = gridlock.Grid(edge_coords, initial=0.0, num_grids=3)
# pmcg.draw_cuboid(center=[700, 0, 0], dimensions=[80, 1e8, 1e8], eps=1)
# pmcg.visualize_isosurface()
2019-08-26 01:12:36 -07:00
def pcolor(v):
vmax = numpy.max(numpy.abs(v))
pyplot.pcolor(v, cmap='seismic', vmin=-vmax, vmax=vmax)
pyplot.axis('equal')
pyplot.colorbar()
2016-07-04 16:35:28 -07:00
'''
Solve!
'''
sim_args = {
'omega': omega,
'dxes': dxes,
'epsilon': vec(grid.grids),
'pec': vec(pecg.grids),
'pmc': vec(pmcg.grids),
}
x = solver(J=vec(J), **sim_args)
2016-05-30 22:30:45 -07:00
b = -1j * omega * vec(J)
2019-08-04 14:13:51 -07:00
A = operators.e_full(**sim_args).tocsr()
print('Norm of the residual is ', norm(A @ x - b))
2016-07-04 16:35:28 -07:00
2016-05-30 22:30:45 -07:00
E = unvec(x, grid.shape)
2016-07-04 16:35:28 -07:00
'''
Plot results
'''
2016-05-30 22:30:45 -07:00
center = grid.pos2ind([0, 0, 0], None).astype(int)
pyplot.figure()
pyplot.subplot(2, 2, 1)
2019-08-26 01:12:36 -07:00
pcolor(numpy.real(E[1][center[0], :, :]).T)
2016-05-30 22:30:45 -07:00
pyplot.subplot(2, 2, 2)
pyplot.plot(numpy.log10(numpy.abs(E[1][:, center[1], center[2]]) + 1e-10))
pyplot.subplot(2, 2, 3)
2019-08-26 01:12:36 -07:00
pcolor(numpy.real(E[1][:, :, center[2]]).T)
2016-05-30 22:30:45 -07:00
pyplot.subplot(2, 2, 4)
def poyntings(E):
e = vec(E)
2019-08-04 14:13:51 -07:00
h = operators.e2h(omega, dxes) @ e
cross1 = operators.poynting_e_cross(e, dxes) @ h.conj()
cross2 = operators.poynting_h_cross(h.conj(), dxes) @ e
2016-05-30 22:30:45 -07:00
s1 = unvec(0.5 * numpy.real(cross1), grid.shape)
s2 = unvec(0.5 * numpy.real(-cross2), grid.shape)
return s1, s2
s1x, s2x = poyntings(E)
pyplot.plot(s1x[0].sum(axis=2).sum(axis=1))
pyplot.plot(s2x[0].sum(axis=2).sum(axis=1))
pyplot.show()
q = []
for i in range(-5, 30):
H_rolled = [numpy.roll(h, i, axis=0) for h in H_overlap]
q += [numpy.abs(vec(E) @ vec(H_rolled))]
pyplot.figure()
pyplot.plot(q)
pyplot.title('Overlap with mode')
pyplot.show()
print('Average overlap with mode:', sum(q)/len(q))
def module_available(name):
return importlib.util.find_spec(name) is not None
2016-05-30 22:30:45 -07:00
if __name__ == '__main__':
2019-08-26 01:12:36 -07:00
#test0()
if module_available('opencl_fdfd'):
from opencl_fdfd import cg_solver as opencl_solver
test1(opencl_solver)
# from opencl_fdfd.csr import fdfd_cg_solver as opencl_csr_solver
# test1(opencl_csr_solver)
# elif module_available('magma_fdfd'):
# from magma_fdfd import solver as magma_solver
# test1(magma_solver)
else:
test1()