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.

**Dynamic optimization of DAEs using direct collocation with CasADi.**This algorithm is the default algorithm for solving optimal control and parameter estimation problems. It is implemented in Python, uses CasADi for computing function derivatives and IPOPT or WORHP for solving the resulting NLP. In terms of functionality, this algorithm is very similar to the default JMU-based algorithm, but offers significant performance improvements in several regards. It is however still in a state of development, and is not as mature as the default algorithm.**Derivative free calibration and optimization of ODEs with FMUs.**This algorithm solves parameter optimization and model calibration problems and is based on FMUs. The algorithm is implemented in Python and relies on a Nelder-Mead derivative free optimization algorithm. Use this method if your model is of large scale and/or contains discontinuities or hybrid elements. Note that this algorithm is applicable to models which have been exported as FMUs also by other tools than JModelica.org.**Dynamic optimization of DAEs using direct collocation with JMUs (Deprecated in JModelica.org 1.15)**. This algorithm is implemented in C, uses CppAD for computing function derivatives and IPOPT for solving the resulting nonlinear program (NLP). Functions and records in models are supported by this algorithm. Use this method if your model is a DAE and does not contain discontinuities.

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

op = transfer_to_casadi_interface("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:

Sets up the selected algorithm with default or user defined options

Invokes the algorithm to find a numerical solution to the problem

Writes the result to file

Returns a result object from which the solution can be retrieved

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.

Again, note that the parameters differs for different model classes. 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.