generateOCProblem

It is one the most important commands of XOptima because it generates the optimised C++ code to be linked with Mechatronix and run with pins. The syntax is intuitive, it requires only the name of the project and the desired options. There is a long list of possible options, they are detailed in this section.

The command is based on a Ruby script that parses the code generated by Maple and applies the necessary transformations for the library. First, the call of the command is:

generateOCProblem( name::string, mesh::list, options )

The first parameter name represents the name of the PINS project. It can be any string of the charset 0-9 a-z A-Z, without spaces, no punctuation or symbols are supported yet. Each generated file will begin with this string, for a quick overview of the structure of generated files see Figure QS:fig:tree_init and The folder tree for the first start with PINS after the code generation and the run of the executable.. The argument mesh is a list that contains lists of kind [“length”=1,”n”=100], that is the length of the segment and the number of intervals in which it is divide. The default interval for the independent variable is set to \([0,1]\). More features for the mesh can be found below in the mesh options.

Post Processing Options

options

type

default

standard_post_processing post_processing integral_post_processing

boolean list([algebraic,string]) list([algebraic,string])

true [] []

It is possible to add user defined variables or expressions to be computed once the solver has converged, this is called post processing. There are variables that do not need to be integrated, e.g. a Mayer term or other combinations of the states; instead if the Lagrange term is required (to be integrated), it is done with integral_post_processing.

The default setting for the post processing is standard_post_processing, which generates a text file called projectname_OCP_result.txt and contains the value of the principal variables for each point of the mesh.

The standard variables are the independent variable \(\zeta\), the state variables, the controls, the associated Lagrangian multipliers, he penalties, the integrand of the Lagrange target.

This last one is not the value of the integral, to obtain the Lagrange target it must be integrated over the suitable interval. For example the Lagrange term is obtained by using the the option integral_post_processing.

As an example, see the problem of the hang glider Hang Glider, where it was useful to plot the functions \(u_a(x)\) or the auxiliary funtion \(v_r\). This is accomplished adding the option:

post_processing = [ [ua(zeta*L(zeta)),"ua"],
                    [vr,"vr"],
                    [zeta*L(zeta),"x"]]

Meshing Options

options

type

default

mesh

list

[]

mesh_zeta0

{integer,float,algebraic}

0

