Skip to content

Commit

Permalink
Merge branch 'develop' into feature/csv-data-series
Browse files Browse the repository at this point in the history
  • Loading branch information
pet-mit authored Feb 11, 2025
2 parents c3acb55 + 9d7593e commit 46b5502
Show file tree
Hide file tree
Showing 15 changed files with 162 additions and 33 deletions.
3 changes: 2 additions & 1 deletion src/solver/modeler/loadFiles/readLibraries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ static Study::SystemModel::Library loadSingleLibrary(const fs::path& filePath)
}
catch (const std::runtime_error& e)
{
logs.error() << "Error while converting this library yaml: " << filePath;
logs.error() << "Error while converting this library yaml: " << filePath << ": "
<< e.what();
throw ErrorLoadingYaml(e.what());
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/solver/modeler/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,9 @@ int main(int argc, const char** argv)
case MipStatus::FEASIBLE:
if (!parameters.noOutput)
{
logs.info() << "Writing variables...";
logs.info() << "Writing objective & variable values...";
std::ofstream sol_out(outputPath / "solution.csv");
sol_out << "objective " << solution->getObjectiveValue() << std::endl;
for (const auto& [name, value]: solution->getOptimalValues())
{
sol_out << name << " " << value << std::endl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ struct VCardLOLD
//! Indentation (GUI)
static constexpr uint8_t nodeDepthForGUI = +0;
//! Decimal precision
static constexpr uint8_t decimal = 2;
static constexpr uint8_t decimal = 4;
//! Number of columns used by the variable (One ResultsType per column)
static constexpr int columnCount = 1;
//! The Spatial aggregation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ struct VCardLOLD_CSR
//! Indentation (GUI)
static constexpr uint8_t nodeDepthForGUI = +0;
//! Decimal precision
static constexpr uint8_t decimal = 2;
static constexpr uint8_t decimal = 4;
//! Number of columns used by the variable (One ResultsType per column)
static constexpr int columnCount = 1;
//! The Spatial aggregation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ struct VCardPrice
//! Indentation (GUI)
static constexpr uint8_t nodeDepthForGUI = +0;
//! Decimal precision
static constexpr uint8_t decimal = 2;
static constexpr uint8_t decimal = 4;
//! Number of columns used by the variable (One ResultsType per column)
static constexpr int columnCount = 1;
//! The Spatial aggregation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ struct VCardPriceCSR
//! Indentation (GUI)
static constexpr uint8_t nodeDepthForGUI = +0;
//! Decimal precision
static constexpr uint8_t decimal = 2;
static constexpr uint8_t decimal = 4;
//! Number of columns used by the variable (One ResultsType per column)
static constexpr int columnCount = 1;
//! The Spatial aggregation
Expand Down
49 changes: 28 additions & 21 deletions src/tests/cucumber/features/modeler-features/epic2/us2.5.feature
Original file line number Diff line number Diff line change
@@ -1,36 +1,43 @@
Feature: 2.5 - Pure modeler simple studies, with no ports and no timeseries

Scenario: 2.5.1: One model with one load and two generators, one timestamp
Scenario: 2.5.1: One model with one load and two generators, one timestep
Given the study path is "modeler/epic2/us2.5/study_2.5.1"
When I run antares modeler
Then the simulation succeeds
And the objective value is 160
And the optimal value of variable node1.gen1_p_0 is 80
And the optimal value of variable node1.gen2_p_0 is 20

Scenario: 2.5.2: One model with one load and two generators (minP), three timestamps
Scenario: 2.5.2: One model with one load and two generators (minP), three timesteps
Given the study path is "modeler/epic2/us2.5/study_2.5.2"
When I run antares modeler
Then the simulation succeeds
And the optimal value of variable node1.gen1_up_0 is 1
And the optimal value of variable node1.gen1_up_1 is 1
And the optimal value of variable node1.gen1_up_2 is 1
And the optimal value of variable node1.gen1_p_0 is 60
And the optimal value of variable node1.gen1_p_1 is 60
And the optimal value of variable node1.gen1_p_2 is 60
And the optimal value of variable node1.gen2_up_0 is 1
And the optimal value of variable node1.gen2_up_1 is 1
And the optimal value of variable node1.gen2_up_2 is 1
And the optimal value of variable node1.gen2_p_0 is 40
And the optimal value of variable node1.gen2_p_1 is 40
And the optimal value of variable node1.gen2_p_2 is 40
And the objective value is 810
And the optimal values of the variables are
| component | variable | timestep | value |
| node1 | gen1_up | 0-2 | 1 |
| node1 | gen1_p | 0-2 | 60 |
| node1 | gen1_up | 0-2 | 1 |
| node1 | gen2_p | 0-2 | 40 |

Scenario: 2.5.3: Two libs, one timestamp
Scenario: 2.5.3: Two libs, one timestep
Given the study path is "modeler/epic2/us2.5/study_2.5.3"
When I run antares modeler
Then the simulation succeeds
And the optimal value of variable node1.gen1_p_0 is 0
And the optimal value of variable node1.gen2_p_0 is 100
And the optimal value of variable node2.gen1_p_0 is 500
And the optimal value of variable node2.gen1_up_0 is 1
And the optimal value of variable node2.gen2_p_0 is 500
And the optimal value of variable node2.gen2_up_0 is 1
And the objective value is 15600
And the optimal values of the variables are
| component | variable | timestep | value |
| node1 | gen1_p | 0 | 0 |
| node1 | gen2_p | 0 | 100 |
| node2 | gen1_p | 0 | 500 |
| node2 | gen1_up | 0 | 1 |
| node2 | gen2_p | 0 | 500 |
| node2 | gen2_up | 0 | 1 |

Scenario: 2.5.4: Test with integer variable
Given the study path is "modeler/epic2/us2.5/study_2.5.4"
When I run antares modeler
Then the simulation succeeds
And the objective value is 540
And the optimal value of variable node1.gen_total_p_0 is 1000
And the optimal value of variable node1.gen_n_on_0 is 4
20 changes: 17 additions & 3 deletions src/tests/cucumber/features/steps/common_steps/steps.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
import pathlib

from behave import *

from common_steps.assertions import *
from common_steps.simulator_utils import run_simulation
from common_steps.modeler_utils import run_modeler
from common_steps.simulator_utils import run_simulation

from features.steps.common_steps.assertions import assert_double_close

Expand Down Expand Up @@ -133,4 +132,19 @@ def run_antares_modeler(context):

@step('the optimal value of variable {var} is {value:g}')
def modeler_var_optimal_value(context, var, value):
assert_double_close(value, context.moh.get_optimal_value(var), 1e-6)
assert_double_close(value, context.moh.get_optimal_value(var), 1e-6)


@step('the objective value is {value:g}')
def modeler_obj_value(context, value):
assert_double_close(value, context.moh.get_optimal_value("objective"), 1e-6)

@step('the optimal values of the variables are')
def modeler_var_optimal_value(context):
for row in context.table:
ts_array = row["timestep"].split("-")
ts_start = int(ts_array[0])
ts_end = int(ts_array[1]) if len(ts_array) == 2 else ts_start
for ts in range(ts_start, ts_end + 1):
var_id = row["component"] + "." + row["variable"] + "_" + str(ts)
assert_double_close(float(row["value"]), context.moh.get_optimal_value(var_id), 1e-6)
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
system:
id: sys_example1
description: test system
description: one load of 100 MW, one cheap generator gen1 (max_p=80 MW, cost=0.5€/MWh), one expensive generator gen2
(max_p=200 MW, cost=6€/MWh). Thus, gen1 must be used fully (80) and gen2 must complete (20), objective=80*0.5+20*6=160
model-libraries: lib_example1

components:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
system:
id: sys_example2
description: test system
description: one load of 100 MW, one cheap generator gen1 (max_p=80 MW, cost=0.5€/MWh), one expensive generator gen2
(min_p=40 MW, cost=6€/MWh). Thus, gen1 does not suffice, gen2 must be used at its min_p (40), and gen_1 must complete
(60); on the 3 timestamps. Objective = 3 * (60 * 0.5 + 40 * 6) = 810
model-libraries: lib_example2

components:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
system:
id: sys_example3
description: test system
description: in node1, gen is enough to fulfill load and is less expensive than gen1; thus gen1 must not be used (0)
and gen2 must be used at load level (100). Objective = 100 * 6 = 600 for node1.
In node2, load is 1000 MW and gen1 is cheap but not enough (max_p=650, cost=10€/MWh), and gen2 is large but more
expensive (min_p=500, cost=20 €/MWh). Thus gen2 must be used at its minimum power (500) and gen1 should complete
(500). Objective = 500 * 10 + 500 * 20 = 15000 for node2.
Total objective = 15600 for both nodes.
model-libraries: lib_example1, lib_example2

components:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
library:
id: lib_example3
description: test model library

models:
- id: node_genCluster_oneLoad
description: A simple node with a generator cluster and one load, to test integer variables
parameters:
- id: load
time-dependent: false
scenario-dependent: false
- id: gen_max_p
time-dependent: false
scenario-dependent: false
- id: gen_min_p
time-dependent: false
scenario-dependent: false
- id: gen_cluster_size
time-dependent: false
scenario-dependent: false
- id: gen_prop_cost
time-dependent: false
scenario-dependent: false
- id: gen_fixed_cost
time-dependent: false
scenario-dependent: false
variables:
- id: gen_total_p
lower-bound: 0
upper-bound: gen_max_p * gen_cluster_size
variable-type: continuous
- id: gen_n_on
lower-bound: 0
upper-bound: gen_cluster_size
variable-type: integer
constraints:
- id: respect_min_p
expression: gen_total_p >= gen_n_on * gen_min_p
- id: respect_max_p
expression: gen_total_p <= gen_n_on * gen_max_p
- id: balance
expression: gen_total_p = load
objective: gen_total_p * gen_prop_cost + gen_n_on * gen_fixed_cost
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
system:
id: sys_example4
description: a node with up to 10 similar generators (min_p=150, max_p=300, cost = 0.5 €/MWh + 10€/hour of up time).
Load is of 1000MW; thus 4 generators should be used. Objective = 1000*0.5 + 4*10 = 540.
model-libraries: lib_example3

components:
- id: node1
model: lib_example3.node_genCluster_oneLoad
scenario-group: sg
parameters:
- id: load
type: constant
value: 1000
- id: gen_min_p
type: constant
value: 150
- id: gen_max_p
type: constant
value: 300
- id: gen_cluster_size
type: constant
value: 10
- id: gen_prop_cost
type: constant
value: 0.5
- id: gen_fixed_cost
type: constant
value: 10
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
\ Generated by MPModelProtoExporter
\ Name :
\ Format : Free
\ Constraints : 3
\ Variables : 2
\ Binary : 0
\ Integer : 1
\ Continuous : 1
Minimize
Obj: +10 node1.gen_n_on_0 +0.5 node1.gen_total_p_0
Subject to
node1.balance_0: +1 node1.gen_total_p_0 = 1000
node1.respect_max_p_0: -300 node1.gen_n_on_0 +1 node1.gen_total_p_0 <= -0
node1.respect_min_p_0: -150 node1.gen_n_on_0 +1 node1.gen_total_p_0 >= -0
Bounds
0 <= node1.gen_n_on_0 <= 10
0 <= node1.gen_total_p_0 <= 3000
Generals
node1.gen_n_on_0
End
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
solver: scip
solver-logs: false
solver-parameters:
no-output: false
first-time-step: 0
last-time-step: 0

0 comments on commit 46b5502

Please sign in to comment.