SHOP YAML Standard#

Reading and writing#

Yaml-data can be read using the load_yaml function as shown below. The function can either read from a file or read a yaml string:

from pyshop import ShopSession

shop = ShopSession()
shop.load_yaml(file_path='basic_model.yaml')
shop.load_yaml(yaml_string='''
model:
  reservoir:
    Reservoir1:
      inflow:
        2018-01-23 00:00:00: 10.0
        2018-01-23 03:00:00: 15.0
''')

Similarly, the model can be dumped as a yaml file using the dump_yaml function. The function has four boolean options:

Option

Default

Description

input_only

True

Only write input data to file

compress_txy

True

Only print timeseries value for timestep if value has changed from previous timestep to keep file compact

compress_connection

True

Write connections on compressed format. Don’t write object type or connection type unless necessary to uniqely identify object/connection

output_only

False

Only write output data to file

shop.dump_yaml('basic_model_results.yaml', False, True, True)
'YAML case is dumped to the provided file path: "basic_model_results.yaml"'

YAML types#

In order to simplify descriptions of the SHOP YAML standard, we start off with defining a set of terms for referring to different YAML constructs.

Map#

Maps are one of the most common components for structuring data stored in YAML. They often appear in the upper levels of the documents and serve the purpose of dividing the data into smaller named subgroups/divisions. We will refer to them as “Maps”, but you should note that they are also often referred to as Dictionaries. Essentially, maps consist of a set of “key” and “value” pairs. Each key is said to “refer to” or “contain” a value. In this standard, keys will always be “strings”, i.e. one or more characters/words stringed together. Values, on the other hand, can contain a single scalar, a string or another structuring component like Map or List

Map example#

The following example is extracted from a real SHOP YAML case and contains three distict examples of YAML Maps. The upper level is a Map containing the keys “Reservoir1” and “Reservoir2”. Each key contains additional Maps with the keys “start_head”, “max_vol”, “lrl”, “hrl” and “vol_head”. Furthermore, the keys “vol_head” contains Maps with the keys “ref”, “x” and “y”.

Note that the key and value is separated by a “:”. The value may be written just after “: ”, which is the case for keys like “start_head”, “max_vol” and “ref”. For more complex values, it is common to add line breaks and indentation, as you can see keys like “Reservoir1”, “vol_head” and “x”.

Reservoir1:
  start_head: 92
  max_vol: 12
  lrl: 90
  hrl: 100
  vol_head:
    ref: 0
    x:
      - 0
      - 12
      - 14
    y:
      - 90
      - 100
      - 101
Reservoir2:
  start_head: 43
  max_vol: 5
  lrl: 40
  hrl: 50
  vol_head:
    ref: 0
    x:
      - 0
      - 5
      - 6
    y:
      - 40
      - 50
      - 51

List#

Lists are another common construct that can be used for structuring. Each value of a list, like the values of maps, can contain a scalar, a string or another structuring component like a Map or a List

List example#

The following example is extracted from a real SHOP YAML case and contains two distict examples of YAML Lists. The value of the “connections” key is a List of Maps and the value of the “commands” key is a List of strings.

Note that each element of the list is preceded by a “-” and for every new element, a line break is added. Also note that despite only having a single value, the value of “commands” is still formatted as a list. It is common to keep the List format when the list happens to have a single value, in order to simplify reading/loading the YAML.

connections:
  - from: Reservoir1
    to: Plant1
  - from: Plant1_G1
    to: Plant1
  - from: Plant1
    to: Reservoir2
  - from: Reservoir2
    to: Plant2
  - from: Plant2_G1
    to: Plant2
commands:
  - start sim 1

Scalar#

Scalars contain a single numeric value. In this standard, we deal with two different types of scalars, “integers” and “doubles”

Integer#

Some attributes expect integer values, that is, numbers without any fractional parts.

NOTE: Numbers written with decimal points are typically not accepted as integers even if the fractional part is 0

plant:
  Plant1:
    time_delay: 0     # "time_delay" is a Int attribute within SHOP
    ownership: 100    # NOTE: Ownership is a Double attribute within SHOP, YAML will typically omit ".0"

Double#

Some attributes expect double values, that is, numbers with fractional parts. Unlike the converse for integers, it is common to accept numbers written without decimal points as doubles.

All the numerical values in the following YAML will be interpreted as doubles by SHOP because they refer to attributes that only deal with double values. Note that the values with “.0” fractional parts have been encoded as integers.

Reservoir1:
  start_vol: 0
  start_head: 92.2
  max_vol: 12
  lrl: 90.5
  hrl: 100.5
  vol_head:
    ref: 0
    x:
      - 0
      - 12
      - 14
    y:
      - 90
      - 100
      - 101

