Skip to content

Commit

Permalink
test test_short_term_storage_base_with_yaml added for components with…
Browse files Browse the repository at this point in the history
… timeseries
  • Loading branch information
vargastat committed Apr 23, 2024
1 parent 495a5c1 commit 7bf7637
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 2 deletions.
4 changes: 3 additions & 1 deletion src/andromede/study/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ def check_requirement(self, time: bool, scenario: bool) -> bool:


def load_ts_from_txt(file_ts: Optional[str]) -> pd.DataFrame:
path = Path(str(file_ts))
base_path = Path.cwd().resolve().parent / "data"
if file_ts is not None:
path = base_path / file_ts
try:
return pd.read_csv(path, header=None, sep="\s+")
except FileNotFoundError:
Expand Down
83 changes: 83 additions & 0 deletions tests/unittests/data/components_for_short_term_storage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Copyright (c) 2024, RTE (https://www.rte-france.com)
#
# See AUTHORS.txt
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# SPDX-License-Identifier: MPL-2.0
#
# This file is part of the Antares project.
study:
nodes:
- id: N
model: node

components:
- id: D
model: demand
parameters:
- name: demand
type: timeseries
timeseries: demand-ts.txt
- id: S
model: spillage
parameters:
- name: cost
type: constant
value: 1
- id: U
model: unsupplied
parameters:
- name: cost
type: constant
value: 10
- id: STS1
model: short-term-storage
parameters:
- name: p_max_injection
type: constant
value: 100
- name: p_max_withdrawal
type: constant
value: 50
- name: level_min
type: constant
value: 0
- name: level_max
type: constant
value: 1000
- name: inflows
type: constant
value: 0
- name: efficiency
type: constant
value: 0.8


connections:
- component1: N
port_1: injection_port
component2: D
port_2: injection_port

- component1: N
port_1: injection_port
component2: STS1
port_2: injection_port

- component1: N
port_1: injection_port
component2: U
port_2: injection_port

- component1: N
port_1: injection_port
component2: S
port_2: injection_port





10 changes: 10 additions & 0 deletions tests/unittests/data/demand-ts.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-18.0
1.6
1.6
1.6
1.6
1.6
1.6
1.6
1.6
1.6
33 changes: 33 additions & 0 deletions tests/unittests/data/lib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,39 @@ library:
binding-constraints:
- name: balance
expression: sum_connections(injection_port.flow) = 0
- id: spillage
description: A basic spillage model
parameters:
- name: cost
time-dependent: false
scenario-dependent: false
variables:
- name: spillage
lower-bound: 0
ports:
- name: injection_port
type: flow
port-field-definitions:
- port: injection_port
field: flow
definition: -spillage
- id: unsupplied
description: A basic unsupplied model
parameters:
- name: cost
time-dependent: false
scenario-dependent: false
variables:
- name: unsupplied_energy
lower-bound: 0
ports:
- name: injection_port
type: flow
port-field-definitions:
- port: injection_port
field: flow
definition: unsupplied_energy


- id: demand
description: A basic fixed demand model
Expand Down
68 changes: 67 additions & 1 deletion tests/unittests/study/test_components_parsing.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from pathlib import Path

import pandas as pd
import pytest

from andromede.model.parsing import InputLibrary, parse_yaml_library
from andromede.model.resolve_library import resolve_library
from andromede.simulation import TimeBlock, build_problem
from andromede.simulation import BlockBorderManagement, TimeBlock, build_problem
from andromede.study import TimeScenarioIndex, TimeScenarioSeriesData
from andromede.study.parsing import InputComponents, parse_yaml_components
from andromede.study.resolve_components import (
build_data_base,
Expand Down Expand Up @@ -76,3 +78,67 @@ def test_basic_balance_using_yaml(input_component, input_library) -> None:
status = problem.solver.Solve()
assert status == problem.solver.OPTIMAL
assert problem.solver.Objective().Value() == 3000


def generate_data_for_short_term_storage_test(scenarios: int) -> TimeScenarioSeriesData:
data = {}
horizon = 10
efficiency = 0.8
for scenario in range(scenarios):
for absolute_timestep in range(10):
if absolute_timestep == 0:
data[TimeScenarioIndex(absolute_timestep, scenario)] = -18
else:
data[TimeScenarioIndex(absolute_timestep, scenario)] = 2 * efficiency

values = [value for value in data.values()]
data_df = pd.DataFrame(values, columns=["Value"])
return TimeScenarioSeriesData(data_df)


def test_short_term_storage_base_with_yaml(data_dir: Path) -> None:
compo_file = data_dir / "components_for_short_term_storage.yml"
lib_file = data_dir / "lib.yml"

with lib_file.open() as lib:
input_library = parse_yaml_library(lib)

with compo_file.open() as c:
components_file = parse_yaml_components(c)
library = resolve_library(input_library)
components_input = resolve_components_and_cnx(components_file, library)
# 18 produced in the 1st time-step, then consumed 2 * efficiency in the rest
scenarios = 1
horizon = 10
time_blocks = [TimeBlock(0, list(range(horizon)))]

database = build_data_base(components_file)
network = build_network(components_input)

problem = build_problem(
network,
database,
time_blocks[0],
scenarios,
border_management=BlockBorderManagement.CYCLE,
)
status = problem.solver.Solve()

assert status == problem.solver.OPTIMAL

# The short-term storage should satisfy the load
# No spillage / unsupplied energy is expected
assert problem.solver.Objective().Value() == 0

count_variables = 0
for variable in problem.solver.variables():
if "injection" in variable.name():
count_variables += 1
assert 0 <= variable.solution_value() <= 100
elif "withdrawal" in variable.name():
count_variables += 1
assert 0 <= variable.solution_value() <= 50
elif "level" in variable.name():
count_variables += 1
assert 0 <= variable.solution_value() <= 1000
assert count_variables == 3 * horizon

0 comments on commit 7bf7637

Please sign in to comment.