def __init__(self, opt_prob: problem.OptimizationProblem, logger: workspace.Logger, optimizer: str = "L-BFGS", monitor_lists: Optional[ optplan.ScipyOptimizerMonitorList] = None, optimization_options: Optional[Dict] = None) -> None: """Initializes transformation for `PenaltyOptimizer`. This transformation solves an optimization problem using the `PenaltyOptimizer` which solves a constrained optimization problem by adding a L1 norm penalty function. For example, the problem minimize f(x) subject to h(x) = 0 is solved by minimizing `f(x) + mu |h(x)|` for successively larger values of `mu`. Args: opt_prob: Optimization problem to solve. logger: Logger to use. optimizer: Name of scipy optimizer to use, e.g. 'L-BFGS'. Should be one of those defined for `scipy.optimize`. monitor_lists: List of monitors to log. optimization_options: Dictionary specifying additional optimizations as defined in the scipy documentation. For example, to specify maximum iterations for 'L-BFGS', `optimization_options` should be set to `{"maxiter": 10}`. """ self._opt_prob = opt_prob self.optimizer = optimizer if optimization_options is None: optimization_options = {} else: for key, value in optimization_options.items(): if not value: del optimization_options[key] self.optimization_options = optimization_options self.monitor_lists = monitor_lists if not self.monitor_lists: self.monitor_lists = optplan.ScipyOptimizerMonitorList() self.logger = logger
def __init__(self, opt_prob: problem.OptimizationProblem, logger: workspace.Logger, optimizer: str = "L-BFGS", monitor_lists: Optional[ optplan.ScipyOptimizerMonitorList] = None, optimization_options: Optional[Dict] = None) -> None: """Initializes transformation for running optimization with scipy. This transformation solves an optimization problem using a scipy optimizer. Args: opt_prob: Optimization problem to solve. logger: Logger to use. optimizer: Name of scipy optimizer to use, e.g. 'L-BFGS'. Should be one of those defined for `scipy.optimize`. monitor_lists: List of monitors to log. optimization_options: Dictionary specifying additional optimizations as defined in the scipy documentation. For example, to specify maximum iterations for 'L-BFGS', `optimization_options` should be set to `{"maxiter": 10}`. """ self._opt_prob = opt_prob self.optimizer = optimizer if optimization_options is None: optimization_options = {} else: for key, value in optimization_options.items(): if not value: del optimization_options[key] self.optimization_options = optimization_options self.monitor_lists = monitor_lists if not self.monitor_lists: self.monitor_lists = optplan.ScipyOptimizerMonitorList() self.logger = logger
def create_transformations( obj: optplan.Function, monitors: List[optplan.Monitor], cont_iters: int, disc_iters: int, sim_space: optplan.SimulationSpaceBase, min_feature: float = 100, cont_to_disc_factor: float = 1.1, ) -> List[optplan.Transformation]: """Creates a list of transformations for the optimization. The grating coupler optimization proceeds as follows: 1) Continuous optimization whereby each pixel can vary between device and background permittivity. 2) Discretization whereby the continuous pixel parametrization is transformed into a discrete grating (Note that L2D is implemented here). 3) Further optimization of the discrete grating by moving the grating edges. Args: opt: The objective function to minimize. monitors: List of monitors to keep track of. cont_iters: Number of iterations to run in continuous optimization. disc_iters: Number of iterations to run in discrete optimization. sim_space: Simulation space ot use. min_feature: Minimum feature size in nanometers. cont_to_disc_factor: Discretize the continuous grating with feature size constraint of `min_feature * cont_to_disc_factor`. `cont_to_disc_factor > 1` gives discrete optimization more wiggle room. Returns: A list of transformations. """ # Setup empty transformation list. trans_list = [] # First do continuous relaxation optimization. cont_param = optplan.PixelParametrization( simulation_space=sim_space, init_method=optplan.UniformInitializer(min_val=0, max_val=1)) trans_list.append( optplan.Transformation( name="opt_cont", parametrization=cont_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=cont_iters), ), )) # Discretize. Note we add a little bit of wiggle room by discretizing with # a slightly larger feature size that what our target is (by factor of # `cont_to_disc_factor`). This is to give the optimization a bit more wiggle # room later on. disc_param = optplan.GratingParametrization( simulation_space=sim_space, inverted=True) trans_list.append( optplan.Transformation( name="cont_to_disc", parametrization=disc_param, transformation=optplan.GratingEdgeFitTransformation( parametrization=cont_param, min_feature=cont_to_disc_factor * min_feature))) # Discrete optimization. trans_list.append( optplan.Transformation( name="opt_disc", parametrization=disc_param, transformation=optplan.ScipyOptimizerTransformation( optimizer="SLSQP", objective=obj, constraints_ineq=[ optplan.GratingFeatureConstraint( min_feature_size=min_feature, simulation_space=sim_space, boundary_constraint_scale=1.0, ) ], monitor_lists=optplan.ScipyOptimizerMonitorList( callback_monitors=monitors, start_monitors=monitors, end_monitors=monitors), optimization_options=optplan.ScipyOptimizerOptions( maxiter=disc_iters), ), )) return trans_list
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