def runSim(params, eps_bg, eps_wg, x_pos, y_pos, size_x, filter_R, beta_start=1): ######## DEFINE A 2D TOPOLOGY OPTIMIZATION REGION ######## geometry = TopologyOptimization2D(params=params, eps_min=eps_bg, eps_max=eps_wg, x=x_pos, y=y_pos, z=0, filter_R=filter_R, beta=beta_start) ######## DEFINE FIGURE OF MERIT ######## # The base simulation script defines a field monitor named 'fom' at the point where we want to modematch to the fundamental TE mode fom = ModeMatch(monitor_name='fom', mode_number='Fundamental TE mode', direction='Forward', norm_p=2) ######## DEFINE OPTIMIZATION ALGORITHM ######## optimizer = ScipyOptimizers(max_iter=50, method='L-BFGS-B', scaling_factor=1, pgtol=1e-6, ftol=1e-4, target_fom=0.5, scale_initial_gradient_to=0.25) ######## LOAD TEMPLATE SCRIPT AND SUBSTITUTE PARAMETERS ######## script = load_from_lsf( os.path.join(CONFIG['root'], 'examples/Ysplitter/splitter_base_2D_TE_topology.lsf')) script = script.replace('opt_size_x=3.5e-6', 'opt_size_x={:1.6g}'.format(size_x)) wavelengths = Wavelengths(start=1450e-9, stop=1650e-9, points=11) opt = Optimization(base_script=script, wavelengths=wavelengths, fom=fom, geometry=geometry, optimizer=optimizer, use_deps=False, hide_fdtd_cad=True, plot_history=False, store_all_simulations=False) ######## RUN THE OPTIMIZER ######## opt.run()
def setUp(self): # base script self.base_script = load_from_lsf(os.path.join(self.file_dir, 'modematch_parallel_plate_waveguide_TM_base.lsf')) # bandwidth self.wavelengths = Wavelengths(start = 1540e-9, stop = 1560e-9, points = 3) # simulation self.sim = Simulation(workingDir = self.file_dir, hide_fdtd_cad = True) self.sim.fdtd.eval(self.base_script) Optimization.set_global_wavelength(self.sim, self.wavelengths) # reference self.ref_fom = 0.6643986
def setUp(self): # Base simulation script self.base_script = load_from_lsf( os.path.join(self.file_dir, 'optimization_parallel_plate_waveguide_TE_base.lsf')) # Simulation bandwidth self.wavelengths = Wavelengths(start=1500e-9, stop=1600e-9, points=11) # Polygon defining a rectangle that can grow or shrink along the y-axis to fill the gap self.mesh_del = 10.0e-9 # must be kept in sych with self.base_script initial_points_y = np.array( [0.01 * self.mesh_del, 1.75 * self.mesh_del]) def wall(param=initial_points_y): assert param.size == 2, "walls defined by two points." self.wg_gap = 10.0 * self.mesh_del # must be kept in synch points_x = 0.5 * np.array( [-self.wg_gap, self.wg_gap, self.wg_gap, -self.wg_gap]) points_y = np.array([-param[0], -param[1], param[1], param[0]]) polygon_points = [(x, y) for x, y in zip(points_x, points_y)] return np.array(polygon_points) self.wg_width = 50.0 * self.mesh_del # must be kept in synch bounds = [(0.0, self.wg_width / 2.0)] * initial_points_y.size self.geometry = FunctionDefinedPolygon( func=wall, initial_params=initial_points_y, bounds=bounds, z=0.0, # must be kept in synch depth=self.wg_width, # must be kept in synch eps_out=1.0**2, # must be kept in synch with eps_in=Material(base_epsilon=4.0**2, name='<Object defined dielectric>', mesh_order=1), # must be kept in sych with edge_precision=50, dx=1.0e-10) # Figure of merit self.fom = ModeMatch( monitor_name='fom', # must be kept in sych mode_number=1, # must be kept in sych direction='Forward', multi_freq_src=True, target_T_fwd=lambda wl: np.ones(wl.size), norm_p=1) # Scipy optimizer self.optimizer = ScipyOptimizers(max_iter=5, method='L-BFGS-B', scaling_factor=1.0e6, pgtol=1.0e-5, ftol=1.0e-12, target_fom=0.0, scale_initial_gradient_to=None)
def _load_simulation_file(self, file): """ Load a simulation file """ # Assumes file is either an absolute path or accessible in the # current directory if '.fsp' in file and os.path.isfile(file): self.fdtd.load(file) elif '.lsf' in file and os.path.isfile(file): script_str = load_from_lsf(file) self._script_eval(script_str) else: raise UserWarning('Input file must be either .fsp or .lsf')
def __init__(self, script_obj): if callable(script_obj): self.callable_obj = script_obj params = signature(script_obj).parameters if len(params) > 1: raise UserWarning( 'function to create base simulation must take a single argument (handle to FDTD CAD).' ) elif isinstance(script_obj, str): if '.fsp' in script_obj and os.path.isfile(script_obj): self.project_file = os.path.abspath(script_obj) elif '.lsf' in script_obj and os.path.isfile(script_obj): self.script_str = load_from_lsf(os.path.abspath(script_obj)) else: self.script_str = str(script_obj) else: raise UserWarning( 'object for generating base simulation must be a Python function, a file name or a string with a Lumerical script.' )
def setUp(self): # Base simulation script self.base_script = load_from_lsf(os.path.join(self.file_dir, 'optimization_waveguide_filter_TM_2D_base.lsf')) # Simulation bandwidth self.wavelengths = Wavelengths(start = 1300e-9, stop = 1800e-9, points = 41) # Polygons to form the two gaps self.mesh_del = 20.0e-9; # must be kept in sych with self.base_script initial_param = 10.0 * np.array([self.mesh_del]) def rectangle(param = initial_param, offset = 0.0): assert param.size == 1, "rectangle grows along a single dimension." wg_width = 35.0 * self.mesh_del # must be kept in synch points_x = 0.5 * np.array([-wg_width, wg_width, wg_width, -wg_width]) points_y = 0.5 * np.array([-param, -param, param, param]) + offset polygon_points = [(x, y) for x, y in zip(points_x, points_y)] return np.array(polygon_points) bounds = [(self.mesh_del, 20.0 * self.mesh_del)] z = 0.0 # must be kept in sych depth = 200.0 * self.mesh_del # must be kept in sych eps_in = Material(base_epsilon = 1.44 ** 2, mesh_order = 1) # must be kept in sych with eps_out = Material(base_epsilon = 2.8 ** 2, mesh_order = 1) # must be kept in sych with edge_precision = 25 dx = 1.0e-10 self.geometry = (FunctionDefinedPolygon(func = lambda param: rectangle(param[0], 2.0 * param[0]), initial_params = initial_param, bounds = bounds, z = z, depth = depth, eps_out = eps_out, eps_in = eps_in, edge_precision = edge_precision, dx = dx) * FunctionDefinedPolygon(func = lambda param: rectangle(param[0],-2.0 * param[0]), initial_params = initial_param, bounds = bounds, z = z, depth = depth, eps_out = eps_out, eps_in = eps_in, edge_precision = edge_precision, dx = dx)) # Broadband figure of merit target_T_fwd = lambda wl: 0.3 + 0.65*np.power(np.sin(np.pi * (wl - wl.min()) / (wl.max() - wl.min())), 6) self.fom = ModeMatch(monitor_name = 'FOM', # must be kept in sych mode_number = 1, # must be kept in sych direction = 'Backward', multi_freq_src = True, target_T_fwd = target_T_fwd, norm_p = 1) # Scipy optimzier self.optimizer = ScipyOptimizers(max_iter = 10, method = 'L-BFGS-B', scaling_factor = 1.0e7, pgtol = 5.6e-3)
import os import numpy as np import scipy as sp # Optimization specific imports from lumopt.utilities.load_lumerical_scripts import load_from_lsf from lumopt.utilities.wavelengths import Wavelengths from lumopt.utilities.materials import Material from lumopt.geometries.polygon import FunctionDefinedPolygon from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.optimizers.generic_optimizers import ScipyOptimizers from lumopt.optimization import Optimization ######## DEFINE BASE SIMULATION ######## script = load_from_lsf( os.path.join(os.path.dirname(__file__), 'splitter_base_TE_modematch_3D.lsf')) ######## DEFINE SPECTRAL RANGE ######### wavelengths = Wavelengths(start=1300e-9, stop=1800e-9, points=21) ######## DEFINE DATABASE MATERIALS ##### silicon = Material(name='Si (Silicon) - Palik', mesh_order=2) ######## DEFINE OPTIMIZABLE GEOMETRY ######## initial_points_x = np.linspace(-1.0e-6, 1.0e-6, 10) initial_points_y = 0.25e-6 + (0.6e-6 - 0.25e-6) * np.power( np.sin(np.pi / 2.0 * (initial_points_x - initial_points_x.min()) / (initial_points_x.max() - initial_points_x.min())), 2)
# General purpose imports import os import numpy as np import scipy as sp from lumopt import CONFIG # Optimization specific imports from lumopt.utilities.load_lumerical_scripts import load_from_lsf from lumopt.utilities.wavelengths import Wavelengths from lumopt.geometries.polygon import FunctionDefinedPolygon from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.optimizers.generic_optimizers import ScipyOptimizers from lumopt.optimization import Optimization ######## DEFINE BASE SIMULATION ######## base_script = load_from_lsf( os.path.join(os.path.dirname(__file__), 'splitter_with_arms.lsf')) ######## DEFINE SPECTRAL RANGE ######### wavelengths = Wavelengths(start=1550e-9, stop=1550e-9, points=1) ######## DEFINE OPTIMIZABLE GEOMETRY ######## # The class FunctionDefinedPolygon needs a parameterized Polygon (with points ordered # in a counter-clockwise direction). Here the geometry is defined by 10 parameters defining # the knots of a spline, and the resulting Polygon has 200 edges, making it quite smooth. def taper_splitter(params=np.linspace(0.25e-6, 2e-6, 20)): ''' Defines a taper where the paramaters are the y coordinates of the nodes of a cubic spline. ''' points_x = np.concatenate(([-2.51e-6], np.linspace(-2.5e-6, 2.5e-6, 20), [2.51e-6])) points_y = np.concatenate(([0.25e-6], params, [2e-6]))
def runGratingOptimization(bandwidth_in_nm, etch_depth, n_grates, params): bounds = [(0.1, 1)] * 4 bounds[0] = (-3, 3) #< Starting position bounds[1] = (0, 0.1) #< Scaling parameter R bounds[2] = (1.5, 3) #< Parameter a bounds[3] = (0, 2) #< Parameter b def grating_params_pos(params, output_waveguide_length=0.5e-6, height=220e-9, y0=0): x_begin = -3e-6 y3 = y0 + height y1 = y3 - etch_depth x_start = params[0] * 1e-6 #< First parameter is the starting position x0 = x_start R = params[1] * 1e6 #< second parameter (unit is 1/um) a = params[2] #< Third parameter (dim-less) b = params[3] #< Fourth parameter (dim-less) verts = np.array([[x_begin, y0], [x_begin, y3], [x0, y3], [x0, y1]]) lambda_c = 1.55e-6 F0 = 0.95 ## Iterate over all but the last for i in range(n_grates - 1): F = F0 - R * (x0 - x_start) Lambda = lambda_c / (a + F * b) x1 = x0 + (1 - F) * Lambda #< Width of the etched region x2 = x0 + Lambda #< Rest of cell verts = np.concatenate( (verts, [[x1, y1], [x1, y3], [x2, y3], [x2, y1]]), axis=0) x0 = x2 F = F0 - R * (x0 - x_start) Lambda = lambda_c / (a + F * b) x1 = x0 + (1 - F) * Lambda #< Width of the etched region x_end = x1 + output_waveguide_length verts = np.concatenate( (verts, [[x1, y1], [x1, y3], [x_end, y3], [x_end, y0]]), axis=0) return verts geometry = FunctionDefinedPolygon(func=grating_params_pos, initial_params=params, bounds=bounds, z=0.0, depth=110e-9, eps_out=1.44**2, eps_in=3.47668**2, edge_precision=5, dx=1e-3) ######## DEFINE FIGURE OF MERIT ######## fom = ModeMatch(monitor_name='fom', mode_number=1, direction='Backward', target_T_fwd=lambda wl: np.ones(wl.size), norm_p=1) ######## DEFINE OPTIMIZATION ALGORITHM ######## optimizer = ScipyOptimizers(max_iter=25, method='L-BFGS-B', scaling_factor=1, pgtol=1e-6) ######## DEFINE BASE SIMULATION ######## base_script = load_from_lsf( os.path.join(os.path.dirname(__file__), 'grating_coupler_2D_2etch.lsf')) ######## PUT EVERYTHING TOGETHER ######## lambda_start = 1550 - bandwidth_in_nm / 2 lambda_end = 1550 + bandwidth_in_nm / 2 lambda_pts = int(bandwidth_in_nm / 10) + 1 wavelengths = Wavelengths(start=lambda_start * 1e-9, stop=lambda_end * 1e-9, points=lambda_pts) opt = Optimization(base_script=base_script, wavelengths=wavelengths, fom=fom, geometry=geometry, optimizer=optimizer, hide_fdtd_cad=True, use_deps=True) ######## RUN THE OPTIMIZER ######## opt.run()
with open('script_file.lsf', 'a') as file: file.write(self.base_script.replace(';', ';\n')) if __name__ == '__main__': import numpy as np from lumopt.geometries.polygon import function_defined_Polygon, cross from lumopt.optimizers.generic_optimizers import ScipyOptimizers from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.utilities.load_lumerical_scripts import load_from_lsf import os import matplotlib.pyplot as plt from lumopt import CONFIG base_script = load_from_lsf( os.path.join(CONFIG['root'], 'examples/crossing/crossing_base_TE_modematch_2D.lsf')) fom = ModeMatch(modeorder=2) optimizer = ScipyOptimizers(max_iter=20) # optimizer=FixedStepGradientDescent(max_dx=20e-9,max_iter=100) bounds = [(0.2e-6, 1e-6)] * 10 geometry = function_defined_Polygon(func=cross, initial_params=np.linspace( 0.25e-6, 0.6e-6, 10), eps_out='SiO2 (Glass) - Palik', eps_in=2.8**2, bounds=bounds, depth=220e-9, edge_precision=5)
import numpy as np from lumopt.optimization import Super_Optimization, Optimization from lumopt.geometries.polygon import function_defined_Polygon from lumopt.optimizers.generic_optimizers import ScipyOptimizers from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.utilities.load_lumerical_scripts import load_from_lsf import os from lumopt import CONFIG import scipy ######## DEFINE BASE SIMULATION ######## #Here I just use the same script for both simulations, but it's just to keep the example simple. You could use two script_1 = load_from_lsf( os.path.join(CONFIG['root'], 'examples/Ysplitter/splitter_base_TE_modematch.lsf')) script_2 = load_from_lsf( os.path.join( CONFIG['root'], 'examples/Ysplitter/splitter_base_TE_modematch_25nmoffset.lsf')) ######## DEFINE OPTIMIZABLE GEOMETRY ######## ## Here the two splitters just have a 25nm offset from each other, so that the result is robust def taper_splitter_1(params, n_points=10): points_x = np.concatenate(([-1.01e-6], np.linspace(-1.1e-6, 0.9e-6, 10), [1.01e-6])) points_y = np.concatenate(([0.25e-6], params, [0.6e-6])) n_interpolation_points = 100
######## IMPORTS ######## # General purpose imports import os import numpy as np # Optimization specific imports from lumopt.utilities.load_lumerical_scripts import load_from_lsf from lumopt.utilities.wavelengths import Wavelengths from lumopt.utilities.materials import Material from lumopt.geometries.polygon import FunctionDefinedPolygon from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.optimizers.generic_optimizers import ScipyOptimizers from lumopt.optimization import Optimization ######## DEFINE BASE SIMULATION ######## script = load_from_lsf( os.path.join(os.path.dirname(__file__), 'grating_base.lsf')) ######## DEFINE SPECTRAL RANGE ######### wavelengths = Wavelengths(start=1300e-9, stop=1800e-9, points=21) ######## DEFINE MATERIALS ############## oxide = Material(1.44**2, mesh_order=1) silicon = Material(3.4**2) ######## DEFINE OPTIMIZABLE GEOMETRY ######## n_grates = 22 def grate_function_generator(grate_number, grate_height=70e-9, grate_center_y=220e-9 - 35e-9):
def runGratingOptimization(bandwidth_in_nm, etch_depth_shallow, etch_depth_deep, n_grates, initial_params = None): ### Yet another parametrization which allows to enforce minimum feature size when the optimizer only supports box constraints ### params = [x0, a1, b1, ..., aN] if initial_params is None: params = np.zeros(4*n_grates) for i in range(n_grates): params[i*4] = 0.2 #< Width up params[i*4+1] = 0.4*(i/n_grates) #< Width of the shallow etch params[i*4+2] = 0.1 #< Width up params[i*4+3] = 0.4*(i/n_grates) #< Width of the deep etch params[0] = 0 #< Overwrite the first since it has a special meaning: Start of the grating at 0um else: params = initial_params bounds = [(0, 1)]*(4*n_grates) bounds[0] = (-3,3) def grating_params_pos(params, output_waveguide_length = 0.5e-6, height = 220e-9, y0 = 0): x_begin = -3e-6 y3 = y0+height y2 = y3-etch_depth_deep y1 = y3-etch_depth_shallow x0 = params[0]*1e-6 #< First parameter is the starting position verts = np.array( [ [x_begin,y0],[x_begin,y3],[x0,y3],[x0,y1] ] ) ## Iterate over all but the last for i in range(n_grates-1): x1 = x0 + params[i*4+1]*1e-6 #< Width of the deep etch x2 = x1 + params[i*4+2]*1e-6 #< Width up x3 = x2 + params[i*4+3]*1e-6 #< Width of the shallow etch x4 = x3 + params[i*4+4]*1e-6 #< Width up verts = np.concatenate((verts,[[x1,y1],[x1,y3],[x2,y3],[x2,y2],[x3,y2],[x3,y3],[x4,y3],[x4,y1]]),axis=0) x0 = x4 x1 = x0 + params[(n_grates-1)*4+1]*1e-6 #< Width of the deep etch x2 = x1 + params[(n_grates-1)*4+2]*1e-6 #< Width up x3 = x2 + params[(n_grates-1)*4+3]*1e-6 #< Width of the shallow etch x_end = x3+output_waveguide_length verts = np.concatenate((verts,[[x1,y1],[x1,y3],[x2,y3],[x2,y2],[x3,y2],[x3,y3],[x_end,y3],[x_end,y0]]),axis=0) return verts geometry = FunctionDefinedPolygon(func = grating_params_pos, initial_params = params, bounds = bounds, z = 0.0, depth = 220e-9, eps_out = 1.44 ** 2, eps_in = 3.47668 ** 2, edge_precision = 5, dx = 1e-3) ######## DEFINE FIGURE OF MERIT ######## fom = ModeMatch(monitor_name = 'fom', mode_number = 1, direction = 'Backward', target_T_fwd = lambda wl: np.ones(wl.size), norm_p = 1) ######## DEFINE OPTIMIZATION ALGORITHM ######## optimizer = ScipyOptimizers(max_iter = 250, method = 'L-BFGS-B', scaling_factor = 1, pgtol = 1e-6) #SLSQP ######## DEFINE BASE SIMULATION ######## base_script = load_from_lsf(os.path.join(os.path.dirname(__file__), 'grating_coupler_2D_2etch.lsf')) ######## PUT EVERYTHING TOGETHER ######## lambda_start = 1550 - bandwidth_in_nm/2 lambda_end = 1550 + bandwidth_in_nm/2 lambda_pts = int(bandwidth_in_nm/10)+1 wavelengths = Wavelengths(start = lambda_start*1e-9, stop = lambda_end*1e-9, points = lambda_pts) opt = Optimization(base_script = base_script, wavelengths = wavelengths, fom = fom, geometry = geometry, optimizer = optimizer, hide_fdtd_cad = True, use_deps = True) ######## RUN THE OPTIMIZER ######## opt.run()
import numpy as np import scipy as sp from lumopt.utilities.load_lumerical_scripts import load_from_lsf from lumopt.utilities.wavelengths import Wavelengths from lumopt.geometries.polygon import FunctionDefinedPolygon from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.optimizers.generic_optimizers import ScipyOptimizers from lumopt.optimization import Optimization ######## DEFINE SPECTRAL RANGE ######### wavelengths = Wavelengths(start = 1550e-9, stop = 1550e-9, points = 1) ######## DEFINE BASE SIMULATION ######## # Use the same script for both simulations, but it's just to keep the example simple. You could use two. script_1 = load_from_lsf(os.path.join(os.path.dirname(__file__), 'splitter_base_TE_modematch.lsf')) script_2 = load_from_lsf(os.path.join(os.path.dirname(__file__), 'splitter_base_TE_modematch_25nmoffset.lsf')) ######## DEFINE OPTIMIZABLE GEOMETRY ######## ## Here the two splitters just have a 25nm offset from each other, so that the result is robust def taper_splitter_1(params,n_points=10): points_x = np.concatenate(([-1.01e-6],np.linspace(-1.1e-6,0.9e-6,10),[1.01e-6])) points_y = np.concatenate(([0.25e-6],params,[0.6e-6])) n_interpolation_points=100 polygon_points_x = np.linspace(min(points_x), max(points_x), n_interpolation_points) interpolator = sp.interpolate.interp1d(points_x, points_y, kind='cubic') polygon_points_y = [max(min(point,1e-6),-1e-6) for point in interpolator(polygon_points_x)] polygon_points_up = [(x, y) for x, y in zip(polygon_points_x, polygon_points_y)] polygon_points_down = [(x, -y) for x, y in zip(polygon_points_x, polygon_points_y)]
import os import numpy as np import scipy as sp from lumopt import CONFIG # Optimization specific imports from lumopt.utilities.load_lumerical_scripts import load_from_lsf from lumopt.geometries.polygon import FunctionDefinedPolygon from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.optimizers.generic_optimizers import ScipyOptimizers from lumopt.optimization import Optimization ######## DEFINE BASE SIMULATION ######## base_script_file_name = os.path.join( CONFIG['root'], 'examples/Ysplitter/splitter_with_arms.lsf') base_script = load_from_lsf(base_script_file_name) ######## DEFINE OPTIMIZABLE GEOMETRY ######## # The class FunctionDefinedPolygon needs a parameterized Polygon (with points ordered # in a counter-clockwise direction). Here the geometry is defined by 10 parameters defining # the knots of a spline, and the resulting Polygon has 200 edges, making it quite smooth. def taper_splitter(params=np.linspace(0.25e-6, 2e-6, 20)): ''' Defines a taper where the paramaters are the y coordinates of the nodes of a cubic spline. ''' points_x = np.concatenate(([-2.51e-6], np.linspace(-2.5e-6, 2.5e-6, 20), [2.51e-6])) points_y = np.concatenate(([0.25e-6], params, [2e-6])) n_interpolation_points = 100 px = np.linspace(min(points_x), max(points_x), n_interpolation_points) interpolator = sp.interpolate.interp1d(points_x, points_y, kind='cubic')
######## IMPORTS ######## # General purpose imports import os import numpy as np import scipy as sp from lumopt.utilities.load_lumerical_scripts import load_from_lsf from lumopt.utilities.wavelengths import Wavelengths from lumopt.geometries.polygon import FunctionDefinedPolygon from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.optimizers.generic_optimizers import ScipyOptimizers from lumopt.optimization import Optimization ######## DEFINE BASE SIMULATION ######## # Use the same script for both simulations, but it's just to keep the example simple. You could use two. script_1550 = load_from_lsf( os.path.join(os.path.dirname(__file__), 'WDM_splitter_base_TE_1550.lsf')) script_1310 = load_from_lsf( os.path.join(os.path.dirname(__file__), 'WDM_splitter_base_TE_1550.lsf')).replace( '1550e-9', '1310e-9') ######## DEFINE SPECTRAL RANGE ######### wavelengths_1551 = Wavelengths(start=1550e-9, stop=1550e-9, points=1) wavelengths_1310 = Wavelengths(start=1310e-9, stop=1310e-9, points=1) ######## DEFINE OPTIMIZABLE GEOMETRY ######## separation = 500.0e-9 size_x = 10.0e-6 def lower_coupler_arm(params, n_points=10):
import numpy as np import os import scipy from lumopt import CONFIG # Optimization specific imports from lumopt.utilities.load_lumerical_scripts import load_from_lsf from lumopt.geometries.polygon import function_defined_Polygon from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.optimization import Optimization from lumopt.optimizers.generic_optimizers import ScipyOptimizers, FixedStepGradientDescent from lumopt.utilities.materials import Material ######## DEFINE BASE SIMULATION ######## script = load_from_lsf( os.path.join(CONFIG['root'], 'examples/grating/grating_base.lsf')) ######## DEFINE OPTIMIZABLE GEOMETRY ######## # The class function_defined_Polygon needs a parameterized Polygon (with points ordered # in a counter-clockwise direction. This funtion will automatically generate all the polygons needed n_grates = 22 def grate_function_generator(grate_number, grate_height=70e-9, grate_center_y=220e-9 - 35e-9): def grate_function(params): grate_position = params[grate_number] grate_width = params[grate_number + len(params) / 2]
# General purpose imports import numpy as np from lumopt.optimization import Super_Optimization, Optimization from lumopt.geometries.polygon import function_defined_Polygon from lumopt.optimizers.generic_optimizers import ScipyOptimizers from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.utilities.load_lumerical_scripts import load_from_lsf import os from lumopt import CONFIG import scipy ######## DEFINE BASE SIMULATION ######## #Here I just use the same script for both simulations, but it's just to keep the example simple. You could use two script_1550=load_from_lsf(os.path.join(CONFIG['root'],'examples/WDM_splitter/WDM_splitter_base_TE_1550.lsf')) script_1310=load_from_lsf(os.path.join(CONFIG['root'],'examples/WDM_splitter/WDM_splitter_base_TE_1550.lsf')).replace('1550e-9','1310e-9') ######## DEFINE OPTIMIZABLE GEOMETRY ######## separation=500e-9 size_x=10e-6 def lower_coupler_arm(params,n_points=10): points_x=np.concatenate(([0.5e-6],np.linspace(0.55e-6,size_x-0.55e-6,20),[size_x-0.5e-6])) points_y=np.concatenate(([-separation/2],params-separation/2,params[::-1]-separation/2,[-separation/2])) n_interpolation_points=100 polygon_points_x = np.linspace(min(points_x), max(points_x), n_interpolation_points) interpolator = scipy.interpolate.interp1d(points_x, points_y, kind='cubic') polygon_points_y = [max(min(point,0e-6),-separation/2-0.25e-6) for point in interpolator(polygon_points_x)]
######## IMPORTS ######## import os import numpy as np import scipy as sp from lumopt.utilities.load_lumerical_scripts import load_from_lsf from lumopt.utilities.wavelengths import Wavelengths from lumopt.geometries.polygon import FunctionDefinedPolygon from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.optimizers.generic_optimizers import ScipyOptimizers from lumopt.optimization import Optimization ######## DEFINE BASE SIMULATION ######## crossing_base = load_from_lsf( os.path.join(os.path.dirname(__file__), 'crossing_base_TE_modematch_2D.lsf')) ######## DEFINE SPECTRAL RANGE ######### wavelengths = Wavelengths(start=1300e-9, stop=1800e-9, points=21) ######## DEFINE OPTIMIZABLE GEOMETRY ######## def cross(params): y_end = params[-1] x_end = 0 - y_end points_x = np.concatenate(([-2.01e-6], np.linspace(-2e-6, x_end, 10))) points_y = np.concatenate(([0.25e-6], params)) n_interpolation_points = 50 polygon_points_x = np.linspace(min(points_x), max(points_x), n_interpolation_points)
if __name__=='__main__': import matplotlib as mpl # mpl.use('TkAgg') import numpy as np # from lumopt.figures_of_merit.modematch_importsource import ModeMatch from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.optimization import Optimization from lumopt.optimizers.generic_optimizers import ScipyOptimizers, FixedStepGradientDescent from lumopt.utilities.load_lumerical_scripts import load_from_lsf import os from lumopt.geometries.polygon import function_defined_Polygon from lumopt.utilities.materials import Material from lumopt import CONFIG import scipy script = load_from_lsf(os.path.join(CONFIG['root'], 'examples/staight_waveguide/straight_waveguide.lsf')) fom = ModeMatch(modeorder=2, precision=50) optimizer = ScipyOptimizers(max_iter=20) nx=401 ny=101 eps = np.ones((nx, ny))*1.44 ** 2 eps[90, 10] = 10 geometry = ContinousEpsilon2D(eps=eps, x=np.linspace(-1e-6, 1e-6, nx), y=np.linspace(-0.4e-6, 0.4e-6, ny)) # function_defined_Polygon(func=waveguide, initial_params=np.linspace(0.25e-6, 0.25e-6, 10), # eps_out=Material(1.44 ** 2), eps_in=Material(2.8 ** 2, 2), bounds=bounds, # depth=220e-9, # edge_precision=5) # geometry=Polygon(eps_in=2.8**2,eps_out=1.44**2) opt = Optimization(base_script=script, fom=fom, geometry=geometry, optimizer=optimizer)
import numpy as np import os import scipy from lumopt import CONFIG # Optimization specific imports from lumopt.utilities.load_lumerical_scripts import load_from_lsf from lumopt.geometries.polygon import function_defined_Polygon from lumopt.figures_of_merit.modematch import ModeMatch from lumopt.optimization import Optimization from lumopt.optimizers.generic_optimizers import ScipyOptimizers ######## DEFINE BASE SIMULATION ######## script = load_from_lsf( os.path.join(CONFIG['root'], 'examples/Ysplitter/splitter_base_TE_modematch_3D.lsf')) ######## DEFINE OPTIMIZABLE GEOMETRY ######## # The class function_defined_Polygon needs a parameterized Polygon (with points ordered # in a counter-clockwise direction. Here the geometry is defined by 10 parameters defining # the knots of a spline, and the resulting Polygon has 200 edges, making it quite smooth def taper_splitter(params=np.linspace(0.25e-6, 0.6e-6, 10)): '''Just a taper where the parameters are the y coordinates of the nodes of a cubic spline''' points_x = np.concatenate(([-1.01e-6], np.linspace(-1e-6, 1e-6, 10), [1.01e-6])) points_y = np.concatenate(([0.25e-6], params, [0.6e-6]))
# General purpose imports import os import numpy as np import scipy as sp from lumopt.utilities.load_lumerical_scripts import load_from_lsf from lumopt.utilities.wavelengths import Wavelengths from lumopt.geometries.polygon import FunctionDefinedPolygon from lumopt.figures_of_merit.modematch import ModeMatch from GLOptimizer import * from lumopt.optimizers.generic_optimizers import ScipyOptimizers from GLOptimization import Optimization ######## DEFINE BASE SIMULATION ######## # Use the same script for both simulations, but it's just to keep the example simple. You could use two. script_1550 = load_from_lsf(os.path.join(os.path.dirname(__file__), 'grating_test.lsf')) ######## DEFINE SPECTRAL RANGE ######### wavelengths_1550 = Wavelengths(start = 1550e-9, stop = 1550e-9, points = 1) ######## DEFINE OPTIMIZABLE GEOMETRY ######## ## Definition Start def make_polygon_func(center_x,center_y,i): def make_rectangle(params,n_points = 16): wg_width = 0.5e-6 #print(params) width = (params[i]*1000000 + 1)*0.035e-6 points_x = np.array([center_x - width/2, center_x + width/2, center_x + width/2 , center_x - width/2]) points_y = np.array([center_y - wg_width/2 , center_y - wg_width/2 , center_y + wg_width/2 , center_y + wg_width/2]) polygon_points = np.array([(x, y) for x, y in zip(points_x, points_y)])