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.