Basics

class rtctools.optimization.timeseries.Timeseries(times: ndarray, values: float | ndarray | list | DM)[source]

Bases: object

Time series object, bundling time stamps with values.

__init__(times: ndarray, values: float | ndarray | list | DM)[source]

Create a new time series object.

Parameters:
  • times – Iterable of time stamps.

  • values – Iterable of values.

property times: ndarray

Array of time stamps.

property values: ndarray

Array of values.

class rtctools.optimization.optimization_problem.OptimizationProblem(**kwargs)[source]

Bases: DataStoreAccessor

Base class for all optimization problems.

bounds() AliasDict[str, Tuple[float | ndarray | Timeseries, float | ndarray | Timeseries]][source]

Returns variable bounds as a dictionary mapping variable names to a pair of bounds. A bound may be a constant, or a time series.

Returns:

A dictionary of variable names and (upper, lower) bound pairs. The bounds may be numbers or Timeseries objects.

Example:

def bounds(self):
    return {'x': (1.0, 2.0), 'y': (2.0, 3.0)}
constant_inputs(ensemble_member: int) AliasDict[str, Timeseries][source]

Returns a dictionary of constant inputs.

Parameters:

ensemble_member – The ensemble member index.

Returns:

A dictionary of constant input names and time series.

constraints(ensemble_member: int) List[Tuple[MX, float | ndarray, float | ndarray]][source]

Returns a list of constraints for the given ensemble member.

Call OptimizationProblem.state_at() to return a symbol representing a model variable at a given time.

Parameters:

ensemble_member – The ensemble member index.

Returns:

A list of triples (f, m, M), with an MX object representing the constraint function f, lower bound m, and upper bound M. The bounds must be numbers.

Example:

def constraints(self, ensemble_member):
    t = 1.0
    constraint1 = (
        2 * self.state_at('x', t, ensemble_member),
        2.0, 4.0)
    constraint2 = (
        self.state_at('x', t, ensemble_member) + self.state_at('y', t, ensemble_member),
        2.0, 3.0)
    return [constraint1, constraint2]
control(variable: str) MX[source]

Returns an MX symbol for the given control input, not bound to any time.

Parameters:

variable – Variable name.

Returns:

MX symbol for given control input.

Raises:

KeyError

abstract control_at(variable: str, t: float, ensemble_member: int = 0, scaled: bool = False) MX[source]

Returns an MX symbol representing the given control input at the given time.

Parameters:
  • variable – Variable name.

  • t – Time.

  • ensemble_member – The ensemble member index.

  • scaled – True to return the scaled variable.

Returns:

MX symbol representing the control input at the given time.

Raises:

KeyError

delayed_feedback() List[Tuple[str, str, float]][source]

Returns the delayed feedback mappings. These are given as a list of triples \((x, y, \tau)\), to indicate that \(y = x(t - \tau)\).

Returns:

A list of triples.

Example:

def delayed_feedback(self):
    fb1 = ['x', 'y', 0.1]
    fb2 = ['x', 'z', 0.2]
    return [fb1, fb2]
abstract der(variable: str) MX[source]

Returns an MX symbol for the time derivative given state, not bound to any time.

Parameters:

variable – Variable name.

Returns:

MX symbol for given state.

Raises:

KeyError

abstract der_at(variable: str, t: float, ensemble_member: int = 0) MX[source]

Returns an expression for the time derivative of the specified variable at time t.

Parameters:
  • variable – Variable name.

  • t – Time.

  • ensemble_member – The ensemble member index.

Returns:

MX object representing the derivative.

Raises:

KeyError

ensemble_member_probability(ensemble_member: int) float[source]

The probability of an ensemble member occurring.

Parameters:

ensemble_member – The ensemble member index.

Returns:

The probability of an ensemble member occurring.

Raises:

IndexError

property ensemble_size: int

The number of ensemble members.

get_timeseries(variable: str, ensemble_member: int = 0) Timeseries[source]

Looks up a timeseries from the internal data store.

Parameters:
  • variable – Variable name.

  • ensemble_member – The ensemble member index.

Returns:

The requested time series.

Return type:

Timeseries

Raises:

KeyError

history(ensemble_member: int) AliasDict[str, Timeseries][source]

Returns the state history.

Parameters:

ensemble_member – The ensemble member index.

