Basics of the model structure
In SpineOpt.jl, the model structure is generated based on the input data, allowing it to be used for a multitude of different problems. Here, we aim to provide you with a basic understanding of the SpineOpt.jl model and data structure, while the Entity Classes, Parameters, and Parameter Value Lists sections provide more in-depth explanations of each concept.
All the building blocks of a model are entities, and each entity belongs to one of the Entity Classes. Zero-dimensional entity classes, such as unit or node, hold the individual things in the model. Multidimensional entity classes, such as unit__to_node, combine two or more entity classes and define how their entities are related to each other. The dimensions of a multidimensional entity class are separated by a double underscore in its name. In the Spine DB editor, both kinds are shown in the Entity tree and created with Add entities....
Older versions of Spine Toolbox and SpineOpt called zero-dimensional entity classes object classes and multidimensional entity classes relationship classes. You may still come across these terms in older material.
Introduction to zero-dimensional entity classes
Essentially, zero-dimensional Entity Classes represent different types of entities that make up the model. For example, every power plant in the model is represented as an entity of the class unit, every power line as an entity of the class connection, and so forth. In order to add anything new to a model, a new entity has to be added to the desired entity class in the input data.
Each entity class has a very specific purpose in SpineOpt.jl, so understanding their differences is key. These can be roughly divided into three distinctive groups, namely Systemic entity classes, Structural entity classes, and Meta entity classes.
Systemic entity classes
As the name implies, systemic entity classes are used to describe the system to be modelled. Essentially, they define what you want to model. These include:
- connection handles the transfer of commodities between nodes.
- grid represents different networks where different commodities can be generated, consumed, transported, etc.
- node ensures the balance of the commodity flows, and can be used to store commodities as well.
- unit handles the generation and consumption of commodities.
Structural entity classes
Structural entity classes are used to define the temporal and stochastic structure of the modelled problem, as well as custom User Constraints and groups of investments. Unlike the above Systemic entity classes, the structural entity classes are more about how you want to model, instead of strictly what you want to model. These include:
- investment_group is a group of investments that need to be done together.
- stochastic_scenario represents a different forecast or another type of an alternative time period.
- stochastic_structure acts as a handle for a group of stochastic_scenarios with set properties.
- temporal_block defines a period of time with the desired temporal resolution.
- user_constraint is an optional custom constraint generated based on the input data.
Meta entity classes
Meta entity classes are used for defining things on the level of models or above, like output and even other models for problem decompositions. These include:
- model represents an individual model, grouping together all the things relevant for itself.
- output defines which Variables are output from the model.
- report groups together multiple output entities.
- settings holds internal SpineOpt settings, which normally do not need to be changed.
- stage defines an additional stage in the optimisation problem, see the Multi-Stage Optimisation Tutorial (experimental).
Introduction to multidimensional entity classes
While zero-dimensional entity classes define all the entities that make up a model, multidimensional Entity Classes define how those entities are related to each other. Thus, they hold no meaning on their own, and always include at least one zero-dimensional entity class.
Similar to zero-dimensional entity classes, each multidimensional entity class has a very specific purpose in SpineOpt.jl, and understanding the purpose of each one is paramount. The multidimensional entity classes can be roughly divided into Systemic multidimensional entity classes, Structural multidimensional entity classes, and Meta multidimensional entity classes, again similar to the zero-dimensional ones.
Systemic multidimensional entity classes
Systemic multidimensional entity classes define how Systemic entity classes are related to each other, thus helping define the system to be modelled. Most of these deal with which units and connections interact with which nodes, and how those interactions work. This essentially defines the possible commodity flows to be modelled. Systemic multidimensional entity classes include:
- connection__from_node defines which node the connection can transfer a commodity from.
- connection__to_node defines which node the connection can transfer a commodity to.
- connection__node__node holds Parameters for connections between two nodes.
- node__grid defines which node is part of which grid.
- node__node holds parameters for direct node-node interactions, like diffusion of commodities.
- node__to_unit defines which node the unit can take an input commodity from.
- unit__to_node defines which node the unit can output a commodity to.
- unit_flow is a superclass of node__to_unit and unit__to_node, i.e. it covers the flows in both directions. It is used as a dimension in other entity classes, such as unit_flow__unit_flow.
- unit_flow__unit_flow defines parameters between node__to_unit and unit__to_node flows.
Structural multidimensional entity classes
Structural multidimensional entity classes primarily relate Structural entity classes to Systemic entity classes, defining what structures the individual parts of the system use. These are mostly used to determine the temporal and stochastic structures to be used in different parts of the modelled system, or custom User Constraints.
SpineOpt.jl has a very flexible temporal and stochastic structure, explained in detail in the Temporal Framework and Stochastic Framework sections of the documentation. Unfortunately, this flexibility requires quite a few different structural multidimensional entity classes, the most important of which are the following:
- node__stochastic_structure defines the stochastic_structure used for the node balance.
- node__temporal_block defines the temporal_blocks used for the node balance.
- parent_stochastic_scenario__child_stochastic_scenario defines the stochastic directed acyclic graph (DAG) of the Stochastic Framework.
- stochastic_structure__stochastic_scenario holds parameters for stochastic_scenarios in the stochastic_structure.
- units_on__stochastic_structure defines the stochastic_structure used for the online variable of the unit.
- units_on__temporal_block defines the temporal_blocks used for the online variable of the unit.
Furthermore, there are also a number of advanced structural multidimensional entity classes, which are only necessary when using some of the optional features of SpineOpt.jl. For Investment Optimization, the following control the stochastic and temporal structures of the investment variables:
- connection__investment_stochastic_structure defines the stochastic_structure used for the investment Variables for the connection.
- connection__investment_temporal_block defines the temporal_blocks used for the investment Variables for the connection.
- node__investment_stochastic_structure defines the stochastic_structure used for the investment Variables for the node.
- node__investment_temporal_block defines the temporal_blocks used for the investment Variables for the node.
- unit__investment_stochastic_structure defines the stochastic_structure used for the investment Variables for the unit.
- unit__investment_temporal_block defines the temporal_blocks used for the investment Variables for the unit.
The following define which investments belong to an investment_group:
- connection__investment_group defines a connection that belongs in an investment_group.
- node__investment_group defines a node that belongs in an investment_group.
- unit__investment_group defines a unit that belongs in an investment_group.
- connection__from_node__investment_group and connection__to_node__investment_group define a flow on a connection whose capacity is counted in the capacity invested available of an investment_group.
- unit_flow__investment_group defines a flow on a unit whose capacity is counted in the capacity invested available of an investment_group.
For User Constraints, which are essentially generic data-driven custom constraints, the following are used to control which variables are included and with what coefficients:
- connection__from_node__user_constraint holds Parameters for the connection_flow variable from the node in question in the custom user_constraint.
- connection__to_node__user_constraint holds Parameters for the connection_flow variable to the node in question in the custom user_constraint.
- connection__user_constraint holds Parameters for the investment Variables of the connection in the custom user_constraint.
- node__user_constraint holds Parameters for the node_state variable or the demand of the node in the custom user_constraint.
- unit__user_constraint holds Parameters for the unit commitment Variables of the unit in the custom user_constraint.
- unit_flow__user_constraint holds Parameters for the unit_flow variable in the custom user_constraint.
Meta multidimensional entity classes
Meta multidimensional entity classes are used for defining model-level settings, like which temporal_blocks or stochastic_structures are active, and what the model output is. These include:
- model__default_investment_stochastic_structure defines a default stochastic_structure to be used for investment Variables when no other definitions exist.
- model__default_investment_temporal_block defines a default temporal_block to be used for investment Variables when no other definitions exist.
- model__default_stochastic_structure defines a default stochastic_structure to be used for nodes and units when no other definitions exist.
- model__default_temporal_block defines a default temporal_block to be used for nodes and units when no other definitions exist.
- model__report connects each report to the desired model.
- report__output defines which outputs are part of which report.
For the experimental multi-stage optimisation (see the Multi-Stage Optimisation Tutorial):
- stage__child_stage defines a parent-child relationship between two stages.
- stage__output defines an output that a stage fixes for all entities in all its children.
- stage__output__connection, stage__output__node and stage__output__unit define an output that a stage fixes for a specific connection, node or unit in all its children.
Introduction to parameters
While the primary function of Entity Classes is to define the system to be modelled and its structure, Parameters exist to constrain them. Every parameter is attributed to at least one entity class, but some appear in many classes whenever they serve a similar purpose.
Parameters accept different types of values depending on their purpose, e.g. whether they act as a flag for some specific functionality or appear as a coefficient in Constraints, so understanding each parameter is key. Most coefficient-type Parameters accept constant, time series, and even stochastic time series form input, but there are some exceptions. Most flag-type Parameters, on the other hand, have a restricted list of acceptable values defined by their Parameter Value Lists.
The existence of some Constraints is controlled based on if the relevant Parameters are defined. As a rule-of-thumb, a constraint only gets generated if at least one of the Parameters appearing in it is defined, but one should refer to the appropriate Constraints and Parameters sections when in doubt.
Introduction to groups of entities
Groups of entities are used within SpineOpt for different purposes. To create a group of entities, simply right-click the corresponding entity class in the Entity tree of the Spine DB editor and select Add entity group.... Groups are essentially special entities, that act as a single handle for all of their members.
On the one hand, groups can be used in order to impose constraints on the aggregation of a variable, e.g. on the sum of multiple unit_flow variables. Constraints based on parameters associated with the unit_flow__unit_flow, unit__to_node, node__to_unit, connection__node__node, connection__to_node, connection__from_node can generally be used for this kind of flow aggregation by defining the parameters on groups of entities, typically node groups. (with the exception of variable fixing parameters, e.g. flow_limits_fix etc.). See for instance constraint_unit_flow_capacity.
On the other hand, a node group can be used for PTDF based powerflows. Here a node group is used to enforce a nodal balance on system level, while suppressing the node balances at individual nodes. See also balance_type and the node balance constraint.