# Angular frequency of the source in Hz
= 2 * np.pi * 200e12
omega # Spatial resolution in meters
= 30e-9
dl # Number of pixels in x-direction
= 120
Nx # Number of pixels in y-direction
= 120
Ny # Number of pixels in the PMLs in each direction
= 20
Npml # Initial value of the structure's relative permittivity
= 12.0
epsr_init # Space between the PMLs and the design region (in pixels)
= 10
space # Width of the waveguide (in pixels)
= 12
wg_width # Length in pixels of the source/probe slices on each side of the center point
= 8
space_slice # Number of epochs in the optimization
= 150
Nsteps # Step size for the Adam optimizer
def step_size(idx):
"""reducing the stepsize linearly for Nsteps (stabilize afterwards just in case)"""
return np.maximum((5e-3)**(idx/Nsteps), 5e-3)
Inverse Design Local
Using the local generator to do the inverse design
An Exception was encountered at ‘In [15]’.
This notebook overwrites the inverse design notebook to use the local_generator
= init_domain(
epsr, bg_epsr, design_region, input_slice, output_slice =space, wg_width=wg_width, space_slice=space_slice
Nx, Ny, Npml, space )
= mask_combine_epsr(epsr, bg_epsr, design_region)
epsr_total
# Setup source
= insert_mode(omega, dl, input_slice.x, input_slice.y, epsr_total, m=1)
source
# Setup probe
= insert_mode(omega, dl, output_slice.x, output_slice.y, epsr_total, m=2) probe
Prepare
= notched_square_brush(5, 1)
brush = new_latent_design((Nx, Ny), r=1) latent
No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
# Simulate initial device
= viz_sim(epsr_total, source, slices=[input_slice, output_slice])
simulation, ax = simulation.solve(source)
_, _, Ez = mode_overlap(Ez, probe) E0
Optimization
from inverse_design.local_generator import dilate
= np.logical_or(bg_epsr>2, design_region)
bg_mask = dilate(np.logical_not(bg_mask), brush)
eroded = dilate(bg_epsr>2, brush)
dilated
= np.logical_not(np.logical_or(eroded, design_region))
init_t_s = np.logical_not(np.logical_or(dilated, design_region))
init_t_v # plt.imshow(init_t_s, vmax=1, vmin=0)
# plt.figure()
# plt.imshow(init_t_v, vmax=1, vmin=0)
= transform(latent, brush)
latent_t
generate_feasible_design_mask(=init_t_s.copy(),
latent_t, brush, init_touches_solid=init_t_v.copy(), verbose=False) init_touches_void
Array([[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
...,
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.],
[-1., -1., -1., ..., -1., -1., -1.]], dtype=float32)
def forward(latent_weights, brush):
= transform(latent_weights, brush) #.reshape((Nx, Ny))
latent_t = generate_feasible_design_mask(latent_t,
design_mask =init_t_s, init_touches_void=init_t_v, verbose=False)
brush, init_touches_solid= (design_mask+1.0)/2.0*(12-1) +1
epsr # complicated expression to avoid where clause, as it caused problems with differentiation
# why did the np.where clause lead to 0 gradients?
return epsr
@jaxit(cache=True)
def inner_loss_fn(epsr):
#print(".")
= mask_combine_epsr(epsr, bg_epsr, design_region)
simulation.eps_r = simulation.solve(source)
_, _, Ez
return -mode_overlap(Ez, probe) / E0
def loss_fn(latent):
= forward(latent, brush)
epsr # def debug_plot(epsr):
# plt.figure(figsize=(0.5,0.5))
# plt.imshow(epsr)
# plt.axis("off")
# plt.show()
# jax.debug.callback(debug_plot, epsr)
return inner_loss_fn(epsr)
Execution using papermill encountered an exception here and stopped:
loss_fn(latent)
= adam(step_size)
init_fn, update_fn, params_fn = init_fn(latent) #.flatten() state
this is the optimization step:
def step_fn(step, state):
= params_fn(state) # we need autograd arrays here...
latent = grad_fn(latent)
loss, grads #loss = loss_fn(latent)
= update_fn(step, grads, state)
optim_state = params_fn(optim_state)
optim_latent = optim_latent/optim_latent.std()
optim_latent return loss, init_fn(optim_latent)
We can now loop over the optimization (let’s only do 5 iterations to avoid excessive computations):
= 5 Nsteps
= trange(Nsteps)
range_ = np.ndarray(Nsteps)
losses for step in range_:
= step_fn(step, state)
loss, state = loss
losses[step] =float(loss)) range_.set_postfix(loss
# Simulate and show the optimal device
= forward(params_fn(state), brush)
epsr_optimum = mask_combine_epsr(epsr_optimum, bg_epsr, design_region)
epsr_optimum_total = viz_sim(epsr_optimum_total, source, slices=[input_slice, output_slice]) simulation, ax
plt.plot(losses)"step number")
plt.xlabel("loss") plt.ylabel(