String#

Strings are a common data type in programming and are essentially strings of characters/words. In YAML, strings can be written with or without quotes. Both “ and ‘ can be used as quotation marks, but you need to close the quote with the same quotation mark it was opened with.

Note that it is common to omit quotation unless they are needed to avoid ambiguity, which is the case for the vast majority of string. String representations of numbers is an example of a class of strings that do need quotation to retain their string nature

connections:
- from: Reservoir1
  to: Plant1
  from_type: reservoir
  to_type: plant
  connection_type: connection_standard
  order: 0
- from: "Plant1_G1"                      # Note: The original example dropped quotation for all strings
  to: 'Plant1'                           # And you would most likely not mix quotation types
  from_type: generator
  to_type: "plant"
  connection_type: 'connection_standard'
  order: 1

Timestamp#

A typical SHOP YAML case will typically contain many strings representing timestamps. Timestamps are used when setting optimization start and end time and the time index of every time series (TODO). Shop expects the format “YYYY-mm-dd HH-MM-ss”.

time:
  starttime: 2018-02-27 00:00:00    # Note: the time part can be omitted because it is 00:00:00
  endtime: 2018-02-28 00:00:00
  timeunit: hour
  timeresolution:
    2018-02-27 00:00:00: 1

SHOP YAML case#

SHOP YAML case consist of four different types of content.

YAML case :

  • time

  • model

  • connections

  • commands

There are currently two different ways of defining a YAML case :

  • Split up the data in 4 different files, named after the data they house, e.g. “time.yaml”

    • External python class is also capable of reading a ZipCase, which is these 4 files zipped together

  • Put everything in the same file/string, where the upper level is a Map with keys for the 4 different types of content

time#

The “time” part contains the optimization time definition. The upper level is a Map with the mandatory keys “starttime”, “endtime” and “timeunit”.

“starttime” and “endtime” both expect timestamp strings.

“timeunit” can be either “minute” or “hour”.

The upper level map of this can also have the optional key “timeresolution”. If present, “timeresolution” contains a Txy specifying the time resolution throughout the optimization time.

time example#

time:
  starttime: 2018-02-27 00:00:00
  endtime: 2018-02-28 00:00:00
  timeunit: hour
  timeresolution:
    2018-02-27 00:00:00: 1

model#

The “model” part defines all objects and attributes defined/set in the SHOP model as well as the values of the defined attributes. The upper three levels of this part are nested Maps.

The uppermost level, referred to as the “object type level”, is a map with keys for each object type present in the case.

The next level, referred to as the “object name level”, consists of a set of maps with keys for each distinct object in the case. So the uppermost level map might have a map under the key “reservoir”, which in turn have maps under “Reservoir1” and “Reservoir2”

The third level, referred to as the “attribute name level”, consists of a set of maps with keys for each defined attributes of its parent object in the case. So the second level map “Reservoir1”, under the uppermost key “reservoir”, might contain the keys “lrl”, “hrl” etc

At the fourth level, the structure and content is defined by the attribute type that is represented. Details can be found in SHOP attribute type formats.

model example#

The following example is based on a real SHOP YAML case where some attributes and objects have been omitted to give a better overview:

model:
  reservoir:
    Reservoir1:
      lrl: 90
      hrl: 100
      vol_head:
        ref: 0
        x:
          - 0
          - 12
          - 14
        y:
          - 90
          - 100
          - 101
      inflow:
        2018-02-27 00:00:00: 101
        2018-02-27 01:00:00: 50
    Reservoir2:
      lrl: 40
      hrl: 50
  plant:
    Plant1:
      less_distribution_eps: 0.001
      main_loss:
        - 0.0002
      penstock_loss:
        - 0.0001
    Plant2:
      less_distribution_eps: 0.001
      main_loss:
        - 0.0002
      penstock_loss:
        - 0.0001
  generator:
    Plant1_G1:
      p_min: 25
      p_max: 100
      p_nom: 100
      turb_eff_curves:
        - ref: 90
          x:
            - 25
            - 90
            - 100
          y:
            - 80
            - 95
            - 90
        - ref: 100
          x:
            - 25
            - 90
            - 100
          y:
            - 82
            - 98
            - 92
      startcost:
        2018-02-27 00:00:00: 500

connections#

The “connections” part contains information about how the objects in the case are connected. This content is made up of a List of Maps, where each map is a fully describes what SHOP needs to recreate the connection.

The full connection format is quite verbose, however, you can often omit specific information. See the table below for details

Keys

Mandatory

Situational Description

Description

“to”, “from”

Always

Always needed

Names of to/from objects respectively

“to_type”, “from_type”

Situational