The argument meshz is a list that contains lists of type [“length”=1,”n”=100]`, that is the length of the segment and the number of intervals in which it is divide.

If you do not want to cast the problem in \([0,1]\) for the independent variable, and you want to set a mesh of \(N\) intervals over the interval \([a,b]\), you can specify the initial point of the interval with the option mesh_zeta0 = a and set the mesh with the option [“length”=b-a,”n”=N].

User parameters

options

type

default

parameters

list(symbol=algebraic)

[]

With the option parameters you can specify all the constants, the varibles and the values that are necessary to initialise XOptima. All those values can be set with expressions in a list like a = expr. If you want to modify these values and rerun the project, it is not necessary to recompile the XOptima file, compile the C++ program and run pins, but it is enough to edit the configuration file projectname_Data.rb (inside the folder data) and simply rerun pins. This saves a lot of time and allows to quickly try different values of some parameters on the same optimal control problem.

Guess generation Options


options

type

default

states_guess

list(symbol=algebraic)

[]

Adding a guess to the solver is often a good way to achieve convergence or to improve the running time. A guess can be specified over the state variables. It can be a constant value as well as a function of the independent variable. Assuming that you use the standard independent variable \(\zeta\in[0,1]\), suppose to specify for the variable \(x\) a linear interpolation of the initial and final values, respectively \(x_i\) and \(x_f:math:\). Then the corresponding implementation in XOptima can be like:

states_guess = [ x = x_i + zeta * (x_f-x_i)]

Controls Options

options

type

default

controls_user_defined

list(symbol=algebraic)

[]

controls_iterative

list(symbol=algebraic)

[]

The optimal control, according to the theorem of Pontryagin, are the solution of the argmin of the Hamiltonian function, often they can be obtained from the solution of the equation of the first order necessary conditions \(\partial_u H(\mathbf{x},\mathbf{\lambda},\mathbf{u})=0\). XOptima tries by default to compute the controls analytically, and if this is not possible, they are obtained using a numeric iterative procedure. It is possible to force XOptima to use the numeric solution even f the analytic solution is available. This can be the case if the analytic solution is too involved. To tell XOptima to ignore the eventual exact solution and use instead the numeric one, use the parameter controls_iterative=true. You can also specify your own control law, by setting the option controls_user_defined=[u1=expr,u2=expr, ...]: this choice prevents XOptima to compute the optimal control either in exact or in numeric form and use the user defined controls.

Warning

creare esempio se \(u=\arctan(y/x)\) …. non fai i 4 quadranti (vedi tutoria Zermelo).

Checking Options

options

type

default

admissible_regions

list({<,`<=`})

[]

With admissible_regions you can specify bounds on state and control variables, that will be used by the solver in the solution process. A typical example is to set the free time to \(T>0\), because often there is a mathematical solution with negative time which has no physical meaning. Notice that you can set also strict inequalities.

Scaling Options (DA IMPLEMENTARE)

options

type

default

states_scaling

list({function,symbol}=algebraic)

[]

equations_scaling

list(integer=algebraic)

[]

For the numeric solver it is useful to have scaled equations in order to deal with numbers with the same magnitude. Hence there are two options to scale the system, with equations_scaling the user can provide a list of the length of the dimension of the system, so that the \(i^{\textrm{th}}\) equation is divided by the \(i^{\textrm{th}}\) value of the list. With the option states_scaling the user specifies the characteristic dimension of the state variables. It is passed as a list of values [d_1, ... , d_n] so that the new scaled variable \(y_i\) is obtained by the non scaled variable \(x_i\) via the relation \(y_i=x_i/d_i\).

Continuation setup

options

type

default

continuation

list(list({[{string,symbol},string],symbol}=algebraic))

[]

The continuation option is very important and makes the difference between an easy convergence and the failure of the solver. It allows the user to start the solver with very smooth parameters and use this suboptimal solution as a guess for the solution of the problem with sharper parameters. This process is continued and automatically setup until there is convergence to the desired parameters. There two phases in the continuation process, the steps in which it is divided and the sequence of suboptimal problems. In the first phase you can divide into groups the parameters for which you want to apply the continuation, then, for each group you can create the sequence of suboptimal problems that start with smooth parameters and ends with the desired sharper value. Usually one step is enough for common OCPs. The syntax is like

continuation = [
  [ param1 = expr, param2 = expr, ... , paramN1 = expr], # step1
  [ param1 = expr, param2 = expr, ... , paramN2 = expr], # step2
           ...
  [ param1 = expr, param2 = expr, ... , paramNM = expr]  # stepM
]

where

param = symbol
param = [ "control/penalty name", "control/penalty parameter"]

As an example, see Example 4: Free Time and Interface Conditions, a pit stop, where, for example, it was set [“p”,”epsilon”] = epsi0 + s*(epsi1-epsi0). If you want a linear interpolation of the two values you can use the simplified version [“p”,”epsilon”] = [epsi0, epsi1]. Those two versions are exactly the same. Here p is the name of the control, epsilon is the parameter that will be initialised with the initial value of epsi0 for \(s=0\). If the optimal control problem is successfully solved with this value, a new value of \(\in[0,1]\) is automatically chosen in order to solve a new problem with a value of epsilon closer and closer to epsi1, which will be reached at the end of the continuation process. For an example with more than one continuation step, see the hang glider Hang Glider.

Code Generation

options

type

default

language

string

“C++”

simplifyExpression

boolean

false

codegenOptions

list

[]

excluded

list(string)

[]

output_directory

string

“../”

clean

boolean

true

This group of options allows to customise the way XOptima generates the code to be linked with Mechatronix. At the moment the only language implemented is C++, but Matlab will soon be ready. A good way to generate efficient and compact code is to enable the flag simplifyExpression which is by default disabled. The reason is that the simplification of long expressions in some problems can be very time consuming. The instruction excluded allows to create a list of files that will not overwritten if you regenerate the project in XOptima. This is a commodity if you use a custom Ruby script to run the project. Note that in general old files are overwritten by the command generateOCProblem if you do not disable the flag clean. Another option you have for file management is to set the folder of the output, with output_directory.

Compiler options

options

type

default

compiler_options

list(string={string,list(string)})

[]

external_libs

list(string)

[]

external_libs_paths

list(string)

[]

external_libs_include_paths

list(string)

[]

The user can give his own extras compiler options, such as external libraries, with their path, or header files.

Extra options

options

type

default

generate_for_lua

boolean

false

generate_BVP_only

boolean

false

show_graph_ordered_parameters

boolean

false

The flag generate_for_lua allows the generation of the project files in the lua format. In particular there will be an additional file in the folder Data, of the same nature of the file in Ruby. The option generate_BVP_only avoids the generation of the C++ code, this can be helpful if the user is interested to work with the optimal control problem directly inside Maple and is not interested in the numerical solution. show_graph_ordered_parameters creates in Maple a graph of the dependencies from the parameters.