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:
2026-05-27 14:55:09 +02:00
parent 1fafc62824
commit a283be231c
2 changed files with 297 additions and 62 deletions
+219
View File
@@ -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()