Implementing new OCP tools
This page explains how to implement new tools in CTModels that follow the AbstractOCPTool interface. Tools are configurable components such as backends, modelers, discretizers, or solvers that expose a common options API.
The interface is defined by the abstract type AbstractOCPTool and the helper functions in nlp/options_schema.jl.
Overview
All concrete tools T <: AbstractOCPTool are expected to:
- store their configuration in two fields
options_values::NamedTuple— effective option values.options_sources::NamedTuple— provenance for each option (:ct_defaultor:user).
- optionally describe their options via
_option_specs(::Type{T}), returning aNamedTupleofOptionSpecvalues. - provide a keyword-only constructor
T(; kwargs...)that uses_build_ocp_tool_optionsto validate and merge user-supplied keyword arguments with tool defaults.
High-level helpers such as get_option_value, get_option_source, get_option_default and show_options then work uniformly on any AbstractOCPTool subtype.
Defining a new tool type
Choose an abstract specialization
Depending on the role of your tool, you will typically subtype one of the following interfaces, all of which inherit from
AbstractOCPTool:AbstractOptimizationModelerfor OCP→NLP modelers (e.g.ADNLPModeler,ExaModeler).AbstractOptimizationSolver(from CTSolvers) for NLP solvers (e.g.IpoptSolver).AbstractOptimalControlDiscretizer(from CTSolvers) for OCP discretizers (e.g.Collocation).
Define the concrete struct
A minimal tool definition looks like:
struct MyTool{Vals,Srcs} <: AbstractOptimizationModeler options_values::Vals options_sources::Srcs endThe field names
options_valuesandoptions_sourcesare required by the generic helpers_options_valuesand_option_sources.
Describing options with OptionSpec
To expose metadata for your tool's options, specialize _option_specs(::Type{T}) on your concrete type. The function should return a NamedTuple whose fields are option names and whose values are OptionSpec instances.
function CTModels._option_specs(::Type{<:MyTool})
return (
tol = CTModels.OptionSpec(;
type = Real,
default = 1e-6,
description = "Optimality tolerance.",
),
max_iter = CTModels.OptionSpec(;
type = Integer,
default = 1000,
description = "Maximum number of iterations.",
),
)
endIf _option_specs returns missing for a tool type, then functions like options_keys and default_options will report that no metadata is available.
Implementing the constructor with _build_ocp_tool_options
The recommended pattern for constructing tools is to delegate keyword processing to _build_ocp_tool_options:
function MyTool(; kwargs...)
values, sources = CTModels._build_ocp_tool_options(
MyTool; kwargs..., strict_keys = true,
)
return MyTool{typeof(values),typeof(sources)}(values, sources)
endThis helper:
- normalizes
kwargsto aNamedTuple; - validates keys and types against
_option_specs(when available); - merges defaults from
default_optionswith user overrides (user wins); - builds the parallel
options_sourcesNamedTuple, marking each entry as:ct_defaultor:user.
Once defined, your tool automatically works with get_option_value, get_option_source, get_option_default and show_options.
Registering tools and assigning symbols
For some categories of tools, CTModels or CTSolvers maintain registries that map symbolic identifiers to concrete types. For example, modelers are registered in REGISTERED_MODELERS in nlp_backends.jl, and solvers and \discretizers are registered similarly in CTSolvers.
To integrate a new tool into such a registry, you typically:
Specialize
get_symbolon the tool type:CTModels.get_symbol(::Type{<:MyTool}) = :mytoolOptionally specialize
tool_package_nameto indicate which external package provides the implementation:CTModels.tool_package_name(::Type{<:MyTool}) = "MyBackendPackage"Add the tool type to the appropriate
REGISTERED_*constant and use the helper that builds a tool from a symbol (e.g.build_modeler_from_symbol(:mytool; kwargs...)).
Examples
ADNLPModeler (CTModels)
ADNLPModeler is a concrete AbstractOptimizationModeler that wraps ADNLPModels.jl:
- it subtypes
AbstractOptimizationModeler <: AbstractOCPTool; - it defines
options_valuesandoptions_sourcesfields; - it specializes
_option_specs(::Type{<:ADNLPModeler})to describe its options (show_time,backend, etc.); - it has a keyword-only constructor implemented via
_build_ocp_tool_options(ADNLPModeler; kwargs...).
Collocation (CTSolvers)
In CTSolvers, Collocation is a concrete discretizer implementing AbstractOptimalControlDiscretizer <: AbstractOCPTool:
- it stores
options_valuesandoptions_sources; - it defines
_option_specs(::Type{<:Collocation})with options such asgrid,lagrange_to_mayerandscheme; - its constructor
Collocation(; kwargs...) = Collocation{typeof(values.scheme)}(values, sources)is built on_build_ocp_tool_options(Collocation; ...).
These examples can be used as templates when adding new tools that follow the AbstractOCPTool interface.