diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index 2c73097adb..daceabc0ff 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -170,6 +170,7 @@ jobs:
run: |
cd _build
ctest -C Release --output-on-failure -L "unit|end-to-end"
+
- name: Upload logs for failed tests
if: ${{ failure() }}
@@ -177,7 +178,7 @@ jobs:
with:
name: test-log
path: ${{ github.workspace }}/_build/Testing/Temporary/LastTest.log
-
+
- name: Run tests about infinity on BCs RHS
if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }}
uses: ./.github/workflows/run-tests
@@ -185,7 +186,7 @@ jobs:
simtest-tag: ${{ env.SIMTEST }}
batch-name: valid-v830
os: ${{ env.os }}
-
+
- name: Run MILP with CBC
if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }}
uses: ./.github/workflows/run-tests
@@ -195,6 +196,23 @@ jobs:
variant: "milp-cbc"
os: ${{ env.os }}
+ - name: Run tests on adequacy patch (CSR)
+ if: ${{ env.RUN_SIMPLE_TESTS == 'true' }}
+ uses: ./.github/workflows/run-tests
+ with:
+ simtest-tag: ${{steps.simtest-version.outputs.prop}}
+ batch-name: adequacy-patch-CSR
+ os: ${{ env.os }}
+
+ - name: Run parallel tests
+ if: ${{ env.RUN_EXTENDED_TESTS == 'true' }}
+ uses: ./.github/workflows/run-tests
+ with:
+ simtest-tag: ${{steps.simtest-version.outputs.prop}}
+ batch-name: valid-parallel
+ os: ${{ env.os }}
+ variant: "parallel"
+
- name: Run tests introduced in 8.6.0
if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }}
uses: ./.github/workflows/run-tests
@@ -248,14 +266,6 @@ jobs:
batch-name: valid-mps
os: ${{ env.os }}
- - name: Run tests for adequacy patch (CSR)
- if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }}
- uses: ./.github/workflows/run-tests
- with:
- simtest-tag: ${{ env.SIMTEST }}
- batch-name: adequacy-patch-CSR
- os: ${{ env.os }}
-
- name: Run parallel tests
if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }}
uses: ./.github/workflows/run-tests
diff --git a/.github/workflows/windows-vcpkg.yml b/.github/workflows/windows-vcpkg.yml
index 5fb4b19603..37d47eaadf 100644
--- a/.github/workflows/windows-vcpkg.yml
+++ b/.github/workflows/windows-vcpkg.yml
@@ -188,6 +188,14 @@ jobs:
batch-name: adequacy-patch-CSR
os: ${{ env.os }}
+ - name: Run tests about infinity on BCs RHS
+ if: ${{ env.RUN_SIMPLE_TESTS == 'true' }}
+ uses: ./.github/workflows/run-tests
+ with:
+ simtest-tag: ${{steps.simtest-version.outputs.prop}}
+ batch-name: valid-v830
+ os: ${{ env.test-platform }}
+
- name: Run tests about infinity on BCs RHS
if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }}
uses: ./.github/workflows/run-tests
diff --git a/sonar-project.properties b/sonar-project.properties
index 0c74bd252a..d4ba8cce37 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -1,3 +1,24 @@
+#
+# Copyright 2007-2024, RTE (https://www.rte-france.com)
+# See AUTHORS.txt
+# SPDX-License-Identifier: MPL-2.0
+# This file is part of Antares-Simulator,
+# Adequacy and Performance assessment for interconnected energy networks.
+#
+# Antares_Simulator is free software: you can redistribute it and/or modify
+# it under the terms of the Mozilla Public Licence 2.0 as published by
+# the Mozilla Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# Antares_Simulator is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Mozilla Public Licence 2.0 for more details.
+#
+# You should have received a copy of the Mozilla Public Licence 2.0
+# along with Antares_Simulator. If not, see .
+#
+
sonar.projectName=Antares_Simulator
sonar.projectKey=AntaresSimulatorTeam_Antares_Simulator
sonar.organization=antaressimulatorteam
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 56dc5e2bf8..13c67fe7a0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -5,7 +5,6 @@ set(ANTARES_VERSION_HI 9)
set(ANTARES_VERSION_LO 2)
set(ANTARES_VERSION_REVISION 0)
-
# Beta release
set(ANTARES_BETA 0)
set(ANTARES_RC 7)
diff --git a/src/libs/antares/exception/LoadingError.cpp b/src/libs/antares/exception/LoadingError.cpp
index cea447153e..32f4b3b1c1 100644
--- a/src/libs/antares/exception/LoadingError.cpp
+++ b/src/libs/antares/exception/LoadingError.cpp
@@ -96,9 +96,8 @@ InvalidSolverSpecificParameters::InvalidSolverSpecificParameters(const std::stri
{
}
-InvalidStudy::InvalidStudy(const Yuni::String& study):
- LoadingError(std::string("The folder `") + study.c_str()
- + "` does not seem to be a valid study")
+InvalidStudy::InvalidStudy(const std::string& study):
+ LoadingError(std::string("The folder `") + study + "` does not seem to be a valid study")
{
}
diff --git a/src/libs/antares/exception/include/antares/exception/LoadingError.hpp b/src/libs/antares/exception/include/antares/exception/LoadingError.hpp
index d70820e5e9..9a5ff14002 100644
--- a/src/libs/antares/exception/include/antares/exception/LoadingError.hpp
+++ b/src/libs/antares/exception/include/antares/exception/LoadingError.hpp
@@ -140,7 +140,7 @@ class InvalidSolverSpecificParameters: public LoadingError
class InvalidStudy: public LoadingError
{
public:
- explicit InvalidStudy(const Yuni::String& study);
+ explicit InvalidStudy(const std::string& study);
};
class NoStudyProvided: public LoadingError
diff --git a/src/libs/antares/study/parameters/adq-patch-params.cpp b/src/libs/antares/study/parameters/adq-patch-params.cpp
index ebf6de321e..800f2d19f8 100644
--- a/src/libs/antares/study/parameters/adq-patch-params.cpp
+++ b/src/libs/antares/study/parameters/adq-patch-params.cpp
@@ -146,6 +146,10 @@ void AdqPatchParams::addExcludedVariables(std::vector& out) const
out.emplace_back("LMR VIOL.");
out.emplace_back("UNSP. ENRG CSR");
out.emplace_back("DTG MRG CSR");
+ out.emplace_back("LOLD CSR");
+ out.emplace_back("LOLP CSR");
+ out.emplace_back("MAX MRG CSR");
+ out.emplace_back("OV. COST CSR");
}
}
diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp
index 96b2d87826..cfd16f521e 100644
--- a/src/libs/antares/study/parts/thermal/cluster.cpp
+++ b/src/libs/antares/study/parts/thermal/cluster.cpp
@@ -298,6 +298,11 @@ void Data::ThermalCluster::calculationOfSpinning()
void Data::ThermalCluster::reverseCalculationOfSpinning()
{
+ if (tsGenBehavior == LocalTSGenerationBehavior::forceNoGen)
+ {
+ return;
+ }
+
// Nothing to do if the spinning is equal to zero
// because it will the same multiply all entries of the matrix by 1.
if (Utils::isZero(spinning))
diff --git a/src/solver/misc/options.cpp b/src/solver/misc/options.cpp
index d72bd4c692..00572039a9 100644
--- a/src/solver/misc/options.cpp
+++ b/src/solver/misc/options.cpp
@@ -82,14 +82,14 @@ std::unique_ptr CreateParser(Settings& settings, StudyLoad
"Solver used for simulation\nAvailable solver list : "
+ availableOrToolsSolversString());
- //--xpress-parameters
+ //--solver-parameters
parser->add(
options.optOptions.solverParameters,
' ',
"solver-parameters",
- "Set xpress solver specific parameters. The specified string must be wrapped into quotes: "
- "--solver-parameters=\"param1 value1 param2 value2\". The syntax of parameters is solver "
- "specfic, examples are given in Antares-Simulator online documentation.");
+ "Set solver-specific parameters, for instance --solver-parameters=\"THREADS 1 PRESOLVE 1\""
+ "for XPRESS or --solver-parameters=\"parallel/maxnthreads 1, lp/presolving TRUE\" for SCIP."
+ "Syntax is solver-dependent, and only supported for SCIP & XPRESS.");
parser->addParagraph("\nParameters");
// --name
diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt
index ec98f298e8..0d64d42e44 100644
--- a/src/solver/optimisation/CMakeLists.txt
+++ b/src/solver/optimisation/CMakeLists.txt
@@ -47,9 +47,7 @@ set(RTESOLVER_OPT
post_process_commands.cpp
include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h
include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.h
- include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h
adequacy_patch_csr/adq_patch_post_process_list.cpp
- adequacy_patch_csr/post_processing.cpp
include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h
adequacy_patch_csr/adq_patch_curtailment_sharing.cpp
adequacy_patch_csr/solve_problem.cpp
diff --git a/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp b/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp
index b480108379..731aaac79c 100644
--- a/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp
+++ b/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp
@@ -25,9 +25,10 @@
#include "antares/solver/optimisation/adequacy_patch_csr/count_constraints_variables.h"
#include "antares/solver/optimisation/adequacy_patch_csr/csr_quadratic_problem.h"
-#include "antares/solver/optimisation/opt_fonctions.h"
#include "antares/solver/simulation/adequacy_patch_runtime_data.h"
+#include "solve_problem.h"
+
using namespace Yuni;
namespace Antares::Data::AdequacyPatch
diff --git a/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp b/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp
index 1d54cb0da0..f9f8aa389b 100644
--- a/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp
+++ b/src/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.cpp
@@ -36,7 +36,7 @@ AdqPatchPostProcessList::AdqPatchPostProcessList(const AdqPatchParams& adqPatchP
{
post_process_list.push_back(
std::make_unique(problemeHebdo_, numSpace_, areas));
-
+ // Here a post process particular to adq patch
post_process_list.push_back(
std::make_unique(problemeHebdo_, areas, false, false));
post_process_list.push_back(std::make_unique(problemeHebdo_,
@@ -44,15 +44,14 @@ AdqPatchPostProcessList::AdqPatchPostProcessList(const AdqPatchParams& adqPatchP
sheddingPolicy,
splxOptimization,
numSpace));
-
- // Here a post process particular to adq patch
post_process_list.push_back(std::make_unique(adqPatchParams,
problemeHebdo_,
areas,
numSpace_));
- // Here a post process particular to adq patch
post_process_list.push_back(
- std::make_unique(problemeHebdo_, areas, numSpace));
+ std::make_unique(problemeHebdo_, areas, numSpace));
+ post_process_list.push_back(
+ std::make_unique(problemeHebdo_, areas, numSpace));
post_process_list.push_back(
std::make_unique(problemeHebdo_, areas, true, false));
post_process_list.push_back(
diff --git a/src/solver/optimisation/adequacy_patch_csr/post_processing.cpp b/src/solver/optimisation/adequacy_patch_csr/post_processing.cpp
deleted file mode 100644
index bc946a3c57..0000000000
--- a/src/solver/optimisation/adequacy_patch_csr/post_processing.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-** Copyright 2007-2024, RTE (https://www.rte-france.com)
-** See AUTHORS.txt
-** SPDX-License-Identifier: MPL-2.0
-** This file is part of Antares-Simulator,
-** Adequacy and Performance assessment for interconnected energy networks.
-**
-** Antares_Simulator is free software: you can redistribute it and/or modify
-** it under the terms of the Mozilla Public Licence 2.0 as published by
-** the Mozilla Foundation, either version 2 of the License, or
-** (at your option) any later version.
-**
-** Antares_Simulator is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** Mozilla Public Licence 2.0 for more details.
-**
-** You should have received a copy of the Mozilla Public Licence 2.0
-** along with Antares_Simulator. If not, see .
-*/
-#include "antares/solver/optimisation/adequacy_patch_csr/post_processing.h"
-
-#include
-
-namespace Antares::Data::AdequacyPatch
-{
-double recomputeDTG_MRG(bool triggered, double dtgMrg, double ens)
-{
- if (triggered)
- {
- return std::max(0.0, dtgMrg - ens);
- }
- else
- {
- return dtgMrg;
- }
-}
-
-double recomputeENS_MRG(bool triggered, double dtgMrg, double ens)
-{
- if (triggered)
- {
- return std::max(0.0, ens - dtgMrg);
- }
- else
- {
- return ens;
- }
-}
-
-double recomputeMRGPrice(double ensCsr, double originalCost, double unsuppliedEnergyCost)
-{
- if (ensCsr > 0.5)
- {
- return -unsuppliedEnergyCost;
- }
- else
- {
- return originalCost;
- }
-}
-} // namespace Antares::Data::AdequacyPatch
diff --git a/src/solver/optimisation/adequacy_patch_csr/solve_problem.h b/src/solver/optimisation/adequacy_patch_csr/solve_problem.h
new file mode 100644
index 0000000000..59b0619ca2
--- /dev/null
+++ b/src/solver/optimisation/adequacy_patch_csr/solve_problem.h
@@ -0,0 +1,14 @@
+
+#pragma once
+
+#include "antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h"
+#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h"
+#include "antares/study/parameters/adq-patch-params.h"
+
+using namespace Antares::Data::AdequacyPatch;
+
+bool ADQ_PATCH_CSR(PROBLEME_ANTARES_A_RESOUDRE&,
+ HourlyCSRProblem&,
+ const AdqPatchParams&,
+ unsigned int week,
+ int year);
diff --git a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h b/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h
index c7fb554c22..6ebb9734e4 100644
--- a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h
+++ b/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h
@@ -31,10 +31,69 @@
#include "../variables/VariableManagerUtils.h"
+struct LinkVariable
+{
+ LinkVariable():
+ directVar(-1),
+ indirectVar(-1)
+ {
+ }
+
+ LinkVariable(int direct, int indirect):
+ directVar(direct),
+ indirectVar(indirect)
+ {
+ }
+
+ inline bool check() const
+ {
+ if (directVar < 0)
+ {
+ Antares::logs.warning() << "directVar < 0 detected, this should not happen";
+ }
+ if (indirectVar < 0)
+ {
+ Antares::logs.warning() << "indirectVar < 0 detected, this should not happen";
+ }
+
+ return (directVar >= 0) && (indirectVar >= 0);
+ }
+
+ int directVar;
+ int indirectVar;
+};
+
struct PROBLEME_HEBDO;
class HourlyCSRProblem
{
+ using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams;
+
+public:
+ explicit HourlyCSRProblem(const AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* p):
+ adqPatchParams_(adqPatchParams),
+ variableManager_(p->CorrespondanceVarNativesVarOptim,
+ p->NumeroDeVariableStockFinal,
+ p->NumeroDeVariableDeTrancheDeStock,
+ p->NombreDePasDeTempsPourUneOptimisation),
+ problemeHebdo_(p)
+ {
+ double temp = pow(10, -adqPatchParams.curtailmentSharing.thresholdVarBoundsRelaxation);
+ belowThisThresholdSetToZero = std::min(temp, 0.1);
+
+ allocateProblem();
+ }
+
+ HourlyCSRProblem(const HourlyCSRProblem&) = delete;
+ HourlyCSRProblem& operator=(const HourlyCSRProblem&) = delete;
+
+ inline void setHour(int hour)
+ {
+ triggeredHour = hour;
+ }
+
+ void run(uint week, uint year);
+
private:
void calculateCsrParameters();
@@ -65,85 +124,26 @@ class HourlyCSRProblem
void setQuadraticCost();
void setLinearCost();
-private:
- using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams;
+public:
+ // TODO [gp] : try to make these members private
+ double belowThisThresholdSetToZero;
+ std::map numberOfConstraintCsrAreaBalance;
+ std::set ensVariablesInsideAdqPatch; // place inside only ENS inside adq-patch
+ std::set varToBeSetToZeroIfBelowThreshold; // place inside only ENS and Spillage variable
+ int triggeredHour;
+
const AdqPatchParams& adqPatchParams_;
VariableManagement::VariableManager variableManager_;
-public:
- void run(uint week, uint year);
-
- // TODO[FOM] Make these members private
- int triggeredHour;
- double belowThisThresholdSetToZero;
PROBLEME_HEBDO* problemeHebdo_;
PROBLEME_ANTARES_A_RESOUDRE problemeAResoudre_;
- explicit HourlyCSRProblem(const AdqPatchParams& adqPatchParams, PROBLEME_HEBDO* p):
- adqPatchParams_(adqPatchParams),
- variableManager_(p->CorrespondanceVarNativesVarOptim,
- p->NumeroDeVariableStockFinal,
- p->NumeroDeVariableDeTrancheDeStock,
- p->NombreDePasDeTempsPourUneOptimisation),
- problemeHebdo_(p)
- {
- double temp = pow(10, -adqPatchParams.curtailmentSharing.thresholdVarBoundsRelaxation);
- belowThisThresholdSetToZero = std::min(temp, 0.1);
-
- allocateProblem();
- }
-
- ~HourlyCSRProblem() = default;
-
- HourlyCSRProblem(const HourlyCSRProblem&) = delete;
- HourlyCSRProblem& operator=(const HourlyCSRProblem&) = delete;
-
- inline void setHour(int hour)
- {
- triggeredHour = hour;
- }
-
std::map numberOfConstraintCsrEns;
- std::map numberOfConstraintCsrAreaBalance;
std::map numberOfConstraintCsrFlowDissociation;
std::map numberOfConstraintCsrHourlyBinding; // length is number of binding constraint
// contains interco 2-2
std::map rhsAreaBalanceValues;
- std::set varToBeSetToZeroIfBelowThreshold; // place inside only ENS and Spillage variable
- std::set ensVariablesInsideAdqPatch; // place inside only ENS inside adq-patch
-
- struct LinkVariable
- {
- LinkVariable():
- directVar(-1),
- indirectVar(-1)
- {
- }
-
- LinkVariable(int direct, int indirect):
- directVar(direct),
- indirectVar(indirect)
- {
- }
-
- inline bool check() const
- {
- if (directVar < 0)
- {
- Antares::logs.warning() << "directVar < 0 detected, this should not happen";
- }
- if (indirectVar < 0)
- {
- Antares::logs.warning() << "indirectVar < 0 detected, this should not happen";
- }
-
- return (directVar >= 0) && (indirectVar >= 0);
- }
-
- int directVar;
- int indirectVar;
- };
// links between two areas inside the adq-patch domain
std::map linkInsideAdqPatch;
diff --git a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h b/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h
deleted file mode 100644
index 3ae5ee2d91..0000000000
--- a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
-** Copyright 2007-2024, RTE (https://www.rte-france.com)
-** See AUTHORS.txt
-** SPDX-License-Identifier: MPL-2.0
-** This file is part of Antares-Simulator,
-** Adequacy and Performance assessment for interconnected energy networks.
-**
-** Antares_Simulator is free software: you can redistribute it and/or modify
-** it under the terms of the Mozilla Public Licence 2.0 as published by
-** the Mozilla Foundation, either version 2 of the License, or
-** (at your option) any later version.
-**
-** Antares_Simulator is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** Mozilla Public Licence 2.0 for more details.
-**
-** You should have received a copy of the Mozilla Public Licence 2.0
-** along with Antares_Simulator. If not, see .
-*/
-
-#pragma once
-
-namespace Antares::Data::AdequacyPatch
-{
-double recomputeDTG_MRG(bool triggered, double dtgMrg, double ens);
-double recomputeENS_MRG(bool triggered, double dtgMrg, double ens);
-double recomputeMRGPrice(double ensCsr, double originalCost, double unsuppliedEnergyCost);
-} // namespace Antares::Data::AdequacyPatch
diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h
index 55cccc4e64..4d761bd558 100644
--- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h
+++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h
@@ -56,13 +56,6 @@ void OPT_InitialiserLesCoutsLineaire(PROBLEME_HEBDO*, const int, const int);
void OPT_InitialiserLesCoutsQuadratiques(PROBLEME_HEBDO*, int);
bool OPT_AppelDuSolveurQuadratique(PROBLEME_ANTARES_A_RESOUDRE*, const int);
-using namespace Antares::Data::AdequacyPatch;
-bool ADQ_PATCH_CSR(PROBLEME_ANTARES_A_RESOUDRE&,
- HourlyCSRProblem&,
- const AdqPatchParams&,
- uint week,
- int year);
-
bool OPT_PilotageOptimisationLineaire(const OptimizationOptions& options,
PROBLEME_HEBDO* problemeHebdo,
Solver::IResultWriter& writer,
diff --git a/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h b/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h
index 4c3fd49bd1..b7e125ad03 100644
--- a/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h
+++ b/src/solver/optimisation/include/antares/solver/optimisation/post_process_commands.h
@@ -69,16 +69,24 @@ class RemixHydroPostProcessCmd: public basePostProcessCommand
SimplexOptimization splx_optimization_;
};
-class DTGmarginForAdqPatchPostProcessCmd: public basePostProcessCommand
+class UpdateMrgPriceAfterCSRcmd: public basePostProcessCommand
{
- using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams;
-
public:
- DTGmarginForAdqPatchPostProcessCmd(PROBLEME_HEBDO* problemeHebdo,
- AreaList& areas,
- unsigned int numSpace);
+ UpdateMrgPriceAfterCSRcmd(PROBLEME_HEBDO* problemeHebdo,
+ AreaList& areas,
+ unsigned int numSpace);
+ void execute(const optRuntimeData&) override;
- void execute(const optRuntimeData& opt_runtime_data) override;
+private:
+ const AreaList& area_list_;
+ unsigned int numSpace_ = 0;
+};
+
+class DTGnettingAfterCSRcmd: public basePostProcessCommand
+{
+public:
+ DTGnettingAfterCSRcmd(PROBLEME_HEBDO* problemeHebdo, AreaList& areas, unsigned int numSpace);
+ void execute(const optRuntimeData&) override;
private:
const AreaList& area_list_;
@@ -112,8 +120,6 @@ class HydroLevelsFinalUpdatePostProcessCmd: public basePostProcessCommand
class CurtailmentSharingPostProcessCmd: public basePostProcessCommand
{
- using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams;
-
public:
CurtailmentSharingPostProcessCmd(const AdqPatchParams& adqPatchParams,
PROBLEME_HEBDO* problemeHebdo,
@@ -128,6 +134,7 @@ class CurtailmentSharingPostProcessCmd: public basePostProcessCommand
std::set identifyHoursForCurtailmentSharing(const std::vector& sumENS) const;
std::set getHoursRequiringCurtailmentSharing() const;
+ using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams;
const AreaList& area_list_;
const AdqPatchParams& adqPatchParams_;
unsigned int numSpace_ = 0;
diff --git a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp
index 2f6f907c5a..304aab13df 100644
--- a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp
+++ b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp
@@ -214,10 +214,9 @@ static SimplexResult OPT_TryToCallSimplex(const OptimizationOptions& options,
mps_writer->runIfNeeded(writer, filename);
TimeMeasurement measure;
-
const bool keepBasis = (optimizationNumber == PREMIERE_OPTIMISATION);
solver = ORTOOLS_Simplexe(&Probleme, solver, keepBasis, options);
- if (solver)
+ if (solver != nullptr)
{
ProblemeAResoudre->ProblemesSpx[NumIntervalle] = (void*)solver;
}
diff --git a/src/solver/optimisation/post_process_commands.cpp b/src/solver/optimisation/post_process_commands.cpp
index b069050960..3ddc06ddde 100644
--- a/src/solver/optimisation/post_process_commands.cpp
+++ b/src/solver/optimisation/post_process_commands.cpp
@@ -22,7 +22,6 @@
#include "antares/solver/optimisation/post_process_commands.h"
#include "antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h"
-#include "antares/solver/optimisation/adequacy_patch_csr/post_processing.h"
#include "antares/solver/simulation/adequacy_patch_runtime_data.h"
#include "antares/solver/simulation/common-eco-adq.h"
@@ -116,53 +115,84 @@ void RemixHydroPostProcessCmd::execute(const optRuntimeData& opt_runtime_data)
hourInYear);
}
-// -----------------------------
-// DTG margin for adq patch
-// -----------------------------
+// ----------------------------------
+// Update marginal price after CSR
+// ----------------------------------
using namespace Antares::Data::AdequacyPatch;
-DTGmarginForAdqPatchPostProcessCmd::DTGmarginForAdqPatchPostProcessCmd(
- PROBLEME_HEBDO* problemeHebdo,
- AreaList& areas,
- unsigned int numSpace):
+UpdateMrgPriceAfterCSRcmd::UpdateMrgPriceAfterCSRcmd(PROBLEME_HEBDO* problemeHebdo,
+ AreaList& areas,
+ unsigned int numSpace):
basePostProcessCommand(problemeHebdo),
area_list_(areas),
numSpace_(numSpace)
{
}
-/*!
-** Calculate Dispatchable margin for all areas after CSR optimization and adjust ENS
-** values if neccessary. If LOLD=1, Sets MRG COST to the max value (unsupplied energy cost)
-** */
-void DTGmarginForAdqPatchPostProcessCmd::execute(const optRuntimeData&)
+void UpdateMrgPriceAfterCSRcmd::execute(const optRuntimeData&)
{
for (uint32_t Area = 0; Area < problemeHebdo_->NombreDePays; Area++)
{
- if (problemeHebdo_->adequacyPatchRuntimeData->areaMode[Area] != physicalAreaInsideAdqPatch)
+ auto& hourlyResults = problemeHebdo_->ResultatsHoraires[Area];
+ const auto& scratchpad = area_list_[Area]->scratchpad[numSpace_];
+ const double unsuppliedEnergyCost = area_list_[Area]->thermal.unsuppliedEnergyCost;
+ const bool areaInside = problemeHebdo_->adequacyPatchRuntimeData->areaMode[Area]
+ == physicalAreaInsideAdqPatch;
+ for (uint hour = 0; hour < nbHoursInWeek; hour++)
{
- continue;
+ const bool isHourTriggeredByCsr = problemeHebdo_->adequacyPatchRuntimeData
+ ->wasCSRTriggeredAtAreaHour(Area, hour);
+
+ if (isHourTriggeredByCsr
+ && hourlyResults.ValeursHorairesDeDefaillancePositive[hour] > 0.5 && areaInside)
+ {
+ hourlyResults.CoutsMarginauxHoraires[hour] = -unsuppliedEnergyCost;
+ }
}
+ }
+}
+
+// -----------------------------
+// DTG margin for adq patch
+// -----------------------------
+DTGnettingAfterCSRcmd::DTGnettingAfterCSRcmd(PROBLEME_HEBDO* problemeHebdo,
+ AreaList& areas,
+ unsigned int numSpace):
+ basePostProcessCommand(problemeHebdo),
+ area_list_(areas),
+ numSpace_(numSpace)
+{
+}
+
+void DTGnettingAfterCSRcmd::execute(const optRuntimeData&)
+{
+ for (uint32_t Area = 0; Area < problemeHebdo_->NombreDePays; Area++)
+ {
+ auto& hourlyResults = problemeHebdo_->ResultatsHoraires[Area];
+ const auto& scratchpad = area_list_[Area]->scratchpad[numSpace_];
for (uint hour = 0; hour < nbHoursInWeek; hour++)
{
- auto& hourlyResults = problemeHebdo_->ResultatsHoraires[Area];
- const auto& scratchpad = area_list_[Area]->scratchpad[numSpace_];
+ const bool isHourTriggeredByCsr = problemeHebdo_->adequacyPatchRuntimeData
+ ->wasCSRTriggeredAtAreaHour(Area, hour);
+
const double dtgMrg = scratchpad.dispatchableGenerationMargin[hour];
const double ens = hourlyResults.ValeursHorairesDeDefaillancePositive[hour];
- const bool triggered = problemeHebdo_->adequacyPatchRuntimeData
- ->wasCSRTriggeredAtAreaHour(Area, hour);
- hourlyResults.ValeursHorairesDtgMrgCsr[hour] = recomputeDTG_MRG(triggered, dtgMrg, ens);
- hourlyResults.ValeursHorairesDeDefaillancePositiveCSR[hour] = recomputeENS_MRG(
- triggered,
- dtgMrg,
- ens);
-
- const double unsuppliedEnergyCost = area_list_[Area]->thermal.unsuppliedEnergyCost;
- hourlyResults.CoutsMarginauxHoraires[hour] = recomputeMRGPrice(
- hourlyResults.ValeursHorairesDtgMrgCsr[hour],
- hourlyResults.CoutsMarginauxHoraires[hour],
- unsuppliedEnergyCost);
+ const bool areaInside = problemeHebdo_->adequacyPatchRuntimeData->areaMode[Area]
+ == physicalAreaInsideAdqPatch;
+ if (isHourTriggeredByCsr && areaInside)
+ {
+ hourlyResults.ValeursHorairesDtgMrgCsr[hour] = std::max(0.0, dtgMrg - ens);
+ hourlyResults.ValeursHorairesDeDefaillancePositiveCSR[hour] = std::max(0.0,
+ ens
+ - dtgMrg);
+ }
+ else
+ {
+ // Default value (when the hour is not triggered by CSR)
+ hourlyResults.ValeursHorairesDtgMrgCsr[hour] = dtgMrg;
+ hourlyResults.ValeursHorairesDeDefaillancePositiveCSR[hour] = ens;
+ }
}
}
}
diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp
index 78785f0fd3..dd7480671c 100644
--- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp
+++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp
@@ -394,6 +394,7 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem,
problem.ResultatsHoraires[k].ValeursHorairesDeDefaillanceNegative.assign(NombreDePasDeTemps,
0.);
+
problem.ResultatsHoraires[k].TurbinageHoraire.assign(NombreDePasDeTemps, 0.);
problem.ResultatsHoraires[k].PompageHoraire.assign(NombreDePasDeTemps, 0.);
problem.ResultatsHoraires[k].CoutsMarginauxHoraires.assign(NombreDePasDeTemps, 0.);
diff --git a/src/solver/variable/CMakeLists.txt b/src/solver/variable/CMakeLists.txt
index 5022d5b542..ed7c017f5b 100644
--- a/src/solver/variable/CMakeLists.txt
+++ b/src/solver/variable/CMakeLists.txt
@@ -78,8 +78,9 @@ set(SRC_VARIABLE_ECONOMY
include/antares/solver/variable/economy/links.h
# Variables for Economy
+ include/antares/solver/variable/economy/max-mrg-utils.h
+ max-mrg-utils.cpp
include/antares/solver/variable/economy/max-mrg.h
- economy/max-mrg.cpp
include/antares/solver/variable/economy/price.h
include/antares/solver/variable/economy/balance.h
include/antares/solver/variable/economy/operatingCost.h
@@ -127,6 +128,7 @@ set(SRC_VARIABLE_ECONOMY
include/antares/solver/variable/economy/links/congestionFeeAbs.h
include/antares/solver/variable/economy/links/marginalCost.h
include/antares/solver/variable/economy/links/congestionProbability.h
+ include/antares/solver/variable/economy/overallCostCsr.h
# Binding constraints
include/antares/solver/variable/economy/bindingConstraints/bindingConstraintsMarginalCost.h
diff --git a/src/solver/variable/economy/max-mrg.cpp b/src/solver/variable/economy/max-mrg.cpp
deleted file mode 100644
index 7cb565037f..0000000000
--- a/src/solver/variable/economy/max-mrg.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
-** Copyright 2007-2024, RTE (https://www.rte-france.com)
-** See AUTHORS.txt
-** SPDX-License-Identifier: MPL-2.0
-** This file is part of Antares-Simulator,
-** Adequacy and Performance assessment for interconnected energy networks.
-**
-** Antares_Simulator is free software: you can redistribute it and/or modify
-** it under the terms of the Mozilla Public Licence 2.0 as published by
-** the Mozilla Foundation, either version 2 of the License, or
-** (at your option) any later version.
-**
-** Antares_Simulator is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** Mozilla Public Licence 2.0 for more details.
-**
-** You should have received a copy of the Mozilla Public Licence 2.0
-** along with Antares_Simulator. If not, see .
-*/
-
-#include "antares/solver/variable/economy/max-mrg.h"
-
-#include
-
-#include
-#include
-
-using namespace Yuni;
-
-namespace Antares::Solver::Variable::Economy
-{
-template
-struct SpillageSelector
-{
- template
- static auto Value(const State&,
- const U& weeklyResults,
- uint) -> decltype(weeklyResults.ValeursHorairesDeDefaillanceNegative)
- {
- return weeklyResults.ValeursHorairesDeDefaillanceNegative;
- }
-};
-
-template<>
-struct SpillageSelector
-{
- template
- static auto Value(const State& state, const U&, uint index) -> decltype(state.resSpilled[index])
- {
- return state.resSpilled[index];
- }
-};
-
-template
-inline void PrepareMaxMRGFor(const State& state, double* opmrg, uint numSpace)
-{
- assert(168 + state.hourInTheYear <= HOURS_PER_YEAR);
- assert(opmrg && "Invalid OP.MRG target");
-
- enum
- {
- offset = 0,
- endHour = 168,
- };
-
- // current area
- auto& area = *state.area;
- // index of the current area
- auto index = area.index;
- assert(area.index < 50000 && "seems invalid");
-
- // current problem
- auto& problem = *state.problemeHebdo;
- // Weekly results from solver for the current area
- auto& weeklyResults = problem.ResultatsHoraires[index];
- // Unsupplied enery for the current area
- auto& D = weeklyResults.ValeursHorairesDeDefaillancePositive;
- // Spillage
- auto S = SpillageSelector::Value(state, weeklyResults, area.index);
-
- double OI[168];
-
- // H.STOR
- std::vector& H = weeklyResults.TurbinageHoraire;
-
- // energie turbinee de la semaine
- {
- // DTG MRG
- const double* M = area.scratchpad[numSpace].dispatchableGenerationMargin;
-
- double WH = 0.;
- {
- // H.STOR
- for (uint i = offset; i != endHour; ++i)
- {
- WH += H[i];
- }
- }
-
- if (Utils::isZero(WH)) // no hydro
- {
- for (uint i = offset; i != endHour; ++i)
- {
- opmrg[i] = +S[i] + M[i] - D[i];
- }
- return;
- }
-
- // initialisation
- for (uint i = offset; i != endHour; ++i)
- {
- OI[i] = +S[i] + M[i] - D[i];
- }
- }
-
- double bottom = +std::numeric_limits::max();
- double top = 0;
-
- for (uint i = offset; i != endHour; ++i)
- {
- double oii = OI[i];
- if (oii > top)
- {
- top = oii;
- }
- if (oii < bottom)
- {
- bottom = oii;
- }
- }
-
- double ecart = 1.;
- uint loop = 100; // arbitrary - maximum number of iterations
-
- // Pmax
- const uint y = problem.year;
- const auto& P = area.hydro.series->maxHourlyGenPower;
-
- do
- {
- double niveau = (top + bottom) * 0.5;
- double SP = 0; // S+
- double SM = 0; // S-
-
- for (uint i = offset; i != endHour; ++i)
- {
- assert(i < HOURS_PER_YEAR && "calendar overflow");
- if (niveau > OI[i])
- {
- opmrg[i] = std::min(niveau,
- OI[i] + P.getCoefficient(y, i + state.hourInTheYear) - H[i]);
- SM += opmrg[i] - OI[i];
- }
- else
- {
- opmrg[i] = std::max(niveau, OI[i] - H[i]);
- SP += OI[i] - opmrg[i];
- }
- }
-
- ecart = SP - SM;
- if (ecart > 0)
- {
- bottom = niveau;
- }
- else
- {
- top = niveau;
- }
-
- if (!--loop)
- {
- logs.error() << "OP.MRG: " << area.name
- << ": infinite loop detected. please check input data";
- return;
- }
- } while (ecart * ecart > 0.25);
-}
-
-void PrepareMaxMRG(const State& state, double* opmrg, uint numSpace)
-{
- if (state.simplexRunNeeded)
- {
- PrepareMaxMRGFor(state, opmrg, numSpace);
- }
- else
- {
- PrepareMaxMRGFor(state, opmrg, numSpace);
- }
-}
-
-} // namespace Antares::Solver::Variable::Economy
diff --git a/src/solver/variable/include/antares/solver/variable/economy/all.h b/src/solver/variable/include/antares/solver/variable/economy/all.h
index 8e1c2ed307..17207c22db 100644
--- a/src/solver/variable/include/antares/solver/variable/economy/all.h
+++ b/src/solver/variable/include/antares/solver/variable/economy/all.h
@@ -49,12 +49,16 @@
#include "inflow.h"
#include "localMatchingRuleViolations.h"
#include "lold.h"
+#include "loldCsr.h"
#include "lolp.h"
+#include "lolpCsr.h"
+#include "max-mrg-csr.h"
#include "max-mrg.h"
#include "nbOfDispatchedUnits.h"
#include "nonProportionalCost.h"
#include "operatingCost.h"
#include "overallCost.h"
+#include "overallCostCsr.h"
#include "overflow.h"
#include "pumping.h"
#include "renewableGeneration.h"
@@ -91,59 +95,62 @@ namespace Antares::Solver::Variable::Economy
/*!
** \brief All variables for a single area (economy)
*/
-typedef // Prices
- OverallCost // Overall Cost (Op. Cost + Unsupplied Eng.)
- >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+typedef // Prices
+ OverallCost // Overall Cost (Op. Cost + Unsupplied Eng.)
+ >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
VariablesPerArea;
/*!
diff --git a/src/solver/variable/include/antares/solver/variable/economy/loldCsr.h b/src/solver/variable/include/antares/solver/variable/economy/loldCsr.h
new file mode 100644
index 0000000000..299e83b94f
--- /dev/null
+++ b/src/solver/variable/include/antares/solver/variable/economy/loldCsr.h
@@ -0,0 +1,242 @@
+/*
+** Copyright 2007-2023 RTE
+** Authors: Antares_Simulator Team
+**
+** This file is part of Antares_Simulator.
+**
+** Antares_Simulator is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** There are special exceptions to the terms and conditions of the
+** license as they are applied to this software. View the full text of
+** the exceptions in file COPYING.txt in the directory of this software
+** distribution
+**
+** Antares_Simulator is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with Antares_Simulator. If not, see .
+**
+** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions
+*/
+#pragma once
+
+#include "../variable.h"
+
+namespace Antares::Solver::Variable::Economy
+{
+
+struct VCardLOLD_CSR
+{
+ //! Caption
+ static std::string Caption()
+ {
+ return "LOLD CSR";
+ }
+
+ //! Unit
+ static std::string Unit()
+ {
+ return "Hours";
+ }
+
+ //! The short description of the variable
+ static std::string Description()
+ {
+ return "LOLD for CSR";
+ }
+
+ //! The expecte results
+ typedef Results>>>>
+ ResultsType;
+
+ static constexpr uint8_t categoryDataLevel = Category::DataLevel::area;
+ //! File level (provided by the type of the results)
+ static constexpr uint8_t categoryFileLevel = ResultsType::categoryFile
+ & (Category::FileLevel::id
+ | Category::FileLevel::va);
+ //! Precision (views)
+ static constexpr uint8_t precision = Category::all;
+ //! Indentation (GUI)
+ static constexpr uint8_t nodeDepthForGUI = +0;
+ //! Decimal precision
+ static constexpr uint8_t decimal = 2;
+ //! Number of columns used by the variable (One ResultsType per column)
+ static constexpr int columnCount = 1;
+ //! The Spatial aggregation
+ static constexpr uint8_t spatialAggregate = Category::spatialAggregateSum;
+ static constexpr uint8_t spatialAggregateMode = Category::spatialAggregateEachYear;
+ static constexpr uint8_t spatialAggregatePostProcessing = 0;
+ //! Intermediate values
+ static constexpr uint8_t hasIntermediateValues = 1;
+ //! Can this variable be non applicable (0 : no, 1 : yes)
+ static constexpr uint8_t isPossiblyNonApplicable = 0;
+
+ typedef IntermediateValues IntermediateValuesBaseType;
+ typedef IntermediateValues* IntermediateValuesType;
+
+ typedef IntermediateValuesBaseType* IntermediateValuesTypeForSpatialAg;
+
+}; // class VCard
+
+/*!
+** \brief
+*/
+template
+class LOLD_CSR: public Variable::IVariable, NextT, VCardLOLD_CSR>
+{
+public:
+ //! Type of the next static variable
+ typedef NextT NextType;
+ //! VCard
+ typedef VCardLOLD_CSR VCardType;
+ //! Ancestor
+ typedef Variable::IVariable, NextT, VCardType> AncestorType;
+
+ //! List of expected results
+ typedef typename VCardType::ResultsType ResultsType;
+
+ typedef VariableAccessor VariableAccessorType;
+
+ enum
+ {
+ //! How many items have we got
+ count = 1 + NextT::count,
+ };
+
+ template
+ struct Statistics
+ {
+ enum
+ {
+ count = ((VCardType::categoryDataLevel & CDataLevel
+ && VCardType::categoryFileLevel & CFile)
+ ? (NextType::template Statistics::count
+ + VCardType::columnCount * ResultsType::count)
+ : NextType::template Statistics::count),
+ };
+ };
+
+public:
+ ~LOLD_CSR()
+ {
+ delete[] pValuesForTheCurrentYear;
+ }
+
+ void initializeFromStudy(Data::Study& study)
+ {
+ pNbYearsParallel = study.maxNbYearsInParallel;
+
+ // Intermediate values
+ InitializeResultsFromStudy(AncestorType::pResults, study);
+
+ pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel];
+ for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++)
+ {
+ pValuesForTheCurrentYear[numSpace].initializeFromStudy(study);
+ }
+ // Next
+ NextType::initializeFromStudy(study);
+ }
+
+ template
+ static void InitializeResultsFromStudy(R& results, Data::Study& study)
+ {
+ VariableAccessorType::InitializeAndReset(results, study);
+ }
+
+ void simulationBegin()
+ {
+ for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++)
+ {
+ pValuesForTheCurrentYear[numSpace].reset();
+ }
+ // Next
+ NextType::simulationBegin();
+ }
+
+ void yearBegin(unsigned int year, unsigned int numSpace)
+ {
+ // Reset the values for the current year
+ pValuesForTheCurrentYear[numSpace].reset();
+
+ // Next variable
+ NextType::yearBegin(year, numSpace);
+ }
+
+ void yearEnd(unsigned int year, unsigned int numSpace)
+ {
+ // Compute all statistics for the current year (daily,weekly,monthly)
+ pValuesForTheCurrentYear[numSpace].computeStatisticsForTheCurrentYear();
+
+ // Next variable
+ NextType::yearEnd(year, numSpace);
+ }
+
+ void computeSummary(std::map& numSpaceToYear,
+ unsigned int nbYearsForCurrentSummary)
+ {
+ for (unsigned int numSpace = 0; numSpace < nbYearsForCurrentSummary; ++numSpace)
+ {
+ // Merge all those values with the global results
+ AncestorType::pResults.merge(numSpaceToYear[numSpace] /*year*/,
+ pValuesForTheCurrentYear[numSpace]);
+ }
+
+ // Next variable
+ NextType::computeSummary(numSpaceToYear, nbYearsForCurrentSummary);
+ }
+
+ void hourForEachArea(State& state, unsigned int numSpace)
+ {
+ if (state.hourlyResults->ValeursHorairesDeDefaillancePositiveCSR[state.hourInTheWeek] > 0.5)
+ {
+ pValuesForTheCurrentYear[numSpace][state.hourInTheYear] = 1.;
+ }
+
+ // Next variable
+ NextType::hourForEachArea(state, numSpace);
+ }
+
+ Antares::Memory::Stored::ConstReturnType retrieveRawHourlyValuesForCurrentYear(
+ unsigned int,
+ unsigned int numSpace) const
+ {
+ return pValuesForTheCurrentYear[numSpace].hour;
+ }
+
+ void localBuildAnnualSurveyReport(SurveyResults& results,
+ int fileLevel,
+ int precision,
+ unsigned int numSpace) const
+ {
+ // Initializing external pointer on current variable non applicable status
+ results.isCurrentVarNA = AncestorType::isNonApplicable;
+
+ if (AncestorType::isPrinted[0])
+ {
+ // Write the data for the current year
+ results.variableCaption = VCardType::Caption();
+ results.variableUnit = VCardType::Unit();
+ pValuesForTheCurrentYear[numSpace]
+ .template buildAnnualSurveyReport(results, fileLevel, precision);
+ }
+ }
+
+private:
+ //! Intermediate values for each year
+ typename VCardType::IntermediateValuesType pValuesForTheCurrentYear;
+ unsigned int pNbYearsParallel;
+
+}; // class LOLD_CSR
+
+} // namespace Antares::Solver::Variable::Economy
diff --git a/src/solver/variable/include/antares/solver/variable/economy/lolpCsr.h b/src/solver/variable/include/antares/solver/variable/economy/lolpCsr.h
new file mode 100644
index 0000000000..45d9ed61ac
--- /dev/null
+++ b/src/solver/variable/include/antares/solver/variable/economy/lolpCsr.h
@@ -0,0 +1,242 @@
+/*
+** Copyright 2007-2023 RTE
+** Authors: Antares_Simulator Team
+**
+** This file is part of Antares_Simulator.
+**
+** Antares_Simulator is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** There are special exceptions to the terms and conditions of the
+** license as they are applied to this software. View the full text of
+** the exceptions in file COPYING.txt in the directory of this software
+** distribution
+**
+** Antares_Simulator is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with Antares_Simulator. If not, see .
+**
+** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions
+*/
+#pragma once
+
+#include "../variable.h"
+
+namespace Antares::Solver::Variable::Economy
+{
+struct VCardLOLP_CSR
+{
+ //! Caption
+ static std::string Caption()
+ {
+ return "LOLP CSR";
+ }
+
+ //! Unit
+ static std::string Unit()
+ {
+ return "%";
+ }
+
+ //! The short description of the variable
+ static std::string Description()
+ {
+ return "LOLP for CSR";
+ }
+
+ //! The expecte results
+ typedef Results>
+ ResultsType;
+
+ //! The VCard to look for for calculating spatial aggregates
+ typedef VCardLOLP_CSR VCardForSpatialAggregate;
+
+ static constexpr uint8_t categoryDataLevel = Category::DataLevel::area;
+ //! File level (provided by the type of the results)
+ static constexpr uint8_t categoryFileLevel = ResultsType::categoryFile
+ & (Category::FileLevel::id
+ | Category::FileLevel::va);
+ //! Precision (views)
+ static constexpr uint8_t precision = Category::all;
+ //! Indentation (GUI)
+ static constexpr uint8_t nodeDepthForGUI = +0;
+ //! Decimal precision
+ static constexpr uint8_t decimal = 2;
+ //! Number of columns used by the variable (One ResultsType per column)
+ static constexpr int columnCount = 1;
+ //! The Spatial aggregation
+ static constexpr uint8_t spatialAggregate = Category::spatialAggregateSum;
+ static constexpr uint8_t spatialAggregateMode = Category::spatialAggregateEachYear;
+ static constexpr uint8_t spatialAggregatePostProcessing = 0;
+ //! Intermediate values
+ static constexpr uint8_t hasIntermediateValues = 1;
+ //! Can this variable be non applicable (0 : no, 1 : yes)
+ static constexpr uint8_t isPossiblyNonApplicable = 0;
+
+ typedef IntermediateValues IntermediateValuesBaseType;
+ typedef IntermediateValues* IntermediateValuesType;
+
+ typedef IntermediateValuesBaseType* IntermediateValuesTypeForSpatialAg;
+
+}; // class VCard
+
+/*!
+** \brief
+*/
+template
+class LOLP_CSR: public Variable::IVariable, NextT, VCardLOLP_CSR>
+{
+public:
+ //! Type of the next static variable
+ typedef NextT NextType;
+ //! VCard
+ typedef VCardLOLP_CSR VCardType;
+ //! Ancestor
+ typedef Variable::IVariable, NextT, VCardType> AncestorType;
+
+ //! List of expected results
+ typedef typename VCardType::ResultsType ResultsType;
+
+ typedef VariableAccessor VariableAccessorType;
+
+ enum
+ {
+ //! How many items have we got
+ count = 1 + NextT::count,
+ };
+
+ template
+ struct Statistics
+ {
+ enum
+ {
+ count = ((VCardType::categoryDataLevel & CDataLevel
+ && VCardType::categoryFileLevel & CFile)
+ ? (NextType::template Statistics::count
+ + VCardType::columnCount * ResultsType::count)
+ : NextType::template Statistics::count),
+ };
+ };
+
+public:
+ ~LOLP_CSR()
+ {
+ delete[] pValuesForTheCurrentYear;
+ }
+
+ void initializeFromStudy(Data::Study& study)
+ {
+ pNbYearsParallel = study.maxNbYearsInParallel;
+
+ // Intermediate values
+ InitializeResultsFromStudy(AncestorType::pResults, study);
+
+ pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel];
+ for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++)
+ {
+ pValuesForTheCurrentYear[numSpace].initializeFromStudy(study);
+ }
+
+ // Next
+ NextType::initializeFromStudy(study);
+ }
+
+ template
+ static void InitializeResultsFromStudy(R& results, Data::Study& study)
+ {
+ VariableAccessorType::InitializeAndReset(results, study);
+ }
+
+ void simulationBegin()
+ {
+ for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++)
+ {
+ pValuesForTheCurrentYear[numSpace].reset();
+ }
+ // Next
+ NextType::simulationBegin();
+ }
+
+ void yearBegin(unsigned int year, unsigned int numSpace)
+ {
+ // Reset the values for the current year
+ pValuesForTheCurrentYear[numSpace].reset();
+
+ // Next variable
+ NextType::yearBegin(year, numSpace);
+ }
+
+ void yearEnd(unsigned int year, unsigned int numSpace)
+ {
+ // Compute all statistics for the current year (daily,weekly,monthly)
+ pValuesForTheCurrentYear[numSpace].computeStatisticsOrForTheCurrentYear();
+
+ // Next variable
+ NextType::yearEnd(year, numSpace);
+ }
+
+ void computeSummary(std::map& numSpaceToYear,
+ unsigned int nbYearsForCurrentSummary)
+ {
+ for (unsigned int numSpace = 0; numSpace < nbYearsForCurrentSummary; ++numSpace)
+ {
+ // Merge all those values with the global results
+ AncestorType::pResults.merge(numSpaceToYear[numSpace] /*year*/,
+ pValuesForTheCurrentYear[numSpace]);
+ }
+
+ // Next variable
+ NextType::computeSummary(numSpaceToYear, nbYearsForCurrentSummary);
+ }
+
+ void hourForEachArea(State& state, unsigned int numSpace)
+ {
+ if (state.hourlyResults->ValeursHorairesDeDefaillancePositiveCSR[state.hourInTheWeek] > 0.5)
+ {
+ pValuesForTheCurrentYear[numSpace][state.hourInTheYear] = 100;
+ }
+
+ // Next variable
+ NextType::hourForEachArea(state, numSpace);
+ }
+
+ Antares::Memory::Stored::ConstReturnType retrieveRawHourlyValuesForCurrentYear(
+ unsigned int,
+ unsigned int numSpace) const
+ {
+ return pValuesForTheCurrentYear[numSpace].hour;
+ }
+
+ void localBuildAnnualSurveyReport(SurveyResults& results,
+ int fileLevel,
+ int precision,
+ unsigned int numSpace) const
+ {
+ // Initializing external pointer on current variable non applicable status
+ results.isCurrentVarNA = AncestorType::isNonApplicable;
+
+ if (AncestorType::isPrinted[0])
+ {
+ // Write the data for the current year
+ results.variableCaption = VCardType::Caption();
+ results.variableUnit = VCardType::Unit();
+ pValuesForTheCurrentYear[numSpace]
+ .template buildAnnualSurveyReport(results, fileLevel, precision);
+ }
+ }
+
+private:
+ //! Intermediate values for each year
+ typename VCardType::IntermediateValuesType pValuesForTheCurrentYear;
+ unsigned int pNbYearsParallel;
+
+}; // class LOLP_CSR
+
+} // namespace Antares::Solver::Variable::Economy
diff --git a/src/solver/variable/include/antares/solver/variable/economy/max-mrg-csr.h b/src/solver/variable/include/antares/solver/variable/economy/max-mrg-csr.h
new file mode 100644
index 0000000000..2ff8edc89d
--- /dev/null
+++ b/src/solver/variable/include/antares/solver/variable/economy/max-mrg-csr.h
@@ -0,0 +1,243 @@
+/*
+** Copyright 2007-2023 RTE
+** Authors: Antares_Simulator Team
+**
+** This file is part of Antares_Simulator.
+**
+** Antares_Simulator is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** There are special exceptions to the terms and conditions of the
+** license as they are applied to this software. View the full text of
+** the exceptions in file COPYING.txt in the directory of this software
+** distribution
+**
+** Antares_Simulator is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with Antares_Simulator. If not, see .
+**
+** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions
+*/
+#pragma once
+
+#include "../variable.h"
+#include "max-mrg-utils.h"
+
+namespace Antares::Solver::Variable::Economy
+{
+struct VCardMAX_MRG_CSR
+{
+ //! Caption
+ static std::string Caption()
+ {
+ return "MAX MRG CSR";
+ }
+
+ //! Unit
+ static std::string Unit()
+ {
+ return "MWh";
+ }
+
+ //! The short description of the variable
+ static std::string Description()
+ {
+ return "Max margin for CSR";
+ }
+
+ //! The expecte results
+ typedef Results>>>>
+ ResultsType;
+
+ //! The VCard to look for for calculating spatial aggregates
+ typedef VCardMAX_MRG_CSR VCardForSpatialAggregate;
+
+ static constexpr uint8_t categoryDataLevel = Category::DataLevel::area;
+ //! File level (provided by the type of the results)
+ static constexpr uint8_t categoryFileLevel = ResultsType::categoryFile
+ & (Category::FileLevel::id
+ | Category::FileLevel::va);
+ //! Precision (views)
+ static constexpr uint8_t precision = Category::all;
+ //! Indentation (GUI)
+ static constexpr uint8_t nodeDepthForGUI = +0;
+ //! Decimal precision
+ static constexpr uint8_t decimal = 0;
+ //! Number of columns used by the variable (One ResultsType per column)
+ static constexpr int columnCount = 1;
+ //! The Spatial aggregation
+ static constexpr uint8_t spatialAggregate = Category::spatialAggregateSum;
+ static constexpr uint8_t spatialAggregateMode = Category::spatialAggregateEachYear;
+ static constexpr uint8_t spatialAggregatePostProcessing = 0;
+ //! Intermediate values
+ static constexpr uint8_t hasIntermediateValues = 1;
+ //! Can this variable be non applicable (0 : no, 1 : yes)
+ static constexpr uint8_t isPossiblyNonApplicable = 0;
+
+ typedef IntermediateValues IntermediateValuesBaseType;
+ typedef IntermediateValues* IntermediateValuesType;
+
+ typedef IntermediateValuesBaseType* IntermediateValuesTypeForSpatialAg;
+
+}; // class VCard
+
+/*!
+** \brief Prepare MAX.MRG results for a given week
+*/
+template
+void PrepareMaxMRGFor(const State& state, double* opmrg, uint numSpace);
+
+/*!
+** \brief Max MRG
+*/
+template
+class MaxMrgCsr: public Variable::IVariable, NextT, VCardMAX_MRG_CSR>
+{
+public:
+ //! Type of the next static variable
+ typedef NextT NextType;
+ //! VCard
+ typedef VCardMAX_MRG_CSR VCardType;
+ //! Ancestor
+ typedef Variable::IVariable, NextT, VCardType> AncestorType;
+
+ //! List of expected results
+ typedef typename VCardType::ResultsType ResultsType;
+
+ typedef VariableAccessor VariableAccessorType;
+
+ enum
+ {
+ //! How many items have we got
+ count = 1 + NextT::count,
+ };
+
+ template
+ struct Statistics
+ {
+ enum
+ {
+ count = ((VCardType::categoryDataLevel & CDataLevel
+ && VCardType::categoryFileLevel & CFile)
+ ? (NextType::template Statistics::count
+ + VCardType::columnCount * ResultsType::count)
+ : NextType::template Statistics::count),
+ };
+ };
+
+public:
+ ~MaxMrgCsr()
+ {
+ delete[] pValuesForTheCurrentYear;
+ }
+
+ void initializeFromStudy(Data::Study& study)
+ {
+ pNbYearsParallel = study.maxNbYearsInParallel;
+
+ // Intermediate values
+ InitializeResultsFromStudy(AncestorType::pResults, study);
+
+ pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel];
+ for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++)
+ {
+ pValuesForTheCurrentYear[numSpace].initializeFromStudy(study);
+ }
+
+ // Next
+ NextType::initializeFromStudy(study);
+ }
+
+ template
+ static void InitializeResultsFromStudy(R& results, Data::Study& study)
+ {
+ VariableAccessorType::InitializeAndReset(results, study);
+ }
+
+ void yearBegin(unsigned int year, unsigned int numSpace)
+ {
+ // Reset the values for the current year
+ pValuesForTheCurrentYear[numSpace].reset();
+ // Next variable
+ NextType::yearBegin(year, numSpace);
+ }
+
+ void yearEnd(unsigned int year, unsigned int numSpace)
+ {
+ // Compute all statistics for the current year (daily,weekly,monthly)
+ pValuesForTheCurrentYear[numSpace].computeStatisticsForTheCurrentYear();
+
+ // Next variable
+ NextType::yearEnd(year, numSpace);
+ }
+
+ void computeSummary(std::map& numSpaceToYear,
+ unsigned int nbYearsForCurrentSummary)
+ {
+ for (unsigned int numSpace = 0; numSpace < nbYearsForCurrentSummary; ++numSpace)
+ {
+ // Merge all those values with the global results
+ AncestorType::pResults.merge(numSpaceToYear[numSpace] /*year*/,
+ pValuesForTheCurrentYear[numSpace]);
+ }
+
+ // Next variable
+ NextType::computeSummary(numSpaceToYear, nbYearsForCurrentSummary);
+ }
+
+ void weekForEachArea(State& state, unsigned int numSpace)
+ {
+ double* rawhourly = Memory::RawPointer(pValuesForTheCurrentYear[numSpace].hour);
+
+ // Getting data required to compute max margin
+ MaxMrgCSRdataFactory maxMRGcsrDataFactory(state, numSpace);
+ MaxMRGinput maxMRGinput = maxMRGcsrDataFactory.data();
+ computeMaxMRG(rawhourly + state.hourInTheYear, maxMRGinput);
+
+ // next
+ NextType::weekForEachArea(state, numSpace);
+ }
+
+ Antares::Memory::Stored::ConstReturnType retrieveRawHourlyValuesForCurrentYear(
+ unsigned int,
+ unsigned int numSpace) const
+ {
+ return pValuesForTheCurrentYear[numSpace].hour;
+ }
+
+ void localBuildAnnualSurveyReport(SurveyResults& results,
+ int fileLevel,
+ int precision,
+ unsigned int numSpace) const
+ {
+ // Initializing external pointer on current variable non applicable status
+ results.isCurrentVarNA = AncestorType::isNonApplicable;
+
+ if (AncestorType::isPrinted[0])
+ {
+ // Write the data for the current year
+ results.variableCaption = VCardType::Caption();
+ results.variableUnit = VCardType::Unit();
+ pValuesForTheCurrentYear[numSpace]
+ .template buildAnnualSurveyReport(results, fileLevel, precision);
+ }
+ }
+
+private:
+ //! Intermediate values for each year
+ typename VCardType::IntermediateValuesType pValuesForTheCurrentYear;
+ unsigned int pNbYearsParallel;
+
+}; // class MaxMrgCsr
+
+} // namespace Antares::Solver::Variable::Economy
diff --git a/src/solver/variable/include/antares/solver/variable/economy/max-mrg-utils.h b/src/solver/variable/include/antares/solver/variable/economy/max-mrg-utils.h
new file mode 100644
index 0000000000..2a5de71b74
--- /dev/null
+++ b/src/solver/variable/include/antares/solver/variable/economy/max-mrg-utils.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include
+
+#include "../state.h"
+
+namespace Antares::Solver::Variable::Economy
+{
+
+struct MaxMRGinput
+{
+ double* spillage = nullptr;
+ double* dens = nullptr;
+ double* hydroGeneration = nullptr;
+ Antares::Data::TimeSeries* maxHourlyGenPower = nullptr;
+ double* dtgMargin = nullptr;
+ unsigned int hourInYear = 0;
+ unsigned int year = 0;
+ Date::Calendar* calendar = nullptr;
+ std::string areaName;
+};
+
+void computeMaxMRG(double* maxMrgOut, const MaxMRGinput& in);
+
+class MaxMrgDataFactory
+{
+public:
+ MaxMrgDataFactory(const State& state, unsigned int numSpace);
+ virtual MaxMRGinput data() = 0;
+
+protected:
+ // in data
+ const State& state_;
+ const unsigned int numSpace_ = 0;
+ RESULTATS_HORAIRES& weeklyResults_;
+ // data to be built
+ MaxMRGinput maxMRGinput_;
+};
+
+class MaxMrgUsualDataFactory: public MaxMrgDataFactory
+{
+ using MaxMrgDataFactory::MaxMrgDataFactory;
+
+public:
+ virtual MaxMRGinput data() override;
+};
+
+class MaxMrgCSRdataFactory: public MaxMrgDataFactory
+{
+ using MaxMrgDataFactory::MaxMrgDataFactory;
+
+public:
+ virtual MaxMRGinput data() override;
+};
+
+} // namespace Antares::Solver::Variable::Economy
diff --git a/src/solver/variable/include/antares/solver/variable/economy/max-mrg.h b/src/solver/variable/include/antares/solver/variable/economy/max-mrg.h
index 959d6f16e7..a53b893947 100644
--- a/src/solver/variable/include/antares/solver/variable/economy/max-mrg.h
+++ b/src/solver/variable/include/antares/solver/variable/economy/max-mrg.h
@@ -23,6 +23,8 @@
#include "antares/solver/variable/variable.h"
+#include "max-mrg-utils.h"
+
namespace Antares
{
namespace Solver
@@ -92,11 +94,6 @@ struct VCardMARGE
}; // class VCard
-/*!
-** \brief Prepare MAX.MRG results for a given week
-*/
-void PrepareMaxMRG(const State& state, double* opmrg, uint numSpace);
-
/*!
** \brief Max MRG
*/
@@ -206,8 +203,6 @@ class Marge: public Variable::IVariable, NextT, VCardMARGE>
{
// Compute all statistics for the current year (daily,weekly,monthly)
pValuesForTheCurrentYear[numSpace].computeStatisticsForTheCurrentYear();
- // Merge all those values with the global results
- // AncestorType::pResults.merge(year, pValuesForTheCurrentYear);
// Next variable
NextType::yearEnd(year, numSpace);
@@ -242,7 +237,11 @@ class Marge: public Variable::IVariable, NextT, VCardMARGE>
void weekForEachArea(State& state, unsigned int numSpace)
{
double* rawhourly = Memory::RawPointer(pValuesForTheCurrentYear[numSpace].hour);
- PrepareMaxMRG(state, rawhourly + state.hourInTheYear, numSpace);
+
+ // Getting data required to compute max margin
+ MaxMrgUsualDataFactory maxMRGdataFactory(state, numSpace);
+ MaxMRGinput maxMRGinput = maxMRGdataFactory.data();
+ computeMaxMRG(rawhourly + state.hourInTheYear, maxMRGinput);
// next
NextType::weekForEachArea(state, numSpace);
diff --git a/src/solver/variable/include/antares/solver/variable/economy/overallCostCsr.h b/src/solver/variable/include/antares/solver/variable/economy/overallCostCsr.h
new file mode 100644
index 0000000000..63739b686b
--- /dev/null
+++ b/src/solver/variable/include/antares/solver/variable/economy/overallCostCsr.h
@@ -0,0 +1,253 @@
+/*
+** Copyright 2007-2023 RTE
+** Authors: Antares_Simulator Team
+**
+** This file is part of Antares_Simulator.
+**
+** Antares_Simulator is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** There are special exceptions to the terms and conditions of the
+** license as they are applied to this software. View the full text of
+** the exceptions in file COPYING.txt in the directory of this software
+** distribution
+**
+** Antares_Simulator is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with Antares_Simulator. If not, see .
+**
+** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions
+*/
+#pragma once
+
+#include "../variable.h"
+
+namespace Antares::Solver::Variable::Economy
+{
+struct VCardOverallCostCsr
+{
+ //! Caption
+ static std::string Caption()
+ {
+ return "OV. COST CSR";
+ }
+
+ //! Unit
+ static std::string Unit()
+ {
+ return "Euro";
+ }
+
+ //! The short description of the variable
+ static std::string Description()
+ {
+ return "Overall Cost throughout all MC years";
+ }
+
+ //! The expecte results
+ typedef Results,
+ R::AllYears::Average // Use these values for spatial cluster
+ >
+ ResultsType;
+
+ //! The VCard to look for for calculating spatial aggregates
+ typedef VCardOverallCostCsr VCardForSpatialAggregate;
+
+ static constexpr uint8_t categoryDataLevel = Category::DataLevel::area;
+ //! File level (provided by the type of the results)
+ static constexpr uint8_t categoryFileLevel = ResultsType::categoryFile
+ & (Category::FileLevel::id
+ | Category::FileLevel::va);
+ //! Precision (views)
+ static constexpr uint8_t precision = Category::all;
+ //! Indentation (GUI)
+ static constexpr uint8_t nodeDepthForGUI = +0;
+ //! Decimal precision
+ static constexpr uint8_t decimal = 0;
+ //! Number of columns used by the variable (One ResultsType per column)
+ static constexpr int columnCount = 1;
+ //! The Spatial aggregation
+ static constexpr uint8_t spatialAggregate = Category::spatialAggregateSum;
+ static constexpr uint8_t spatialAggregateMode = Category::spatialAggregateEachYear;
+ static constexpr uint8_t spatialAggregatePostProcessing = 0;
+ //! Intermediate values
+ static constexpr uint8_t hasIntermediateValues = 1;
+ //! Can this variable be non applicable (0 : no, 1 : yes)
+ static constexpr uint8_t isPossiblyNonApplicable = 0;
+
+ typedef IntermediateValues IntermediateValuesBaseType;
+ typedef IntermediateValues* IntermediateValuesType;
+
+ typedef IntermediateValuesBaseType* IntermediateValuesTypeForSpatialAg;
+
+}; // class VCard
+
+/*!
+** \brief C02 Average value of the overall OverallCostCsr emissions expected from all
+** the thermal dispatchable clusters
+*/
+template
+class OverallCostCsr: public Variable::IVariable, NextT, VCardOverallCostCsr>
+{
+public:
+ //! Type of the next static variable
+ typedef NextT NextType;
+ //! VCard
+ typedef VCardOverallCostCsr VCardType;
+ //! Ancestor
+ typedef Variable::IVariable, NextT, VCardType> AncestorType;
+
+ //! List of expected results
+ typedef typename VCardType::ResultsType ResultsType;
+
+ typedef VariableAccessor VariableAccessorType;
+
+ enum
+ {
+ //! How many items have we got
+ count = 1 + NextT::count,
+ };
+
+ template
+ struct Statistics
+ {
+ enum
+ {
+ count = ((VCardType::categoryDataLevel & CDataLevel
+ && VCardType::categoryFileLevel & CFile)
+ ? (NextType::template Statistics::count
+ + VCardType::columnCount * ResultsType::count)
+ : NextType::template Statistics::count),
+ };
+ };
+
+public:
+ ~OverallCostCsr()
+ {
+ delete[] pValuesForTheCurrentYear;
+ }
+
+ void initializeFromStudy(Data::Study& study)
+ {
+ pNbYearsParallel = study.maxNbYearsInParallel;
+
+ // Intermediate values
+ InitializeResultsFromStudy(AncestorType::pResults, study);
+
+ // Intermediate values
+ pValuesForTheCurrentYear = new VCardType::IntermediateValuesBaseType[pNbYearsParallel];
+ for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++)
+ {
+ pValuesForTheCurrentYear[numSpace].initializeFromStudy(study);
+ }
+
+ NextType::initializeFromStudy(study);
+ }
+
+ template
+ static void InitializeResultsFromStudy(R& results, Data::Study& study)
+ {
+ VariableAccessorType::InitializeAndReset(results, study);
+ }
+
+ void yearBegin(unsigned int year, unsigned int numSpace)
+ {
+ // Reset the values for the current year
+ pValuesForTheCurrentYear[numSpace].reset();
+
+ NextType::yearBegin(year, numSpace);
+ }
+
+ void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace)
+ {
+ for (unsigned int i = state.study.runtime.rangeLimits.hour[Data::rangeBegin];
+ i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd];
+ ++i)
+ {
+ pValuesForTheCurrentYear[numSpace][i] += state.thermalClusterOperatingCostForYear[i];
+ }
+
+ NextType::yearEndBuildForEachThermalCluster(state, year, numSpace);
+ }
+
+ void yearEnd(unsigned int year, unsigned int numSpace)
+ {
+ // Compute all statistics for the current year (daily, weekly, monthly)
+ pValuesForTheCurrentYear[numSpace].computeStatisticsForTheCurrentYear();
+
+ NextType::yearEnd(year, numSpace);
+ }
+
+ void computeSummary(std::map& numSpaceToYear,
+ unsigned int nbYearsForCurrentSummary)
+ {
+ for (unsigned int numSpace = 0; numSpace < nbYearsForCurrentSummary; ++numSpace)
+ {
+ // Merge all those values with the global results
+ AncestorType::pResults.merge(numSpaceToYear[numSpace] /*year*/,
+ pValuesForTheCurrentYear[numSpace]);
+ }
+
+ NextType::computeSummary(numSpaceToYear, nbYearsForCurrentSummary);
+ }
+
+ void hourForEachArea(State& state, unsigned int numSpace)
+ {
+ const double costForSpilledOrUnsuppliedEnergyCSR =
+ // Total UnsupliedEnergy emissions
+ (state.hourlyResults->ValeursHorairesDeDefaillancePositiveCSR[state.hourInTheWeek]
+ * state.area->thermal.unsuppliedEnergyCost)
+ + (state.hourlyResults->ValeursHorairesDeDefaillanceNegative[state.hourInTheWeek]
+ * state.area->thermal.spilledEnergyCost)
+ // Current hydro storage and pumping generation costs
+ + (state.hourlyResults->valeurH2oHoraire[state.hourInTheWeek]
+ * (state.hourlyResults->TurbinageHoraire[state.hourInTheWeek]
+ - state.area->hydro.pumpingEfficiency
+ * state.hourlyResults->PompageHoraire[state.hourInTheWeek]));
+
+ pValuesForTheCurrentYear[numSpace][state.hourInTheYear]
+ += costForSpilledOrUnsuppliedEnergyCSR;
+
+ NextType::hourForEachArea(state, numSpace);
+ }
+
+ Antares::Memory::Stored::ConstReturnType retrieveRawHourlyValuesForCurrentYear(
+ unsigned int,
+ unsigned int numSpace) const
+ {
+ return pValuesForTheCurrentYear[numSpace].hour;
+ }
+
+ void localBuildAnnualSurveyReport(SurveyResults& results,
+ int fileLevel,
+ int precision,
+ unsigned int numSpace) const
+ {
+ // Initializing external pointer on current variable non applicable status
+ results.isCurrentVarNA = AncestorType::isNonApplicable;
+
+ if (AncestorType::isPrinted[0])
+ {
+ // Write the data for the current year
+ results.variableCaption = VCardType::Caption();
+ results.variableUnit = VCardType::Unit();
+ pValuesForTheCurrentYear[numSpace]
+ .template buildAnnualSurveyReport(results, fileLevel, precision);
+ }
+ }
+
+private:
+ //! Intermediate values for each year
+ typename VCardType::IntermediateValuesType pValuesForTheCurrentYear;
+ unsigned int pNbYearsParallel;
+
+}; // class OverallCostCsr
+
+} // namespace Antares::Solver::Variable::Economy
diff --git a/src/solver/variable/include/antares/solver/variable/economy/unsupliedEnergyCsr.h b/src/solver/variable/include/antares/solver/variable/economy/unsupliedEnergyCsr.h
index e4a989de2c..a83ccb2e03 100644
--- a/src/solver/variable/include/antares/solver/variable/economy/unsupliedEnergyCsr.h
+++ b/src/solver/variable/include/antares/solver/variable/economy/unsupliedEnergyCsr.h
@@ -60,8 +60,6 @@ struct VCardUnsupliedEnergyCSR
//! The VCard to look for for calculating spatial aggregates
typedef VCardUnsupliedEnergyCSR VCardForSpatialAggregate;
-
- //! Data Level
static constexpr uint8_t categoryDataLevel = Category::DataLevel::area;
//! File level (provided by the type of the results)
static constexpr uint8_t categoryFileLevel = ResultsType::categoryFile
diff --git a/src/solver/variable/max-mrg-utils.cpp b/src/solver/variable/max-mrg-utils.cpp
new file mode 100644
index 0000000000..bfa93c1567
--- /dev/null
+++ b/src/solver/variable/max-mrg-utils.cpp
@@ -0,0 +1,171 @@
+/*
+** Copyright 2007-2023 RTE
+** Authors: Antares_Simulator Team
+**
+** This file is part of Antares_Simulator.
+**
+** Antares_Simulator is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** There are special exceptions to the terms and conditions of the
+** license as they are applied to this software. View the full text of
+** the exceptions in file COPYING.txt in the directory of this software
+** distribution
+**
+** Antares_Simulator is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with Antares_Simulator. If not, see .
+**
+** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions
+*/
+
+#include
+
+#include
+#include
+#include
+
+using namespace Yuni;
+
+const unsigned int nbHoursInWeek = 168;
+
+namespace Antares::Solver::Variable::Economy
+{
+
+MaxMrgDataFactory::MaxMrgDataFactory(const State& state, unsigned int numSpace):
+ state_(state),
+ numSpace_(numSpace),
+ weeklyResults_(state.problemeHebdo->ResultatsHoraires[state.area->index])
+{
+ maxMRGinput_.hydroGeneration = weeklyResults_.TurbinageHoraire.data();
+ maxMRGinput_.maxHourlyGenPower = &state_.area->hydro.series->maxHourlyGenPower;
+ maxMRGinput_.dtgMargin = state_.area->scratchpad[numSpace].dispatchableGenerationMargin;
+ maxMRGinput_.hourInYear = state.hourInTheYear;
+ maxMRGinput_.year = state.problemeHebdo->year;
+ maxMRGinput_.calendar = &state.study.calendar;
+ maxMRGinput_.areaName = state_.area->name.c_str();
+}
+
+MaxMRGinput MaxMrgUsualDataFactory::data()
+{
+ if (state_.simplexRunNeeded)
+ {
+ maxMRGinput_.spillage = weeklyResults_.ValeursHorairesDeDefaillanceNegative.data();
+ }
+ else
+ {
+ maxMRGinput_.spillage = state_.resSpilled[state_.area->index];
+ }
+
+ maxMRGinput_.dens = weeklyResults_.ValeursHorairesDeDefaillancePositive.data();
+ return maxMRGinput_;
+}
+
+MaxMRGinput MaxMrgCSRdataFactory::data()
+{
+ maxMRGinput_.spillage = weeklyResults_.ValeursHorairesDeDefaillanceNegative.data();
+ maxMRGinput_.dens = weeklyResults_.ValeursHorairesDeDefaillancePositiveCSR.data();
+ return maxMRGinput_;
+}
+
+void computeMaxMRG(double* maxMrgOut, const MaxMRGinput& in)
+{
+ assert(maxMrgOut && "Invalid OP.MRG target");
+
+ // Following block could be replaced with :
+ // double weekHydroGen = std::accumulate(in.hydroGeneration, in.hydroGeneration + nbHoursInWeek,
+ // 0.);
+ double weekHydroGen = 0.;
+ for (uint h = 0; h != nbHoursInWeek; ++h)
+ {
+ weekHydroGen += in.hydroGeneration[h];
+ }
+
+ if (Yuni::Math::Zero(weekHydroGen))
+ {
+ for (uint h = 0; h != nbHoursInWeek; ++h)
+ {
+ maxMrgOut[h] = in.spillage[h] + in.dtgMargin[h] - in.dens[h];
+ }
+ return;
+ }
+
+ // Initialisation
+ std::vector OI(nbHoursInWeek);
+ for (uint h = 0; h != nbHoursInWeek; ++h)
+ {
+ OI[h] = in.spillage[h] + in.dtgMargin[h] - in.dens[h];
+ }
+
+ // Following block could be replaced with :
+ // double bottom = *std::min_element(OI.begin(), OI.end());
+ // double top = *std::max_element(OI.begin(), OI.end());
+ double bottom = +std::numeric_limits::max();
+ double top = 0;
+ for (uint i = 0; i != nbHoursInWeek; ++i)
+ {
+ double oii = OI[i];
+ if (oii > top)
+ {
+ top = oii;
+ }
+ if (oii < bottom)
+ {
+ bottom = oii;
+ }
+ }
+
+ double ecart = 1.;
+ uint loop = 100; // arbitrary - maximum number of iterations
+
+ do
+ {
+ double niveau = (top + bottom) * 0.5;
+ double SP = 0; // S+
+ double SM = 0; // S-
+
+ for (uint h = 0; h != nbHoursInWeek; ++h)
+ {
+ assert(h < HOURS_PER_YEAR && "calendar overflow");
+ if (niveau > OI[h])
+ {
+ maxMrgOut[h] = Math::Min(niveau,
+ OI[h]
+ + in.maxHourlyGenPower->getCoefficient(in.year,
+ h + in.hourInYear)
+ - in.hydroGeneration[h]);
+ SM += maxMrgOut[h] - OI[h];
+ }
+ else
+ {
+ maxMrgOut[h] = Math::Max(niveau, OI[h] - in.hydroGeneration[h]);
+ SP += OI[h] - maxMrgOut[h];
+ }
+ }
+
+ ecart = SP - SM;
+ if (ecart > 0)
+ {
+ bottom = niveau;
+ }
+ else
+ {
+ top = niveau;
+ }
+
+ if (!--loop)
+ {
+ logs.error() << "OP.MRG: " << in.areaName
+ << ": infinite loop detected. please check input data";
+ return;
+ }
+ } while (ecart * ecart > 0.25);
+}
+
+} // namespace Antares::Solver::Variable::Economy
diff --git a/src/tests/src/libs/antares/writer/test_zip_writer.cpp b/src/tests/src/libs/antares/writer/test_zip_writer.cpp
new file mode 100644
index 0000000000..ffa0d89fed
--- /dev/null
+++ b/src/tests/src/libs/antares/writer/test_zip_writer.cpp
@@ -0,0 +1,127 @@
+/*
+** Copyright 2007-2023 RTE
+** Authors: Antares_Simulator Team
+**
+** This file is part of Antares_Simulator.
+**
+** Antares_Simulator is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** There are special exceptions to the terms and conditions of the
+** license as they are applied to this software. View the full text of
+** the exceptions in file COPYING.txt in the directory of this software
+** distribution
+**
+** Antares_Simulator is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with Antares_Simulator. If not, see .
+**
+** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions
+*/
+#define BOOST_TEST_MODULE test - writer tests
+
+#include
+#include
+
+#include "yuni/job/queue/service.h"
+
+#include "antares/benchmarking/DurationCollector.h"
+#include "antares/writer/i_writer.h"
+#include "antares/writer/writer_factory.h"
+
+#include "utils.h"
+
+extern "C"
+{
+#include
+#include
+#include
+#include
+}
+
+using namespace Yuni::Job;
+using Antares::Solver::IResultWriter;
+using Benchmarking::IDurationCollector;
+using Benchmarking::NullDurationCollector;
+
+// Handles lifetime of necessary objects
+struct TestContext
+{
+ std::shared_ptr threadPool;
+ std::unique_ptr durationCollector;
+ std::shared_ptr writer;
+};
+
+std::shared_ptr createThreadPool(int size)
+{
+ auto threadPool = std::make_shared();
+ threadPool->maximumThreadCount(size);
+ threadPool->start();
+ return threadPool;
+}
+
+std::string removeExtension(const std::string& name, const std::string& ext)
+{
+ int length = name.size();
+ if (name.size() > ext.size() && name.substr(length - ext.size()) == ext)
+ {
+ return name.substr(0, length - ext.size());
+ }
+ return name;
+}
+
+TestContext createContext(const std::filesystem::path zipPath, int threadCount)
+{
+ auto threadPool = createThreadPool(threadCount);
+ std::unique_ptr
+ durationCollector = std::make_unique();
+ std::string archiveName = zipPath.string();
+ auto writer = Antares::Solver::resultWriterFactory(Antares::Data::zipArchive,
+ removeExtension(zipPath.string(), ".zip"),
+ threadPool,
+ *durationCollector);
+ return {threadPool, std::move(durationCollector), writer};
+}
+
+using ZipReaderHandle = void*;
+
+void checkZipContent(ZipReaderHandle handle,
+ const std::string& path,
+ const std::string& expectedContent)
+{
+ BOOST_CHECK(mz_zip_reader_locate_entry(handle, path.c_str(), 0) == MZ_OK);
+ BOOST_CHECK(mz_zip_reader_entry_open(handle) == MZ_OK);
+ char buffer[4096];
+ int bytesRead = mz_zip_reader_entry_read(handle, buffer, sizeof(buffer));
+ std::string stringRead(buffer, bytesRead);
+ BOOST_CHECK(stringRead == expectedContent);
+ mz_zip_reader_entry_close(handle);
+}
+
+BOOST_AUTO_TEST_CASE(test_zip)
+{
+ // Writer some content to test.zip, possibly from 2 threads
+ auto working_tmp_dir = CREATE_TMP_DIR_BASED_ON_TEST_NAME();
+ auto zipPath = working_tmp_dir / "test.zip";
+ auto context = createContext(zipPath, 2);
+ std::string content1 = "test-content1";
+ std::string content2 = "test-content2";
+ context.writer->addEntryFromBuffer("test-path", content1);
+ context.writer->addEntryFromBuffer("test-second-path", content2);
+ context.writer->flush();
+ context.writer->finalize(true);
+
+ // Check content is correct
+ ZipReaderHandle readerHandle = mz_zip_reader_create();
+ std::string zipPathStr = zipPath.string();
+ BOOST_CHECK(mz_zip_reader_open_file(readerHandle, zipPathStr.c_str()) == MZ_OK);
+ checkZipContent(readerHandle, "test-path", "test-content1");
+ checkZipContent(readerHandle, "test-second-path", "test-content2");
+ mz_zip_reader_close(readerHandle);
+}
diff --git a/src/tests/src/solver/optimisation/adequacy_patch.cpp b/src/tests/src/solver/optimisation/adequacy_patch.cpp
new file mode 100644
index 0000000000..f6c5fddeb0
--- /dev/null
+++ b/src/tests/src/solver/optimisation/adequacy_patch.cpp
@@ -0,0 +1,386 @@
+#define BOOST_TEST_MODULE test adequacy patch functions
+
+#define WIN32_LEAN_AND_MEAN
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include "antares/study/parameters/adq-patch-params.h"
+
+#include "adequacy_patch_csr/adq_patch_curtailment_sharing.h"
+#include "adequacy_patch_local_matching/adq_patch_local_matching.h"
+
+static double origineExtremite = -1;
+static double extremiteOrigine = 5;
+
+using namespace Antares::Data::AdequacyPatch;
+namespace tt = boost::test_tools;
+
+static const double flowArea0toArea1_positive = 10;
+static const double flowArea0toArea1_negative = -10;
+static const double flowArea2toArea0_positive = 30;
+static const double flowArea2toArea0_negative = -30;
+static const double positiveEnsInit = 50.0;
+
+std::pair calculateAreaFlowBalanceForOneTimeStep(
+ double ensInit,
+ bool includeFlowsOutsideAdqPatchToDensNew,
+ AdequacyPatchMode Area1Mode,
+ AdequacyPatchMode Area2Mode,
+ double flowToArea1,
+ double flowFromArea2)
+{
+ PROBLEME_HEBDO problem;
+ int Area = 0;
+ uint hour = 0;
+
+ // allocate memory
+ problem.adequacyPatchRuntimeData = std::make_shared();
+ problem.adequacyPatchRuntimeData->originAreaMode.resize(3);
+ problem.adequacyPatchRuntimeData->extremityAreaMode.resize(3);
+
+ AdqPatchParams adqPatchParams;
+
+ problem.ResultatsHoraires.resize(1);
+ problem.ResultatsHoraires[0].ValeursHorairesDeDefaillancePositive = std::vector(1);
+ problem.ValeursDeNTC = std::vector(1);
+ problem.ValeursDeNTC[0].ValeurDuFlux = std::vector(3);
+ problem.IndexSuivantIntercoOrigine = std::vector(3);
+ problem.IndexSuivantIntercoExtremite = std::vector(3);
+ problem.IndexDebutIntercoOrigine = std::vector(1);
+ problem.IndexDebutIntercoExtremite = std::vector(1);
+
+ // input values
+ adqPatchParams.localMatching.setToZeroOutsideInsideLinks
+ = !includeFlowsOutsideAdqPatchToDensNew;
+ problem.ResultatsHoraires[Area].ValeursHorairesDeDefaillancePositive[hour] = ensInit;
+ int Interco = 1;
+ problem.IndexDebutIntercoOrigine[Area] = Interco;
+ problem.adequacyPatchRuntimeData->extremityAreaMode[Interco] = Area1Mode;
+ problem.ValeursDeNTC[hour].ValeurDuFlux[Interco] = flowToArea1;
+ problem.IndexSuivantIntercoOrigine[Interco] = -1;
+
+ Interco = 2;
+ problem.IndexDebutIntercoExtremite[Area] = Interco;
+ problem.adequacyPatchRuntimeData->originAreaMode[Interco] = Area2Mode;
+ problem.ValeursDeNTC[hour].ValeurDuFlux[Interco] = flowFromArea2;
+ problem.IndexSuivantIntercoExtremite[Interco] = -1;
+
+ // get results
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew, std::ignore) = calculateAreaFlowBalance(
+ &problem,
+ adqPatchParams.localMatching.setToZeroOutsideInsideLinks,
+ Area,
+ hour);
+
+ return std::make_pair(netPositionInit, densNew);
+}
+
+AdqPatchParams createParams()
+{
+ AdqPatchParams p;
+ p.enabled = true;
+ p.curtailmentSharing.includeHurdleCost = true;
+ p.curtailmentSharing.priceTakingOrder = AdqPatchPTO::isDens;
+
+ return p;
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 virtual-area, and Area2-virtual area
+// flow from Area0 -> Area1 is positive
+// flow from Area2 -> Area0 is positive
+// DensNew parameter should NOT include flows from areas outside adq patch
+BOOST_AUTO_TEST_CASE(
+ calculateAreaFlowBalanceForOneTimeStep_virtual_virtual_NotIncludeOut_positiveFlow)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 0.0,
+ false,
+ virtualArea,
+ virtualArea,
+ flowArea0toArea1_positive,
+ flowArea2toArea0_positive);
+ BOOST_CHECK_EQUAL(netPositionInit, 0.0);
+ BOOST_CHECK_EQUAL(densNew, 0.0);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area inside adq-patch, and Area2-virtual area
+// flow from Area0 -> Area1 is positive
+// flow from Area2 -> Area0 is positive
+// DensNew parameter should NOT include flows from areas outside adq patch
+BOOST_AUTO_TEST_CASE(
+ calculateAreaFlowBalanceForOneTimeStep_inside_virtual_NotIncludeOut_positiveFlow)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 0.0,
+ false,
+ physicalAreaInsideAdqPatch,
+ virtualArea,
+ flowArea0toArea1_positive,
+ flowArea2toArea0_positive);
+ BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive);
+ BOOST_CHECK_EQUAL(densNew, 0.0);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area inside adq-patch, and Area2-virtual area
+// flow from Area0 -> Area1 is positive
+// flow from Area2 -> Area0 is positive
+// DensNew parameter should NOT include flows from areas outside adq patch
+// ensInit = 50.0
+BOOST_AUTO_TEST_CASE(
+ calculateAreaFlowBalanceForOneTimeStep_inside_virtual_NotIncludeOut_positiveFlow_ensInitGraterThanZero)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ positiveEnsInit,
+ false,
+ physicalAreaInsideAdqPatch,
+ virtualArea,
+ flowArea0toArea1_positive,
+ flowArea2toArea0_positive);
+ BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive);
+ BOOST_CHECK_EQUAL(densNew, positiveEnsInit - flowArea0toArea1_positive);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area inside adq-patch, and Area2 physical area outside adq-patch
+// flow from Area0 -> Area1 is positive
+// flow from Area2 -> Area0 is positive
+// DensNew parameter should NOT include flows from areas outside adq patch
+BOOST_AUTO_TEST_CASE(
+ calculateAreaFlowBalanceForOneTimeStep_inside_outside_NotIncludeOut_positiveFlow)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 0.0,
+ false,
+ physicalAreaInsideAdqPatch,
+ physicalAreaOutsideAdqPatch,
+ flowArea0toArea1_positive,
+ flowArea2toArea0_positive);
+ BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive);
+ BOOST_CHECK_EQUAL(densNew, 0.0);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area inside adq-patch, and Area2 physical area inside adq-patch
+// flow from Area0 -> Area1 is positive
+// flow from Area2 -> Area0 is positive
+// DensNew parameter should NOT include flows from areas outside adq patch
+BOOST_AUTO_TEST_CASE(
+ calculateAreaFlowBalanceForOneTimeStep_inside_inside_NotIncludeOut_positiveFlow)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 0.0,
+ false,
+ physicalAreaInsideAdqPatch,
+ physicalAreaInsideAdqPatch,
+ flowArea0toArea1_positive,
+ flowArea2toArea0_positive);
+ BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive + flowArea2toArea0_positive);
+ BOOST_CHECK_EQUAL(densNew, -flowArea0toArea1_positive + flowArea2toArea0_positive);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area inside adq-patch, and Area2 physical area outside adq-patch
+// flow from Area0 -> Area1 is positive
+// flow from Area2 -> Area0 is positive
+// DensNew parameter SHOULD include flows from areas outside adq patch
+BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_inside_outside_IncludeOut_positiveFlow)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 0.0,
+ true,
+ physicalAreaInsideAdqPatch,
+ physicalAreaOutsideAdqPatch,
+ flowArea0toArea1_positive,
+ flowArea2toArea0_positive);
+ BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive);
+ BOOST_CHECK_EQUAL(densNew, -flowArea0toArea1_positive + flowArea2toArea0_positive);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area outside adq-patch, and Area2 physical area outside adq-patch
+// flow from Area0 -> Area1 is positive
+// flow from Area2 -> Area0 is positive
+// DensNew parameter SHOULD include flows from areas outside adq patch
+BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_outside_outside_IncludeOut_positiveFlow)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 0.0,
+ true,
+ physicalAreaOutsideAdqPatch,
+ physicalAreaOutsideAdqPatch,
+ flowArea0toArea1_positive,
+ flowArea2toArea0_positive);
+ BOOST_CHECK_EQUAL(netPositionInit, 0.0);
+ BOOST_CHECK_EQUAL(densNew, flowArea2toArea0_positive);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area outside adq-patch, and Area2 physical area inside adq-patch
+// flow from Area0 -> Area1 is positive
+// flow from Area2 -> Area0 is positive
+// DensNew parameter SHOULD include flows from areas outside adq patch
+BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_outside_inside_IncludeOut_positiveFlow)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 0.0,
+ true,
+ physicalAreaOutsideAdqPatch,
+ physicalAreaInsideAdqPatch,
+ flowArea0toArea1_positive,
+ flowArea2toArea0_positive);
+ BOOST_CHECK_EQUAL(netPositionInit, +flowArea2toArea0_positive);
+ BOOST_CHECK_EQUAL(densNew, +flowArea2toArea0_positive);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area inside adq-patch, and Area2 physical area outside adq-patch
+// flow from Area0 -> Area1 is negative
+// flow from Area2 -> Area0 is negative
+// DensNew parameter SHOULD include flows from areas outside adq patch
+BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_inside_outside_IncludeOut_negativeFlow)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 0.0,
+ true,
+ physicalAreaInsideAdqPatch,
+ physicalAreaOutsideAdqPatch,
+ flowArea0toArea1_negative,
+ flowArea2toArea0_negative);
+ BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_negative);
+ BOOST_CHECK_EQUAL(densNew, -flowArea0toArea1_negative);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area outside adq-patch, and Area2 physical area outside adq-patch
+// flow from Area0 -> Area1 is negative
+// flow from Area2 -> Area0 is negative
+// DensNew parameter SHOULD include flows from areas outside adq patch
+BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_outside_outside_IncludeOut_negativeFlow)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 0.0,
+ true,
+ physicalAreaOutsideAdqPatch,
+ physicalAreaOutsideAdqPatch,
+ flowArea0toArea1_negative,
+ flowArea2toArea0_negative);
+ BOOST_CHECK_EQUAL(netPositionInit, 0.0);
+ BOOST_CHECK_EQUAL(densNew, -flowArea0toArea1_negative);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area outside adq-patch, and Area2 physical area inside adq-patch
+// flow from Area0 -> Area1 is negative
+// flow from Area2 -> Area0 is negative
+// DensNew parameter SHOULD include flows from areas outside adq patch
+BOOST_AUTO_TEST_CASE(calculateAreaFlowBalanceForOneTimeStep_outside_inside_IncludeOut_negativeFlow)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 0.0,
+ true,
+ physicalAreaOutsideAdqPatch,
+ physicalAreaInsideAdqPatch,
+ flowArea0toArea1_negative,
+ flowArea2toArea0_negative);
+ BOOST_CHECK_EQUAL(netPositionInit, flowArea2toArea0_negative);
+ BOOST_CHECK_EQUAL(densNew, 0.0);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area inside adq-patch, and Area2 physical area inside adq-patch
+// flow from Area0 -> Area1 is positiive
+// flow from Area2 -> Area0 is negative
+// DensNew parameter SHOULD include flows from areas outside adq patch
+// ensInit = 50.0
+BOOST_AUTO_TEST_CASE(
+ calculateAreaFlowBalanceForOneTimeStep_outside_inside_IncludeOut_negativeFlow_initEnsEqualTo50)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ positiveEnsInit,
+ true,
+ physicalAreaInsideAdqPatch,
+ physicalAreaInsideAdqPatch,
+ flowArea0toArea1_positive,
+ flowArea2toArea0_negative);
+ BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive + flowArea2toArea0_negative);
+ BOOST_CHECK_EQUAL(densNew, positiveEnsInit + netPositionInit);
+}
+
+// Area 0 is physical area inside adq-patch connected to two areas:
+// Area1 physical area inside adq-patch, and Area2 physical area inside adq-patch
+// flow from Area0 -> Area1 is positiive
+// flow from Area2 -> Area0 is negative
+// DensNew parameter SHOULD include flows from areas outside adq patch
+// ensInit = 2.0
+BOOST_AUTO_TEST_CASE(
+ calculateAreaFlowBalanceForOneTimeStep_outside_inside_IncludeOut_negativeFlow_initEnsEqualTo0)
+{
+ double netPositionInit;
+ double densNew;
+ std::tie(netPositionInit, densNew) = calculateAreaFlowBalanceForOneTimeStep(
+ 2.0,
+ true,
+ physicalAreaInsideAdqPatch,
+ physicalAreaInsideAdqPatch,
+ flowArea0toArea1_positive,
+ flowArea2toArea0_negative);
+ BOOST_CHECK_EQUAL(netPositionInit, -flowArea0toArea1_positive + flowArea2toArea0_negative);
+ BOOST_CHECK_EQUAL(densNew, 0.0);
+}
+
+BOOST_AUTO_TEST_CASE(check_valid_adq_param)
+{
+ auto p = createParams();
+ BOOST_CHECK_NO_THROW(
+ p.checkAdqPatchSimulationModeEconomyOnly(Antares::Data::SimulationMode::Economy));
+ BOOST_CHECK_NO_THROW(p.checkAdqPatchIncludeHurdleCost(true));
+}
+
+BOOST_AUTO_TEST_CASE(check_adq_param_wrong_mode)
+{
+ auto p = createParams();
+ BOOST_CHECK_THROW(p.checkAdqPatchSimulationModeEconomyOnly(
+ Antares::Data::SimulationMode::Adequacy),
+ Error::IncompatibleSimulationModeForAdqPatch);
+}
+
+BOOST_AUTO_TEST_CASE(check_adq_param_wrong_hurdle_cost)
+{
+ auto p = createParams();
+ BOOST_CHECK_THROW(p.checkAdqPatchIncludeHurdleCost(false), Error::IncompatibleHurdleCostCSR);
+}
diff --git a/src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp b/src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp
index ea9762838b..9f716ecb77 100644
--- a/src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp
+++ b/src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp
@@ -31,7 +31,6 @@
#include
#include
#include "antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h"
-#include "antares/solver/optimisation/adequacy_patch_csr/post_processing.h"
#include "antares/study/parameters/adq-patch-params.h"
static double origineExtremite = -1;
@@ -402,75 +401,3 @@ BOOST_AUTO_TEST_CASE(check_adq_param_wrong_hurdle_cost)
auto p = createParams();
BOOST_CHECK_THROW(p.checkAdqPatchIncludeHurdleCost(false), Error::IncompatibleHurdleCostCSR);
}
-
-BOOST_AUTO_TEST_SUITE(adq_patch_post_processing)
-
-BOOST_AUTO_TEST_CASE(dtg_mrg_triggered_low_ens)
-{
- const bool triggered = true;
- const double dtgMrg = 32.;
- const double ens = 21.;
-
- BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == 11., tt::tolerance(1.e-6));
-
- BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens)
- == std::abs(dtgMrg - ens),
- tt::tolerance(1.e-6));
-}
-
-BOOST_AUTO_TEST_CASE(dtg_mrg_triggered_high_ens)
-{
- const bool triggered = true;
- const double dtgMrg = 32.;
- const double ens = 42.;
-
- BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == 0., tt::tolerance(1.e-6));
-
- BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens)
- == std::abs(dtgMrg - ens),
- tt::tolerance(1.e-6));
-}
-
-BOOST_AUTO_TEST_CASE(dtg_mrg_not_triggered_low_ens)
-{
- const bool triggered = false;
- const double dtgMrg = 32.;
- const double ens = 21.;
-
- BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == dtgMrg, tt::tolerance(1.e-6));
- BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens)
- == dtgMrg + ens,
- tt::tolerance(1.e-6));
-}
-
-BOOST_AUTO_TEST_CASE(dtg_mrg_not_triggered_high_ens)
-{
- const bool triggered = false;
- const double dtgMrg = 32.;
- const double ens = 42.;
-
- BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == dtgMrg, tt::tolerance(1.e-6));
- BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens)
- == dtgMrg + ens,
- tt::tolerance(1.e-6));
-}
-
-BOOST_AUTO_TEST_CASE(mrgprice_high_enscsr)
-{
- const double ensCsr = 21.;
- const double originalCost = 3.;
- const double unsuppliedEnergyCost = 1000.;
- BOOST_TEST(recomputeMRGPrice(ensCsr, originalCost, unsuppliedEnergyCost)
- == -unsuppliedEnergyCost,
- tt::tolerance(1.e-6));
-}
-
-BOOST_AUTO_TEST_CASE(mrgprice_low_enscsr)
-{
- const double ensCsr = 0.;
- const double originalCost = 3.;
- const double unsuppliedEnergyCost = 1000.;
- BOOST_TEST(recomputeMRGPrice(ensCsr, originalCost, unsuppliedEnergyCost) == originalCost,
- tt::tolerance(1.e-6));
-}
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/ui/simulator/application/main/create.cpp b/src/ui/simulator/application/main/create.cpp
index 03d3f57a71..bb2182d148 100644
--- a/src/ui/simulator/application/main/create.cpp
+++ b/src/ui/simulator/application/main/create.cpp
@@ -293,7 +293,13 @@ void ApplWnd::internalInitialize()
statusbar->SetStatusStyles(2, styles);
statusbar->SetMinHeight(14);
- statusbar->SetStatusText(wxT(""), 1);
+ statusbar->Connect(statusbar->GetId(),
+ wxEVT_CONTEXT_MENU,
+ wxContextMenuEventHandler(ApplWnd::evtOnContextMenuStatusBar),
+ nullptr,
+ this);
+
+ statusbar->SetStatusText(wxT("| "), 1);
wxFont f = statusbar->GetFont();
f.SetPointSize(f.GetPointSize() - 1);
diff --git a/src/ui/simulator/application/main/internal-ids.h b/src/ui/simulator/application/main/internal-ids.h
index 33d8f6f764..57893d5187 100644
--- a/src/ui/simulator/application/main/internal-ids.h
+++ b/src/ui/simulator/application/main/internal-ids.h
@@ -172,6 +172,16 @@ enum MenusID
mnIDLaunchAnalyzer,
mnIDLaunchConstraintsBuilder,
+ //! \name Popup Menu Operator for selected cells on any grid
+ //@{
+ mnIDPopupOpNone,
+ mnIDPopupOpAverage,
+ mnIDPopupOpCellCount,
+ mnIDPopupOpMinimum,
+ mnIDPopupOpMaximum,
+ mnIDPopupOpSum,
+ //@}
+
//! \name Popup Menu Operator for selected nodes on any layer
//@{
mnIDPopupSelectionHide,
diff --git a/src/ui/simulator/application/main/main.cpp b/src/ui/simulator/application/main/main.cpp
index 137b009c2b..38131d6552 100644
--- a/src/ui/simulator/application/main/main.cpp
+++ b/src/ui/simulator/application/main/main.cpp
@@ -179,6 +179,14 @@ EVT_MENU(mnInternalLogMessage, ApplWnd::onLogMessage)
EVT_MENU(mnIDLaunchAnalyzer, ApplWnd::evtLaunchAnalyzer)
EVT_MENU(mnIDLaunchConstraintsBuilder, ApplWnd::evtLaunchConstraintsBuilder)
+// Context menu : Operator for selected cells (grid)
+EVT_MENU(mnIDPopupOpNone, ApplWnd::evtOnContextMenuChangeOperator)
+EVT_MENU(mnIDPopupOpAverage, ApplWnd::evtOnContextMenuChangeOperator)
+EVT_MENU(mnIDPopupOpCellCount, ApplWnd::evtOnContextMenuChangeOperator)
+EVT_MENU(mnIDPopupOpMinimum, ApplWnd::evtOnContextMenuChangeOperator)
+EVT_MENU(mnIDPopupOpMaximum, ApplWnd::evtOnContextMenuChangeOperator)
+EVT_MENU(mnIDPopupOpSum, ApplWnd::evtOnContextMenuChangeOperator)
+
EVT_MENU_OPEN(ApplWnd::evtOnMenuOpen)
EVT_MENU_CLOSE(ApplWnd::evtOnMenuClose)
@@ -245,6 +253,8 @@ ApplWnd::ApplWnd() :
pageRenewableCommon(nullptr),
pageNodalOptim(nullptr),
pWndBindingConstraints(nullptr),
+ pGridSelectionOperator(new Component::Datagrid::Selection::CellCount()),
+ pGridSelectionAttachedGrid(nullptr),
pMapContextMenu(nullptr),
pUserNotes(nullptr),
pMainNotebookAlreadyHasItsComponents(false),
@@ -308,6 +318,13 @@ ApplWnd::~ApplWnd()
OnStudyAreasChanged.clear();
OnStudyAreaDelete.clear();
+ // Delete the grid operator
+ if (pGridSelectionOperator)
+ {
+ delete pGridSelectionOperator;
+ pGridSelectionOperator = nullptr; // May be needed in some cases
+ }
+
// Disconnect all events
destroyBoundEvents();
// Unregister the global pointer to the instance
@@ -346,6 +363,34 @@ void ApplWnd::selectSystem()
pNotebook->select(wxT("sys"), true);
}
+void ApplWnd::evtOnContextMenuChangeOperator(wxCommandEvent& evt)
+{
+ switch (evt.GetId())
+ {
+ case mnIDPopupOpNone:
+ gridOperatorSelectedCells(nullptr);
+ break;
+ case mnIDPopupOpAverage:
+ gridOperatorSelectedCells(new Component::Datagrid::Selection::Average());
+ break;
+ case mnIDPopupOpCellCount:
+ gridOperatorSelectedCells(new Component::Datagrid::Selection::CellCount());
+ break;
+ case mnIDPopupOpMinimum:
+ gridOperatorSelectedCells(new Component::Datagrid::Selection::Minimum());
+ break;
+ case mnIDPopupOpMaximum:
+ gridOperatorSelectedCells(new Component::Datagrid::Selection::Maximum());
+ break;
+ case mnIDPopupOpSum:
+ gridOperatorSelectedCells(new Component::Datagrid::Selection::Sum());
+ break;
+ default:
+ break;
+ }
+ evt.Skip();
+}
+
static inline void EnableItem(wxMenuBar* menu, int id, bool opened)
{
auto* item = menu->FindItem(id);
@@ -494,6 +539,7 @@ void ApplWnd::evtOnUpdateGUIAfterStudyIO(bool opened)
// Reset the status bar
resetDefaultStatusBarText();
+ gridOperatorSelectedCellsUpdateResult(pGridSelectionAttachedGrid);
// reload the user notes and districts
if (not aboutToQuit and study)
@@ -519,6 +565,7 @@ void ApplWnd::evtOnUpdateGUIAfterStudyIO(bool opened)
{
GetSizer()->Clear(true);
pUserNotes = nullptr;
+ pGridSelectionAttachedGrid = nullptr;
pBigDaddy = nullptr;
pMainSizer = nullptr;
pData->wipPanel = nullptr;
@@ -778,6 +825,24 @@ void ApplWnd::onRenewableGenerationModellingChanged(bool init)
refreshInputMenuOnRenewableModellingChanged(aggregated);
}
+void ApplWnd::gridOperatorSelectedCells(Component::Datagrid::Selection::IOperator* v)
+{
+ delete pGridSelectionOperator;
+ pGridSelectionOperator = v;
+ gridOperatorSelectedCellsUpdateResult(pGridSelectionAttachedGrid);
+}
+
+Component::Datagrid::Selection::IOperator* ApplWnd::gridOperatorSelectedCells() const
+{
+ return pGridSelectionOperator;
+}
+
+void ApplWnd::disableGridOperatorIfGrid(wxGrid* grid)
+{
+ if (pGridSelectionAttachedGrid == grid)
+ gridOperatorSelectedCellsUpdateResult(nullptr);
+}
+
void ApplWnd::title()
{
assert(wxIsMainThread() == true and "Must be ran from the main thread");
diff --git a/src/ui/simulator/application/main/main.h b/src/ui/simulator/application/main/main.h
index 0b1f9dd8bb..7b7683805e 100644
--- a/src/ui/simulator/application/main/main.h
+++ b/src/ui/simulator/application/main/main.h
@@ -26,6 +26,7 @@
#include
#include "../../toolbox/components/notebook/notebook.h"
+#include "../../toolbox/components/datagrid/selectionoperation.h"
#include "../../toolbox/components/map/settings.h"
#include
#include "fwd.h"
@@ -105,6 +106,41 @@ class ApplWnd final : public Component::Frame::WxLocalFrame, public Yuni::IEvent
*/
Map::Component* map() const;
+ /*!
+ ** \name Grid operator (for selected cells)
+ **
+ ** A grid operator computes an operation (Sum, average...) on all selected
+ ** cells of the grid that currently has the focus. The result of this
+ ** computation is displayed in the status bar.
+ **
+ ** \see Antares::Component::Datagrid::Component::onGridEnter()
+ ** \see Antares::Component::Datagrid::Component::onGridLeave()
+ */
+ //@{
+ /*!
+ ** \brief Get the current grid operator for selected cells
+ */
+ Component::Datagrid::Selection::IOperator* gridOperatorSelectedCells() const;
+
+ /*!
+ ** \brief Set the grid operator for selected cells
+ */
+ void gridOperatorSelectedCells(Component::Datagrid::Selection::IOperator* v);
+
+ /*!
+ ** \brief Update the GUI to display the result of the grid operator
+ **
+ ** This method should be called each time the cells selection changes.
+ ** \param grid The `wxGrid` that has currently the focus (may be NULL)
+ */
+ void gridOperatorSelectedCellsUpdateResult(wxGrid* grid);
+
+ /*!
+ ** \brief Disable the grid operator
+ */
+ void disableGridOperatorIfGrid(wxGrid* grid);
+ //@}
+
//! \name Title of the Window
//@{
void title();
@@ -327,6 +363,8 @@ class ApplWnd final : public Component::Frame::WxLocalFrame, public Yuni::IEvent
//! Create a complete menu for the window
wxMenuBar* createMenu();
+ //! Create a popup menu for all available operators on selected cells (grid)
+ wxMenu* createPopupMenuOperatorsOnGrid();
//! Create menu: File
wxMenu* createMenuFiles();
@@ -398,6 +436,9 @@ class ApplWnd final : public Component::Frame::WxLocalFrame, public Yuni::IEvent
//! \name Event: Context menu
//@{
+ //! Show the context menu associated to the status bar
+ void evtOnContextMenuStatusBar(wxContextMenuEvent& evt);
+ void evtOnContextMenuChangeOperator(wxCommandEvent& evt);
void evtOnContextMenuMap(int x, int y);
//@}
@@ -696,6 +737,10 @@ class ApplWnd final : public Component::Frame::WxLocalFrame, public Yuni::IEvent
Component::Notebook::Page* pageScBuilderHydroInitialLevels;
Component::Notebook::Page* pageScBuilderHydroFinalLevels;
+ //! The current grid operator to use on selected cells
+ Component::Datagrid::Selection::IOperator* pGridSelectionOperator;
+ wxGrid* pGridSelectionAttachedGrid;
+
//! A context menu for the map
wxMenu* pMapContextMenu;
diff --git a/src/ui/simulator/application/main/menu.cpp b/src/ui/simulator/application/main/menu.cpp
index 11121bce3c..619269b283 100644
--- a/src/ui/simulator/application/main/menu.cpp
+++ b/src/ui/simulator/application/main/menu.cpp
@@ -64,6 +64,21 @@ wxMenuBar* ApplWnd::createMenu()
return ret;
}
+wxMenu* ApplWnd::createPopupMenuOperatorsOnGrid()
+{
+ auto* menu = new wxMenu();
+
+ // Wizard
+ Menu::CreateItem(menu, mnIDPopupOpNone, wxT("None"), "images/16x16/empty.png");
+ menu->AppendSeparator();
+ Menu::CreateItem(menu, mnIDPopupOpAverage, wxT("Average "));
+ Menu::CreateItem(menu, mnIDPopupOpCellCount, wxT("Cell count "));
+ Menu::CreateItem(menu, mnIDPopupOpMinimum, wxT("Minimum "));
+ Menu::CreateItem(menu, mnIDPopupOpMaximum, wxT("Maximum "));
+ Menu::CreateItem(menu, mnIDPopupOpSum, wxT("Sum "));
+ return menu;
+}
+
wxMenu* ApplWnd::createMenuFiles()
{
delete pMenuFile;
diff --git a/src/ui/simulator/application/main/statusbar.cpp b/src/ui/simulator/application/main/statusbar.cpp
index a12dd4a290..ed33372524 100644
--- a/src/ui/simulator/application/main/statusbar.cpp
+++ b/src/ui/simulator/application/main/statusbar.cpp
@@ -22,17 +22,16 @@
#include
#include "main.h"
#include "../../windows/version.h"
-#include "antares/study/study.h"
-// Datagrid
-#include "../../toolbox/components/datagrid/component.h"
+#include "../study.h"
#include "../../toolbox/components/datagrid/gridhelper.h"
#include
#include
-namespace Antares
-{
-namespace Forms
+using namespace Component::Datagrid;
+
+namespace Antares::Forms
{
+
void ApplWnd::resetDefaultStatusBarText()
{
assert(wxIsMainThread() == true && "Must be ran from the main thread");
@@ -41,5 +40,216 @@ void ApplWnd::resetDefaultStatusBarText()
#endif
}
-} // namespace Forms
-} // namespace Antares
+
+bool oneCellSelected(wxGrid& grid)
+{
+ const wxGridCellCoordsArray& cells(grid.GetSelectedCells());
+ return cells.size() > 0;
+}
+
+size_t updateStatisticsOpForOneCell(wxGrid& grid,
+ VGridHelper* gridHelper,
+ Selection::IOperator* op)
+{
+ size_t totalCell = 0;
+ const wxGridCellCoordsArray& cells(grid.GetSelectedCells());
+ for (uint i = 0; i < (uint)cells.size(); ++i)
+ {
+ auto& cell = cells[i];
+ op->appendValue(gridHelper->GetNumericValue(cell.GetRow(), cell.GetCol()));
+ ++totalCell;
+ }
+ return totalCell;
+}
+
+bool rowsSelected(wxGrid& grid)
+{
+ const wxArrayInt& rows(grid.GetSelectedRows());
+ return rows.size() > 0;
+}
+
+size_t updateStatisticsOpForRows(wxGrid& grid,
+ VGridHelper* gridHelper,
+ Selection::IOperator* op)
+{
+ size_t totalCell = 0;
+ int colCount = grid.GetNumberCols();
+ const wxArrayInt& rows(grid.GetSelectedRows());
+ for (uint i = 0; i < (uint)rows.size(); ++i)
+ {
+ for (int col = 0; col < colCount; ++col)
+ {
+ op->appendValue(gridHelper->GetNumericValue(rows[i], col));
+ ++totalCell;
+ }
+ }
+ return totalCell;
+}
+
+bool columnsSelected(wxGrid& grid)
+{
+ const wxArrayInt& cols(grid.GetSelectedCols());
+ return cols.size() > 0;
+}
+
+size_t updateStatisticsOpForColumns(wxGrid& grid,
+ VGridHelper* gridHelper,
+ Selection::IOperator* op)
+{
+ size_t totalCell = 0;
+ int rowCount = grid.GetNumberRows();
+ const wxArrayInt& cols(grid.GetSelectedCols());
+ for (uint i = 0; i < (uint)cols.size(); ++i)
+ {
+ for (int row = 0; row < rowCount; ++row)
+ {
+ op->appendValue(gridHelper->GetNumericValue(row, cols[i]));
+ ++totalCell;
+ }
+ }
+ return totalCell;
+}
+
+bool blockSelected(wxGrid& grid)
+{
+ // Blocks. We always expect blocks top left and bottom right to have the same size, since their
+ // entries are supposed to correspond.
+ const wxGridCellCoordsArray& blockTopLeft(grid.GetSelectionBlockTopLeft());
+ const wxGridCellCoordsArray& blockBottomRight(grid.GetSelectionBlockBottomRight());
+ return (blockTopLeft.size() == blockBottomRight.size()) && (blockTopLeft.size() > 0);
+}
+
+size_t updateStatisticsOpForBlock(wxGrid& grid,
+ VGridHelper* gridHelper,
+ Selection::IOperator* op)
+{
+ size_t totalCell = 0;
+ const wxGridCellCoordsArray& blockTopLeft(grid.GetSelectionBlockTopLeft());
+ const wxGridCellCoordsArray& blockBottomRight(grid.GetSelectionBlockBottomRight());
+ size_t blockSize = blockTopLeft.size();
+
+ for (uint i = 0; i < blockSize; ++i)
+ {
+ const wxGridCellCoords& topLeft = blockTopLeft[i];
+ const wxGridCellCoords& bottomRight = blockBottomRight[i];
+ for (int row = topLeft.GetRow(); row <= bottomRight.GetRow(); ++row)
+ {
+ for (int col = topLeft.GetCol(); col <= bottomRight.GetCol(); ++col)
+ {
+ op->appendValue(gridHelper->GetNumericValue(row, col));
+ ++totalCell;
+ }
+ }
+ }
+ return totalCell;
+}
+
+/*
+** Applies a functor to all selected cells. Returns the number of selected
+** cells.
+*/
+static size_t applyOperatorOnSelectedCells(wxGrid& grid,
+ VGridHelper* gridHelper,
+ Selection::IOperator* op)
+{
+ assert(wxIsMainThread() == true and "Must be ran from the main thread");
+
+ if (oneCellSelected(grid))
+ {
+ return updateStatisticsOpForOneCell(grid, gridHelper, op);
+ }
+
+ if (rowsSelected(grid))
+ {
+ return updateStatisticsOpForRows(grid, gridHelper, op);
+ }
+
+ if (columnsSelected(grid))
+ {
+ return updateStatisticsOpForColumns(grid, gridHelper, op);
+ }
+
+ if (blockSelected(grid))
+ {
+ return updateStatisticsOpForBlock(grid, gridHelper, op);
+ }
+
+ return 0;
+}
+
+void ApplWnd::gridOperatorSelectedCellsUpdateResult(wxGrid* grid)
+{
+ assert(wxIsMainThread() == true and "Must be ran from the main thread");
+ enum
+ {
+ fieldIndex = 1,
+ };
+ // The status bar
+ auto* statusBar = GetStatusBar();
+ pGridSelectionAttachedGrid = grid;
+ if (statusBar)
+ {
+ if (not CurrentStudyIsValid())
+ {
+ statusBar->SetStatusText(wxEmptyString, fieldIndex);
+ return;
+ }
+ if (not pGridSelectionOperator)
+ {
+ statusBar->SetStatusText(wxT("| (none)"), fieldIndex);
+ return;
+ }
+
+ if (grid and grid->GetTable())
+ {
+ auto* gridHelper = dynamic_cast(grid->GetTable());
+ if (gridHelper)
+ {
+ // Reset of the operator
+ pGridSelectionOperator->reset();
+ // Browse all selected cells
+ if (applyOperatorOnSelectedCells(*grid, gridHelper, pGridSelectionOperator))
+ {
+ // Update the GUI
+ statusBar->SetStatusText(wxString()
+ << wxT("| ") << pGridSelectionOperator->caption()
+ << wxT(" = ") << pGridSelectionOperator->result(),
+ fieldIndex);
+ return;
+ }
+ }
+ }
+ // Empty
+ statusBar->SetStatusText(
+ wxString(wxT("| (")) << pGridSelectionOperator->caption() << wxT(')'), fieldIndex);
+ }
+}
+
+void ApplWnd::evtOnContextMenuStatusBar(wxContextMenuEvent& evt)
+{
+ if (GUIIsLock())
+ return;
+
+ wxStatusBar* statusBar = GetStatusBar();
+ if (statusBar)
+ {
+ wxRect rect;
+ if (statusBar->GetFieldRect(1, rect))
+ {
+ const wxPoint pos = statusBar->ScreenToClient(evt.GetPosition());
+ if (rect.Contains(pos))
+ {
+ if (!pPopupMenuOperatorsGrid)
+ {
+ // Popup menu: Operators for selected cells on any grid
+ pPopupMenuOperatorsGrid = createPopupMenuOperatorsOnGrid();
+ }
+
+ statusBar->PopupMenu(pPopupMenuOperatorsGrid);
+ }
+ }
+ }
+ evt.Skip();
+}
+
+} // namespace Antares::Forms
\ No newline at end of file
diff --git a/src/ui/simulator/cmake/components.cmake b/src/ui/simulator/cmake/components.cmake
index 0586928a48..df72d40b83 100644
--- a/src/ui/simulator/cmake/components.cmake
+++ b/src/ui/simulator/cmake/components.cmake
@@ -48,6 +48,7 @@ SET(SRC_TOOLBOX_COM_DBGRID_RENDERERS
toolbox/components/datagrid/renderer.h
toolbox/components/datagrid/renderer.hxx
toolbox/components/datagrid/renderer.cpp
+ toolbox/components/datagrid/selectionoperation.h
toolbox/components/datagrid/renderer/adequacy-patch-area-grid.h
toolbox/components/datagrid/renderer/adequacy-patch-area-grid.cpp
toolbox/components/datagrid/renderer/area.h
diff --git a/src/ui/simulator/toolbox/components/datagrid/dbgrid.cpp b/src/ui/simulator/toolbox/components/datagrid/dbgrid.cpp
index dc8624172e..84fe490800 100644
--- a/src/ui/simulator/toolbox/components/datagrid/dbgrid.cpp
+++ b/src/ui/simulator/toolbox/components/datagrid/dbgrid.cpp
@@ -120,6 +120,11 @@ DBGrid::DBGrid(Component* parent) :
DBGrid::~DBGrid()
{
+ // Remove any remaining reference
+ auto* mainFrm = Forms::ApplWnd::Instance();
+ if (mainFrm)
+ mainFrm->disableGridOperatorIfGrid(this);
+
pParentComponent = nullptr;
otherGrid_ = nullptr;
}
@@ -128,6 +133,10 @@ void DBGrid::onGridSelectCell(wxGridEvent& evt)
{
assert(GetParent() && "invalid parent");
+ auto* mainFrm = Forms::ApplWnd::Instance();
+ if (mainFrm)
+ mainFrm->gridOperatorSelectedCellsUpdateResult(this);
+ pCurrentPosition.x = evt.GetCol();
pCurrentPosition.y = evt.GetRow();
auto* r = ((Component*)GetParent())->renderer();
@@ -141,6 +150,9 @@ void DBGrid::onGridRangeSelect(wxGridRangeSelectEvent& evt)
{
assert(GetGridWindow() && "invalid grid window");
+ Forms::ApplWnd* mainFrm = Forms::ApplWnd::Instance();
+ if (mainFrm)
+ mainFrm->gridOperatorSelectedCellsUpdateResult(this);
if (GetGridWindow())
GetGridWindow()->SetFocus();
evt.Skip();
@@ -148,6 +160,9 @@ void DBGrid::onGridRangeSelect(wxGridRangeSelectEvent& evt)
void DBGrid::onGridLeave(wxFocusEvent& evt)
{
+ auto* mainFrm = Forms::ApplWnd::Instance();
+ if (mainFrm)
+ mainFrm->gridOperatorSelectedCellsUpdateResult(nullptr);
evt.Skip();
}
@@ -202,6 +217,10 @@ void DBGrid::ensureDataAreLoaded()
r->invalidate = false;
// Post an event to update the gui after the data are loaded
+ Forms::ApplWnd* mainFrm = Forms::ApplWnd::Instance();
+ if (mainFrm)
+ mainFrm->disableGridOperatorIfGrid(this);
+
assert(pAllowRefresh == true);
parent->forceRefresh();
if (GetTable())
diff --git a/src/ui/simulator/toolbox/components/datagrid/selectionoperation.h b/src/ui/simulator/toolbox/components/datagrid/selectionoperation.h
new file mode 100644
index 0000000000..a7deebcf32
--- /dev/null
+++ b/src/ui/simulator/toolbox/components/datagrid/selectionoperation.h
@@ -0,0 +1,247 @@
+/*
+** Copyright 2007-2018 RTE
+** Authors: Antares_Simulator Team
+**
+** This file is part of Antares_Simulator.
+**
+** Antares_Simulator is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** There are special exceptions to the terms and conditions of the
+** license as they are applied to this software. View the full text of
+** the exceptions in file COPYING.txt in the directory of this software
+** distribution
+**
+** Antares_Simulator is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with Antares_Simulator. If not, see .
+**
+** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions
+*/
+#ifndef __ANTARES_TOOLBOX_COMPONENT_DATAGRID_SELECTION_OPERATION_H__
+#define __ANTARES_TOOLBOX_COMPONENT_DATAGRID_SELECTION_OPERATION_H__
+
+#include "wx-wrapper.h"
+#include
+#include
+
+namespace Antares
+{
+namespace Component
+{
+namespace Datagrid
+{
+namespace Selection
+{
+class IOperator
+{
+public:
+ IOperator()
+ {
+ }
+ virtual ~IOperator()
+ {
+ }
+
+ /*!
+ ** \brief Caption of the operator
+ */
+ virtual const wxChar* caption() const = 0;
+
+ /*!
+ ** \brief Reset all internal values
+ */
+ virtual void reset() = 0;
+
+ /*!
+ ** \brief Manage a new value
+ */
+ virtual void appendValue(const double v) = 0;
+
+ /*!
+ ** \brief Get the result
+ */
+ virtual double result() const = 0;
+
+}; // class IOperator
+
+class Average final : public IOperator
+{
+public:
+ Average() : pValue(0.), pCount(0)
+ {
+ }
+
+ virtual ~Average()
+ {
+ }
+
+ virtual const wxChar* caption() const
+ {
+ return wxT("Average");
+ }
+
+ virtual void reset()
+ {
+ pValue = 0.;
+ pCount = 0;
+ }
+
+ virtual void appendValue(const double v)
+ {
+ pValue += v;
+ ++pCount;
+ }
+
+ virtual double result() const
+ {
+ return pValue / (double)pCount;
+ }
+
+private:
+ double pValue;
+ uint pCount;
+
+}; // class Average
+
+class Sum final : public IOperator
+{
+public:
+ Sum() : pValue(0.)
+ {
+ }
+
+ virtual const wxChar* caption() const
+ {
+ return wxT("Sum");
+ }
+
+ virtual void reset()
+ {
+ pValue = 0.;
+ }
+
+ virtual void appendValue(const double v)
+ {
+ pValue += v;
+ }
+
+ virtual double result() const
+ {
+ return pValue;
+ }
+
+private:
+ double pValue;
+
+}; // class Sum
+
+class CellCount final : public IOperator
+{
+public:
+ CellCount() : pCount(0)
+ {
+ }
+
+ virtual const wxChar* caption() const
+ {
+ return wxT("Cell Count");
+ }
+
+ virtual void reset()
+ {
+ pCount = 0;
+ }
+
+ virtual void appendValue(const double)
+ {
+ ++pCount;
+ }
+
+ virtual double result() const
+ {
+ return (double)pCount;
+ }
+
+private:
+ uint pCount;
+
+}; // class Average
+
+class Minimum final : public IOperator
+{
+public:
+ Minimum() : pValue(std::numeric_limits::infinity())
+ {
+ }
+
+ virtual const wxChar* caption() const
+ {
+ return wxT("Minimum");
+ }
+
+ virtual void reset()
+ {
+ pValue = std::numeric_limits::infinity();
+ }
+
+ virtual void appendValue(const double v)
+ {
+ if (v < pValue)
+ pValue = v;
+ }
+
+ virtual double result() const
+ {
+ return pValue;
+ }
+
+private:
+ double pValue;
+
+}; // class Sum
+
+class Maximum final : public IOperator
+{
+public:
+ Maximum() : pValue(-std::numeric_limits::infinity())
+ {
+ }
+
+ virtual const wxChar* caption() const
+ {
+ return wxT("Maximum");
+ }
+ virtual void reset()
+ {
+ pValue = -std::numeric_limits::infinity();
+ }
+
+ virtual void appendValue(const double v)
+ {
+ if (v > pValue)
+ pValue = v;
+ }
+
+ virtual double result() const
+ {
+ return pValue;
+ }
+
+private:
+ double pValue;
+
+}; // class Sum
+
+} // namespace Selection
+} // namespace Datagrid
+} // namespace Component
+} // namespace Antares
+
+#endif // __ANTARES_TOOLBOX_COMPONENT_DATAGRID_SELECTION_OPERATION_H__