Returns:

A dictionary of variable names and historical time series (up to and including t0).

property initial_time: float

The initial time in seconds.

abstract integral(variable: str, t0: float = None, tf: float = None, ensemble_member: int = 0) MX[source]

Returns an expression for the integral over the interval [t0, tf].

Parameters:
  • variable – Variable name.

  • t0 – Left bound of interval. If equal to None, the initial time is used.

  • tf – Right bound of interval. If equal to None, the final time is used.

  • ensemble_member – The ensemble member index.

Returns:

MX object representing the integral.

Raises:

KeyError

interpolate(t: float | ndarray, ts: ndarray, fs: ndarray, f_left: float = nan, f_right: float = nan, mode: int = 0) float | ndarray[source]

Linear interpolation over time.

Parameters:
  • t (float or vector of floats) – Time at which to evaluate the interpolant.

  • ts (numpy array) – Time stamps.

  • fs – Function values at time stamps ts.

  • f_left – Function value left of leftmost time stamp.

  • f_right – Function value right of rightmost time stamp.

  • mode – Interpolation mode.

Returns:

The interpolated value.

lookup_tables(ensemble_member: int) AliasDict[str, LookupTable][source]

Returns a dictionary of lookup tables.

Parameters:

ensemble_member – The ensemble member index.

Returns:

A dictionary of variable names and lookup tables.

static merge_bounds(a: Tuple[float | ndarray | Timeseries, float | ndarray | Timeseries], b: Tuple[float | ndarray | Timeseries, float | ndarray | Timeseries]) Tuple[float | ndarray | Timeseries, float | ndarray | Timeseries][source]

Returns a pair of bounds which is the intersection of the two pairs of bounds given as input.

Parameters:
  • a – First pair (upper, lower) bounds

  • b – Second pair (upper, lower) bounds

Returns:

A pair of (upper, lower) bounds which is the intersection of the two input bounds.

objective(ensemble_member: int) MX[source]

The objective function for the given ensemble member.

Call OptimizationProblem.state_at() to return a symbol representing a model variable at a given time.

Parameters:

ensemble_member – The ensemble member index.

Returns:

An MX object representing the objective function.

Example:

def objective(self, ensemble_member):
    # Return value of state 'x' at final time:
    times = self.times()
    return self.state_at('x', times[-1], ensemble_member)
optimize(preprocessing: bool = True, postprocessing: bool = True, log_solver_failure_as_error: bool = True) bool[source]

Perform one initialize-transcribe-solve-finalize cycle.

Parameters:
  • preprocessing – True to enable a call to pre preceding the optimization.

  • postprocessing – True to enable a call to post following the optimization.

Returns:

True on success.

parameters(ensemble_member: int) AliasDict[str, bool | int | float | MX][source]

Returns a dictionary of parameters.

Parameters:

ensemble_member – The ensemble member index.

Returns:

A dictionary of parameter names and values.

path_constraints(ensemble_member: int) List[Tuple[MX, float | ndarray, float | ndarray]][source]

Returns a list of path constraints.

Path constraints apply to all times and ensemble members simultaneously. Call OptimizationProblem.state() to return a time- and ensemble-member-independent symbol representing a model variable.

Parameters:

ensemble_member – The ensemble member index. This index may only be used to supply member-dependent bounds.

Returns:

A list of triples (f, m, M), with an MX object representing the path constraint function f, lower bound m, and upper bound M. The bounds may be numbers or Timeseries objects.

Example:

def path_constraints(self, ensemble_member):
    # 2 * x must lie between 2 and 4 for every time instance.
    path_constraint1 = (2 * self.state('x'), 2.0, 4.0)
    # x + y must lie between 2 and 3 for every time instance
    path_constraint2 = (self.state('x') + self.state('y'), 2.0, 3.0)
    return [path_constraint1, path_constraint2]
path_objective(ensemble_member: int) MX[source]

Returns a path objective the given ensemble member.

Path objectives apply to all times and ensemble members simultaneously. Call OptimizationProblem.state() to return a time- and ensemble-member-independent symbol representing a model variable.

Parameters:

ensemble_member – The ensemble member index. This index is currently unused, and here for future use only.

Returns:

A MX object representing the path objective.

Example:

