mirror of
https://github.com/edoverg/modeconverter.git
synced 2026-10-14 23:06:39 +00:00
1) minor changes to metapeg_v2, but we no longer modify the chunk property and leave it to the default value (=True). Setting it to False causes segmentation errors in the adjoint loop, but works for direct simulations (for example in the normalization run) 2) added sim_opt_design, which is used to simulate an optimized design given the values of an optimized MaterialGrid after and outside the main optimization algorithm
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
#this file serves to simulate the optimized design parameters
|
||||
#it imports data from the optimization process and runs a meep simulation to verify the results
|
||||
import faulthandler
|
||||
faulthandler.enable()
|
||||
from typing import List, NamedTuple, Tuple
|
||||
from autograd import numpy as npa, tensor_jacobian_product, grad
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.animation as animation
|
||||
import meep as mp
|
||||
import meep.adjoint as mpa
|
||||
import nlopt
|
||||
import numpy as np
|
||||
import os
|
||||
import xarray as xr
|
||||
from PIL import Image
|
||||
import pickle
|
||||
|
||||
if not os.path.exists("sim_opt_design_results"):
|
||||
os.makedirs("sim_opt_design_results")
|
||||
#import data from previous savez file
|
||||
try:
|
||||
with open("results/optimal_design.pkl", "rb") as f:
|
||||
data = pickle.load(f)
|
||||
RESOLUTION=data['RESOLUTION']
|
||||
MAX_RUN_TIME = data['MAX_RUN_TIME']
|
||||
WAVELENGTH_MIN_UM = data['WAVELENGTH_MIN_UM']
|
||||
WAVELENGTH_MAX_UM = data['WAVELENGTH_MAX_UM']
|
||||
DESIGN_REGION_CENTER = data['DESIGN_REGION_CENTER']
|
||||
SILICON = data['SILICON']
|
||||
SILICON_DIOXIDE = data['SILICON_DIOXIDE']
|
||||
AIR = data['AIR']
|
||||
cell_um = data['cell_um']
|
||||
SUBSTRATE_THICKNESS = data['SUBSTRATE_THICKNESS']
|
||||
SUBSTRATE_SIZE = data['SUBSTRATE_SIZE']
|
||||
SUBSTRATE_CENTER = data['SUBSTRATE_CENTER']
|
||||
physical_domains_size = data['physical_domains_size']
|
||||
frequency_min = data['frequency_min']
|
||||
frequency_max = data['frequency_max']
|
||||
frequency_center = data['frequency_center']
|
||||
frequency_width = data['frequency_width']
|
||||
frequencies = data['frequencies']
|
||||
num_wavelength = data['num_wavelengths']
|
||||
SOURCE_CENTER = data['SOURCE_CENTER']
|
||||
SOURCE_SIZE = data['SOURCE_SIZE']
|
||||
NEAR_REGION_MONITOR_CENTER = data['NEAR_REGION_MONITOR_CENTER']
|
||||
NEAR_REGION_MONITOR_SIZE = data['NEAR_REGION_MONITOR_SIZE']
|
||||
FF_MONITOR_CENTER = data['FF_MONITOR_CENTER']
|
||||
FF_MONITOR_SIZE = data['FF_MONITOR_SIZE']
|
||||
xs = data['xs']
|
||||
ys = data['ys']
|
||||
ff_points = data['ff_points']
|
||||
DESIGN_WAVELENGTHS_UM=data['DESIGN_WAVELENGTHS_UM']
|
||||
BUFFER=data['BUFFER']
|
||||
PML_UM=data['PML_UM']
|
||||
DESIGN_REGION_UM=data['DESIGN_REGION_UM']
|
||||
DESIGN_REGION_RESOLUTION=data['DESIGN_REGION_RESOLUTION']
|
||||
NX_DESIGN_GRID=data['NX_DESIGN_GRID']
|
||||
NY_DESIGN_GRID=data['NY_DESIGN_GRID']
|
||||
MIN_LENGTH_UM=data['MIN_LENGTH_UM']
|
||||
sigmoid_biases=data['sigmoid_biases']
|
||||
max_eval=data['max_eval']
|
||||
objfunc_history=data['objfunc_history']
|
||||
epivar_history=data['epivar_history']
|
||||
epigraph_variable=data['epigraph_variable']
|
||||
unmapped_design_weights=data['unmapped_design_weights']
|
||||
optimal_design_weights=data['optimal_design_weights']
|
||||
except FileNotFoundError:
|
||||
raise FileNotFoundError("Optimal design data not found.")
|
||||
|
||||
print(optimal_design_weights)
|
||||
pml_layers = [mp.PML(PML_UM)]
|
||||
|
||||
view_2D_plane_xz = mp.Volume(
|
||||
center=mp.Vector3(0,0,0),
|
||||
size=mp.Vector3(cell_um.x,0,cell_um.z)
|
||||
)
|
||||
|
||||
view_2D_plane_xy = mp.Volume(
|
||||
center=mp.Vector3(0,0,DESIGN_REGION_CENTER.z/2),
|
||||
size=mp.Vector3(cell_um.x,cell_um.y,0)
|
||||
)
|
||||
|
||||
matgrid = mp.MaterialGrid(
|
||||
grid_size = mp.Vector3(NX_DESIGN_GRID, NY_DESIGN_GRID,0),
|
||||
medium1 = AIR,
|
||||
medium2 = SILICON,
|
||||
weights = optimal_design_weights.reshape((NX_DESIGN_GRID, NY_DESIGN_GRID))
|
||||
)
|
||||
|
||||
matgrid_region = mpa.DesignRegion(
|
||||
matgrid,
|
||||
volume=mp.Volume(
|
||||
center=DESIGN_REGION_CENTER,
|
||||
size=DESIGN_REGION_UM
|
||||
)
|
||||
)
|
||||
|
||||
matgrid_block = mp.Block(
|
||||
center=matgrid_region.center,
|
||||
size=matgrid_region.size,
|
||||
material=matgrid,
|
||||
)
|
||||
|
||||
substrate_block = mp.Block(
|
||||
center = SUBSTRATE_CENTER,
|
||||
size = SUBSTRATE_SIZE,
|
||||
material = SILICON_DIOXIDE,
|
||||
)
|
||||
|
||||
geometry = [
|
||||
matgrid_block,
|
||||
substrate_block,
|
||||
]
|
||||
|
||||
sources = [
|
||||
mp.Source(
|
||||
src=mp.GaussianSource(frequency_center, fwidth=frequency_width),
|
||||
component=mp.Ex,
|
||||
size=SOURCE_SIZE,
|
||||
center=SOURCE_CENTER,
|
||||
)
|
||||
]
|
||||
|
||||
sim = mp.Simulation(
|
||||
resolution=RESOLUTION,
|
||||
default_material=AIR,
|
||||
cell_size=cell_um,
|
||||
sources=sources,
|
||||
geometry=geometry,
|
||||
boundary_layers=pml_layers,
|
||||
k_point=mp.Vector3(),
|
||||
)
|
||||
|
||||
plt.figure()
|
||||
ax = plt.gca()
|
||||
sim.plot2D(output_plane=view_2D_plane_xz, ax=ax)
|
||||
plt.savefig(f"sim_opt_design_results/simulation_setup.pdf")
|
||||
plt.close()
|
||||
|
||||
NearRegions = [
|
||||
mp.Near2FarRegion(
|
||||
center=NEAR_REGION_MONITOR_CENTER,
|
||||
size=NEAR_REGION_MONITOR_SIZE,
|
||||
weight=+1,
|
||||
)
|
||||
]
|
||||
|
||||
FarFields = mpa.Near2FarFields(
|
||||
sim=sim,
|
||||
Near2FarRegions=NearRegions,
|
||||
far_pts=ff_points,
|
||||
)
|
||||
obj_list = [FarFields]
|
||||
|
||||
def dummy_J1(ff):
|
||||
return [1]*num_wavelength
|
||||
|
||||
opt = mpa.OptimizationProblem(
|
||||
simulation=sim,
|
||||
objective_functions=[dummy_J1],
|
||||
objective_arguments=[FarFields],
|
||||
design_regions=[matgrid_region],
|
||||
frequencies=frequencies,
|
||||
maximum_run_time=MAX_RUN_TIME,
|
||||
)
|
||||
|
||||
#make a plot of the optimization setup
|
||||
plt.figure(figsize=(12,6))
|
||||
ax1 = plt.subplot(1,2,1)
|
||||
ax2 = plt.subplot(1,2,2)
|
||||
opt.plot2D(True, output_plane=view_2D_plane_xz, ax=ax1)
|
||||
|
||||
opt.plot2D(True, output_plane=view_2D_plane_xy, ax=ax2)
|
||||
|
||||
plt.savefig(f"sim_opt_design_results/optimization_setup.pdf")
|
||||
|
||||
plt.close()
|
||||
|
||||
|
||||
print(type(optimal_design_weights), optimal_design_weights.shape)
|
||||
dummy = opt(
|
||||
[
|
||||
optimal_design_weights.flatten()
|
||||
],
|
||||
need_gradient=False,
|
||||
)
|
||||
|
||||
#note that get_objective_arguments returns
|
||||
# a LIST of the arguments passed to the obj. fun.
|
||||
#we select the first list element, since we ony have one obj. fun.
|
||||
solved_ff = opt.get_objective_arguments()[0]
|
||||
|
||||
def intensity_from_farfields(FarFields) -> np.ndarray:
|
||||
'''Computes the intensity pattern at the monitor location from the simulated far-fields
|
||||
|
||||
Args:
|
||||
FarFields: the simulated far-field patterns at the farfield
|
||||
monitor location, for each wavelength
|
||||
Returns:
|
||||
A 2D-array [Nx*Ny,num_wavelengths] of intensities, for each wavelength,
|
||||
at the monitor location.
|
||||
'''
|
||||
intensity_x = npa.abs(FarFields[:,:,0]) ** 2
|
||||
|
||||
return intensity_x
|
||||
|
||||
solved_intensity = intensity_from_farfields(solved_ff)
|
||||
|
||||
#make a plot of the ff intensities (at the center frequency)
|
||||
array_to_plot = solved_intensity[:,1].reshape(NX_DESIGN_GRID, NY_DESIGN_GRID)
|
||||
plt.figure()
|
||||
plt.imshow(array_to_plot, origin='lower', extent=(-cell_um.x/2,cell_um.x/2,-cell_um.y/2,cell_um.y/2))
|
||||
plt.xlabel("x (um)")
|
||||
plt.ylabel("y (um)")
|
||||
plt.title("Simulated far-field intensity at center frequency")
|
||||
plt.colorbar(label="Intensity (a.u.)")
|
||||
plt.savefig(f"sim_opt_design_results/simulated_farfield_intensity.pdf")
|
||||
plt.close()
|
||||
|
||||
Reference in New Issue
Block a user