emopt.optimizer¶
This Optimizer class provides a simple wrapper around scipy.minimize.optimize
which allows you optimize an electromagnetic structure given an arbitrary
(user-defined) set of design parameters. The Optimizer class
minimizes a figure of merit defined in an
emopt.adjoint_method.AdjointMethod object and takes advantage of the
gradient computed by the supplied
emopt.adjoint_method.AdjointMethod object.
Examples
The Optimizer is used approximately as follows:
# Setup the simulation object
sim = ...
# Define a custom adjoint method class and instantiate it
am = MyAdjointMethod(...)
# Define a callback function
def my_callback(params, ...):
...
callback_func = lambda params : my_callback(params, other_inputs)
# Specify initial guess for the design parameters
design_params = ....
# Create the optimizer object
opt = Optimizer(sim, am, design_params, callback=callback_func)
# run the optimization
opt.run()
-
class
emopt.optimizer.Optimizer(am, p0, callback_func=None, opt_method='BFGS', Nmax=1000, tol=1e-05, bounds=None, scipy_verbose=True)¶ Bases:
future.types.newobject.newobjectHandles the optimization of an electromagnetic structure.
Given a set of design variables, a figure of merit, and a gradient, any electromagnetic structure can be optimized regardless of the underlying implementations of the simulator. With these quantities defined, it is in theory quite easy to run an optimization.
Currently, the optimization code is based on scipy.optimize.minimize, which is not parallel/MPI-compatible. As is such, this class manages the interface between the sequential scipy calls and the parallel components of EMOpt (like running simulations).
Fully parallelizing the optimization code should be possible using petsc. However, parallelizing the gradient computation is quite tricky for the most general case of arbitrary design variables. The process of computing gradients in paralle is significantly simplified when the material in each grid cell is an independent design variable (i.e. grayscale topology optimization). This type of problem, however, is not the core goal of EMOpt. This functionality may be added in the future.
Parameters: - sim (emopt.fdfd.FDFD) – Simulation object
- am (emopt.adjoint_method.AdjointMethod) – Object containing problem-specific implementation of AdjointMethod
- p0 (numpy.ndarray or list) – Initial guess for design parameters of system
- callback_func (function) – Function which accepts the current design variables as the only argument. This function is called after each iteration of the optimization. By default, no callback function is used.
- opt_method (str) – Optimization method to use. The recommended options are: CG, BFGS, L-BFGS-B, TNC, SLSQP. (default=’BFGS’)
- Nmax (int) – Maximum number of interations of optimization method before process is terminated. (default=1000)
- tol (float) – Minimum change in figure of merit below which the optimization will complete. (default=1e-5)
- bounds (list of tuples) – List of tuples containing two floats which specify the lower and upper bounds on each design variable. This is not compatible with all optimization methods. Consult the scipy.optimize.minimize documentation for details. (default=None)
-
am¶ The adjoint method object for calculating FOM and gradient
Type: emopt.adjoint_method.AdjointMethod
-
callback¶ The callback function to call after each optimization iteration.
Type: function
-
bounds¶ The list of bounds to put on design variables in the formate (minv, maxv)
Type: list of 2-tuple
-
run(self)¶ Run the optimization.
-
run_sequence(self, sim, am)¶ Define the sequence of figure of merit and gradient calls for the optimization.
-
class
RunCommands¶ Bases:
future.types.newobject.newobjectRun command codes used during message passing.
We need a way to signal the non-master nodes to perform different operations during the optimization. We do this by sending integers from the master node to the other nodes containing a command code. The commands are specified using an enum-like class.
-
EXIT= 2
-
FOM= 0
-
GRAD= 1
-
-
run() Run the optimization.
Returns: - float – The final figure of merit
- numpy.array – The optimized design parameters
-
run_sequence(am) Sequential optimization code.
In general, the optimization itself is run in parallel. Instead, only the calculation of the figure of merit and gradient takes advantage of paralellism (which is where the bulk of the computational complexity comes in). This function defines the sequential optimization code and makes calls to the parallel components.
Notes
Override this method for custom functionality!
Parameters: am ( emopt.adjoint_method.AdjointMethod) – The adjoint method object responsible for FOM and gradient calculations.Returns: The optimized figure of merit and the corresponding set of optimal design parameters. Return type: (float, numpy.ndarray)