def path_objective(self, ensemble_member):
    # Minimize x(t) for all t
    return self.state('x')
post() None[source]

Postprocessing logic is performed here.

pre() None[source]

Preprocessing logic is performed here.

seed(ensemble_member: int) AliasDict[str, float | Timeseries][source]

Seeding data. The optimization algorithm is seeded with the data returned by this method.

Parameters:

ensemble_member – The ensemble member index.

Returns:

A dictionary of variable names and seed time series.

set_timeseries(variable: str, timeseries: Timeseries, ensemble_member: int = 0, output: bool = True, check_consistency: bool = True) None[source]

Sets a timeseries in the internal data store.

Parameters:
  • variable – Variable name.

  • timeseries (iterable of floats, or Timeseries) – Time series data.

  • ensemble_member – The ensemble member index.

  • output – Whether to include this time series in output data files.

  • check_consistency – Whether to check consistency between the time stamps on the new timeseries object and any existing time stamps.

solver_options() Dict[str, str | int | float | bool][source]

Returns a dictionary of CasADi optimization problem solver options.

The default solver for continuous problems is Ipopt.

The default solver for mixed integer problems is Bonmin.

Returns:

A dictionary of solver options. See the CasADi and respective solver documentation for details.

solver_success(solver_stats: Dict[str, str | bool], log_solver_failure_as_error: bool) Tuple[bool, int][source]

Translates the returned solver statistics into a boolean and log level to indicate whether the solve was succesful, and how to log it.

Parameters:
  • solver_stats – Dictionary containing information about the solver status. See explanation below.

  • log_solver_failure_as_error – Indicates whether a solve failure Should be logged as an error or info message.

solver_stats typically consist of three fields:

  • return_status: str

  • secondary_return_status: str

  • success: bool

By default we rely on CasADi’s interpretation of the return_status (and secondary status) to the success variable, with an exception for IPOPT (see below).

The logging level is typically logging.INFO for success, and logging.ERROR for failure. Only for IPOPT an exception is made for Not_Enough_Degrees_Of_Freedom, which returns logging.WARNING instead. For example, this can happen when too many goals are specified, and lower priority goals cannot improve further on the current result.

Returns:

A tuple indicating whether or not the solver has succeeded, and what level to log it with.

state(variable: str) MX[source]

Returns an MX symbol for the given state, not bound to any time.

Parameters:

variable – Variable name.

Returns:

MX symbol for given state.

Raises:

KeyError

abstract state_at(variable: str, t: float, ensemble_member: int = 0, scaled: bool = False) MX[source]

Returns an MX symbol representing the given variable at the given time.

Parameters:
  • variable – Variable name.

  • t – Time.

  • ensemble_member – The ensemble member index.

  • scaled – True to return the scaled variable.

Returns:

MX symbol representing the state at the given time.

Raises:

KeyError

abstract states_in(variable: str, t0: float = None, tf: float = None, ensemble_member: int = 0) Iterator[MX][source]

Iterates over symbols for states in the interval [t0, tf].

Parameters:
  • variable – Variable name.

  • t0 – Left bound of interval. If equal to None, the initial time is used.

  • tf – Right bound of interval. If equal to None, the final time is used.

  • ensemble_member – The ensemble member index.

Raises:

KeyError

timeseries_at(variable: str, t: float, ensemble_member: int = 0) float[source]

Return the value of a time series at the given time.

Parameters:
  • variable – Variable name.

  • t – Time.

  • ensemble_member – The ensemble member index.

Returns:

The interpolated value of the time series.

Raises:

KeyError

rtctools.util.run_optimization_problem(optimization_problem_class, base_folder='..', log_level=20, profile=False, **kwargs)[source]

Sets up and solves an optimization problem.

This function makes the following assumptions:

  1. That the base_folder contains subfolders input, output, and model, containing input data, output data, and the model, respectively.

  2. When using CSVLookupTableMixin, that the base folder contains a subfolder lookup_tables.

  3. When using ModelicaMixin, that the base folder contains a subfolder model.

  4. When using ModelicaMixin, that the toplevel Modelica model name equals the class name.

Parameters:
  • optimization_problem_class – Optimization problem class to solve.

  • base_folder – Base folder.

  • log_level – The log level to use.

  • profile – Whether or not to enable profiling.

Returns:

OptimizationProblem instance.