Quickstart Guide

Note

This library is an extension for the RTC-Tools library. These instructions assume some basic familarity with RTC-Tools.

Even though rtc-tools-meta allows for powerful aggregation of rtc-tools models, the api is relatively simple. This is because it is able to reuse all of the configuration of the sub-models. This guide shows the steps to get rtc-tools-meta working for your models.

1. Inherit from MetaMixin

If you are familiar with the rtc-tools api, this one will come as no surprise to you. Every rtc-tools optimization problem that you want to link into your meta optimization problem must inherit from MetaMixin. Don’t worry, you can still run your models independently like normal even after you inherit from it- it only takes effect on your model while the meta optimization problem is running. You can inherit from MetaMixin like this:

from rtc_tools_meta.meta_mixin import MetaMixin  # First import the mixin

class MyOptimizationProblem(
    MetaMixin,
    # Other mixins (ModelicaMixin, etc.)
)

2. Define the MetaOptimizationProblem

This class contains all the guts for aggregation and deaggregation. We inherit from this class to build meta-model classes. Note that submodels may also be other MetaOptimizationProblem classes- just make sure you map the interfaces correctly. Here is how that is done.

First we get the dependencies imported:

 # Useful for specifying path to submodels
from pathlib import Path

# Needed to define meta_objective
import casadi as ca

# Our meta model inherits from this class
from rtc_tools_meta.meta_optimization_problem import MetaOptimizationProblem

# A handy function to make referencing submodels easy
from rtc_tools_meta.util import collect_model_instance

Next, we define a new class:

class ModelAB(MetaOptimizationProblem):
    """Meta Problem Optimizing ModelA and ModelB"""

The bulk of the meta optimization problem configuration is in defining the attributes submodels, variable_mappings, and meta_objective. Here are the details about what these should look like:

MetaOptimizationProblem.submodels

Dictionary of submodels

This variable is where we store the submodel instances. The models are indexed by a unique short name. For example:

# Meta Problem Optimizing ModelA and ModelB
submodels = {
    "ModelA": collect_model_instance('ModelA', path_to_a),
    "ModelB": collect_model_instance('ModelB', path_to_b),
}
Return type:Dict[str, OptimizationProblem]
MetaOptimizationProblem.variable_mappings

Mappings that constrain variables in separate submodels to be equal

To define how submodels interact with each other, we set variable_mappings equal to a list of 3-tuples. The 3-tuples have the structure (var1, var2, sign). For example:

# Meta Problem Optimizing ModelA and ModelB
variable_mappings = [
    (
        "ModelA::some_variable",
        "ModelB::another_variable",
        "-",  # Either "-" (if vars are equal) or "+" (if they sum to 0)
    )
]
Return type:List[Tuple[str, str, str]]
MetaOptimizationProblem.meta_objective()[source]

Symbolic expression to be minimized

For example, here is a quadratic minimization objective:

def meta_objective(self):
    return ca.sum1(self.states_in("ModelA::var_name")) ** 2.0
Return type:MX

3. Run your problem

Once everything is properly connected, just run the optimize() method of your highest level MetaOptimizationProblem class- the library will do the rest. When it completes, you can import the results of the submodels in their respective output folders. Here is an example of all the code together:

# Useful for specifying path to submodels
from pathlib import Path

# Needed to define meta_objective
import casadi as ca

# Our meta model inherits from this class
from rtc_tools_meta.meta_optimization_problem import MetaOptimizationProblem

# A handy function to make referencing submodels easy
from rtc_tools_meta.util import collect_model_instance


class ModelAB(MetaOptimizationProblem):
    """Meta Problem Optimizing ModelA and ModelB"""
    submodels = {
       "ModelA": collect_model_instance('ModelA', path_to_a),
       "ModelB": collect_model_instance('ModelB', path_to_b),
    }
    variable_mappings = [
       (
             "ModelA::some_variable",
             "ModelB::another_variable",
             "-",
       )
    ]

    def meta_objective(self):
       return ca.sum1(self.states_in("ModelA::var_name")) ** 2.0


if __name__ == "__main__":
   problem = ModelAB()
   problem.optimize()