def create_transformations( obj: optplan.Function, monitors: List[optplan.Monitor], sim_space: optplan.SimulationSpaceBase, cont_iters: int, # require more to optimise power better num_stages: int = 3, min_feature: float = 100, ) -> List[optplan.Transformation]: """Creates a list of transformations for the device optimization. The transformations dictate the sequence of steps used to optimize the device. The optimization uses `num_stages` of continuous optimization. For each stage, the "discreteness" of the structure is increased (through controlling a parameter of a sigmoid function). Args: opt: The objective function to minimize. monitors: List of monitors to keep track of. sim_space: Simulation space ot use. cont_iters: Number of iterations to run in continuous optimization total across all stages. num_stages: Number of continuous stages to run. The more stages that are run, the more discrete the structure will become. min_feature: Minimum feature size in nanometers. Returns: A list of transformations. """ # Setup empty transformation list. trans_list = [] # First do continuous relaxation optimization. # This is done through cubic interpolation and then applying a sigmoid # function. param = optplan.CubicParametrization( # Specify the coarseness of the cubic interpolation points in terms # of number of Yee cells. Feature size is approximated by having # control points on the order of `min_feature / GRID_SPACING`. undersample=3.5 * min_feature / GRID_SPACING, simulation_space=sim_space, init_method=optplan.UniformInitializer(min_val=0.6, max_val=0.9), ) iters = max(cont_iters // num_stages, 1) for stage in range(num_stages): trans_list.append( optplan.Transformation( name="opt_cont{}".format(stage), parametrization=param, transformation=optplan.ScipyOptimizerTransformation( optimizer="L-BFGS-B", objective=obj, monitor_lists=optplan.ScipyOptimizerMonitorList( callback_monitors=monitors, start_monitors=monitors, end_monitors=monitors), optimization_options=optplan.ScipyOptimizerOptions( maxiter=iters), ), )) if stage < num_stages - 1: # Make the structure more discrete. trans_list.append( optplan.Transformation( name="sigmoid_change{}".format(stage), parametrization=param, # The larger the sigmoid strength value, the more "discrete" # structure will be. transformation=optplan.CubicParamSigmoidStrength( value=4 * (stage + 1)), )) return trans_list
def create_transformations( obj: optplan.Function, monitors: List[optplan.Monitor], sim_space: optplan.SimulationSpaceBase, cont_iters: int, num_stages: int = 3, min_feature: float = 100, ) -> List[optplan.Transformation]: """Creates a list of transformations for the device optimization. The transformations dictate the sequence of steps used to optimize the device. The optimization uses `num_stages` of continuous optimization. For each stage, the "discreteness" of the structure is increased (through controlling a parameter of a sigmoid function). Args: obj: The objective function to minimize. monitors: List of monitors to keep track of. sim_space: Simulation space ot use. cont_iters: Number of iterations to run in continuous optimization total across all stages. num_stages: Number of continuous stages to run. The more stages that are run, the more discrete the structure will become. min_feature: Minimum feature size in nanometers. fab_obj: Objective including fabrication penalties to be used in the second half of the optimization Returns: A list of transformations. """ # Setup empty transformation list. trans_list = [] # First do continuous relaxation optimization. # This is done through cubic interpolation and then applying a sigmoid # function. param = optplan.CubicParametrization( # Specify the coarseness of the cubic interpolation points in terms # of number of Yee cells. Feature size is approximated by having # control points on the order of `min_feature / GRID_SPACING`. undersample=3.5 * min_feature / GRID_SPACING, simulation_space=sim_space, init_method=optplan.WaveguideInitializer3(lower_min=0, lower_max=.2, upper_min=.7, upper_max=1, extent_frac_x=1, extent_frac_y=1 / 2, center_frac_x=1 / 2, center_frac_y=1 / 2), # init_method=optplan.GradientInitializer(min=0, max=1, random=0.3, extent_frac_x=1, extent_frac_y=0.4, # center_frac_x=0.5, center_frac_y=0.55) # init_method=optplan.UniformInitializer(min_val=0, max_val=0) # init_method=optplan.PeriodicInitializer(random=0.2, min=0, max=1, period=400, sim_width=6000, # center_frac_y=0.5, extent_frac_y=0.4) ) trans_list.append( optplan.Transformation( name="sigmoid_change_init", parametrization=param, # The larger the sigmoid strength value, the more "discrete" # structure will be. transformation=optplan.CubicParamSigmoidStrength(value=4, ))) iters = max(cont_iters // num_stages, 1) for stage in range(num_stages): trans_list.append( optplan.Transformation( name="opt_cont{}".format(stage), parametrization=param, transformation=optplan.ScipyOptimizerTransformation( optimizer="L-BFGS-B", objective=obj, monitor_lists=optplan.ScipyOptimizerMonitorList( callback_monitors=monitors, start_monitors=monitors, end_monitors=monitors), optimization_options=optplan.ScipyOptimizerOptions( maxiter=iters), ), )) if stage < num_stages - 1: # Make the structure more discrete. trans_list.append( optplan.Transformation( name="sigmoid_change{}".format(stage), parametrization=param, # The larger the sigmoid strength value, the more "discrete" # structure will be. transformation=optplan.CubicParamSigmoidStrength( value=2 * (stage + 3)), )) return trans_list