Add a problem
To add a new problem to OptimalControlProblems, you must follow these steps:
1. Create a new file in the ext/MetaData directory with the name of your problem, containing the required information about the problem in a dictionary. For example, if your problem is called new_problem, create a file named new_problem.jl. The dictionary should follow the template:
new_problem_meta = OrderedDict(
:grid_size => 100, # Number of steps
:parameters => (
t0 = 0, # Value of the initial time
tf = 1, # Value of the final time
),
)For more details about the metadata, see the MetaData section.
2. Define the OptimalControl model of the problem in a file named new_problem.jl in the ext/OptimalControlModels directory, following the template:
Get inspiration from the already existing problems in OptimalControlProblems.jl/ext/OptimalControlModels. Especially if the final time is free.
"""
Documentation of the method
"""
function OptimalControlProblems.new_problem(
::OptimalControlBackend,
description::Symbol...;
grid_size::Int=grid_size_data(:new_problem),
parameters::Union{Nothing, NamedTuple}=nothing,
kwargs...,
)
# parameters
params = parameters_data(:beam, parameters)
t0 = params[:t0]
tf = params[:tf]
# model
@def ocp begin
t ∈ [t0, tf], time
...
end
# initial guess for the problem
init = ()
# discretise the optimal control problem
docp = direct_transcription(
ocp,
description...;
lagrange_to_mayer=false,
init=init,
grid_size=grid_size,
disc_method=:trapeze,
kwargs...,
)
return docp
end3. Define the scalarised OptimalControl model of the problem in a file named new_problem_s.jl in the ext/OptimalControlModels_s directory. This version is similar to the previous case but, as an example, replace the dynamics:
ẋ(t) == [x₂(t), u(t)]by
∂(x₁)(t) == x₂(t)
∂(x₂)(t) == u(t)The dynamics and the nonlinear constraints must be in scalar form. See the section Dynamics (coordinatewise) and the following section for more details.
4. Define the JuMP model of the problem in a file named new_problem.jl in the ext/JuMPModels directory, following the template:
"""
Documentation of the method
"""
function OptimalControlProblems.new_problem(
::JuMPBackend, args...;
grid_size::Int=grid_size_data(:new_problem),
parameters::Union{Nothing, NamedTuple}=nothing,
kwargs...
)
# parameters
params = parameters_data(:beam, parameters)
t0 = params[:t0]
tf = params[:tf]
# model
model = JuMP.Model(args...; kwargs...)
# metadata: required
model[:time_grid] = () -> range(t0, tf, grid_size+1) # tf is a fixed
model[:state_components] = ["x₁", "x₂"]
model[:costate_components] = ["∂x₁", "∂x₂"]
model[:control_components] = ["u"]
model[:variable_components] = String[] # no variable
# N = grid_size
@expression(model, N, grid_size)
# variables and initial guess
@variables(
model,
begin
x₁[0:N], (start = 0.5) # consistent with model[:state_components]
x₂[0:N], (start = 0.1) # consistent with model[:state_components]
u[0:N], (start = 0.1) # consistent with model[:control_components]
end
)
# @constraints, @objective...
return model
end- The metadata in JuMP are required and must be consistent with the other models.
- If
tfis free, then define:
model[:time_grid] = () -> range(t0, value(model[:tf]), grid_size+1) # tf is a freeGet inspiration from the already existing problems in OptimalControlProblems.jl/ext/JuMPModels. Especially if the final time is free.
5. Describe the problem in a file named new_problem.jl in the ext/Descriptions directory. Get inspiration from the already existing descriptions in OptimalControlProblems.jl/ext/Descriptions.