Needed when object names are ambiguous. E.g. a plant and a generator has the same name

Types of to/from objects respectively

“connection_type”

Situational

Only needed when connecting a reservoir to a “spill” or “bypass” gate

Specification of connection type

“order”

Situational

Needed when connection order matters. Currently only needed for connections to junction or to junction_gate

Integer indicating connection order. “0” will be connected before “1”, “1” before “2” and so on

connections example#

The following example is constructed to illustrate the most relevant use-cases.

connections:
- from: Reservoir1                     # Verbose connection
  to: Plant1
  from_type: reservoir
  to_type: plant
  connection_type: connection_standard
  order: 0
  
- from: Reservoir2                     # Simplified connection: Requires non-ambiguos object names
  to: Plant2
  
- from: Reservoir3                     # Connections to Junctions require "order"
  to: Junction2
  order: 0
- from: Junction1
  to: Junction2
  order: 1
  
- from: Reservoir4                     # Spill and Bypass gates are defined by specifying "connection_type"
  to: Gate1
  connection_type: connection_spill

commands#

The “commands” part contains all SHOP commands executed in the case. The upper level of this file is a List of strings. The command format is identical to the one used in the SHOP executable (TODO).

commands example#

commands:
  - start sim 1 
  - set code /incremental
  - start sim 3

SHOP attribute type formats#

Each SHOP attribute has a designated “type”. The type is determined by how the attribute is used and specifies what kind of data is stored within the attribute. This section describes the format of the different SHOP attribute types when stored in YAML.

int#

Represented by a single integer. Remember to refrain from adding a decimal point.

plant:
  Plant1:
    time_delay: 0           # int attribute example

double#

Represented by a single double.

reservoir:
  Reservoir1:
    lrl: 90.2               # double attribute example

string#

Represented by a single string.

market:
  Market1:
    market_type: ENERGY     # string attribute example

int_array#

Represented by a List of Integers. Remember to refrain from adding a decimal points.

plant:
  Plant1:
    gen_priority:           # int_array attribute example
      - 1
      - 2

double_array#

Represented by a List of Doubles.

plant:
  Plant1:
    main_loss:              # double_array attribute example 
      - 0.0002

xy#

Represented by a Map with the mandatory keys “x”, “y” and “ref”.

Keys “x” and “y” both contain double_arrays.

“ref” contains a Double.

reservoir:
  Reservoir1:
    vol_head:               # xy attribute example
      ref: 0
      x:
        - 0
        - 12
        - 14
      y:
        - 90
        - 100
        - 101

xy_array#

Represented by a List of Xy.

plant:
  Plant1:
    turb_eff_curves:        # xy_array attribute example
      - ref: 90
        x:
          - 25
          - 90
          - 100
        y:
          - 80
          - 95
          - 90
      - ref: 100
        x:
          - 25
          - 90
          - 100
        y:
          - 82
          - 98
          - 92

txy#

Represented by a Map of Doubles. The keys are Timestamps and make out the time index

Note: A different format is required for multi-scenario txy, txy(stochastic)

reservoir:
  Reservoir1:
    inflow:                      # txy attribute example 
      2018-02-27 00:00:00: 101
      2018-02-27 01:00:00: 50

txy(stochastic)#

Represented by a Map of strings. The first key and value make out a “header”.

The first key is “ Scenario#”. The first value is not really important, but for the sake of clarity in the file you might want to use it to enumerate the scenarios. E.g. “ 1 2 3 4 5 6” if there are six scenarios.

The remaining keys are all Timestamps.

The remaining values are strings that can be split on whitespace and cast to double in order to get one value for each scenario.

market:
  Market1:
    sale_price:              # txy (stochastic) attribute example
      "         Scenario #": "    1    2    3    4    5    6    7    8    9   10   11   12"
      "2018-02-27 00:00:00": "   39   39   39   39   39   39   39   39   39   39   39   39"
      "2018-02-27 01:00:00": " 38.5   39 39.5   40 38.5   39 39.5   40 38.5   39 39.5   40"

xyt#

Represented by a List of Xy, but where the ref field is replaced with time that should be a Timestamps.

  average_level_rolling_ramping_up:
    - time: 2023-01-01 00:00:00
      x:
        - 360
        - 720
      y:
        - 0.04
        - 0.05
    - time: 2023-01-02 00:00:00
      x:
        - 1080
      y:
        - 0.03

sy#

Represented by a Map with the mandatory keys “s” and “y”. Keys “s” contain string_arrays and “y” contain double_arrays.

  busbar:
    Busbar1:
      ptdf:
        s:
          - AC_line1
          - AC_line2
          - AC_line3
        y:
          - 0.4
          - 0.6
          - 0.4