3. Solving optimization problems

The first step when solving an optimization problem is to formulate a model and an optimization specification and then compile the model as described in the following sections in this chapter. There are currently three different optimization algorithms available in JModelica.org, which are suitable for different classes of optimization problems.

To illustrate how to solve optimization problems the Van der Pol problem presented above is used. First, the model is transferred into Python

op = transfer_optimization_problem("VDP_pack.VDP_Opt2", "VDP_Opt.mop")

All operations that can be performed on the model are available as methods of the op object and can be accessed by tab completion. Invoking an optimization algorithm is done by calling the method OptimizationProblem.optimize, which performs the following tasks:

The interactive help for the optimize method is displayed by the command:

>>> help(op.optimize)
    Solve an optimization problem.
        
    Parameters::
        
        algorithm --
            The algorithm which will be used for the optimization is 
            specified by passing the algorithm class name as string or 
            class object in this argument. 'algorithm' can be any 
            class which implements the abstract class AlgorithmBase 
            (found in algorithm_drivers.py). In this way it is 
            possible to write custom algorithms and to use them with this 
            function.
    
            The following algorithms are available:
            - 'LocalDAECollocationAlg'. This algorithm is based on
              direct collocation on finite elements and the algorithm IPOPT
              is used to obtain a numerical solution to the problem.
            Default: 'LocalDAECollocationAlg'
            
        options -- 
            The options that should be used in the algorithm. The options
            documentation can be retrieved from an options object:
            
                >>> myModel = OptimizationProblem(...)
                >>> opts = myModel.optimize_options()
                >>> opts?
    
            Valid values are: 
            - A dict that overrides some or all of the algorithm's default values. 
              An empty  dict will thus give all options with default values.
            - An Options object for the corresponding algorithm, e.g. 
              LocalDAECollocationAlgOptions for LocalDAECollocationAlg.
            Default: Empty dict
        
    Returns::
        
        A result object, subclass of algorithm_drivers.ResultBase.

The optimize method can be invoked without any arguments, in which case the default optimization algorithm, with default options, is invoked:

res = vdp.optimize()

In the remainder of this chapter the available algorithms are described in detail. Options for an algorithm can be set using the options argument to the optimize method. It is convenient to first obtain an options object in order to access the documentation and default option values. This is done by invoking the method optimize_options:

>>> help(op.optimize_options)
    Returns an instance of the optimize options class containing options 
    default values. If called without argument then the options class for 
    the default optimization algorithm will be returned.
    
    Parameters::
    
        algorithm --
            The algorithm for which the options class should be returned. 
            Possible values are: 'LocalDAECollocationAlg'.
            Default: 'LocalDAECollocationAlg'
            
    Returns::
    
        Options class for the algorithm specified with default values.

The option object is essentially a Python dictionary and options are set simply by using standard dictionary syntax:

opts = vdp.optimize_options()
opts['n_e'] = 5

The optimization algorithm may then be invoked again with the new options:

res = vdp.optimize(options=opts)

Available options for each algorithm are documented in their respective sections in this Chapter.

The optimize method returns a result object containing the optimization result and some meta information about the solution. The most common operation is to retrieve variable trajectories from the result object:

time = res['time']
x1 = res['x1']

Variable data is returned as NumPy arrays. The result object also contains references to the model that was optimized, the name of the result file that was written to disk, a solver object representing the optimization algorithm and an options object that was used when solving the optimization problem.