diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml index 9bb8f34512..9b91102fa0 100644 --- a/.github/workflows/doxygen.yml +++ b/.github/workflows/doxygen.yml @@ -4,7 +4,6 @@ on: push: branches: - develop # Set a branch name to trigger deployment - pull_request: jobs: deploy: diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml deleted file mode 100644 index 91d574200a..0000000000 --- a/.github/workflows/sonarcloud.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: SonarCloud - -on: - push: - branches: - - main - - develop - - release/* - pull_request: - -jobs: - sonarcloud: - name: SonarCloud - runs-on: ${{ matrix.os }} - if: "!contains(github.event.head_commit.message, '[skip ci]')" - strategy: - matrix: - os: [ubuntu-20.04] - - env: - SONAR_SERVER_URL: "https://sonarcloud.io" - ORTOOLS_DIR: ${{ github.workspace }}/or-tools - ORTOOLS_URL: "https://github.com/rte-france/or-tools/releases/download/v9.5-rte2.0/ortools_cxx_ubuntu-20.04_static_sirius.zip" - - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - - name: Install sonar-scanner and build-wrapper - uses: SonarSource/sonarcloud-github-c-cpp@v2 - - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: sonarcloud-${{ env.SONAR_SCANNER_VERSION }} - - - name: Install libraries - run: | - sudo apt-get update - sudo apt-get install uuid-dev libwxgtk3.0-gtk3-dev - sudo apt-get install libboost-test-dev - - - name: Read antares-deps version - id: antares-deps-version - uses: notiz-dev/github-action-json-property@release - with: - path: 'antares-deps-version.json' - prop_path: 'antares_deps_version' - - - name: Download pre-compiled librairies - uses: ./.github/workflows/download-extract-precompiled-libraries-tgz - with: - antares-deps-version: ${{steps.antares-deps-version.outputs.prop}} - os: ${{matrix.os}} - buildtype: Debug - ortools-url: ${{env.ORTOOLS_URL}} - ortools-dir: ${{env.ORTOOLS_DIR}} - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: 3.8 - - - name: Install gcovr - run: sudo pip install gcovr==5.0 #5.1 generate issues with sonarcloud report parsing - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip3 install -r src/tests/examples/requirements.txt - - - name: Init submodule - run: | - git submodule update --init src/antares-deps - git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests - - - name: Configure - run: | - cmake -B _build -S src \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DDEPS_INSTALL_DIR=./rte-antares-deps-Debug \ - -DCODE_COVERAGE=ON \ - -DCMAKE_BUILD_TYPE=debug \ - -DCMAKE_PREFIX_PATH="../install;${{ env.ORTOOLS_DIR }}/install" \ - -DBUILD_TESTING=ON \ - -DMZ_CODE_COVERAGE=ON \ - -DBUILD_not_system=OFF - - - name: Build - run: | - build-wrapper-linux-x86-64 --out-dir $GITHUB_WORKSPACE/_build/output cmake --build _build --config release -j2 - - - name: Test and generate coverage - continue-on-error: true - run: | - cd $GITHUB_WORKSPACE/_build - ctest -C Release --output-on-failure -L "unit" - - - name: Collect coverage into one XML report - run: | - gcovr --sonarqube --output coverage.xml - - - name: Run sonar-scanner - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: sonar-scanner --define sonar.host.url="${{ env.SONAR_SERVER_URL }}" diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml deleted file mode 100644 index 07941c0e6d..0000000000 --- a/.github/workflows/ubuntu.yml +++ /dev/null @@ -1,269 +0,0 @@ -name: Ubuntu CI (push and/or release) - -on: - release: - types: [created] - push: - branches: - - develop - - feature/* - - features/* - - fix/* - - issue-* - - release/* - - doc/* - schedule: - - cron: '21 2 * * *' - -env: - GITHUB_TOKEN: ${{ github.token }} - IS_RELEASE: ${{ github.event_name == 'release' && github.event.action == 'created' }} - IS_PUSH: ${{ github.event_name == 'push' }} - RUN_EXTENDED_TESTS: ${{ github.event_name == 'schedule' || github.event_name == 'release' }} - -jobs: - - build: - name: Build - env: - ORTOOLS_DIR: ${{ github.workspace }}/or-tools - - outputs: - os: ${{ matrix.os }} - - runs-on: ${{ matrix.os }} - if: "!contains(github.event.head_commit.message, '[skip ci]')" - strategy: - matrix: - os: [ubuntu-20.04] - test-platform: [ubuntu-20.04] - - steps: - - uses: actions/checkout@v3 - - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ${{ matrix.os }} - - - name: Install libraries - run: | - sudo apt-get update - sudo apt-get install uuid-dev libwxgtk3.0-gtk3-dev - sudo apt-get install libboost-test-dev - - - name: Read antares-deps version - id: antares-deps-version - uses: notiz-dev/github-action-json-property@release - with: - path: 'antares-deps-version.json' - prop_path: 'antares_deps_version' - - - - name: Config OR-Tools URL - run: | - echo "ORTOOLS_URL=https://github.com/rte-france/or-tools/releases/download/v9.5-rte2.0/ortools_cxx_ubuntu-20.04_static_sirius.zip" >> $GITHUB_ENV - - - name: Download pre-compiled librairies - uses: ./.github/workflows/download-extract-precompiled-libraries-tgz - with: - antares-deps-version: ${{steps.antares-deps-version.outputs.prop}} - os: ${{matrix.os}} - ortools-url: ${{env.ORTOOLS_URL}} - ortools-dir: ${{env.ORTOOLS_DIR}} - - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: 3.x - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip3 install -r src/tests/examples/requirements.txt - - - name: Init submodule - run: | - git submodule update --init src/antares-deps - git submodule update --init --remote --recursive src/tests/resources/Antares_Simulator_Tests - - - name: Configure push - run: | - cmake -B _build -S src \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DDEPS_INSTALL_DIR=${{github.workspace}}/rte-antares-deps-Release \ - -DCMAKE_BUILD_TYPE=release \ - -DBUILD_TESTING=ON \ - -DBUILD_not_system=OFF \ - -DBUILD_TOOLS=ON \ - -DCMAKE_PREFIX_PATH=${{ env.ORTOOLS_DIR }}/install \ - - - name: Build - run: | - cmake --build _build --config release -j2 - - - # simtest - - name: Read simtest version - id: simtest-version - uses: notiz-dev/github-action-json-property@release - with: - path: 'simtest.json' - prop_path: 'version' - - - name: Run named mps tests - if: ${{ env.IS_PUSH == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-named-mps - os: ${{ matrix.test-platform }} - variant: "named-mps" - - - name: Run unfeasibility-related tests - if: ${{ env.IS_PUSH == 'true' }} - run: | - cd _build - ctest -C Release --output-on-failure -R unfeasible - - - name: Run unit and end-to-end tests - if: ${{ env.IS_PUSH == 'true' }} - run: | - cd _build - ctest -C ${{ matrix.buildtype }} --output-on-failure -L "unit|end-to-end" - - - name: Run kirchhoff constraints tests - if: ${{ false }} - shell: bash - run: | - tar xvf src/tests/kirchhoff-cbuilder/reference.tar.gz -C src/tests/kirchhoff-cbuilder/ - cd _build - ctest -C Release --output-on-failure -R kirchhoff - - - name: Upload logs for failed tests - if: ${{ failure() }} - uses: actions/upload-artifact@v3 - with: - name: test-log - path: ${{ github.workspace }}/_build/Testing/Temporary/LastTest.log - - - name: Run tests about infinity on BCs RHS - if: ${{ env.IS_PUSH == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v830 - os: ${{ matrix.test-platform }} - - - name: Run tests introduced in v860 - if: ${{ env.IS_PUSH == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v860 - os: ${{ matrix.test-platform }} - - - name: Run short-tests - if: ${{ env.IS_PUSH == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: short-tests - os: ${{ matrix.test-platform }} - - - name: Run mps tests - if: ${{ env.IS_PUSH == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-mps - os: ${{ matrix.test-platform }} - - - name: Run tests for adequacy patch (CSR) - if: ${{ env.IS_PUSH == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: adequacy-patch-CSR - os: ${{ matrix.test-platform }} - - - name: Run medium-tests - if: ${{ env.RUN_EXTENDED_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: medium-tests - os: ${{ matrix.test-platform }} - - - name: Run long-tests-1 - if: ${{ env.RUN_EXTENDED_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: long-tests-1 - os: ${{ matrix.test-platform }} - - - name: Run long-tests-2 - if: ${{ env.RUN_EXTENDED_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: long-tests-2 - os: ${{ matrix.test-platform }} - - - name: Run long-tests-3 - if: ${{ env.RUN_EXTENDED_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: long-tests-3 - os: ${{ matrix.test-platform }} - - - name: Installer .deb creation - run: | - cd _build - cpack -G DEB - - - name: .tar.gz creation - run: | - cd _build - cpack -G TGZ - - - name: Solver archive creation - run: | - cd _build - cmake --install . --prefix install - pushd . - cd install/bin - tar czf ../../antares-solver_ubuntu20.04.tar.gz antares-*-solver libsirius_solver.so - popd - rm -rf install - - - name: Installer archive upload push - uses: actions/upload-artifact@v3 - with: - path: _build/*.tar.gz - - - name: Installer deb upload push - uses: actions/upload-artifact@v3 - with: - path: _build/*.deb - - publish_assets: - name: Publish assets - needs: build - runs-on: ${{needs.build.outputs.os}} - steps: - - name: Download all artifacts - if: ${{ env.IS_RELEASE == 'true' }} - uses: actions/download-artifact@v3 - - - - name: Publish assets - if: ${{ env.IS_RELEASE == 'true' }} - uses: alexellis/upload-assets@0.4.0 - env: - GITHUB_TOKEN: ${{ github.token }} - with: - asset_paths: '["*/*.tar.gz", "*/*.deb"]' diff --git a/.github/workflows/windows-release.yml b/.github/workflows/windows-release.yml index cdd36467db..c365797c25 100644 --- a/.github/workflows/windows-release.yml +++ b/.github/workflows/windows-release.yml @@ -51,7 +51,7 @@ jobs: uses: actions/setup-python@v4 with: architecture: 'x64' - python-version: '3.11' + python-version: '3.12' - name : Install deps with VCPKG run: | @@ -99,7 +99,8 @@ jobs: -DCMAKE_BUILD_TYPE=release \ -DBUILD_TESTING=ON \ -DBUILD_TOOLS=ON \ - -DBUILD_not_system=OFF + -DBUILD_not_system=OFF \ + -DPython3_EXECUTABLE='${{ steps.setup-python.outputs.python-path }}' - name: Build run: | diff --git a/.github/workflows/windows-vcpkg.yml b/.github/workflows/windows-vcpkg.yml index 3a9bc71d65..9a4adbdde0 100644 --- a/.github/workflows/windows-vcpkg.yml +++ b/.github/workflows/windows-vcpkg.yml @@ -85,11 +85,12 @@ jobs: ortools-url: ${{env.ORTOOLS_URL}} ortools-dir: ${{env.ORTOOLS_DIR}} - - name: Setup Python 3.11 + - name: Setup Python 3.12 uses: actions/setup-python@v4 + id: setup-python with: architecture: 'x64' - python-version: '3.11' + python-version: '3.12' - name: Install pip dependencies if necessary run: pip install -r src/tests/examples/requirements.txt @@ -107,13 +108,14 @@ jobs: run: | cmake -B _build -S src \ -DDEPS_INSTALL_DIR=rte-antares-deps-Release \ - -DCMAKE_PREFIX_PATH="${{ env.ORTOOLS_DIR }}/install" \ + -DCMAKE_PREFIX_PATH="${{ env.ORTOOLS_DIR }}/install;rte-antares-deps-Release" \ -DVCPKG_ROOT="${{env.VCPKG_ROOT}}" \ -DVCPKG_TARGET_TRIPLET=${{ matrix.triplet }} \ -DCMAKE_BUILD_TYPE=release \ -DBUILD_TESTING=ON \ -DBUILD_TOOLS=ON \ - -DBUILD_not_system=OFF + -DBUILD_not_system=OFF \ + -DPython3_EXECUTABLE='${{ steps.setup-python.outputs.python-path }}' - name: Build shell: bash diff --git a/README.md b/README.md index dea3006bc4..5644ef906e 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ Until 2018 it was distributed under the terms of a proprietary license. In May 2018 RTE decided to release the project under the GPLv3 license. +The GUI is deprecated in favor of [Antares Web](https://github.com/AntaresSimulatorTeam/AntaREST). + [linux_system_svg]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/workflows/Linux%20CI%20(system%20libs)/badge.svg [linux_system_link]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions?query=workflow%3A"Linux%20CI%20(system%20libs)" @@ -40,6 +42,7 @@ In May 2018 RTE decided to release the project under the GPLv3 license. - Antares web site : https://antares-simulator.org - RTE web site : http://www.rte-france.com/ - Doxygen code documentation : https://antaressimulatorteam.github.io/Antares_Simulator/ +- Antares Web : https://github.com/AntaresSimulatorTeam/AntaREST # Installation diff --git a/docs/reference-guide/13-file-format.md b/docs/reference-guide/13-file-format.md index 24b4d64abb..5339a71c6b 100644 --- a/docs/reference-guide/13-file-format.md +++ b/docs/reference-guide/13-file-format.md @@ -1,10 +1,19 @@ # Study format changes This is a list of all recent changes that came with new Antares Simulator features. The main goal of this document is to lower the costs of changing existing interfaces, both GUI and scripts. -## v8.7.1 +## v8.8.0 ### Input ### Short-term storage If no value is specified for `initiallevel`, then a default value of 50% is used. Note that this value is used only if `initialleveloptim=false`, and that `false` is the default value for `initialleveloptim`. +### Experimental "MILP" mode +New value `milp` for existing property `other preferences/unit-commitment-mode` in file **settings/generaldata.ini**. + +Using this property requires OR-Tools and a MILP solver (XPRESS, COIN) + +``` +antares-8.8-solver --use-ortools --ortools-solver coin|xpress ... +``` + ## v8.7.0 ### Input #### Scenarized RHS for binding constraints diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 077445d3b7..7570b715dd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -285,7 +285,7 @@ find_package(minizip) if(NOT minizip_FOUND OR BUILD_MINIZIP) # Repository + tag set(MZ_REPOSITORY "https://github.com/zlib-ng/minizip-ng.git") - set(MZ_TAG "3.0.7") + set(MZ_TAG "4.0.1") # CMake flags set(MZ_LZMA "OFF" CACHE INTERNAL "") set(MZ_ZSTD "OFF" CACHE INTERNAL "") diff --git a/src/analyzer/CMakeLists.txt b/src/analyzer/CMakeLists.txt index 77a74e2957..1a3759f1c3 100644 --- a/src/analyzer/CMakeLists.txt +++ b/src/analyzer/CMakeLists.txt @@ -51,6 +51,7 @@ INSTALL(EXPORT antares-analyzer target_link_libraries(antares-${ANTARES_PRG_VERSION}-analyzer PRIVATE yuni-static-core + Antares::args_helper ${CMAKE_THREADS_LIBS_INIT} antares-core #local.h PUBLIC diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index fc328791a4..22b7f37ca7 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -28,7 +28,7 @@ #include #include #include -#include "../ui/common/winmain.hxx" +#include #include #include "atsp/atsp.h" #include @@ -115,7 +115,8 @@ int main(int argc, char* argv[]) InitializeDefaultLocale(); logs.applicationName("analyzer"); - argv = AntaresGetUTF8Arguments(argc, argv); + IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); + std::tie(argc, argv) = toUTF8ArgsTranslator.convert(); String optSettings; diff --git a/src/libs/antares/CMakeLists.txt b/src/libs/antares/CMakeLists.txt index 6f7ce1063e..02d9254105 100644 --- a/src/libs/antares/CMakeLists.txt +++ b/src/libs/antares/CMakeLists.txt @@ -1,6 +1,7 @@ OMESSAGE("Antares Core library") +add_subdirectory(args) add_subdirectory(writer) add_subdirectory(memory) @@ -8,7 +9,7 @@ add_subdirectory(object) add_subdirectory(array) add_subdirectory(correlation) - +add_subdirectory(concurrency) add_subdirectory(logs) add_subdirectory(jit) @@ -58,6 +59,7 @@ add_subdirectory(stdcxx) add_subdirectory(utils) add_subdirectory(paths) add_subdirectory(mersenne-twister) +add_subdirectory(series) add_library(antares-core antares.h diff --git a/src/libs/antares/args/CMakeLists.txt b/src/libs/antares/args/CMakeLists.txt new file mode 100644 index 0000000000..eb9559c360 --- /dev/null +++ b/src/libs/antares/args/CMakeLists.txt @@ -0,0 +1,22 @@ +set(SRC_ARGS_HELPER + include/antares/args/args_to_utf8.h + args_to_utf8.cpp +) + +source_group("misc\\args_helper" FILES ${SRC_ARGS_HELPER}) + +add_library(args_helper + ${SRC_ARGS_HELPER} +) + +add_library(Antares::args_helper ALIAS args_helper) + +target_link_libraries(args_helper + PRIVATE + yuni-static-core + ) + +target_include_directories(args_helper + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include +) \ No newline at end of file diff --git a/src/libs/antares/args/args_to_utf8.cpp b/src/libs/antares/args/args_to_utf8.cpp new file mode 100644 index 0000000000..7ac874e4d1 --- /dev/null +++ b/src/libs/antares/args/args_to_utf8.cpp @@ -0,0 +1,44 @@ + +#include +#include "antares/args/args_to_utf8.h" + +#ifdef YUNI_OS_WINDOWS +#include +#include +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif // WIN32_LEAN_AND_MEAN +#include +#include +#endif // YUNI_OS_WINDOWS + +IntoUTF8ArgsTranslator::IntoUTF8ArgsTranslator(int argc, char** argv) : argc_(argc), argv_(argv) +{ +} + +std::pair IntoUTF8ArgsTranslator::convert() +{ +#ifdef YUNI_OS_WINDOWS + wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc_); + argv_ = (char**)malloc(argc_ * sizeof(char*)); + for (int i = 0; i != argc_; ++i) + { + const uint len = (uint)wcslen(wargv[i]); + const uint newLen = WideCharToMultiByte(CP_UTF8, 0, wargv[i], len, NULL, 0, NULL, NULL); + argv_[i] = (char*)malloc((newLen + 1) * sizeof(char)); + memset(argv_[i], 0, (newLen + 1) * sizeof(char)); + WideCharToMultiByte(CP_UTF8, 0, wargv[i], len, argv_[i], newLen, NULL, NULL); + argv_[i][newLen] = '\0'; + } +#endif + return {argc_, argv_}; +} + +IntoUTF8ArgsTranslator::~IntoUTF8ArgsTranslator() +{ +#ifdef YUNI_OS_WINDOWS + for (int i = 0; i != argc_; ++i) + free(argv_[i]); + free(argv_); +#endif +} diff --git a/src/libs/antares/args/include/antares/args/args_to_utf8.h b/src/libs/antares/args/include/antares/args/args_to_utf8.h new file mode 100644 index 0000000000..cb1c0085c6 --- /dev/null +++ b/src/libs/antares/args/include/antares/args/args_to_utf8.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +class IntoUTF8ArgsTranslator +{ +public: + IntoUTF8ArgsTranslator(int argc, char** argv); + std::pair convert(); + ~IntoUTF8ArgsTranslator(); + +private: + int argc_; + char** argv_; +}; diff --git a/src/libs/antares/checks/antares/checks/checkLoadedInputData.h b/src/libs/antares/checks/antares/checks/checkLoadedInputData.h index 8900cbfd62..ad036cafc0 100644 --- a/src/libs/antares/checks/antares/checks/checkLoadedInputData.h +++ b/src/libs/antares/checks/antares/checks/checkLoadedInputData.h @@ -26,6 +26,10 @@ */ namespace Antares::Check { +void checkOrtoolsUsage(Antares::Data::UnitCommitmentMode ucMode, + bool ortoolsUsed, + const std::string& solverName); + void checkStudyVersion(const AnyString& optStudyFolder); void checkSimplexRangeHydroPricing(Antares::Data::SimplexOptimization optRange, diff --git a/src/libs/antares/checks/checkLoadedInputData.cpp b/src/libs/antares/checks/checkLoadedInputData.cpp index 3fcad20e02..d585ffdaa1 100644 --- a/src/libs/antares/checks/checkLoadedInputData.cpp +++ b/src/libs/antares/checks/checkLoadedInputData.cpp @@ -29,11 +29,31 @@ #include #include +#include #include #include namespace Antares::Check { +void checkOrtoolsUsage(Antares::Data::UnitCommitmentMode ucMode, + bool ortoolsUsed, + const std::string& solverName) +{ + using namespace Antares::Data; + if (ucMode == UnitCommitmentMode::ucMILP) + { + if (!ortoolsUsed) + { + throw Error::IncompatibleMILPWithoutOrtools(); + } + + if (solverName == "sirius") + { + throw Error::IncompatibleMILPOrtoolsSolver(); + } + } +} + void checkStudyVersion(const AnyString& optStudyFolder) { using namespace Antares::Data; @@ -142,7 +162,7 @@ void checkMinStablePower(bool tsGenThermal, const Antares::Data::AreaList& areas // TS template static void checkThermalColumnNumber(const Antares::Data::AreaList& areas, - Matrix Antares::Data::EconomicInputData::*matrix) + Antares::Data::TimeSeries::TS Antares::Data::EconomicInputData::*matrix) { ExceptionT exception; bool error = false; @@ -155,7 +175,7 @@ static void checkThermalColumnNumber(const Antares::Data::AreaList& areas, if (cluster.costgeneration == Antares::Data::setManually) continue; const uint otherMatrixWidth = (cluster.ecoInput.*matrix).width; - uint tsWidth = cluster.series->timeSeries.width; + uint tsWidth = cluster.series.timeSeries.width; if (otherMatrixWidth != 1 && otherMatrixWidth != tsWidth) { logs.warning() << "Area: " << area.name << ". Cluster name: " << cluster.name() diff --git a/src/libs/antares/concurrency/CMakeLists.txt b/src/libs/antares/concurrency/CMakeLists.txt new file mode 100644 index 0000000000..ca8eb73c0e --- /dev/null +++ b/src/libs/antares/concurrency/CMakeLists.txt @@ -0,0 +1,9 @@ + + +add_library(concurrency) +add_library(Antares::concurrency ALIAS concurrency) + +target_sources(concurrency PRIVATE concurrency.cpp) +target_include_directories(concurrency PUBLIC include) + +target_link_libraries(concurrency yuni-static-core) \ No newline at end of file diff --git a/src/libs/antares/concurrency/concurrency.cpp b/src/libs/antares/concurrency/concurrency.cpp new file mode 100644 index 0000000000..51f683372a --- /dev/null +++ b/src/libs/antares/concurrency/concurrency.cpp @@ -0,0 +1,83 @@ +/* +** 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 "yuni/job/job.h" +#include "antares/concurrency/concurrency.h" + +namespace Antares::Concurrency +{ + +namespace { + +/*! +* Just wraps an arbitrary task as a yuni job, and allows to retrieve the corresponding future. +*/ +class PackagedJob : public Yuni::Job::IJob { +public: + PackagedJob(const Task& task) : task_(task) {} + + TaskFuture getFuture() { + return task_.get_future(); + } + +protected: + void onExecute() override { + task_(); + } + +private: + std::packaged_task task_; +}; + +} + +std::future AddTask(Yuni::Job::QueueService& threadPool, + const Task& task, + Yuni::Job::Priority priority) { + auto job = std::make_unique(task); + auto future = job->getFuture(); + threadPool.add(job.release(), priority); + return future; +} + +void FutureSet::add(TaskFuture&& f) { + std::lock_guard lock(mutex_); + futures_.push_back(std::move(f)); +} + +void FutureSet::join() { + std::vector toBeJoined; + { + std::lock_guard lock(mutex_); + std::swap(futures_, toBeJoined); + } + for (auto& f: toBeJoined) { + f.get(); + } +} + +} diff --git a/src/libs/antares/concurrency/include/antares/concurrency/concurrency.h b/src/libs/antares/concurrency/include/antares/concurrency/concurrency.h new file mode 100644 index 0000000000..8813f3eeb1 --- /dev/null +++ b/src/libs/antares/concurrency/include/antares/concurrency/concurrency.h @@ -0,0 +1,88 @@ +/* +** 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 +*/ +#ifndef ANTARES_CONCURRENCY_H +#define ANTARES_CONCURRENCY_H + +#include +#include "yuni/job/queue/service.h" + +namespace Antares::Concurrency +{ + +using Task = std::function; +using TaskFuture = std::future; + +/*! + * \brief Queues the provided function and returns the corresponding std::future. + * + * This allows to handle exceptions occuring in the underlying task, + * as opposite to Yuni::Job::QueueService::add which swallows them. + */ +[[nodiscard]] TaskFuture AddTask(Yuni::Job::QueueService& threadPool, + const Task& task, + Yuni::Job::Priority priority = Yuni::Job::priorityDefault); + +/*! + * \brief Utility class to gather futures to wait for. + */ +class FutureSet +{ +public: + FutureSet() = default; + ~FutureSet() = default; + + FutureSet(const FutureSet&) = delete; + FutureSet& operator=(const FutureSet&) = delete; + FutureSet(FutureSet&&) = delete; + FutureSet& operator=(FutureSet&&) = delete; + + /*! + * \brief Adds one future to be monitored by this set. + * + * Note: the provided future will be left in "moved from" state. + */ + void add(TaskFuture&& f); + + /*! + * \brief Waits for completion of all added futures. + * + * If one of the future ends on exception, re-throws the first encountered exception. + * Note that futures cannot be added while some thread is waiting for completion. + * + * Joining also resets the list of tasks to wait for. + */ + void join(); + +private: + std::mutex mutex_; + std::vector futures_; +}; + +} + + +#endif //ANTARES_CONCURRENCY_H diff --git a/src/libs/antares/exception/LoadingError.cpp b/src/libs/antares/exception/LoadingError.cpp index 5334b0912d..92c6f26bfa 100644 --- a/src/libs/antares/exception/LoadingError.cpp +++ b/src/libs/antares/exception/LoadingError.cpp @@ -72,6 +72,16 @@ IncompatibleParallelOptions::IncompatibleParallelOptions() : { } +IncompatibleMILPWithoutOrtools::IncompatibleMILPWithoutOrtools() : + LoadingError("Unit Commitment mode 'milp' must be used with an OR-Tools solver ") +{ +} + +IncompatibleMILPOrtoolsSolver::IncompatibleMILPOrtoolsSolver() : + LoadingError("'milp' mode does not work with OR-Tools using Sirius solver") +{ +} + IncompatibleOptRangeHydroPricing::IncompatibleOptRangeHydroPricing() : LoadingError("Simplex optimization range and hydro pricing mode : values are not compatible ") { diff --git a/src/libs/antares/exception/antares/exception/LoadingError.hpp b/src/libs/antares/exception/antares/exception/LoadingError.hpp index a9b7b0fa30..d3b7e15b74 100644 --- a/src/libs/antares/exception/antares/exception/LoadingError.hpp +++ b/src/libs/antares/exception/antares/exception/LoadingError.hpp @@ -92,6 +92,18 @@ class IncompatibleParallelOptions : public LoadingError IncompatibleParallelOptions(); }; +class IncompatibleMILPWithoutOrtools : public LoadingError +{ +public: + IncompatibleMILPWithoutOrtools(); +}; + +class IncompatibleMILPOrtoolsSolver : public LoadingError +{ +public: + IncompatibleMILPOrtoolsSolver(); +}; + class IncompatibleOptRangeHydroPricing : public LoadingError { public: diff --git a/src/libs/antares/series/CMakeLists.txt b/src/libs/antares/series/CMakeLists.txt new file mode 100644 index 0000000000..c91d30ae10 --- /dev/null +++ b/src/libs/antares/series/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(series) +add_library(Antares::series ALIAS series) + +set(SRC_STUDY_PART_SERIES + include/antares/series/series.h + series.cpp +) +target_sources(series PUBLIC ${SRC_STUDY_PART_SERIES}) + +target_link_libraries(series PUBLIC Antares::array) + +target_include_directories(series + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include +) diff --git a/src/libs/antares/series/include/antares/series/series.h b/src/libs/antares/series/include/antares/series/series.h new file mode 100644 index 0000000000..48b7b7e4fd --- /dev/null +++ b/src/libs/antares/series/include/antares/series/series.h @@ -0,0 +1,96 @@ +/* +** 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 +*/ +#ifndef __ANTARES_LIBS_STUDY_PARTS_COMMON_TIMESERIES_H__ +#define __ANTARES_LIBS_STUDY_PARTS_COMMON_TIMESERIES_H__ + +#include + +namespace Antares::Data +{ + +class TimeSeries +{ + /*! + ** \brief This class is used to represent the generic time series + ** + ** The goal is to handle indexing with the time series numbers: getCoefficient() + ** and also providing a wrapper for all the Matrix<> functions such as resize() + */ + +public: + using numbers = Matrix; + using TS = Matrix; + + explicit TimeSeries(numbers& tsNumbers); + /*! + ** \brief Load series from a file + ** + ** \param path path of the file + ** \param dataBuffer yuni dependency to use loadFromCSV + ** \param average used to average timeseries + ** \return A non-zero value if the operation succeeded, 0 otherwise + */ + bool loadFromFile(const std::string& path, + Matrix<>::BufferType dataBuffer, + const bool average); + /*! + ** \brief Save time series to a file + ** \ingroup windseries + ** + ** \param areaID The ID of the area associated to the data series + ** \param folder The target folder + ** \param prefix the prefix for the filename + ** \return A non-zero value if the operation succeeded, 0 otherwise + */ + int saveToFolder(const AreaName& areaID, + const std::string& folder, + const std::string& prefix) const; + + double getCoefficient(uint32_t year, uint32_t timestep) const; + const double* getColumn(uint32_t year) const; + uint32_t getSeriesIndex(uint32_t year) const; + + double* operator[](uint32_t index); + + void reset(); + void unloadFromMemory() const; + void roundAllEntries(); + void resize(uint32_t timeSeriesCount, uint32_t timestepCount); + void averageTimeseries(); + + bool forceReload(bool reload = false) const; + void markAsModified() const; + uint64_t memoryUsage() const; + + TS timeSeries; + numbers& timeseriesNumbers; + + static const double emptyColumn[HOURS_PER_YEAR]; +}; + +} // namespace Antares::Data +#endif /* __ANTARES_LIBS_STUDY_PARTS_COMMON_TIMESERIES_H__ */ diff --git a/src/libs/antares/series/series.cpp b/src/libs/antares/series/series.cpp new file mode 100644 index 0000000000..793ff4c9ff --- /dev/null +++ b/src/libs/antares/series/series.cpp @@ -0,0 +1,140 @@ +/* +** 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 "antares/series/series.h" + +using namespace Yuni; + +#define SEP IO::Separator + + +namespace Antares::Data +{ + +const double TimeSeries::emptyColumn[] = {0}; + +TimeSeries::TimeSeries(numbers& tsNumbers) : timeseriesNumbers(tsNumbers) +{} + +bool TimeSeries::loadFromFile(const std::string& path, + Matrix<>::BufferType dataBuffer, + const bool average) +{ + bool ret = true; + ret = timeSeries.loadFromCSVFile(path, 1, HOURS_PER_YEAR, &dataBuffer) && ret; + + if (average) + timeSeries.averageTimeseries(); + + timeseriesNumbers.clear(); + + return ret; +} + +int TimeSeries::saveToFolder(const AreaName& areaID, + const std::string& folder, + const std::string& prefix) const +{ + Clob buffer; + buffer.clear() << folder << SEP << prefix << areaID << ".txt"; + return timeSeries.saveToCSVFile(buffer, 0); +} + + +double TimeSeries::getCoefficient(uint32_t year, uint32_t timestep) const +{ + if (timeSeries.width == 0) + return 0; + return timeSeries[getSeriesIndex(year)][timestep]; +} + +const double* TimeSeries::getColumn(uint32_t year) const +{ + if (timeSeries.width == 0) + return emptyColumn; + return timeSeries[getSeriesIndex(year)]; +} + +uint32_t TimeSeries::getSeriesIndex(uint32_t year) const +{ + if (timeSeries.width == 1) + return 0; + else + return timeseriesNumbers[0][year]; +} + +double* TimeSeries::operator[](uint32_t index) +{ + if (timeSeries.width <= index) + return nullptr; + return timeSeries[index]; +} + +void TimeSeries::reset() +{ + timeSeries.reset(1, HOURS_PER_YEAR); +} + +void TimeSeries::resize(uint32_t timeSeriesCount, uint32_t timestepCount) +{ + timeSeries.resize(timeSeriesCount, timestepCount); +} + +void TimeSeries::roundAllEntries() +{ + timeSeries.roundAllEntries(); +} + +void TimeSeries::averageTimeseries() +{ + timeSeries.averageTimeseries(); +} + +void TimeSeries::unloadFromMemory() const +{ + timeSeries.unloadFromMemory(); +} + +bool TimeSeries::forceReload(bool reload) const +{ + return timeSeries.forceReload(reload); +} + +void TimeSeries::markAsModified() const +{ + timeSeries.markAsModified(); +} + +uint64_t TimeSeries::memoryUsage() const +{ + return timeSeries.memoryUsage(); +} + +} // namespace Antares::Data diff --git a/src/libs/antares/study/CMakeLists.txt b/src/libs/antares/study/CMakeLists.txt index b4db365a29..127f872f27 100644 --- a/src/libs/antares/study/CMakeLists.txt +++ b/src/libs/antares/study/CMakeLists.txt @@ -58,8 +58,6 @@ source_group("study\\area\\ui" FILES ${SRC_STUDY_AREA_UI}) set(SRC_STUDY_PART_COMMON - parts/common/series.h - parts/common/series.cpp parts/common/cluster.cpp parts/common/cluster.h parts/common/cluster_list.h @@ -114,9 +112,6 @@ source_group("study\\part\\short-term-storage" FILES ${SRC_STUDY_PART_SHORT_TERM set(SRC_STUDY_PART_WIND parts/wind/container.h parts/wind/container.cpp - parts/wind/series.h - parts/wind/series.hxx - parts/wind/series.cpp parts/wind/prepro.h parts/wind/prepro.hxx parts/wind/prepro.cpp @@ -127,7 +122,6 @@ set(SRC_STUDY_PART_HYDRO parts/hydro/container.h parts/hydro/container.cpp parts/hydro/series.h - parts/hydro/series.hxx parts/hydro/series.cpp parts/hydro/prepro.h parts/hydro/prepro.cpp @@ -202,9 +196,6 @@ set(SRC_STUDY # Load parts/load/container.h parts/load/container.cpp - parts/load/series.h - parts/load/series.hxx - parts/load/series.cpp parts/load/prepro.cpp parts/load/prepro.h parts/load/prepro.hxx @@ -212,9 +203,6 @@ set(SRC_STUDY # Solar parts/solar/container.h parts/solar/container.cpp - parts/solar/series.h - parts/solar/series.hxx - parts/solar/series.cpp parts/solar/prepro.cpp parts/solar/prepro.h parts/solar/prepro.hxx @@ -312,6 +300,7 @@ target_link_libraries(study Antares::mersenne Antares::result_writer #study.h Antares::object + Antares::series PRIVATE Antares::exception Antares::benchmarking diff --git a/src/libs/antares/study/area/area.cpp b/src/libs/antares/study/area/area.cpp index 030af80586..21f5715eab 100644 --- a/src/libs/antares/study/area/area.cpp +++ b/src/libs/antares/study/area/area.cpp @@ -205,16 +205,8 @@ void Area::createMissingData() void Area::createMissingTimeSeries() { - if (!load.series) - load.series = new DataSeriesLoad(); - if (!solar.series) - solar.series = new DataSeriesSolar(); - if (!wind.series) - wind.series = new DataSeriesWind(); if (!hydro.series) hydro.series = new DataSeriesHydro(); - thermal.list.ensureDataTimeSeries(); - renewable.list.ensureDataTimeSeries(); } void Area::createMissingPrepros() { @@ -269,16 +261,13 @@ void Area::resizeAllTimeseriesNumbers(uint n) assert(n < 200000); // arbitrary number // asserts - assert(load.series and "load.series must not be nullptr !"); - assert(solar.series and "solar.series must not be nullptr !"); - assert(wind.series and "wind.series must not be nullptr !"); assert(hydro.series and "series must not be nullptr !"); if (!n) { - load.series->timeseriesNumbers.clear(); - solar.series->timeseriesNumbers.clear(); - wind.series->timeseriesNumbers.clear(); + load.series.timeseriesNumbers.clear(); + solar.series.timeseriesNumbers.clear(); + wind.series.timeseriesNumbers.clear(); hydro.series->timeseriesNumbers.clear(); for (auto& namedLink : links) { @@ -288,9 +277,9 @@ void Area::resizeAllTimeseriesNumbers(uint n) } else { - load.series->timeseriesNumbers.resize(1, n); - solar.series->timeseriesNumbers.resize(1, n); - wind.series->timeseriesNumbers.resize(1, n); + load.series.timeseriesNumbers.resize(1, n); + solar.series.timeseriesNumbers.resize(1, n); + wind.series.timeseriesNumbers.resize(1, n); hydro.series->timeseriesNumbers.resize(1, n); for (auto& namedLink : links) { diff --git a/src/libs/antares/study/area/area.h b/src/libs/antares/study/area/area.h index d65d840625..1a59fd5346 100644 --- a/src/libs/antares/study/area/area.h +++ b/src/libs/antares/study/area/area.h @@ -795,31 +795,16 @@ AreaLink* AreaListAddLink(AreaList* l, const char area[], const char with[], boo void AreaListClearAllLinks(AreaList* l); -/*! -** \brief Ensure data for load time-series are initialized -*/ -void AreaListEnsureDataLoadTimeSeries(AreaList* l); - /*! ** \brief Ensure data for load prepro are initialized */ void AreaListEnsureDataLoadPrepro(AreaList* l); -/*! -** \brief Ensure data for load time-series are initialized -*/ -void AreaListEnsureDataSolarTimeSeries(AreaList* l); - /*! ** \brief Ensure data for solar prepro are initialized */ void AreaListEnsureDataSolarPrepro(AreaList* l); -/*! -** \brief Ensure data for wind time-series are initialized -*/ -void AreaListEnsureDataWindTimeSeries(AreaList* l); - /*! ** \brief Ensure data for wind prepro are initialized */ @@ -835,15 +820,6 @@ void AreaListEnsureDataHydroTimeSeries(AreaList* l); */ void AreaListEnsureDataHydroPrepro(AreaList* l); -/*! -** \brief Ensure data for thermal time-series are initialized -*/ -void AreaListEnsureDataThermalTimeSeries(AreaList* l); - -/*! -** \brief Ensure data for renewable time-series are initialized -*/ -void AreaListEnsureDataRenewableTimeSeries(AreaList* l); /*! ** \brief Ensure data for thermal prepro are initialized diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index 0526108ee0..5ce8975540 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -215,11 +215,8 @@ static bool AreaListSaveToFolderSingleArea(const Area& area, Clob& buffer, const << area.id; ret = area.load.prepro->saveToFolder(buffer) && ret; } - if (area.load.series) // Series - { - buffer.clear() << folder << SEP << "input" << SEP << "load" << SEP << "series"; - ret = DataSeriesLoadSaveToFolder(area.load.series, area.id, buffer.c_str()) && ret; - } + buffer.clear() << folder << SEP << "input" << SEP << "load" << SEP << "series"; + area.load.series.saveToFolder(area.id, buffer.c_str(), "load_") && ret; } // Solar @@ -230,11 +227,8 @@ static bool AreaListSaveToFolderSingleArea(const Area& area, Clob& buffer, const << area.id; ret = area.solar.prepro->saveToFolder(buffer) && ret; } - if (area.solar.series) // Series - { - buffer.clear() << folder << SEP << "input" << SEP << "solar" << SEP << "series"; - ret = DataSeriesSolarSaveToFolder(area.solar.series, area.id, buffer.c_str()) && ret; - } + buffer.clear() << folder << SEP << "input" << SEP << "solar" << SEP << "series"; + ret = area.solar.series.saveToFolder(area.id, buffer.c_str(), "solar_") && ret; } // Hydro @@ -263,11 +257,9 @@ static bool AreaListSaveToFolderSingleArea(const Area& area, Clob& buffer, const << area.id; ret = area.wind.prepro->saveToFolder(buffer) && ret; } - if (area.wind.series) // Series - { - buffer.clear() << folder << SEP << "input" << SEP << "wind" << SEP << "series"; - ret = DataSeriesWindSaveToFolder(area.wind.series, area.id, buffer.c_str()) && ret; - } + + buffer.clear() << folder << SEP << "input" << SEP << "wind" << SEP << "series"; + ret = area.wind.series.saveToFolder(area.id, buffer.c_str(), "wind_") && ret; } // Thermal cluster list @@ -848,6 +840,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, ret = area.ui->loadFromFile(buffer) && ret; } + bool averageTs = (study.usedByTheSolver && study.parameters.derated); // Load { if (area.load.prepro) // Prepro @@ -857,10 +850,11 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, << area.id; ret = area.load.prepro->loadFromFolder(buffer) && ret; } - if (area.load.series && (!options.loadOnlyNeeded || !area.load.prepro)) // Series + if (!options.loadOnlyNeeded || !area.load.prepro) // Series { - buffer.clear() << study.folderInput << SEP << "load" << SEP << "series"; - ret = DataSeriesLoadLoadFromFolder(study, area.load.series, area.id, buffer.c_str()) + buffer.clear() << study.folderInput << SEP << "load" << SEP << "series" << SEP + << "load_" << area.id << ".txt"; + ret = area.load.series.loadFromFile(buffer.c_str(), study.dataBuffer, averageTs) && ret; } @@ -877,11 +871,13 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, << area.id; ret = area.solar.prepro->loadFromFolder(buffer) && ret; } - if (area.solar.series && (!options.loadOnlyNeeded || !area.solar.prepro)) // Series + if (!options.loadOnlyNeeded || !area.solar.prepro) // Series { - buffer.clear() << study.folderInput << SEP << "solar" << SEP << "series"; - ret = DataSeriesSolarLoadFromFolder(study, area.solar.series, area.id, buffer.c_str()) - && ret; + buffer.clear() << study.folderInput << SEP << "solar" << SEP << "series" << SEP + << "solar_" << area.id << ".txt"; + ret = area.solar.series.loadFromFile(buffer.c_str(), study.dataBuffer, averageTs) + && ret; + } ++options.progressTicks; @@ -920,10 +916,11 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, << area.id; ret = area.wind.prepro->loadFromFolder(buffer) && ret; } - if (area.wind.series && (!options.loadOnlyNeeded || !area.wind.prepro)) // Series + if (!options.loadOnlyNeeded || !area.wind.prepro) // Series { - buffer.clear() << study.folderInput << SEP << "wind" << SEP << "series"; - ret = DataSeriesWindLoadFromFolder(study, area.wind.series, area.id, buffer.c_str()) + buffer.clear() << study.folderInput << SEP << "wind" << SEP << "series" << SEP + << "wind_" << area.id << ".txt"; + ret = area.wind.series.loadFromFile(buffer.c_str(), study.dataBuffer, averageTs) && ret; } @@ -1036,12 +1033,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, void AreaList::ensureDataIsInitialized(Parameters& params, bool loadOnlyNeeded) { - AreaListEnsureDataLoadTimeSeries(this); - AreaListEnsureDataSolarTimeSeries(this); - AreaListEnsureDataWindTimeSeries(this); AreaListEnsureDataHydroTimeSeries(this); - AreaListEnsureDataThermalTimeSeries(this); - AreaListEnsureDataRenewableTimeSeries(this); if (loadOnlyNeeded) { @@ -1246,17 +1238,6 @@ Area* AreaListFindPtr(AreaList* l, const Area* ptr) return nullptr; } -void AreaListEnsureDataLoadTimeSeries(AreaList* l) -{ - /* Asserts */ - assert(l); - - l->each([&](Data::Area& area) { - if (!area.load.series) - area.load.series = new DataSeriesLoad(); - }); -} - void AreaListEnsureDataLoadPrepro(AreaList* l) { /* Asserts */ @@ -1268,17 +1249,6 @@ void AreaListEnsureDataLoadPrepro(AreaList* l) }); } -void AreaListEnsureDataSolarTimeSeries(AreaList* l) -{ - /* Asserts */ - assert(l); - - l->each([&](Data::Area& area) { - if (!area.solar.series) - area.solar.series = new DataSeriesSolar(); - }); -} - void AreaListEnsureDataSolarPrepro(AreaList* l) { /* Asserts */ @@ -1290,17 +1260,6 @@ void AreaListEnsureDataSolarPrepro(AreaList* l) }); } -void AreaListEnsureDataWindTimeSeries(AreaList* l) -{ - /* Asserts */ - assert(l); - - l->each([&](Data::Area& area) { - if (!area.wind.series) - area.wind.series = new DataSeriesWind(); - }); -} - void AreaListEnsureDataWindPrepro(AreaList* l) { /* Asserts */ @@ -1334,18 +1293,6 @@ void AreaListEnsureDataHydroPrepro(AreaList* l) }); } -void AreaListEnsureDataThermalTimeSeries(AreaList* l) -{ - assert(l); - l->each([&](Data::Area& area) { area.thermal.list.ensureDataTimeSeries(); }); -} - -void AreaListEnsureDataRenewableTimeSeries(AreaList* l) -{ - assert(l); - l->each([&](Data::Area& area) { area.renewable.list.ensureDataTimeSeries(); }); -} - void AreaListEnsureDataThermalPrepro(AreaList* l) { assert(l && "The area list must not be nullptr"); @@ -1604,34 +1551,31 @@ void AreaList::updateNameIDSet() const void AreaList::removeLoadTimeseries() { - each([&](Data::Area& area) { area.load.series->timeSeries.reset(1, HOURS_PER_YEAR); }); + each([](Data::Area& area) { area.load.series.reset(); }); } void AreaList::removeHydroTimeseries() { - each([&](Data::Area& area) { - area.hydro.series->ror.reset(1, HOURS_PER_YEAR); - area.hydro.series->storage.reset(1, DAYS_PER_YEAR); - area.hydro.series->mingen.reset(1, HOURS_PER_YEAR); - area.hydro.series->count = 1; + each([](Data::Area& area) { + area.hydro.series->reset(); }); } void AreaList::removeSolarTimeseries() { - each([&](Data::Area& area) { area.solar.series->timeSeries.reset(1, HOURS_PER_YEAR); }); + each([](Data::Area& area) { area.solar.series.reset(); }); } void AreaList::removeWindTimeseries() { - each([&](Data::Area& area) { area.wind.series->timeSeries.reset(1, HOURS_PER_YEAR); }); + each([](Data::Area& area) { area.wind.series.reset(); }); } void AreaList::removeThermalTimeseries() { - each([&](Data::Area& area) { + each([](Data::Area& area) { area.thermal.list.each( - [&](Data::ThermalCluster& cluster) { cluster.series->timeSeries.reset(1, HOURS_PER_YEAR); }); + [](Data::ThermalCluster& cluster) { cluster.series.reset(); }); }); } diff --git a/src/libs/antares/study/area/scratchpad.cpp b/src/libs/antares/study/area/scratchpad.cpp index 6c63ebf9ac..26595ae28d 100644 --- a/src/libs/antares/study/area/scratchpad.cpp +++ b/src/libs/antares/study/area/scratchpad.cpp @@ -111,7 +111,7 @@ AreaScratchpad::AreaScratchpad(const StudyRuntimeInfos& rinfos, Area& area) if (!area.hydro.prepro) // not in prepro mode { assert(area.hydro.series); - hydroHasInflows = MatrixTestForAtLeastOnePositiveValue(area.hydro.series->storage); + hydroHasInflows = MatrixTestForAtLeastOnePositiveValue(area.hydro.series->storage.timeSeries); } else { diff --git a/src/libs/antares/study/area/store-timeseries-numbers.cpp b/src/libs/antares/study/area/store-timeseries-numbers.cpp index ebecde7625..aa207a05ac 100644 --- a/src/libs/antares/study/area/store-timeseries-numbers.cpp +++ b/src/libs/antares/study/area/store-timeseries-numbers.cpp @@ -69,12 +69,12 @@ static void genericStoreTimeseriesNumbers(Solver::IResultWriter& writer, void storeTimeseriesNumbersForLoad(Solver::IResultWriter& writer, const Area& area) { - genericStoreTimeseriesNumbers(writer, area.load.series->timeseriesNumbers, area.id, "load"); + genericStoreTimeseriesNumbers(writer, area.load.series.timeseriesNumbers, area.id, "load"); } void storeTimeseriesNumbersForSolar(Solver::IResultWriter& writer, const Area& area) { - genericStoreTimeseriesNumbers(writer, area.solar.series->timeseriesNumbers, area.id, "solar"); + genericStoreTimeseriesNumbers(writer, area.solar.series.timeseriesNumbers, area.id, "solar"); } void storeTimeseriesNumbersForHydro(Solver::IResultWriter& writer, const Area& area) @@ -84,7 +84,7 @@ void storeTimeseriesNumbersForHydro(Solver::IResultWriter& writer, const Area& a void storeTimeseriesNumbersForWind(Solver::IResultWriter& writer, const Area& area) { - genericStoreTimeseriesNumbers(writer, area.wind.series->timeseriesNumbers, area.id, "wind"); + genericStoreTimeseriesNumbers(writer, area.wind.series.timeseriesNumbers, area.id, "wind"); } void storeTimeseriesNumbersForThermal(Solver::IResultWriter& writer, const Area& area) diff --git a/src/libs/antares/study/fwd.cpp b/src/libs/antares/study/fwd.cpp index 5988b26e7e..bfba0dc762 100644 --- a/src/libs/antares/study/fwd.cpp +++ b/src/libs/antares/study/fwd.cpp @@ -264,8 +264,10 @@ UnitCommitmentMode StringToUnitCommitmentMode(const AnyString& text) s.trim(); s.toLower(); if (s == "fast") - return ucHeuristic; - if (s == "accurate") // mixed integer linear problem + return ucHeuristicFast; + if (s == "accurate") + return ucHeuristicAccurate; + if (s == "milp") // mixed integer linear problem return ucMILP; return ucUnknown; @@ -275,10 +277,12 @@ const char* UnitCommitmentModeToCString(UnitCommitmentMode ucommitment) { switch (ucommitment) { - case ucHeuristic: + case ucHeuristicFast: return "fast"; - case ucMILP: + case ucHeuristicAccurate: return "accurate"; // (slow) + case ucMILP: + return "milp"; // (possibly very slow) case ucUnknown: return ""; } diff --git a/src/libs/antares/study/fwd.h b/src/libs/antares/study/fwd.h index 6db7c2ee57..8e3dca76d1 100644 --- a/src/libs/antares/study/fwd.h +++ b/src/libs/antares/study/fwd.h @@ -464,8 +464,16 @@ SheddingPolicy StringToSheddingPolicy(const AnyString& text); enum UnitCommitmentMode { - ucHeuristic = 0, - ucMILP, // mixed integer linear problem + //! Heuristic in which 2 LP problems are solved + //! No explicit modelling for the number of ON/OFF units + ucHeuristicFast = 0, + //! Heuristic in which 2 LP problems are solved + //! Explicit modelling for the number of ON/OFF units + ucHeuristicAccurate, + //! A single MILP problem is solved, with explicit modelling + //! for the number of ON/OFF units + ucMILP, + //! Unknown mode, mainly used for error handling ucUnknown, }; diff --git a/src/libs/antares/study/parameters.cpp b/src/libs/antares/study/parameters.cpp index c10519942f..ec128bda4e 100644 --- a/src/libs/antares/study/parameters.cpp +++ b/src/libs/antares/study/parameters.cpp @@ -302,7 +302,7 @@ void Parameters::reset() power.fluctuations = lssFreeModulations; shedding.policy = shpShavePeaks; - unitCommitment.ucMode = ucHeuristic; + unitCommitment.ucMode = ucHeuristicFast; nbCores.ncMode = ncAvg; renewableGeneration.rgModelling = rgAggregated; @@ -730,7 +730,7 @@ static bool SGDIntLoadFamily_OtherPreferences(Parameters& d, } logs.warning() << "parameters: invalid unit commitment mode. Got '" << value << "'. reset to fast mode"; - d.unitCommitment.ucMode = ucHeuristic; + d.unitCommitment.ucMode = ucHeuristicFast; return false; } // Renewable generation modelling @@ -1344,6 +1344,7 @@ void Parameters::prepareForSimulation(const StudyLoadOptions& options) std::vector excluded_vars; renewableGeneration.addExcludedVariables(excluded_vars); adqPatchParams.addExcludedVariables(excluded_vars); + unitCommitment.addExcludedVariables(excluded_vars); variablesPrintInfo.prepareForSimulation(thematicTrimming, excluded_vars); @@ -1792,4 +1793,25 @@ bool Parameters::RenewableGeneration::isClusters() const { return rgModelling == Antares::Data::rgClusters; } + +// Some variables rely on dual values & marginal costs +void Parameters::UCMode::addExcludedVariables(std::vector& out) const +{ + // These variables rely on dual values & marginal costs + // these don't really make sense for MILP problems + // TODO : solve a LP problem with fixed values for integer variables + // extract values for dual variables & marginal costs from LP problem + const static std::vector milpExclude = {{"MARG. COST"}, + {"BC. MARG. COST"}, + {"CONG. FEE (ALG.)"}, + {"CONG. FEE (ABS.)"}, + {"MRG. PRICE"}, + {"STS Cashflow By Cluster"}, + {"Profit by plant"}}; + + if (ucMode == ucMILP) + { + out.insert(out.end(), milpExclude.begin(), milpExclude.end()); + } +} } // namespace Antares::Data diff --git a/src/libs/antares/study/parameters.h b/src/libs/antares/study/parameters.h index ffb5f1d643..98357e4709 100644 --- a/src/libs/antares/study/parameters.h +++ b/src/libs/antares/study/parameters.h @@ -43,7 +43,6 @@ #include - namespace Antares::Data { /*! @@ -433,11 +432,15 @@ class Parameters final PowerFluctuations fluctuations; } power; - struct + struct UCMode { //! Unit Commitment Mode UnitCommitmentMode ucMode; - } unitCommitment; + + //! Some variables rely on dual values & marginal costs + void addExcludedVariables(std::vector&) const; + }; + UCMode unitCommitment; struct { @@ -488,7 +491,6 @@ class Parameters final SimplexOptimization simplexOptimizationRange; //@} - AdequacyPatch::AdqPatchParams adqPatchParams; //! \name Scenariio Builder - Rules diff --git a/src/libs/antares/study/parts/common/cluster.cpp b/src/libs/antares/study/parts/common/cluster.cpp index f302675b8a..64e925f8a5 100644 --- a/src/libs/antares/study/parts/common/cluster.cpp +++ b/src/libs/antares/study/parts/common/cluster.cpp @@ -15,8 +15,7 @@ Cluster::Cluster(Area* parent) : index(0), nominalCapacity(0.), areaWideIndex((uint)-1), - series(nullptr) - + series(tsNumbers) { } @@ -61,7 +60,7 @@ int Cluster::saveDataSeriesToFolder(const AnyString& folder) const { int ret = 1; buffer.clear() << folder << SEP << parentArea->id << SEP << id() << SEP << "series.txt"; - ret = series->timeSeries.saveToCSVFile(buffer, precision()) && ret; + ret = series.timeSeries.saveToCSVFile(buffer, precision()) && ret; return ret; } @@ -79,12 +78,12 @@ int Cluster::loadDataSeriesFromFolder(Study& s, const AnyString& folder) int ret = 1; buffer.clear() << folder << SEP << parentArea->id << SEP << id() << SEP << "series." << s.inputExtension; - ret = series->timeSeries.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, &s.dataBuffer) && ret; + ret = series.timeSeries.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, &s.dataBuffer) && ret; if (s.usedByTheSolver && s.parameters.derated) - series->timeSeries.averageTimeseries(); + series.timeSeries.averageTimeseries(); - series->timeseriesNumbers.clear(); + series.timeseriesNumbers.clear(); return ret; } @@ -109,10 +108,7 @@ void Cluster::reset() enabled = true; nominalCapacity = 0.; - if (not series) - series = new DataSeriesCommon(); - - series->timeSeries.reset(1, HOURS_PER_YEAR); + series.timeSeries.reset(1, HOURS_PER_YEAR); } bool CompareClusterName::operator()(const Cluster* s1, const Cluster* s2) const diff --git a/src/libs/antares/study/parts/common/cluster.h b/src/libs/antares/study/parts/common/cluster.h index 9cd20ba798..eee596ede1 100644 --- a/src/libs/antares/study/parts/common/cluster.h +++ b/src/libs/antares/study/parts/common/cluster.h @@ -3,8 +3,8 @@ #include #include -#include "series.h" #include +#include #include "../../fwd.h" #include @@ -118,7 +118,9 @@ class Cluster uint areaWideIndex; //! Series - DataSeriesCommon* series; + TimeSeries series; + + TimeSeries::numbers tsNumbers; /*! ** \brief Modulation matrix diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index 5d70ae0ede..ee9ae9c8cb 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -151,11 +151,11 @@ void ClusterList::resizeAllTimeseriesNumbers(uint n) { if (0 == n) { - each([&](Cluster& cluster) { cluster.series->timeseriesNumbers.clear(); }); + each([&](Cluster& cluster) { cluster.series.timeseriesNumbers.clear(); }); } else { - each([&](Cluster& cluster) { cluster.series->timeseriesNumbers.resize(1, n); }); + each([&](Cluster& cluster) { cluster.series.timeseriesNumbers.resize(1, n); }); } } } @@ -176,7 +176,7 @@ void ClusterList::storeTimeseriesNumbers(Solver::IResultWriter& writer path.clear() << "ts-numbers" << SEP << typeID() << SEP << cluster.parentArea->id << SEP << cluster.id() << ".txt"; ts_content.clear(); // We must clear ts_content here, since saveToBuffer does not do it. - cluster.series->timeseriesNumbers.saveToBuffer(ts_content, 0, true, predicate, true); + cluster.series.timeseriesNumbers.saveToBuffer(ts_content, 0, true, predicate, true); writer.addEntryFromBuffer(path.c_str(), ts_content); }); } @@ -338,8 +338,7 @@ int ClusterList::saveDataSeriesToFolder(const AnyString& folder) const for (auto it = cluster.begin(); it != end; ++it) { auto& cluster = *(it->second); - if (cluster.series) - ret = cluster.saveDataSeriesToFolder(folder) and ret; + ret = cluster.saveDataSeriesToFolder(folder) and ret; } return ret; } @@ -357,12 +356,9 @@ int ClusterList::saveDataSeriesToFolder(const AnyString& folder, const for (auto it = cluster.begin(); it != end; ++it) { auto& cluster = *(it->second); - if (cluster.series) - { - logs.info() << msg << " " << (ticks * 100 / (1 + this->cluster.size())) - << "% complete"; - ret = cluster.saveDataSeriesToFolder(folder) and ret; - } + logs.info() << msg << " " << (ticks * 100 / (1 + this->cluster.size())) + << "% complete"; + ret = cluster.saveDataSeriesToFolder(folder) and ret; ++ticks; } return ret; @@ -379,8 +375,7 @@ int ClusterList::loadDataSeriesFromFolder(Study& s, int ret = 1; each([&](ClusterT& c) { - if (c.series) - ret = c.loadDataSeriesFromFolder(s, folder) and ret; + ret = c.loadDataSeriesFromFolder(s, folder) and ret; ++options.progressTicks; options.pushProgressLogs(); @@ -388,18 +383,6 @@ int ClusterList::loadDataSeriesFromFolder(Study& s, return ret; } -template -void ClusterList::ensureDataTimeSeries() -{ - auto end = cluster.end(); - for (auto it = cluster.begin(); it != end; ++it) - { - SharedPtr cluster = it->second; - if (not cluster->series) - cluster->series = new DataSeriesCommon(); - } -} - template void ClusterList::retrieveTotalCapacityAndUnitCount(double& total, uint& unitCount) const { diff --git a/src/libs/antares/study/parts/common/cluster_list.h b/src/libs/antares/study/parts/common/cluster_list.h index 584140bded..5fde367e39 100644 --- a/src/libs/antares/study/parts/common/cluster_list.h +++ b/src/libs/antares/study/parts/common/cluster_list.h @@ -246,8 +246,6 @@ class ClusterList virtual bool saveToFolder(const AnyString& folder) const = 0; - void ensureDataTimeSeries(); - //! \name Informations //@{ /*! diff --git a/src/libs/antares/study/parts/common/series.cpp b/src/libs/antares/study/parts/common/series.cpp deleted file mode 100644 index cfbf5e372a..0000000000 --- a/src/libs/antares/study/parts/common/series.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* -** 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 "../../study.h" -#include "series.h" - -using namespace Yuni; - -#define SEP IO::Separator - - -namespace Antares::Data -{ -bool DataSeriesCommon::forceReload(bool reload) const -{ - return timeSeries.forceReload(reload); -} - -void DataSeriesCommon::markAsModified() const -{ - timeSeries.markAsModified(); -} - -uint64_t DataSeriesCommon::memoryUsage() const -{ - return timeSeries.memoryUsage(); -} - -double DataSeriesCommon::getAvailablePower(unsigned int hour, unsigned int year) const -{ - return timeSeries[getSeriesIndex(year)][hour]; -} - -const DataSeriesCommon::SingleYear& DataSeriesCommon::getAvailablePowerYearly(unsigned int year) const -{ - return timeSeries[getSeriesIndex(year)]; -} - -uint DataSeriesCommon::getSeriesIndex(unsigned int year) const -{ - if (timeSeries.width == 1) - return 0; - else - return timeseriesNumbers[0][year]; -} - -} // namespace Antares::Data - diff --git a/src/libs/antares/study/parts/common/series.h b/src/libs/antares/study/parts/common/series.h deleted file mode 100644 index 94ca55db35..0000000000 --- a/src/libs/antares/study/parts/common/series.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -** 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 -*/ -#ifndef __ANTARES_LIBS_STUDY_PARTS_COMMON_TIMESERIES_H__ -#define __ANTARES_LIBS_STUDY_PARTS_COMMON_TIMESERIES_H__ - -#include -#include -#include "../../fwd.h" - -namespace Antares::Data -{ -/*! -** \brief Data series (Common) -*/ -class DataSeriesCommon -{ -public: - using AllYears = Matrix; - using SingleYear = AllYears::ColumnType; - - bool forceReload(bool reload = false) const; - - void markAsModified() const; - - uint64_t memoryUsage() const; - - double getAvailablePower(unsigned int hour, unsigned int year) const; - const SingleYear& getAvailablePowerYearly(unsigned int year) const; - - /*! - ** \brief Series (MW) - ** - ** Merely a matrix of TimeSeriesCount * 8760 values - */ - AllYears timeSeries; - - /*! - ** \brief Monte-Carlo - */ - Matrix timeseriesNumbers; - -private: - uint getSeriesIndex(unsigned int year) const; - -}; // class DataSeriesCommon - -} // namespace Antares::Data -#endif /* __ANTARES_LIBS_STUDY_PARTS_COMMON_TIMESERIES_H__ */ diff --git a/src/libs/antares/study/parts/hydro/series.cpp b/src/libs/antares/study/parts/hydro/series.cpp index d9b1c488b8..1b5f5f9588 100644 --- a/src/libs/antares/study/parts/hydro/series.cpp +++ b/src/libs/antares/study/parts/hydro/series.cpp @@ -41,13 +41,29 @@ namespace Antares { namespace Data { -DataSeriesHydro::DataSeriesHydro() : count(0) +DataSeriesHydro::DataSeriesHydro() : + ror(timeseriesNumbers), + storage(timeseriesNumbers), + mingen(timeseriesNumbers) { // Pmin was introduced in v8.6 // The previous behavior was Pmin=0 // For compatibility reasons with existing studies, mingen is set to one column of zeros // by default - mingen.reset(1, HOURS_PER_YEAR); + mingen.reset(); +} + +void DataSeriesHydro::copyGenerationTS(const DataSeriesHydro& source) +{ + ror.timeSeries = source.ror.timeSeries; + storage.timeSeries = source.storage.timeSeries; + mingen.timeSeries = source.mingen.timeSeries; + + count = source.count; + + source.ror.unloadFromMemory(); + source.storage.unloadFromMemory(); + source.mingen.unloadFromMemory(); } bool DataSeriesHydro::saveToFolder(const AreaName& areaID, const AnyString& folder) const @@ -61,11 +77,11 @@ bool DataSeriesHydro::saveToFolder(const AreaName& areaID, const AnyString& fold // Saving data buffer.clear() << folder << SEP << areaID << SEP << "ror.txt"; - ret = ror.saveToCSVFile(buffer, 0) && ret; + ret = ror.timeSeries.saveToCSVFile(buffer, 0) && ret; buffer.clear() << folder << SEP << areaID << SEP << "mod.txt"; - ret = storage.saveToCSVFile(buffer, 0) && ret; + ret = storage.timeSeries.saveToCSVFile(buffer, 0) && ret; buffer.clear() << folder << SEP << areaID << SEP << "mingen.txt"; - ret = mingen.saveToCSVFile(buffer, 0) && ret; + ret = mingen.timeSeries.saveToCSVFile(buffer, 0) && ret; return ret; } return false; @@ -78,84 +94,87 @@ bool DataSeriesHydro::loadFromFolder(Study& study, const AreaName& areaID, const buffer.clear() << folder << SEP << areaID << SEP << "ror." << study.inputExtension; - ret = ror.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, &study.dataBuffer) && ret; + ret = ror.timeSeries.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, &study.dataBuffer) && ret; buffer.clear() << folder << SEP << areaID << SEP << "mod." << study.inputExtension; - ret = storage.loadFromCSVFile(buffer, 1, DAYS_PER_YEAR, &study.dataBuffer) && ret; + ret = storage.timeSeries.loadFromCSVFile(buffer, 1, DAYS_PER_YEAR, &study.dataBuffer) && ret; // The number of time-series - count = storage.width; + count = storage.timeSeries.width; - if (ror.width > count) - count = ror.width; + if (ror.timeSeries.width > count) + count = ror.timeSeries.width; if (study.header.version >= 860) { buffer.clear() << folder << SEP << areaID << SEP << "mingen." << study.inputExtension; - ret = mingen.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, &study.dataBuffer) && ret; + ret = mingen.timeSeries.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, &study.dataBuffer) && ret; } - if (study.usedByTheSolver) + if (!study.usedByTheSolver) { - if (0 == count) - { - logs.error() << "Hydro: `" << areaID - << "`: empty matrix detected. Fixing it with default values"; - ror.reset(1, HOURS_PER_YEAR); - storage.reset(1, DAYS_PER_YEAR); - mingen.reset(1, HOURS_PER_YEAR); - } - else + timeseriesNumbers.clear(); + return ret; + } + + if (count == 0) + { + logs.error() << "Hydro: `" << areaID + << "`: empty matrix detected. Fixing it with default values"; + ror.reset(); + storage.reset(); + mingen.reset(); + } + else + { + if (count > 1 && storage.timeSeries.width != ror.timeSeries.width) { - if (count > 1 && storage.width != ror.width) + if (ror.timeSeries.width != 1 && storage.timeSeries.width != 1) { - if (ror.width != 1 && storage.width != 1) + logs.fatal() << "Hydro: `" << areaID + << "`: The matrices ROR (run-of-the-river) and hydro-storage must " + "have the same number of time-series."; + study.gotFatalError = true; + } + else + { + if (ror.timeSeries.width == 1) { - logs.fatal() << "Hydro: `" << areaID - << "`: The matrices ROR (run-of-the-river) and hydro-storage must " - "have the same number of time-series."; - study.gotFatalError = true; + ror.timeSeries.resizeWithoutDataLost(count, ror.timeSeries.height); + for (uint x = 1; x < count; ++x) + ror.timeSeries.pasteToColumn(x, ror[0]); } else { - if (ror.width == 1) + if (storage.timeSeries.width == 1) { - ror.resizeWithoutDataLost(count, ror.height); + storage.timeSeries.resizeWithoutDataLost(count, storage.timeSeries.height); for (uint x = 1; x < count; ++x) - ror.pasteToColumn(x, ror[0]); + storage.timeSeries.pasteToColumn(x, storage[0]); } - else - { - if (storage.width == 1) - { - storage.resizeWithoutDataLost(count, storage.height); - for (uint x = 1; x < count; ++x) - storage.pasteToColumn(x, storage[0]); - } - } - Area* areaToInvalidate = study.areas.find(areaID); - if (areaToInvalidate) - { - areaToInvalidate->invalidateJIT = true; - logs.info() - << " '" << areaID << "': The hydro data have been normalized to " - << count << " timeseries"; - } - else - logs.error() - << "Impossible to find the area `" << areaID << "` to invalidate it"; } + Area* areaToInvalidate = study.areas.find(areaID); + if (areaToInvalidate) + { + areaToInvalidate->invalidateJIT = true; + logs.info() + << " '" << areaID << "': The hydro data have been normalized to " + << count << " timeseries"; + } + else + logs.error() + << "Impossible to find the area `" << areaID << "` to invalidate it"; } - checkMinGenTsNumber(study, areaID); } + checkMinGenTsNumber(study, areaID); + } - if (study.parameters.derated) - { - ror.averageTimeseries(); - storage.averageTimeseries(); - mingen.averageTimeseries(); - count = 1; - } + if (study.parameters.derated) + { + ror.averageTimeseries(); + storage.averageTimeseries(); + mingen.averageTimeseries(); + count = 1; } timeseriesNumbers.clear(); @@ -165,9 +184,9 @@ bool DataSeriesHydro::loadFromFolder(Study& study, const AreaName& areaID, const void DataSeriesHydro::checkMinGenTsNumber(Study& study, const AreaName& areaID) { - if (mingen.width != storage.width) + if (mingen.timeSeries.width != storage.timeSeries.width) { - if (mingen.width > 1) + if (mingen.timeSeries.width > 1) { logs.fatal() << "Hydro: `" << areaID << "`: The matrices Minimum Generation must " @@ -176,9 +195,9 @@ void DataSeriesHydro::checkMinGenTsNumber(Study& study, const AreaName& areaID) } else { - mingen.resizeWithoutDataLost(count, mingen.height); + mingen.timeSeries.resizeWithoutDataLost(count, mingen.timeSeries.height); for (uint x = 1; x < count; ++x) - mingen.pasteToColumn(x, mingen[0]); + mingen.timeSeries.pasteToColumn(x, mingen[0]); Area* areaToInvalidate = study.areas.find(areaID); if (areaToInvalidate) { @@ -211,20 +230,30 @@ void DataSeriesHydro::markAsModified() const void DataSeriesHydro::reset() { - ror.reset(1, HOURS_PER_YEAR); - storage.reset(1, DAYS_PER_YEAR); - mingen.reset(1, HOURS_PER_YEAR); + ror.reset(); + storage.reset(); + mingen.reset(); count = 1; } -uint64_t DataSeriesHydro::memoryUsage() const +void DataSeriesHydro::resizeRORandSTORAGE(unsigned int width) { - return sizeof(double) + ror.memoryUsage() + storage.memoryUsage() + mingen.memoryUsage(); + ror.resize(width, HOURS_PER_YEAR); + storage.resize(width, DAYS_PER_YEAR); + count = width; +} + +void DataSeriesHydro::resizeGenerationTS(unsigned int w, unsigned int h) +{ + ror.resize(w, h); + storage.resize(w, h); + mingen.resize(w, h); + count = w; } -unsigned int DataSeriesHydro::getIndex(unsigned int year) const +uint64_t DataSeriesHydro::memoryUsage() const { - return (count != 1) ? timeseriesNumbers[0][year] : 0; + return sizeof(double) + ror.memoryUsage() + storage.memoryUsage() + mingen.memoryUsage(); } } // namespace Data diff --git a/src/libs/antares/study/parts/hydro/series.h b/src/libs/antares/study/parts/hydro/series.h index d0e4c768eb..08fc8dff93 100644 --- a/src/libs/antares/study/parts/hydro/series.h +++ b/src/libs/antares/study/parts/hydro/series.h @@ -27,6 +27,7 @@ #ifndef __ANTARES_LIBS_STUDY_PARTS_HYDRO_TIMESERIES_H__ #define __ANTARES_LIBS_STUDY_PARTS_HYDRO_TIMESERIES_H__ +#include #include #include "../../fwd.h" @@ -48,6 +49,8 @@ class DataSeriesHydro DataSeriesHydro(); //@} + void copyGenerationTS(const DataSeriesHydro& source); + //! \name Data //@{ /*! @@ -55,6 +58,9 @@ class DataSeriesHydro */ void reset(); + void resizeRORandSTORAGE(unsigned int width); + void resizeGenerationTS(unsigned int w, unsigned int h); + /*! ** \brief Load all data not already loaded ** @@ -105,8 +111,6 @@ class DataSeriesHydro */ void checkMinGenTsNumber(Study& s, const AreaName& areaID); - unsigned int getIndex(unsigned int year) const; - public: /*! ** \brief Run-of-the-river - ROR (MW) @@ -114,7 +118,7 @@ class DataSeriesHydro ** (it was DAYS_PER_YEAR before 3.9) */ - Matrix ror; + TimeSeries ror; /*! ** \brief Mod (MW) @@ -122,14 +126,21 @@ class DataSeriesHydro ** Merely a matrix of TimeSeriesCount * 365 values ** This matrix is not used in `adequation` mode. */ - Matrix storage; + TimeSeries storage; /*! ** \brief Minimum Generation (MW) ** ** Merely a matrix of TimeSeriesCount * HOURS_PER_YEAR values */ - Matrix mingen; + TimeSeries mingen; + + unsigned int TScount() const { return count; }; + + /*! + ** \brief Monte-Carlo + */ + Matrix timeseriesNumbers; /*! ** \brief The number of time-series @@ -139,18 +150,12 @@ class DataSeriesHydro ** (for example using `fatal.width` and `mod.width` in the same routine, it might ** indicate that the two values are not strictly equal) */ - uint count; - - /*! - ** \brief Monte-Carlo - */ - Matrix timeseriesNumbers; +private: + uint count = 0; }; // class DataSeriesHydro } // namespace Data } // namespace Antares -#include "series.hxx" - #endif /* __ANTARES_LIBS_STUDY_PARTS_HYDRO_TIMESERIES_H__ */ diff --git a/src/libs/antares/study/parts/hydro/series.hxx b/src/libs/antares/study/parts/hydro/series.hxx deleted file mode 100644 index 6be220a868..0000000000 --- a/src/libs/antares/study/parts/hydro/series.hxx +++ /dev/null @@ -1,39 +0,0 @@ -/* -** 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 -*/ -#ifndef __ANTARES_LIBS_STUDY_PARTS_HYDRO_TIMESERIES_HXX__ -#define __ANTARES_LIBS_STUDY_PARTS_HYDRO_TIMESERIES_HXX__ - -namespace Antares -{ -namespace Data -{ -// gp : whole file to be removed - -} // namespace Data -} // namespace Antares - -#endif // __ANTARES_LIBS_STUDY_PARTS_HYDRO_TIMESERIES_HXX__ diff --git a/src/libs/antares/study/parts/load/container.cpp b/src/libs/antares/study/parts/load/container.cpp index fcc32a1e8d..37193181ad 100644 --- a/src/libs/antares/study/parts/load/container.cpp +++ b/src/libs/antares/study/parts/load/container.cpp @@ -34,7 +34,7 @@ using namespace Yuni; namespace Antares::Data::Load { -Container::Container() : prepro(nullptr), series(nullptr) +Container::Container() : prepro(nullptr), series(tsNumbers) { } @@ -42,15 +42,12 @@ Container::~Container() { delete prepro; prepro = nullptr; - delete series; - series = nullptr; } bool Container::forceReload(bool reload) const { bool ret = true; - if (series) - ret = series->forceReload(reload) && ret; + ret = series.forceReload(reload) && ret; if (prepro) ret = prepro->forceReload(reload) && ret; return ret; @@ -58,22 +55,19 @@ bool Container::forceReload(bool reload) const void Container::markAsModified() const { - if (series) - series->markAsModified(); + series.markAsModified(); if (prepro) prepro->markAsModified(); } uint64_t Container::memoryUsage() const { - return sizeof(Container) + ((!series) ? 0 : DataSeriesLoadMemoryUsage(series)) - + ((!prepro) ? 0 : prepro->memoryUsage()); + return sizeof(Container) + series.memoryUsage() + ((!prepro) ? 0 : prepro->memoryUsage()); } void Container::resetToDefault() { - if (series) - series->timeSeries.reset(1, HOURS_PER_YEAR); + series.reset(); if (prepro) prepro->resetToDefault(); } diff --git a/src/libs/antares/study/parts/load/container.h b/src/libs/antares/study/parts/load/container.h index 4776e3865c..ca250cc25a 100644 --- a/src/libs/antares/study/parts/load/container.h +++ b/src/libs/antares/study/parts/load/container.h @@ -27,7 +27,7 @@ #ifndef __ANTARES_LIBS_STUDY_PARTS_LOAD_CONTAINER_H__ #define __ANTARES_LIBS_STUDY_PARTS_LOAD_CONTAINER_H__ -#include "series.h" +#include #include namespace Antares @@ -75,7 +75,9 @@ class Container final : private Yuni::NonCopyable //! Data for the pre-processor Data::Load::Prepro* prepro; /*! Data for time-series */ - DataSeriesLoad* series; + TimeSeries series; + + TimeSeries::numbers tsNumbers; }; // class Container diff --git a/src/libs/antares/study/parts/load/series.cpp b/src/libs/antares/study/parts/load/series.cpp deleted file mode 100644 index 35d70cd3a2..0000000000 --- a/src/libs/antares/study/parts/load/series.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* -** 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 "series.h" -#include "../../study.h" - -using namespace Yuni; - -#define SEP IO::Separator - -namespace Antares -{ -namespace Data -{ -int DataSeriesLoadLoadFromFolder(Study& study, - DataSeriesLoad* s, - const AreaName& areaID, - const char* folder) -{ - /* Assert */ - assert(s); - assert(folder); - assert('\0' != *folder); - - auto& buffer = study.buffer; - - int ret = 1; - /* Load the matrix */ - buffer.clear() << folder << SEP << "load_" << areaID << '.' << study.inputExtension; - ret = s->timeSeries.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, &study.dataBuffer) && ret; - - if (study.usedByTheSolver && study.parameters.derated) - s->timeSeries.averageTimeseries(); - - s->timeseriesNumbers.clear(); - - return ret; -} - -int DataSeriesLoadSaveToFolder(DataSeriesLoad* s, const AreaName& areaID, const char folder[]) -{ - if (!s) - return 1; - - /* Assert */ - assert(folder); - assert('\0' != *folder); - - if (IO::Directory::Create(folder)) - { - int res = 1; - - Clob buffer; - buffer.clear() << folder << SEP << "load_" << areaID << ".txt"; - res = s->timeSeries.saveToCSVFile(buffer, /*decimal*/ 0) && res; - - return res; - } - return 0; -} - -double* DataSeriesLoad::getColumn(unsigned int year) const -{ - return timeSeries[getIndex(year)]; -} - -double DataSeriesLoad::getCoefficient(const unsigned int year, const unsigned int hour) const -{ - return timeSeries[getIndex(year)][hour]; -} - -unsigned int DataSeriesLoad::getIndex(unsigned int year) const -{ - return (timeSeries.width != 1) ? timeseriesNumbers[0][year] : 0; -} - -bool DataSeriesLoad::forceReload(bool reload) const -{ - return timeSeries.forceReload(reload); -} - -void DataSeriesLoad::markAsModified() const -{ - return timeSeries.markAsModified(); -} - -} // namespace Data -} // namespace Antares diff --git a/src/libs/antares/study/parts/load/series.h b/src/libs/antares/study/parts/load/series.h deleted file mode 100644 index 477ee71fcc..0000000000 --- a/src/libs/antares/study/parts/load/series.h +++ /dev/null @@ -1,106 +0,0 @@ -/* -** 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 -*/ -#ifndef __ANTARES_LIBS_STUDY_PARTS_LOAD_TIMESERIES_H__ -#define __ANTARES_LIBS_STUDY_PARTS_LOAD_TIMESERIES_H__ - -#include -#include "../../fwd.h" - -namespace Antares -{ -namespace Data -{ -/*! -** \brief Data series (Load) -*/ -class DataSeriesLoad -{ -public: - - - bool forceReload(bool reload = false) const; - - /*! - ** \brief Mark the load data as modified - */ - void markAsModified() const; - - double* getColumn(unsigned int year) const; - double getCoefficient(const unsigned int year, const unsigned int hour) const; - unsigned int getIndex(unsigned int year) const; - -public: - /*! - ** \brief Time series (MW) - ** - ** Merely a matrix of TimeSeriesCount * 8760 values - */ - Matrix timeSeries; - - /*! - ** \brief Monte-Carlo - */ - Matrix timeseriesNumbers; - -}; /* class DataSeriesLoad */ - -/*! -** \brief Load wind data series from a file -** \ingroup windseries -** -** \param d Data series -** \param areaID The ID of the area associated to the data series -** \param folder The source folder -** \return A non-zero value if the operation succeeded, 0 otherwise -*/ -int DataSeriesLoadLoadFromFolder(Study& s, - DataSeriesLoad* d, - const AreaName& areaID, - const char folder[]); - -/*! -** \brief Save wind data series from a file -** \ingroup windseries -** -** \param d Data series -** \param areaID The ID of the area associated to the data series -** \param folder The target folder -** \return A non-zero value if the operation succeeded, 0 otherwise -*/ -int DataSeriesLoadSaveToFolder(DataSeriesLoad* d, const AreaName& areaID, const char folder[]); - -/*! -** \brief Get the size (bytes) in memory occupied by a `DataSeriesLoad` structure -*/ -uint64_t DataSeriesLoadMemoryUsage(DataSeriesLoad* w); - -} // namespace Data -} // namespace Antares - -#include "series.hxx" - -#endif /* __ANTARES_LIBS_STUDY_PARTS_LOAD_TIMESERIES_H__ */ diff --git a/src/libs/antares/study/parts/load/series.hxx b/src/libs/antares/study/parts/load/series.hxx deleted file mode 100644 index ddebe31d35..0000000000 --- a/src/libs/antares/study/parts/load/series.hxx +++ /dev/null @@ -1,42 +0,0 @@ -/* -** 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 -*/ -#ifndef __ANTARES_LIBS_STUDY_PARTS_LOAD_TIMESERIES_HXX__ -#define __ANTARES_LIBS_STUDY_PARTS_LOAD_TIMESERIES_HXX__ - -namespace Antares -{ -namespace Data -{ -inline uint64_t DataSeriesLoadMemoryUsage(DataSeriesLoad* l) -{ - return (l) ? l->timeSeries.memoryUsage() : 0; -} - -} // namespace Data -} // namespace Antares - -#endif // __ANTARES_LIBS_STUDY_PARTS_LOAD_TIMESERIES_HXX__ diff --git a/src/libs/antares/study/parts/parts.h b/src/libs/antares/study/parts/parts.h index d59933f179..fef42e95f0 100644 --- a/src/libs/antares/study/parts/parts.h +++ b/src/libs/antares/study/parts/parts.h @@ -28,11 +28,9 @@ #define __ANTARES_LIBS_STUDY_PARTS_H__ // Load -#include "load/series.h" #include "load/container.h" // Solar -#include "solar/series.h" #include "solar/prepro.h" #include "solar/container.h" @@ -43,7 +41,6 @@ // Wind #include "wind/prepro.h" -#include "wind/series.h" #include "wind/container.h" // Thermal diff --git a/src/libs/antares/study/parts/renewable/cluster.cpp b/src/libs/antares/study/parts/renewable/cluster.cpp index 8a229d6d65..ba8d2b6a9d 100644 --- a/src/libs/antares/study/parts/renewable/cluster.cpp +++ b/src/libs/antares/study/parts/renewable/cluster.cpp @@ -53,11 +53,6 @@ Data::RenewableCluster::RenewableCluster(Area* parent) : assert(parent and "A parent for a renewable dispatchable cluster can not be null"); } -Data::RenewableCluster::~RenewableCluster() -{ - delete series; -} - uint RenewableCluster::groupId() const { return groupID; @@ -82,14 +77,10 @@ void Data::RenewableCluster::copyFrom(const RenewableCluster& cluster) // ts-mode tsMode = cluster.tsMode; - // Making sure that the data related to the timeseries are present - if (not series) - series = new DataSeriesCommon(); - // timseries - series->timeSeries = cluster.series->timeSeries; - cluster.series->timeSeries.unloadFromMemory(); - series->timeseriesNumbers.clear(); + series.timeSeries = cluster.series.timeSeries; + cluster.series.timeSeries.unloadFromMemory(); + series.timeseriesNumbers.clear(); // The parent must be invalidated to make sure that the clusters are really // re-written at the next 'Save' from the user interface. @@ -136,16 +127,12 @@ void Data::RenewableCluster::setGroup(Data::ClusterName newgrp) bool Data::RenewableCluster::forceReload(bool reload) const { - bool ret = true; - if (series) - ret = series->forceReload(reload) and ret; - return ret; + return series.forceReload(reload); } void Data::RenewableCluster::markAsModified() const { - if (series) - series->markAsModified(); + series.markAsModified(); } void Data::RenewableCluster::reset() @@ -200,15 +187,12 @@ YString Data::RenewableCluster::getTimeSeriesModeAsString() const return "unknown"; } -double RenewableCluster::valueAtTimeStep(uint hourInYear, uint year) const +double RenewableCluster::valueAtTimeStep(uint year, uint hourInYear) const { if (!enabled) return 0.; - uint timeSeriesIndex = (series->timeSeries.width == 1) ? 0 : series->timeseriesNumbers[0][year]; - assert(hourInYear < series->timeSeries.height); - assert(timeSeriesIndex < series->timeSeries.width); - const double tsValue = series->timeSeries[timeSeriesIndex][hourInYear]; + const double tsValue = series.getCoefficient(year, hourInYear); switch (tsMode) { case powerGeneration: @@ -222,8 +206,7 @@ double RenewableCluster::valueAtTimeStep(uint hourInYear, uint year) const uint64_t RenewableCluster::memoryUsage() const { uint64_t amount = sizeof(RenewableCluster); - if (series) - amount += series->memoryUsage(); + amount += series.memoryUsage(); return amount; } diff --git a/src/libs/antares/study/parts/renewable/cluster.h b/src/libs/antares/study/parts/renewable/cluster.h index 61e6df2a8e..5ac3d838dc 100644 --- a/src/libs/antares/study/parts/renewable/cluster.h +++ b/src/libs/antares/study/parts/renewable/cluster.h @@ -98,8 +98,6 @@ class RenewableCluster final : public Cluster ** \brief Default constructor, with a parent area */ explicit RenewableCluster(Data::Area* parent); - //! Destructor - ~RenewableCluster(); //@} /*! @@ -155,7 +153,7 @@ class RenewableCluster final : public Cluster /* ! ** Get production value at time-step ts */ - double valueAtTimeStep(uint hourInYear, uint year) const; + double valueAtTimeStep(uint year, uint hourInYear) const; public: /*! diff --git a/src/libs/antares/study/parts/solar/container.cpp b/src/libs/antares/study/parts/solar/container.cpp index 35e15319da..033a26b4c7 100644 --- a/src/libs/antares/study/parts/solar/container.cpp +++ b/src/libs/antares/study/parts/solar/container.cpp @@ -38,21 +38,18 @@ namespace Data { namespace Solar { -Container::Container() : prepro(nullptr), series(nullptr) -{ -} +Container::Container() : prepro(nullptr), series(tsNumbers) +{} Container::~Container() { delete prepro; - delete series; } bool Container::forceReload(bool reload) const { bool ret = true; - if (series) - ret = series->forceReload(reload) && ret; + ret = series.forceReload(reload) && ret; if (prepro) ret = prepro->forceReload(reload) && ret; return ret; @@ -60,22 +57,20 @@ bool Container::forceReload(bool reload) const void Container::markAsModified() const { - if (series) - series->markAsModified(); + series.markAsModified(); if (prepro) prepro->markAsModified(); } uint64_t Container::memoryUsage() const { - return sizeof(Container) + ((!series) ? 0 : DataSeriesSolarMemoryUsage(series)) + return sizeof(Container) + series.memoryUsage() + ((!prepro) ? 0 : prepro->memoryUsage()); } void Container::resetToDefault() { - if (series) - series->timeSeries.reset(1, HOURS_PER_YEAR); + series.timeSeries.reset(); if (prepro) prepro->resetToDefault(); } diff --git a/src/libs/antares/study/parts/solar/container.h b/src/libs/antares/study/parts/solar/container.h index ba37906391..b06aba10f4 100644 --- a/src/libs/antares/study/parts/solar/container.h +++ b/src/libs/antares/study/parts/solar/container.h @@ -27,7 +27,7 @@ #ifndef __ANTARES_LIBS_STUDY_PARTS_SOLAR_CONTAINER_H__ #define __ANTARES_LIBS_STUDY_PARTS_SOLAR_CONTAINER_H__ -#include "series.h" +#include namespace Antares { @@ -73,7 +73,9 @@ class Container //! Data for the pre-processor Data::Solar::Prepro* prepro; /*! Data for time-series */ - DataSeriesSolar* series; + TimeSeries series; + + TimeSeries::numbers tsNumbers; }; // class Container diff --git a/src/libs/antares/study/parts/solar/series.cpp b/src/libs/antares/study/parts/solar/series.cpp deleted file mode 100644 index 2a4b8de360..0000000000 --- a/src/libs/antares/study/parts/solar/series.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* -** 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 "series.h" -#include "../../study.h" - -using namespace Yuni; - -#define SEP IO::Separator - -namespace Antares -{ -namespace Data -{ -int DataSeriesSolarLoadFromFolder(Study& study, - DataSeriesSolar* s, - const AreaName& areaID, - const char* folder) -{ - /* Assert */ - assert(s); - assert(folder); - assert('\0' != *folder); - - Yuni::String& buffer = study.buffer; - - int ret = 1; - /* Solar the matrix */ - buffer.clear() << folder << SEP << "solar_" << areaID << '.' << study.inputExtension; - ret = s->timeSeries.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, &study.dataBuffer) && ret; - - if (study.usedByTheSolver && study.parameters.derated) - s->timeSeries.averageTimeseries(); - - s->timeseriesNumbers.clear(); - - return ret; -} - -int DataSeriesSolarSaveToFolder(DataSeriesSolar* s, const AreaName& areaID, const char folder[]) -{ - if (!s) - return 1; - - /* Assert */ - assert(folder); - assert('\0' != *folder); - - if (IO::Directory::Create(folder)) - { - int res = 1; - - String buffer; - buffer.clear() << folder << SEP << "solar_" << areaID << ".txt"; - res = s->timeSeries.saveToCSVFile(buffer, /*decimal*/ 0) && res; - - return res; - } - return 0; -} - -double* DataSeriesSolar::getColumn(unsigned int year) const -{ - return timeSeries[getIndex(year)]; -} - -double DataSeriesSolar::getCoefficient(const unsigned int year, const unsigned int hour) const -{ - return timeSeries[getIndex(year)][hour]; -} - -unsigned int DataSeriesSolar::getIndex(unsigned int year) const -{ - return (timeSeries.width != 1) ? timeseriesNumbers[0][year] : 0; -} - -bool DataSeriesSolar::forceReload(bool reload) const -{ - return timeSeries.forceReload(reload); -} - -void DataSeriesSolar::markAsModified() const -{ - timeSeries.markAsModified(); -} - -} // namespace Data -} // namespace Antares diff --git a/src/libs/antares/study/parts/solar/series.h b/src/libs/antares/study/parts/solar/series.h deleted file mode 100644 index 1f94c24117..0000000000 --- a/src/libs/antares/study/parts/solar/series.h +++ /dev/null @@ -1,102 +0,0 @@ -/* -** 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 -*/ -#ifndef __ANTARES_LIBS_STUDY_PARTS_SOLAR_TIMESERIES_H__ -#define __ANTARES_LIBS_STUDY_PARTS_SOLAR_TIMESERIES_H__ - -#include -#include "../../fwd.h" - -namespace Antares -{ -namespace Data -{ -/*! -** \brief Data series (Solar) -*/ -class DataSeriesSolar -{ -public: - - bool forceReload(bool reload = false) const; - - void markAsModified() const; - - double* getColumn(unsigned int year) const; - double getCoefficient(const unsigned int year, const unsigned int hour) const; - unsigned int getIndex(unsigned int year) const; - -public: - /*! - ** \brief Time series (MW) - ** - ** Merely a matrix of TimeSeriesCount * 8760 values - */ - Matrix timeSeries; - - /*! - ** \brief Monte-Carlo - */ - Matrix timeseriesNumbers; - -}; /* class DataSeriesSolar */ - -/*! -** \brief Solar wind data series from a file -** \ingroup windseries -** -** \param d Data series -** \param areaID The ID of the area associated to the data series -** \param folder The source folder -** \return A non-zero value if the operation succeeded, 0 otherwise -*/ -int DataSeriesSolarLoadFromFolder(Study& s, - DataSeriesSolar* d, - const AreaName& areaID, - const char folder[]); - -/*! -** \brief Save wind data series from a file -** \ingroup windseries -** -** \param d Data series -** \param areaID The ID of the area associated to the data series -** \param folder The target folder -** \return A non-zero value if the operation succeeded, 0 otherwise -*/ -int DataSeriesSolarSaveToFolder(DataSeriesSolar* d, const AreaName& areaID, const char folder[]); - -/*! -** \brief Get the size (bytes) in memory occupied by a `DataSeriesSolar` structure -*/ -uint64_t DataSeriesSolarMemoryUsage(DataSeriesSolar* w); - -} // namespace Data -} // namespace Antares - -#include "series.hxx" - -#endif /* __ANTARES_LIBS_STUDY_PARTS_SOLAR_TIMESERIES_H__ */ diff --git a/src/libs/antares/study/parts/solar/series.hxx b/src/libs/antares/study/parts/solar/series.hxx deleted file mode 100644 index 3654163ae0..0000000000 --- a/src/libs/antares/study/parts/solar/series.hxx +++ /dev/null @@ -1,42 +0,0 @@ -/* -** 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 -*/ -#ifndef __ANTARES_LIBS_STUDY_PARTS_SOLAR_TIMESERIES_HXX__ -#define __ANTARES_LIBS_STUDY_PARTS_SOLAR_TIMESERIES_HXX__ - -namespace Antares -{ -namespace Data -{ -inline uint64_t DataSeriesSolarMemoryUsage(DataSeriesSolar* l) -{ - return (l) ? l->timeSeries.memoryUsage() : 0; -} - -} // namespace Data -} // namespace Antares - -#endif // __ANTARES_LIBS_STUDY_PARTS_SOLAR_TIMESERIES_HXX__ diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index a6c8c49d6d..72548e03fe 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -140,13 +140,12 @@ Data::ThermalCluster::ThermalCluster(Area* parent) : costsTimeSeries(1, CostsTimeSeries()) { // assert - assert(parent and "A parent for a thermal dispatchable cluster can not be null"); + assert(parent && "A parent for a thermal dispatchable cluster can not be null"); } Data::ThermalCluster::~ThermalCluster() { delete prepro; - delete series; } uint ThermalCluster::groupId() const @@ -217,16 +216,14 @@ void Data::ThermalCluster::copyFrom(const ThermalCluster& cluster) // prepro if (not prepro) prepro = new PreproThermal(this->weak_from_this()); - if (not series) - series = new DataSeriesCommon(); prepro->copyFrom(*cluster.prepro); ecoInput.copyFrom(cluster.ecoInput); // timseries - series->timeSeries = cluster.series->timeSeries; - cluster.series->timeSeries.unloadFromMemory(); - series->timeseriesNumbers.clear(); + series.timeSeries = cluster.series.timeSeries; + cluster.series.timeSeries.unloadFromMemory(); + series.timeseriesNumbers.clear(); // The parent must be invalidated to make sure that the clusters are really // re-written at the next 'Save' from the user interface. @@ -274,11 +271,10 @@ void Data::ThermalCluster::setGroup(Data::ClusterName newgrp) bool Data::ThermalCluster::forceReload(bool reload) const { bool ret = true; - ret = modulation.forceReload(reload) and ret; - if (series) - ret = series->forceReload(reload) and ret; + ret = modulation.forceReload(reload) && ret; + ret = series.forceReload(reload) && ret; if (prepro) - ret = prepro->forceReload(reload) and ret; + ret = prepro->forceReload(reload) && ret; ret = ecoInput.forceReload(reload) && ret; return ret; } @@ -286,8 +282,7 @@ bool Data::ThermalCluster::forceReload(bool reload) const void Data::ThermalCluster::markAsModified() const { modulation.markAsModified(); - if (series) - series->markAsModified(); + series.markAsModified(); if (prepro) prepro->markAsModified(); ecoInput.markAsModified(); @@ -295,8 +290,6 @@ void Data::ThermalCluster::markAsModified() const void Data::ThermalCluster::calculationOfSpinning() { - assert(this->series); - // nominal capacity (for solver) nominalCapacityWithSpinning = nominalCapacity; @@ -306,7 +299,7 @@ void Data::ThermalCluster::calculationOfSpinning() { logs.debug() << " Calculation of spinning... " << parentArea->name << "::" << pName; - auto& ts = series->timeSeries; + auto& ts = series.timeSeries; // The formula // const double s = 1. - cluster.spinning / 100.; */ @@ -420,8 +413,6 @@ double Data::ThermalCluster::computeMarketBidCost(double fuelCost, void Data::ThermalCluster::reverseCalculationOfSpinning() { - assert(this->series); - // Nothing to do if the spinning is equal to zero // because it will the same multiply all entries of the matrix by 1. if (not Math::Zero(spinning)) @@ -429,7 +420,7 @@ void Data::ThermalCluster::reverseCalculationOfSpinning() logs.debug() << " Calculation of spinning (reverse)... " << parentArea->name << "::" << pName; - auto& ts = series->timeSeries; + auto& ts = series.timeSeries; // The formula // const double s = 1. - cluster.spinning / 100.; @@ -594,7 +585,7 @@ bool Data::ThermalCluster::integrityCheck() { CString buffer; buffer << "Thermal cluster: " << parentArea->name << '/' << pName << ": Modulation"; - ret = MatrixTestForPositiveValues(buffer.c_str(), &modulation) and ret; + ret = MatrixTestForPositiveValues(buffer.c_str(), &modulation) && ret; } // la valeur minStablePower should not be modified @@ -647,8 +638,7 @@ uint64_t ThermalCluster::memoryUsage() const uint64_t amount = sizeof(ThermalCluster) + modulation.memoryUsage(); if (prepro) amount += prepro->memoryUsage(); - if (series) - amount += series->memoryUsage(); + amount += series.memoryUsage(); amount += ecoInput.memoryUsage(); return amount; } @@ -772,7 +762,7 @@ double ThermalCluster::getMarginalCost(uint serieIndex, uint hourInTheYear) cons double ThermalCluster::getMarketBidCost(uint hourInTheYear, uint year) const { - uint serieIndex = (series->timeSeries.width == 1) ? 0 : series->timeseriesNumbers[0][year]; + uint serieIndex = series.getSeriesIndex(year); double mod = modulation[thermalModulationMarketBid][serieIndex]; @@ -797,17 +787,17 @@ void ThermalCluster::checkAndCorrectAvailability() bool condition = false; bool report = false; - for (uint y = 0; y != series->timeSeries.height; ++y) + for (uint y = 0; y != series.timeSeries.height; ++y) { - for (uint x = 0; x != series->timeSeries.width; ++x) + for (uint x = 0; x != series.timeSeries.width; ++x) { auto rightpart = PminDUnGroupeDuPalierThermique - * ceil(series->timeSeries.entry[x][y] / PmaxDUnGroupeDuPalierThermique); - condition = rightpart > series->timeSeries.entry[x][y]; + * ceil(series.timeSeries.entry[x][y] / PmaxDUnGroupeDuPalierThermique); + condition = rightpart > series.timeSeries.entry[x][y]; if (condition) { - series->timeSeries.entry[x][y] = rightpart; + series.timeSeries.entry[x][y] = rightpart; report = true; } } diff --git a/src/libs/antares/study/parts/thermal/ecoInput.h b/src/libs/antares/study/parts/thermal/ecoInput.h index b275227200..e70c537b78 100644 --- a/src/libs/antares/study/parts/thermal/ecoInput.h +++ b/src/libs/antares/study/parts/thermal/ecoInput.h @@ -27,6 +27,7 @@ #ifndef __ANTARES_LIBS_STUDY_PARTS_THERMAL_ECOINPUT_H__ #define __ANTARES_LIBS_STUDY_PARTS_THERMAL_ECOINPUT_H__ +#include #include "cluster.h" #include #include "defines.h" @@ -86,8 +87,8 @@ class EconomicInputData //! All {FO,PO}{Duration,Rate} annual values // max x DAYS_PER_YEAR - Matrix fuelcost; - Matrix co2cost; + TimeSeries::TS fuelcost; + TimeSeries::TS co2cost; }; // class EconomicInputData diff --git a/src/libs/antares/study/parts/wind/container.cpp b/src/libs/antares/study/parts/wind/container.cpp index c25ce757d8..9aae8eb814 100644 --- a/src/libs/antares/study/parts/wind/container.cpp +++ b/src/libs/antares/study/parts/wind/container.cpp @@ -37,44 +37,39 @@ namespace Data { namespace Wind { -Container::Container() : prepro(nullptr), series(nullptr) +Container::Container() : prepro(nullptr), series(tsNumbers) { } Container::~Container() { delete prepro; - delete series; } bool Container::forceReload(bool reload) const { bool ret = true; - if (series) - ret = series->forceReload(reload) and ret; + ret = series.forceReload(reload) && ret; if (prepro) - ret = prepro->forceReload(reload) and ret; + ret = prepro->forceReload(reload) && ret; return ret; } void Container::markAsModified() const { - if (series) - series->markAsModified(); + series.markAsModified(); if (prepro) prepro->markAsModified(); } uint64_t Container::memoryUsage() const { - return sizeof(Container) + ((!series) ? 0 : DataSeriesWindMemoryUsage(series)) - + ((!prepro) ? 0 : prepro->memoryUsage()); + return sizeof(Container) + series.memoryUsage() + ((!prepro) ? 0 : prepro->memoryUsage()); } void Container::resetToDefault() { - if (series) - series->timeSeries.reset(1, HOURS_PER_YEAR); + series.reset(); if (prepro) prepro->resetToDefault(); } diff --git a/src/libs/antares/study/parts/wind/container.h b/src/libs/antares/study/parts/wind/container.h index 05a696f1d4..9983c6c069 100644 --- a/src/libs/antares/study/parts/wind/container.h +++ b/src/libs/antares/study/parts/wind/container.h @@ -28,7 +28,7 @@ #define __ANTARES_LIBS_STUDY_PARTS_WIND_CONTAINER_H__ #include "prepro.h" -#include "series.h" +#include namespace Antares { @@ -73,7 +73,9 @@ class Container //! Data for the pre-processor Data::Wind::Prepro* prepro; /*! Data for time-series */ - DataSeriesWind* series; + TimeSeries series; + + TimeSeries::numbers tsNumbers; }; // class Container diff --git a/src/libs/antares/study/parts/wind/series.cpp b/src/libs/antares/study/parts/wind/series.cpp deleted file mode 100644 index cf47110941..0000000000 --- a/src/libs/antares/study/parts/wind/series.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* -** 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 "series.h" -#include "../../study.h" - -using namespace Yuni; - -#define SEP IO::Separator - -namespace Antares -{ -namespace Data -{ -int DataSeriesWindLoadFromFolder(Study& s, - DataSeriesWind* d, - const AreaName& areaID, - const char folder[]) -{ - if (!d) - return 1; - String& buffer = s.bufferLoadingTS; - - int ret = 1; - buffer.clear() << folder << SEP << "wind_" << areaID << '.' << s.inputExtension; - ret = d->timeSeries.loadFromCSVFile(buffer, 1, HOURS_PER_YEAR, &s.dataBuffer) && ret; - - if (s.usedByTheSolver && s.parameters.derated) - d->timeSeries.averageTimeseries(); - - d->timeseriesNumbers.clear(); - - return ret; -} - -int DataSeriesWindSaveToFolder(DataSeriesWind* d, const AreaName& areaID, const char folder[]) -{ - if (!d) - return 1; - - Clob buffer; - int ret = 1; - buffer.clear() << folder << SEP << "wind_" << areaID << ".txt"; - ret = d->timeSeries.saveToCSVFile(buffer, 0) && ret; - - return ret; -} - -double* DataSeriesWind::getColumn(unsigned int year) const -{ - return timeSeries[getIndex(year)]; -} - -double DataSeriesWind::getCoefficient(const unsigned int year, const unsigned int hour) const -{ - return timeSeries[getIndex(year)][hour]; -} - -unsigned int DataSeriesWind::getIndex(unsigned int year) const -{ - return (timeSeries.width != 1) ? timeseriesNumbers[0][year] : 0; -} - -bool DataSeriesWind::forceReload(bool reload) const -{ - return timeSeries.forceReload(reload); -} - -void DataSeriesWind::markAsModified() const -{ - timeSeries.markAsModified(); -} - -} // namespace Data -} // namespace Antares diff --git a/src/libs/antares/study/parts/wind/series.h b/src/libs/antares/study/parts/wind/series.h deleted file mode 100644 index c7f77fc350..0000000000 --- a/src/libs/antares/study/parts/wind/series.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -** 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 -*/ -#ifndef __ANTARES_LIBS_STUDY_PARTS_WIND_TIMESERIES_H__ -#define __ANTARES_LIBS_STUDY_PARTS_WIND_TIMESERIES_H__ - -#include -#include "../../fwd.h" - -namespace Antares -{ -namespace Data -{ -/*! -** \brief Data series (Wind) -*/ -class DataSeriesWind -{ -public: - - - bool forceReload(bool reload = false) const; - - void markAsModified() const; - - double* getColumn(unsigned int year) const; - double getCoefficient(const unsigned int year, const unsigned int hour) const; - unsigned int getIndex(unsigned int year) const; - -public: - /*! - ** \brief Time series (MW) - ** - ** Merely a matrix of TimeSeriesCount * 8760 values - */ - Matrix timeSeries; - - /*! - ** \brief Monte-Carlo - */ - Matrix timeseriesNumbers; - -}; /* class DataSeriesWind */ - -/*! -** \brief Load wind data series from a file -** \ingroup windseries -** -** \param d Data series -** \param areaID The ID of the area associated to the data series -** \param folder The source folder -** \return A non-zero value if the operation succeeded, 0 otherwise -*/ -int DataSeriesWindLoadFromFolder(Study& s, - DataSeriesWind* d, - const AreaName& areaID, - const char folder[]); - -/*! -** \brief Save wind data series from a file -** \ingroup windseries -** -** \param d Data series -** \param areaID The ID of the area associated to the data series -** \param folder The target folder -** \return A non-zero value if the operation succeeded, 0 otherwise -*/ -int DataSeriesWindSaveToFolder(DataSeriesWind* d, const AreaName& areaID, const char folder[]); - -/*! -** \brief Get the size (bytes) in memory occupied by a `DataSeriesWind` structure -*/ -uint64_t DataSeriesWindMemoryUsage(DataSeriesWind* w); - -} // namespace Data -} // namespace Antares - -#include "series.hxx" - -#endif /* __ANTARES_LIBS_STUDY_PARTS_WIND_TIMESERIES_H__ */ diff --git a/src/libs/antares/study/parts/wind/series.hxx b/src/libs/antares/study/parts/wind/series.hxx deleted file mode 100644 index f714cbc2e4..0000000000 --- a/src/libs/antares/study/parts/wind/series.hxx +++ /dev/null @@ -1,42 +0,0 @@ -/* -** 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 -*/ -#ifndef __ANTARES_LIBS_STUDY_PARTS_WIND_TIMESERIES_HXX__ -#define __ANTARES_LIBS_STUDY_PARTS_WIND_TIMESERIES_HXX__ - -namespace Antares -{ -namespace Data -{ -inline uint64_t DataSeriesWindMemoryUsage(DataSeriesWind* w) -{ - return (w) ? w->timeSeries.memoryUsage() : 0; -} - -} // namespace Data -} // namespace Antares - -#endif // __ANTARES_LIBS_STUDY_PARTS_WIND_TIMESERIES_HXX__ diff --git a/src/libs/antares/study/scenario-builder/LoadTSNumberData.cpp b/src/libs/antares/study/scenario-builder/LoadTSNumberData.cpp index 142d411429..6b14313e9b 100644 --- a/src/libs/antares/study/scenario-builder/LoadTSNumberData.cpp +++ b/src/libs/antares/study/scenario-builder/LoadTSNumberData.cpp @@ -37,8 +37,8 @@ bool loadTSNumberData::apply(Study& study) const MatrixType::ColumnType& col = pTSNumberRules[areaIndex]; logprefix.clear() << "Load: Area '" << area.name << "': "; - ret = ApplyToMatrix(errors, logprefix, *area.load.series, col, tsGenCountLoad) && ret; + ret = ApplyToMatrix(errors, logprefix, area.load.series, col, tsGenCountLoad) && ret; } return ret; } -} \ No newline at end of file +} diff --git a/src/libs/antares/study/scenario-builder/RenewableTSNumberData.cpp b/src/libs/antares/study/scenario-builder/RenewableTSNumberData.cpp index 24d356ad03..7b176ab304 100644 --- a/src/libs/antares/study/scenario-builder/RenewableTSNumberData.cpp +++ b/src/libs/antares/study/scenario-builder/RenewableTSNumberData.cpp @@ -42,7 +42,7 @@ bool renewableTSNumberData::apply(Study& study) logprefix.clear() << "Renewable: area '" << area.name << "', cluster: '" << cluster.name() << "': "; - ret = ApplyToMatrix(errors, logprefix, *cluster.series, col, tsGenCountRenewable) && ret; + ret = ApplyToMatrix(errors, logprefix, cluster.series, col, tsGenCountRenewable) && ret; } return ret; } @@ -104,4 +104,4 @@ bool renewableTSNumberData::reset(const Study& study) pTSNumberRules.reset(clusterCount, nbYears); return true; } -} \ No newline at end of file +} diff --git a/src/libs/antares/study/scenario-builder/SolarTSNumberData.cpp b/src/libs/antares/study/scenario-builder/SolarTSNumberData.cpp index 50e8ec2dd5..4185a9545f 100644 --- a/src/libs/antares/study/scenario-builder/SolarTSNumberData.cpp +++ b/src/libs/antares/study/scenario-builder/SolarTSNumberData.cpp @@ -37,8 +37,8 @@ bool solarTSNumberData::apply(Study& study) const MatrixType::ColumnType& col = pTSNumberRules[areaIndex]; logprefix.clear() << "Solar: area '" << area.name << "': "; - ret = ApplyToMatrix(errors, logprefix, *area.solar.series, col, tsGenCountSolar) && ret; + ret = ApplyToMatrix(errors, logprefix, area.solar.series, col, tsGenCountSolar) && ret; } return ret; } -} \ No newline at end of file +} diff --git a/src/libs/antares/study/scenario-builder/ThermalTSNumberData.cpp b/src/libs/antares/study/scenario-builder/ThermalTSNumberData.cpp index bdd9e20582..d9fd64b378 100644 --- a/src/libs/antares/study/scenario-builder/ThermalTSNumberData.cpp +++ b/src/libs/antares/study/scenario-builder/ThermalTSNumberData.cpp @@ -94,7 +94,7 @@ bool thermalTSNumberData::apply(Study& study) logprefix.clear() << "Thermal: area '" << area.name << "', cluster: '" << cluster.name() << "': "; - ret = ApplyToMatrix(errors, logprefix, *cluster.series, col, tsGenCountThermal) && ret; + ret = ApplyToMatrix(errors, logprefix, cluster.series, col, tsGenCountThermal) && ret; } return ret; } @@ -107,4 +107,4 @@ uint thermalTSNumberData::get_tsGenCount(const Study& study) const bool tsGenThermal = (0 != (parameters.timeSeriesToGenerate & timeSeriesThermal)); return tsGenThermal ? parameters.nbTimeSeriesThermal : 0u; } -} \ No newline at end of file +} diff --git a/src/libs/antares/study/scenario-builder/WindTSNumberData.cpp b/src/libs/antares/study/scenario-builder/WindTSNumberData.cpp index c77c856348..fa8182307b 100644 --- a/src/libs/antares/study/scenario-builder/WindTSNumberData.cpp +++ b/src/libs/antares/study/scenario-builder/WindTSNumberData.cpp @@ -36,8 +36,8 @@ bool windTSNumberData::apply(/*const*/ Study& study) const MatrixType::ColumnType& col = pTSNumberRules[areaIndex]; logprefix.clear() << "Wind: area '" << area.name << "': "; - ret = ApplyToMatrix(errors, logprefix, *area.wind.series, col, tsGenCountWind) && ret; + ret = ApplyToMatrix(errors, logprefix, area.wind.series, col, tsGenCountWind) && ret; } return ret; } -} \ No newline at end of file +} diff --git a/src/libs/antares/study/scenario-builder/applyToMatrix.hxx b/src/libs/antares/study/scenario-builder/applyToMatrix.hxx index c2990af51d..2937c57a76 100644 --- a/src/libs/antares/study/scenario-builder/applyToMatrix.hxx +++ b/src/libs/antares/study/scenario-builder/applyToMatrix.hxx @@ -25,7 +25,7 @@ inline bool CheckValidity(uint value, uint tsGenMax) { // When the TS-Generators are not used - return (!tsGenMax) ? (value < data.count) : (value < tsGenMax); + return (!tsGenMax) ? (value < data.TScount()) : (value < tsGenMax); } template<> diff --git a/src/libs/antares/study/study.cpp b/src/libs/antares/study/study.cpp index d46123f8dd..dfaf427287 100644 --- a/src/libs/antares/study/study.cpp +++ b/src/libs/antares/study/study.cpp @@ -587,7 +587,7 @@ void Study::performTransformationsBeforeLaunchingSimulation() } // Informations about time-series for the load - auto& matrix = area.load.series->timeSeries; + auto& matrix = area.load.series.timeSeries; auto& dsmvalues = area.reserves[fhrDSM]; // Adding DSM values @@ -1010,7 +1010,7 @@ bool Study::areaRename(Area* area, AreaName newName) bool Study::clusterRename(Cluster* cluster, ClusterName newName) { // A name must not be empty - if (!cluster or !newName.empty()) + if (!cluster or newName.empty()) return false; String beautifyname; diff --git a/src/libs/antares/study/study.h b/src/libs/antares/study/study.h index 73698e6b1a..d52b587604 100644 --- a/src/libs/antares/study/study.h +++ b/src/libs/antares/study/study.h @@ -610,7 +610,7 @@ class Study: public Yuni::NonCopyable, public IObject, public LayerData ScenarioBuilder::Sets* scenarioRules = nullptr; //@} - Matrix scenarioHydroLevels; + TimeSeries::TS scenarioHydroLevels; /*! ** \brief Runtime informations diff --git a/src/libs/antares/study/study.importprepro.cpp b/src/libs/antares/study/study.importprepro.cpp index 5c3499a64b..1579588b79 100644 --- a/src/libs/antares/study/study.importprepro.cpp +++ b/src/libs/antares/study/study.importprepro.cpp @@ -60,7 +60,7 @@ bool Study::importTimeseriesIntoInput() areas.each([&](const Data::Area& area) { logs.info() << "Importing load timeseries : " << area.name; buffer.clear() << folderInput << SEP << "load" << SEP << "series"; - ret = DataSeriesLoadSaveToFolder(area.load.series, area.id, buffer.c_str()) && ret; + ret = area.load.series.saveToFolder(area.id, buffer.c_str(), "load_") && ret; ++progression; }); } @@ -72,8 +72,7 @@ bool Study::importTimeseriesIntoInput() areas.each([&](const Data::Area& area) { logs.info() << "Importing solar timeseries : " << area.name; buffer.clear() << folderInput << SEP << "solar" << SEP << "series"; - ret - = DataSeriesSolarSaveToFolder(area.solar.series, area.id, buffer.c_str()) && ret; + ret = area.solar.series.saveToFolder(area.id, buffer.c_str(), "solar_") && ret; ++progression; }); } @@ -97,7 +96,7 @@ bool Study::importTimeseriesIntoInput() areas.each([&](const Data::Area& area) { logs.info() << "Importing wind timeseries : " << area.name; buffer.clear() << folderInput << SEP << "wind" << SEP << "series"; - ret = DataSeriesWindSaveToFolder(area.wind.series, area.id, buffer.c_str()) && ret; + area.wind.series.saveToFolder(area.id, buffer.c_str(), "wind_") && ret; ++progression; }); } diff --git a/src/libs/antares/writer/CMakeLists.txt b/src/libs/antares/writer/CMakeLists.txt index ef7129cc51..1f468f5151 100644 --- a/src/libs/antares/writer/CMakeLists.txt +++ b/src/libs/antares/writer/CMakeLists.txt @@ -32,12 +32,13 @@ target_include_directories(result_writer target_link_libraries(result_writer PUBLIC Antares::benchmarking - PRIVATE yuni-static-core + PRIVATE MINIZIP::minizip logs inifile io + Antares::concurrency ) diff --git a/src/libs/antares/writer/antares/writer/i_writer.h b/src/libs/antares/writer/antares/writer/i_writer.h index 0256ccc292..be579165e5 100644 --- a/src/libs/antares/writer/antares/writer/i_writer.h +++ b/src/libs/antares/writer/antares/writer/i_writer.h @@ -4,11 +4,22 @@ #include #include +#include namespace Antares { namespace Solver { + +/*! + * A generic I/O exception that may be thrown by writer operations. + */ +class IOError : public std::runtime_error +{ +public: + using std::runtime_error::runtime_error; +}; + class IResultWriter { public: @@ -16,6 +27,12 @@ class IResultWriter virtual void addEntryFromBuffer(const std::string& entryPath, Yuni::Clob& entryContent) = 0; virtual void addEntryFromBuffer(const std::string& entryPath, std::string& entryContent) = 0; virtual void addEntryFromFile(const std::string& entryPath, const std::string& filePath) = 0; + + /*! + * Waits for completion of every write operation previously appended. + * An IOError may be raised if any of those fails. + */ + virtual void flush() = 0; virtual bool needsTheJobQueue() const = 0; virtual void finalize(bool verbose) = 0; }; @@ -24,6 +41,7 @@ class NullResultWriter: public Solver::IResultWriter { void addEntryFromBuffer(const std::string &, Yuni::Clob &) override; void addEntryFromBuffer(const std::string &, std::string &) override; void addEntryFromFile(const std::string &, const std::string &) override; + void flush() override; bool needsTheJobQueue() const override; void finalize(bool ) override; }; diff --git a/src/libs/antares/writer/ensure_queue_started.cpp b/src/libs/antares/writer/ensure_queue_started.cpp index 18618a5f96..8c77b524e7 100644 --- a/src/libs/antares/writer/ensure_queue_started.cpp +++ b/src/libs/antares/writer/ensure_queue_started.cpp @@ -15,6 +15,7 @@ EnsureQueueStartedIfNeeded::EnsureQueueStartedIfNeeded( qs->start(); } } + EnsureQueueStartedIfNeeded::~EnsureQueueStartedIfNeeded() { if (startQueue) diff --git a/src/libs/antares/writer/immediate_file_writer.cpp b/src/libs/antares/writer/immediate_file_writer.cpp index ed0b521302..8d3ff5e016 100644 --- a/src/libs/antares/writer/immediate_file_writer.cpp +++ b/src/libs/antares/writer/immediate_file_writer.cpp @@ -112,6 +112,9 @@ void ImmediateFileResultWriter::addEntryFromFile(const std::string& entryPath, } } +void ImmediateFileResultWriter::flush() +{} + bool ImmediateFileResultWriter::needsTheJobQueue() const { return false; @@ -128,6 +131,9 @@ void NullResultWriter::addEntryFromBuffer(const std::string&, std::string&) {} void NullResultWriter::addEntryFromFile(const std::string&, const std::string&) {} +void NullResultWriter::flush() +{} + bool NullResultWriter::needsTheJobQueue() const { return false; diff --git a/src/libs/antares/writer/private/immediate_file_writer.h b/src/libs/antares/writer/private/immediate_file_writer.h index fad9422bab..91f45719e5 100644 --- a/src/libs/antares/writer/private/immediate_file_writer.h +++ b/src/libs/antares/writer/private/immediate_file_writer.h @@ -15,6 +15,7 @@ class ImmediateFileResultWriter : public IResultWriter void addEntryFromBuffer(const std::string& entryPath, Yuni::Clob& entryContent) override; void addEntryFromBuffer(const std::string& entryPath, std::string& entryContent) override; void addEntryFromFile(const std::string& entryPath, const std::string& filePath) override; + void flush() override; bool needsTheJobQueue() const override; void finalize(bool verbose) override; diff --git a/src/libs/antares/writer/private/zip_writer.h b/src/libs/antares/writer/private/zip_writer.h index 734d15eced..4b3f076742 100644 --- a/src/libs/antares/writer/private/zip_writer.h +++ b/src/libs/antares/writer/private/zip_writer.h @@ -4,11 +4,11 @@ #include #include -#include #include #include "antares/writer/i_writer.h" #include +#include "antares/concurrency/concurrency.h" namespace Antares::Solver @@ -20,15 +20,23 @@ enum class ZipState }; class ZipWriter; + +/*! + * In charge of writing one entry into the underlying zip. + * May be used as a function object. + */ template -class ZipWriteJob final : public Yuni::Job::IJob +class ZipWriteJob { public: ZipWriteJob(ZipWriter& writer, std::string entryPath, ContentT& content, Benchmarking::IDurationCollector& duration_collector); - virtual void onExecute() override; + void writeEntry(); + void operator()() { + writeEntry(); + } private: // Pointer to Zip handle @@ -55,9 +63,9 @@ class ZipWriter : public IResultWriter void addEntryFromBuffer(const std::string& entryPath, Yuni::Clob& entryContent) override; void addEntryFromBuffer(const std::string& entryPath, std::string& entryContent) override; void addEntryFromFile(const std::string& entryPath, const std::string& filePath) override; + void flush() override; bool needsTheJobQueue() const override; void finalize(bool verbose) override; - friend class ZipWriteJob; friend class ZipWriteJob; @@ -75,6 +83,8 @@ class ZipWriter : public IResultWriter // Benchmarking. Passed to jobs Benchmarking::IDurationCollector& pDurationCollector; + Concurrency::FutureSet pendingTasks_; + private: template void addEntryFromBufferHelper(const std::string& entryPath, ContentType& entryContent); diff --git a/src/libs/antares/writer/private/zip_writer.hxx b/src/libs/antares/writer/private/zip_writer.hxx index 945251457b..a933f94a5b 100644 --- a/src/libs/antares/writer/private/zip_writer.hxx +++ b/src/libs/antares/writer/private/zip_writer.hxx @@ -1,5 +1,6 @@ #pragma once +#include "antares/concurrency/concurrency.h" #include "ensure_queue_started.h" namespace Antares::Solver @@ -11,8 +12,9 @@ void ZipWriter::addEntryFromBufferHelper(const std::string& entryPath, ContentTy return; EnsureQueueStartedIfNeeded ensureQueue(this, pQueueService); - pQueueService->add( - new ZipWriteJob(*this, entryPath, entryContent, pDurationCollector), - Yuni::Job::priorityLow); + pendingTasks_.add(Concurrency::AddTask(*pQueueService, + ZipWriteJob(*this, entryPath, entryContent, pDurationCollector), + Yuni::Job::priorityLow)); } + } // namespace Antares::Solver diff --git a/src/libs/antares/writer/zip_writer.cpp b/src/libs/antares/writer/zip_writer.cpp index 51c33b5562..11745ebcd9 100644 --- a/src/libs/antares/writer/zip_writer.cpp +++ b/src/libs/antares/writer/zip_writer.cpp @@ -16,9 +16,22 @@ extern "C" #include // std::time #include +#include namespace Antares::Solver { + +namespace +{ + +void logErrorAndThrow(const std::string& errorMessage) +{ + logs.error() << errorMessage; + throw IOError(errorMessage); +} + +} + // Class ZipWriteJob template ZipWriteJob::ZipWriteJob(ZipWriter& writer, @@ -46,7 +59,7 @@ static std::unique_ptr createInfo(const std::string& entryPath) } template -void ZipWriteJob::onExecute() +void ZipWriteJob::writeEntry() { // Don't write data if finalize() has been called if (pState != ZipState::can_receive_data) @@ -62,13 +75,14 @@ void ZipWriteJob::onExecute() Benchmarking::Timer timer_write; if (int32_t ret = mz_zip_writer_entry_open(pZipHandle, file_info.get()); ret != MZ_OK) - logs.error() << "Error opening entry " << pEntryPath << " (" << ret << ")"; - + { + logErrorAndThrow("Error opening entry " + pEntryPath + " (" + std::to_string(ret) + ")"); + } int32_t bw = mz_zip_writer_entry_write(pZipHandle, pContent.data(), pContent.size()); if (static_cast(bw) != pContent.size()) { - logs.error() << "Error writing entry " << pEntryPath << "(written = " << bw - << ", size = " << pContent.size() << ")"; + logErrorAndThrow("Error writing entry " + pEntryPath + "(written = " + std::to_string(bw) + + ", size = " + std::to_string(pContent.size()) + ")"); } timer_write.stop(); @@ -84,10 +98,10 @@ ZipWriter::ZipWriter(std::shared_ptr qs, pArchivePath(std::string(archivePath) + ".zip"), pDurationCollector(duration_collector) { - mz_zip_writer_create(&pZipHandle); + pZipHandle = mz_zip_writer_create(); if (int32_t ret = mz_zip_writer_open_file(pZipHandle, pArchivePath.c_str(), 0, 0); ret != MZ_OK) { - logs.error() << "Error opening zip file " << pArchivePath << " (" << ret << ")"; + logErrorAndThrow("Error opening zip file " + pArchivePath + " (" + std::to_string(ret) + ")"); } // TODO : make level of compression configurable mz_zip_writer_set_compress_level(pZipHandle, MZ_COMPRESS_LEVEL_FAST); @@ -129,16 +143,16 @@ void ZipWriter::addEntryFromFile(const std::string& entryPath, const std::string addEntryFromBufferHelper(entryPath, buffer); break; case errNotFound: - logs.error() << filePath << ": file does not exist"; + logErrorAndThrow(filePath + ": file does not exist"); break; - case errReadFailed: - logs.error() << "Read failed '" << filePath << "'"; + case errReadFailed: + logErrorAndThrow("Read failed '" + filePath + "'"); break; case errMemoryLimit: - logs.error() << "Size limit hit for file '" << filePath << "'"; + logErrorAndThrow("Size limit hit for file '" + filePath + "'"); break; default: - logs.error() << "Unhandled error"; + logErrorAndThrow("Unhandled error"); break; } } @@ -150,6 +164,9 @@ bool ZipWriter::needsTheJobQueue() const void ZipWriter::finalize(bool verbose) { + //wait for completion of pending writing tasks + flush(); + // Prevent new jobs from being submitted pState = ZipState::blocking; @@ -169,4 +186,10 @@ void ZipWriter::finalize(bool verbose) if (verbose) logs.notice() << "Done"; } + +void ZipWriter::flush() +{ + pendingTasks_.join(); +} + } // namespace Antares::Solver diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index e30a6089c4..1d55b9b7df 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -12,7 +12,6 @@ add_subdirectory(variable) add_subdirectory(hydro) add_subdirectory(simulation) add_subdirectory(ts-generator) -add_subdirectory(aleatoire) add_subdirectory(utils) add_subdirectory(optimisation) add_subdirectory(main) @@ -74,6 +73,7 @@ add_executable(antares-solver set_target_properties(antares-solver PROPERTIES OUTPUT_NAME ${exec_name}) set(ANTARES_SOLVER_LIBS + Antares::args_helper Antares::date Antares::benchmarking Antares::result_writer @@ -89,7 +89,6 @@ set(ANTARES_SOLVER_LIBS ${ANTARES_SOLVER_LIBS} antares-solver-main-economy antares-solver-main-adequacy antares-solver-hydro - antares-solver-aleatoire antares-solver-variable antares-solver-simulation antares-solver-ts-generator diff --git a/src/solver/aleatoire/CMakeLists.txt b/src/solver/aleatoire/CMakeLists.txt deleted file mode 100644 index 609d979cd5..0000000000 --- a/src/solver/aleatoire/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -set(SRC_ALEATOIRE - alea_fonctions.h - alea_sys.h - alea_tirage_au_sort_chroniques.cpp) -source_group("aleatoire" FILES ${SRC_ALEATOIRE}) - - -add_library(antares-solver-aleatoire ${SRC_ALEATOIRE}) - -target_include_directories(antares-solver-aleatoire - PRIVATE - ${CMAKE_SOURCE_DIR}/solver) - -target_link_libraries(antares-solver-aleatoire - PUBLIC - Antares::study -) diff --git a/src/solver/aleatoire/alea_fonctions.h b/src/solver/aleatoire/alea_fonctions.h deleted file mode 100644 index e54d825358..0000000000 --- a/src/solver/aleatoire/alea_fonctions.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -** 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 "../simulation/sim_structure_donnees.h" -#include "antares/study/study.h" - -void ApplyRandomTSnumbers(const Antares::Data::Study& study, - unsigned int year, - uint numSpace); \ No newline at end of file diff --git a/src/solver/aleatoire/alea_sys.h b/src/solver/aleatoire/alea_sys.h deleted file mode 100644 index 434e67decb..0000000000 --- a/src/solver/aleatoire/alea_sys.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -** 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 -*/ -#ifndef __SOLVER_RANDOM_SYSHDR_H__ -#define __SOLVER_RANDOM_SYSHDR_H__ - -#include -#include -#include -#include -#include - -#include "../config.h" -#include -#include "../simulation/simulation.h" - -#endif /* __SOLVER_RANDOM_SYSHDR_H__ */ diff --git a/src/solver/aleatoire/alea_tirage_au_sort_chroniques.cpp b/src/solver/aleatoire/alea_tirage_au_sort_chroniques.cpp deleted file mode 100644 index 3739933de0..0000000000 --- a/src/solver/aleatoire/alea_tirage_au_sort_chroniques.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* -** 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 "../simulation/sim_extern_variables_globales.h" -#include "alea_fonctions.h" -#include - -using namespace Yuni; -using namespace Antares; -using namespace Antares::Data; - -void ApplyRandomTSnumbers(const Study& study, - unsigned int year, - uint numSpace) -{ - // ------------------------------ - // Transmission capacities - // ------------------------------ - // each link - for (unsigned int linkIndex = 0; linkIndex < study.runtime->interconnectionsCount(); ++linkIndex) - { - AreaLink* link = study.runtime->areaLink[linkIndex]; - assert(year < link->timeseriesNumbers.height); - NUMERO_CHRONIQUES_TIREES_PAR_INTERCONNEXION& ptchro - = NumeroChroniquesTireesParInterconnexion[numSpace][linkIndex]; - const uint directWidth = link->directCapacities.width; - [[maybe_unused]] const uint indirectWidth = link->indirectCapacities.width; - assert(directWidth == indirectWidth); - ptchro.TransmissionCapacities - = (directWidth != 1) ? link->timeseriesNumbers[0][year] : 0; // zero-based - } - - // ------------------------------ - //Binding constraints - // ------------------------------ - //Setting 0 for time_series of width 0 is done when using the value. - //To do this here we would have to check every BC for its width - for (const auto& group: study.bindingConstraintsGroups) { - [[maybe_unused]] auto number_of_ts_numbers = group->timeseriesNumbers.height; - assert(year < number_of_ts_numbers); //If only 1 ts_number we suppose only one TS. Any "year" will be converted to "0" later - NumeroChroniquesTireesParGroup[numSpace][group->name()] = group->timeseriesNumbers[0][year]; - } -} diff --git a/src/solver/application.cpp b/src/solver/application.cpp index 143d0fe240..a2aa4e3dbd 100644 --- a/src/solver/application.cpp +++ b/src/solver/application.cpp @@ -140,6 +140,9 @@ void Application::prepare(int argc, char* argv[]) // Some more checks require the existence of pParameters, hence of a study. // Their execution is delayed up to this point. + checkOrtoolsUsage( + pParameters->unitCommitment.ucMode, pParameters->ortoolsUsed, pParameters->ortoolsSolver); + checkSimplexRangeHydroPricing(pParameters->simplexOptimizationRange, pParameters->hydroPricing.hpMode); @@ -281,8 +284,11 @@ void Application::processCaption(const Yuni::String& caption) void Application::prepareWriter(Antares::Data::Study& study, Benchmarking::IDurationCollector& duration_collector) { + ioQueueService = std::make_shared(); + ioQueueService->maximumThreadCount(1); + ioQueueService->start(); resultWriter = resultWriterFactory( - study.parameters.resultFormat, study.folderOutput, study.pQueueService, duration_collector); + study.parameters.resultFormat, study.folderOutput, ioQueueService, duration_collector); } void Application::readDataForTheStudy(Data::StudyLoadOptions& options) @@ -302,31 +308,38 @@ void Application::readDataForTheStudy(Data::StudyLoadOptions& options) // Load the study from a folder Benchmarking::Timer timer; - if (study.loadFromFolder(pSettings.studyFolder, options) && !study.gotFatalError) + std::exception_ptr loadingException; + try { - logs.info() << "The study is loaded."; - logs.info() << LOG_UI_DISPLAY_MESSAGES_OFF; - } + if (study.loadFromFolder(pSettings.studyFolder, options) && !study.gotFatalError) + { + logs.info() << "The study is loaded."; + logs.info() << LOG_UI_DISPLAY_MESSAGES_OFF; + } - timer.stop(); - pDurationCollector.addDuration("study_loading", timer.get_duration()); + timer.stop(); + pDurationCollector.addDuration("study_loading", timer.get_duration()); - if (study.gotFatalError) - throw Error::ReadingStudy(); + if (study.gotFatalError) + throw Error::ReadingStudy(); - if (study.areas.empty()) - { - throw Error::NoAreas(); - } + if (study.areas.empty()) + { + throw Error::NoAreas(); + } - // no output ? - study.parameters.noOutput = pSettings.noOutput; + // no output ? + study.parameters.noOutput = pSettings.noOutput; - if (pSettings.forceZipOutput) + if (pSettings.forceZipOutput) + { + pParameters->resultFormat = Antares::Data::zipArchive; + } + } + catch (...) { - pParameters->resultFormat = Antares::Data::zipArchive; + loadingException = std::current_exception(); } - // This settings can only be enabled from the solver // Prepare the output for the study study.prepareOutput(); @@ -334,6 +347,14 @@ void Application::readDataForTheStudy(Data::StudyLoadOptions& options) // Initialize the result writer prepareWriter(study, pDurationCollector); + // Some checks may have failed, but we need a writer to copy the logs + // to the output directory + // So we wait until we have initialized the writer to rethrow + if (loadingException) + { + std::rethrow_exception(loadingException); + } + Antares::Solver::initializeSignalHandlers(resultWriter); // Save about-the-study files (comments, notes, etc.) @@ -407,7 +428,7 @@ void Application::readDataForTheStudy(Data::StudyLoadOptions& options) // Apply transformations needed by the solver only (and not the interface for example) study.performTransformationsBeforeLaunchingSimulation(); - //alloc global vectors + // alloc global vectors SIM_AllocationTableaux(study); // Random-numbers generators @@ -453,8 +474,9 @@ Application::~Application() { logs.info() << LOG_UI_SOLVER_DONE; - // Copy the log file - if (!pStudy->parameters.noOutput) { + // Copy the log file if a result writer is available + if (!pStudy->parameters.noOutput && resultWriter) + { pStudy->importLogsToOutputFolder(*resultWriter); } @@ -466,4 +488,3 @@ Application::~Application() } } } // namespace Antares::Solver - diff --git a/src/solver/application.h b/src/solver/application.h index 76f75de59a..7740087a73 100644 --- a/src/solver/application.h +++ b/src/solver/application.h @@ -94,6 +94,7 @@ class Application : public Yuni::IEventObserver ioQueueService; IResultWriter::Ptr resultWriter = nullptr; void prepareWriter(Antares::Data::Study& study, diff --git a/src/solver/hydro/management/daily.cpp b/src/solver/hydro/management/daily.cpp index e2648e37b7..f28b9600ac 100644 --- a/src/solver/hydro/management/daily.cpp +++ b/src/solver/hydro/management/daily.cpp @@ -81,7 +81,6 @@ enum struct DebugData { - using InflowsType = Matrix::ColumnType; using MaxPowerType = Matrix::ColumnType; using ReservoirLevelType = Matrix::ColumnType; @@ -100,7 +99,7 @@ struct DebugData Solver::IResultWriter& pWriter; const TmpDataByArea& data; const VENTILATION_HYDRO_RESULTS_BY_AREA& ventilationResults; - const InflowsType& srcinflows; + const double* srcinflows; const MaxPowerType& maxP; const MaxPowerType& maxE; const double* dailyTargetGen; @@ -110,7 +109,7 @@ struct DebugData DebugData(Solver::IResultWriter& writer, const TmpDataByArea& data, const VENTILATION_HYDRO_RESULTS_BY_AREA& ventilationResults, - const InflowsType& srcinflows, + const double* srcinflows, const MaxPowerType& maxP, const MaxPowerType& maxE, const double* dailyTargetGen, @@ -230,10 +229,7 @@ inline void HydroManagement::prepareDailyOptimalGenerations(Solver::Variable::St uint z = area.index; assert(z < areas_.size()); - auto& inflowsmatrix = area.hydro.series->storage; - - auto tsIndex = area.hydro.series->getIndex(y); - auto const& srcinflows = inflowsmatrix[tsIndex < inflowsmatrix.width ? tsIndex : 0]; + auto const srcinflows = area.hydro.series->storage.getColumn(y); auto& data = tmpDataByArea_[numSpace][z]; diff --git a/src/solver/hydro/management/management.cpp b/src/solver/hydro/management/management.cpp index 7328e3bbe8..853caf5d2d 100644 --- a/src/solver/hydro/management/management.cpp +++ b/src/solver/hydro/management/management.cpp @@ -126,14 +126,11 @@ HydroManagement::~HydroManagement() void HydroManagement::prepareInflowsScaling(uint numSpace, uint year) { - areas_.each([&](Data::Area& area) + areas_.each([&](const Data::Area& area) { uint z = area.index; - auto& inflowsmatrix = area.hydro.series->storage; - assert(inflowsmatrix.width && inflowsmatrix.height); - auto tsIndex = area.hydro.series->getIndex(year); - auto const& srcinflows = inflowsmatrix[tsIndex < inflowsmatrix.width ? tsIndex : 0]; + auto const& srcinflows = area.hydro.series->storage.getColumn(year); auto& data = tmpDataByArea_[numSpace][z]; double totalYearInflows = 0.0; @@ -177,14 +174,11 @@ void HydroManagement::prepareInflowsScaling(uint numSpace, uint year) void HydroManagement::minGenerationScaling(uint numSpace, uint year) const { - areas_.each([this, &numSpace, &year](Data::Area& area) + areas_.each([this, &numSpace, &year](const Data::Area& area) { - uint z = area.index; - - auto& mingenmatrix = area.hydro.series->mingen; - auto tsIndex = area.hydro.series->getIndex(year); - auto const& srcmingen = mingenmatrix[tsIndex < mingenmatrix.width ? tsIndex : 0]; + auto const& srcmingen = area.hydro.series->mingen.getColumn(year); + uint z = area.index; auto& data = tmpDataByArea_[numSpace][z]; double totalYearMingen = 0.0; @@ -234,7 +228,7 @@ void HydroManagement::minGenerationScaling(uint numSpace, uint year) const }); } -bool HydroManagement::checkMonthlyMinGeneration(uint numSpace, uint tsIndex, const Data::Area& area) const +bool HydroManagement::checkMonthlyMinGeneration(uint numSpace, uint year, const Data::Area& area) const { const auto& data = tmpDataByArea_[numSpace][area.index]; for (uint month = 0; month != 12; ++month) @@ -245,7 +239,8 @@ bool HydroManagement::checkMonthlyMinGeneration(uint numSpace, uint tsIndex, con { logs.error() << "In Area " << area.name << " the minimum generation of " << data.totalMonthMingen[realmonth] << " MW in month " << month + 1 - << " of TS-" << tsIndex + 1 << " is incompatible with the inflows of " + << " of TS-" << area.hydro.series->mingen.getSeriesIndex(year) + 1 + << " is incompatible with the inflows of " << data.totalMonthInflows[realmonth] << " MW."; return false; } @@ -253,26 +248,25 @@ bool HydroManagement::checkMonthlyMinGeneration(uint numSpace, uint tsIndex, con return true; } -bool HydroManagement::checkYearlyMinGeneration(uint numSpace, uint tsIndex, const Data::Area& area) const +bool HydroManagement::checkYearlyMinGeneration(uint numSpace, uint year, const Data::Area& area) const { const auto& data = tmpDataByArea_[numSpace][area.index]; if (data.totalYearMingen > data.totalYearInflows) { // Yearly minimum generation <= Yearly inflows logs.error() << "In Area " << area.name << " the minimum generation of " - << data.totalYearMingen << " MW of TS-" << tsIndex + 1 + << data.totalYearMingen << " MW of TS-" + << area.hydro.series->mingen.getSeriesIndex(year) + 1 << " is incompatible with the inflows of " << data.totalYearInflows << " MW."; return false; } return true; } -bool HydroManagement::checkWeeklyMinGeneration(uint tsIndex, Data::Area& area) const +bool HydroManagement::checkWeeklyMinGeneration(uint year, const Data::Area& area) const { - auto& inflowsmatrix = area.hydro.series->storage; - auto& mingenmatrix = area.hydro.series->mingen; - auto const& srcinflows = inflowsmatrix[tsIndex < inflowsmatrix.width ? tsIndex : 0]; - auto const& srcmingen = mingenmatrix[tsIndex < mingenmatrix.width ? tsIndex : 0]; + auto const& srcinflows = area.hydro.series->storage.getColumn(year); + auto const& srcmingen = area.hydro.series->mingen.getColumn(year); // Weekly minimum generation <= Weekly inflows for each week for (uint week = 0; week < calendar_.maxWeeksInYear - 1; ++week) { @@ -295,7 +289,8 @@ bool HydroManagement::checkWeeklyMinGeneration(uint tsIndex, Data::Area& area) c { logs.error() << "In Area " << area.name << " the minimum generation of " << totalWeekMingen << " MW in week " << week + 1 << " of TS-" - << tsIndex + 1 << " is incompatible with the inflows of " + << area.hydro.series->mingen.getSeriesIndex(year) + 1 + << " is incompatible with the inflows of " << totalWeekInflows << " MW."; return false; } @@ -303,11 +298,11 @@ bool HydroManagement::checkWeeklyMinGeneration(uint tsIndex, Data::Area& area) c return true; } -bool HydroManagement::checkHourlyMinGeneration(uint tsIndex, Data::Area& area) const +bool HydroManagement::checkHourlyMinGeneration(uint year, const Data::Area& area) const { // Hourly minimum generation <= hourly max generation for each hour - auto& mingenmatrix = area.hydro.series->mingen; - auto const& srcmingen = mingenmatrix[tsIndex < mingenmatrix.width ? tsIndex : 0]; + + auto const& srcmingen = area.hydro.series->mingen.getColumn(year); auto const& maxPower = area.hydro.maxPower; auto const& maxP = maxPower[Data::PartHydro::genMaxP]; @@ -328,7 +323,7 @@ bool HydroManagement::checkHourlyMinGeneration(uint tsIndex, Data::Area& area) c logs.error() << "In area: " << area.name << " [hourly] minimum generation of " << srcmingen[day * 24 + h] << " MW in timestep " << day * 24 + h + 1 - << " of TS-" << tsIndex + 1 + << " of TS-" << area.hydro.series->mingen.getSeriesIndex(year) + 1 << " is incompatible with the maximum generation of " << maxP[day] << " MW."; return false; @@ -342,48 +337,45 @@ bool HydroManagement::checkHourlyMinGeneration(uint tsIndex, Data::Area& area) c bool HydroManagement::checkMinGeneration(uint numSpace, uint year) const { bool ret = true; - areas_.each([this, &numSpace, &ret, &year](Data::Area& area) + areas_.each([this, &numSpace, &ret, &year](const Data::Area& area) { - auto tsIndex = area.hydro.series->getIndex(year); - bool useHeuristicTarget = area.hydro.useHeuristicTarget; bool followLoadModulations = area.hydro.followLoadModulations; bool reservoirManagement = area.hydro.reservoirManagement; - ret = checkHourlyMinGeneration(tsIndex, area) && ret; + ret = checkHourlyMinGeneration(year, area) && ret; if (!useHeuristicTarget) return; if (!followLoadModulations) { - ret = checkWeeklyMinGeneration(tsIndex, area) && ret; + ret = checkWeeklyMinGeneration(year, area) && ret; return; } if (reservoirManagement) - ret = checkYearlyMinGeneration(numSpace, tsIndex, area) && ret; + ret = checkYearlyMinGeneration(numSpace, year, area) && ret; else - ret = checkMonthlyMinGeneration(numSpace, tsIndex, area) && ret; + ret = checkMonthlyMinGeneration(numSpace, year, area) && ret; }); return ret; } void HydroManagement::prepareNetDemand(uint numSpace, uint year, Data::StudyMode mode) { - areas_.each([&](Data::Area& area) { + areas_.each([this, &year, &numSpace, &mode](const Data::Area& area) { uint z = area.index; auto& scratchpad = area.scratchpad[numSpace]; - auto& rormatrix = area.hydro.series->ror; - auto tsIndex = area.hydro.series->getIndex(year); - auto& ror = rormatrix[tsIndex < rormatrix.width ? tsIndex : 0]; + const auto& rormatrix = area.hydro.series->ror; + const auto* ror = rormatrix.getColumn(year); auto& data = tmpDataByArea_[numSpace][z]; - const double* loadSeries = area.load.series->getColumn(year); - const double* windSeries = area.wind.series->getColumn(year); - const double* solarSeries = area.solar.series->getColumn(year); + const double* loadSeries = area.load.series.getColumn(year); + const double* windSeries = area.wind.series.getColumn(year); + const double* solarSeries = area.solar.series.getColumn(year); for (uint hour = 0; hour != HOURS_PER_YEAR; ++hour) { @@ -410,8 +402,8 @@ void HydroManagement::prepareNetDemand(uint numSpace, uint year, Data::StudyMode : scratchpad.originalMustrunSum[hour]); area.renewable.list.each([&](const Antares::Data::RenewableCluster& cluster) { - assert(cluster.series->timeSeries.jit == NULL && "No JIT data from the solver"); - netdemand -= cluster.valueAtTimeStep(hour, year); + assert(cluster.series.timeSeries.jit == nullptr && "No JIT data from the solver"); + netdemand -= cluster.valueAtTimeStep(year, hour); }); } diff --git a/src/solver/hydro/management/management.h b/src/solver/hydro/management/management.h index deb1f1f4d5..90bb8d0f24 100644 --- a/src/solver/hydro/management/management.h +++ b/src/solver/hydro/management/management.h @@ -125,13 +125,13 @@ class HydroManagement final //! Prepare minimum generation scaling for each area void minGenerationScaling(uint numSpace, uint year) const; //! check Monthly minimum generation is lower than available inflows - bool checkMonthlyMinGeneration(uint numSpace, uint tsIndex, const Data::Area& area) const; + bool checkMonthlyMinGeneration(uint numSpace, uint year, const Data::Area& area) const; //! check Yearly minimum generation is lower than available inflows - bool checkYearlyMinGeneration(uint numSpace, uint tsIndex, const Data::Area& area) const; + bool checkYearlyMinGeneration(uint numSpace, uint year, const Data::Area& area) const; //! check Weekly minimum generation is lower than available inflows - bool checkWeeklyMinGeneration(uint tsIndex, Data::Area& area) const; + bool checkWeeklyMinGeneration(uint year, const Data::Area& area) const; //! check Hourly minimum generation is lower than available inflows - bool checkHourlyMinGeneration(uint tsIndex, Data::Area& area) const; + bool checkHourlyMinGeneration(uint year, const Data::Area& area) const; //! check minimum generation is lower than available inflows bool checkMinGeneration(uint numSpace, uint year) const; //! Prepare the net demand for each area diff --git a/src/solver/main.cpp b/src/solver/main.cpp index b261d55f9b..367278b7b9 100644 --- a/src/solver/main.cpp +++ b/src/solver/main.cpp @@ -28,7 +28,7 @@ #include #include "application.h" -#include "../ui/common/winmain.hxx" //TODO: remove that reverse dependency to UI +#include #include #include @@ -127,15 +127,13 @@ int main(int argc, char** argv) InitializeDefaultLocale(); // Getting real UTF8 arguments - argv = AntaresGetUTF8Arguments(argc, argv); - + IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); + std::tie(argc, argv) = toUTF8ArgsTranslator.convert(); Antares::Solver::Application application; application.prepare(argc, argv); application.execute(); application.writeExectutionInfo(); - FreeUTF8Arguments(argc, argv); - // to avoid a bug from wxExecute, we should wait a little before returning SuspendMilliSeconds(200 /*ms*/); diff --git a/src/solver/main/CMakeLists.txt b/src/solver/main/CMakeLists.txt index 239702e682..592a0a87e7 100644 --- a/src/solver/main/CMakeLists.txt +++ b/src/solver/main/CMakeLists.txt @@ -12,10 +12,12 @@ add_library(antares-solver-main-adequacy ${SRC_SOLVER_MAIN_ADEQUACY}) target_link_libraries(antares-solver-main-adequacy PRIVATE Antares::infoCollection + antares-solver-simulation ) add_library(antares-solver-main-economy ${SRC_SOLVER_MAIN_ECONOMY}) target_link_libraries(antares-solver-main-economy PRIVATE Antares::infoCollection + antares-solver-simulation ) diff --git a/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.cpp b/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.cpp index 432d84414a..03119ed030 100644 --- a/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.cpp +++ b/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.cpp @@ -41,7 +41,7 @@ void ConsistenceNumberOfDispatchableUnits::add(int pays, } else { - nbTermesContraintesPourLesCoutsDeDemarrage += 4; + problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage += 4; problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.h b/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.h index ae3b1341b8..43af772514 100644 --- a/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.h +++ b/src/solver/optimisation/constraints/ConsistenceNumberOfDispatchableUnits.h @@ -16,5 +16,4 @@ class ConsistenceNumberOfDispatchableUnits : private ConstraintFactory * @param Simulation : --- */ void add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation); - int nbTermesContraintesPourLesCoutsDeDemarrage = 0; }; \ No newline at end of file diff --git a/src/solver/optimisation/constraints/MinDownTime.cpp b/src/solver/optimisation/constraints/MinDownTime.cpp index e70e220e54..ca4805d007 100644 --- a/src/solver/optimisation/constraints/MinDownTime.cpp +++ b/src/solver/optimisation/constraints/MinDownTime.cpp @@ -43,7 +43,7 @@ void MinDownTime::add(int pays, int cluster, int clusterIndex, int pdt, bool Sim } else { - nbTermesContraintesPourLesCoutsDeDemarrage + problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage += 1 + DureeMinimaleDArretDUnGroupeDuPalierThermique; problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; } diff --git a/src/solver/optimisation/constraints/MinDownTime.h b/src/solver/optimisation/constraints/MinDownTime.h index 5d24da5058..567a766b6d 100644 --- a/src/solver/optimisation/constraints/MinDownTime.h +++ b/src/solver/optimisation/constraints/MinDownTime.h @@ -16,5 +16,4 @@ class MinDownTime : private ConstraintFactory * @param Simulation : --- */ void add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation); - int nbTermesContraintesPourLesCoutsDeDemarrage = 0; }; \ No newline at end of file diff --git a/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp b/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp index 31c23ac290..06a341f14d 100644 --- a/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp +++ b/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.cpp @@ -52,7 +52,7 @@ void NbDispUnitsMinBoundSinceMinUpTime::add(int pays, } else { - nbTermesContraintesPourLesCoutsDeDemarrage + problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage += 1 + 2 * DureeMinimaleDeMarcheDUnGroupeDuPalierThermique; problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; } diff --git a/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.h b/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.h index ec0c1afd7f..ab86556a21 100644 --- a/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.h +++ b/src/solver/optimisation/constraints/NbDispUnitsMinBoundSinceMinUpTime.h @@ -17,5 +17,4 @@ class NbDispUnitsMinBoundSinceMinUpTime : private ConstraintFactory * @param Simulation : --- */ void add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation); - int nbTermesContraintesPourLesCoutsDeDemarrage = 0; }; \ No newline at end of file diff --git a/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.cpp b/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.cpp index 1a7e0f3a7f..472aedc323 100644 --- a/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.cpp +++ b/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.cpp @@ -35,7 +35,7 @@ void NbUnitsOutageLessThanNbUnitsStop::add(int pays, } else { - nbTermesContraintesPourLesCoutsDeDemarrage += 4; + problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage += 2; problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.h b/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.h index fb8035324c..79c9f714fb 100644 --- a/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.h +++ b/src/solver/optimisation/constraints/NbUnitsOutageLessThanNbUnitsStop.h @@ -17,5 +17,4 @@ class NbUnitsOutageLessThanNbUnitsStop : private ConstraintFactory * @param Simulation : --- */ void add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation); - int nbTermesContraintesPourLesCoutsDeDemarrage = 0; }; \ No newline at end of file diff --git a/src/solver/optimisation/constraints/PMaxDispatchableGeneration.cpp b/src/solver/optimisation/constraints/PMaxDispatchableGeneration.cpp index c41448bd45..92f4d06eed 100644 --- a/src/solver/optimisation/constraints/PMaxDispatchableGeneration.cpp +++ b/src/solver/optimisation/constraints/PMaxDispatchableGeneration.cpp @@ -32,7 +32,7 @@ void PMaxDispatchableGeneration::add(int pays, } else { - nbTermesContraintesPourLesCoutsDeDemarrage += 2; + problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage += 2; problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/PMaxDispatchableGeneration.h b/src/solver/optimisation/constraints/PMaxDispatchableGeneration.h index 58f14c8223..b82c5dd196 100644 --- a/src/solver/optimisation/constraints/PMaxDispatchableGeneration.h +++ b/src/solver/optimisation/constraints/PMaxDispatchableGeneration.h @@ -17,5 +17,4 @@ class PMaxDispatchableGeneration : private ConstraintFactory * @param Simulation : --- */ void add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation); - int nbTermesContraintesPourLesCoutsDeDemarrage = 0; }; \ No newline at end of file diff --git a/src/solver/optimisation/constraints/PMinDispatchableGeneration.cpp b/src/solver/optimisation/constraints/PMinDispatchableGeneration.cpp index faa7e53d80..c2fe75b9ea 100644 --- a/src/solver/optimisation/constraints/PMinDispatchableGeneration.cpp +++ b/src/solver/optimisation/constraints/PMinDispatchableGeneration.cpp @@ -32,7 +32,7 @@ void PMinDispatchableGeneration::add(int pays, } else { - nbTermesContraintesPourLesCoutsDeDemarrage += 2; - problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; + problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage += 2; + problemeHebdo->ProblemeAResoudre->NombreDeContraintes++; } } diff --git a/src/solver/optimisation/constraints/PMinDispatchableGeneration.h b/src/solver/optimisation/constraints/PMinDispatchableGeneration.h index 0d9acf6373..58b1f36438 100644 --- a/src/solver/optimisation/constraints/PMinDispatchableGeneration.h +++ b/src/solver/optimisation/constraints/PMinDispatchableGeneration.h @@ -17,5 +17,4 @@ class PMinDispatchableGeneration : private ConstraintFactory * @param Simulation : --- */ void add(int pays, int cluster, int clusterIndex, int pdt, bool Simulation); - int nbTermesContraintesPourLesCoutsDeDemarrage = 0; }; \ No newline at end of file diff --git a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp index 4e9457c5a9..809ea0f5d5 100644 --- a/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp +++ b/src/solver/optimisation/opt_alloc_probleme_a_optimiser.cpp @@ -82,8 +82,11 @@ void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* Pr ProblemeAResoudre->Pi.assign(nbVariables, 0.); ProblemeAResoudre->Colonne.assign(nbVariables, 0); + // Names ProblemeAResoudre->NomDesVariables.resize(nbVariables); ProblemeAResoudre->NomDesContraintes.resize(nbConstraints); + // Integer variables ? (MILP) + ProblemeAResoudre->VariablesEntieres.resize(nbVariables); } static void optimisationAllocateProblem(PROBLEME_HEBDO* problemeHebdo, const int mxPaliers) diff --git a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp index 7b505b814a..29210ca02e 100644 --- a/src/solver/optimisation/opt_appel_solveur_lineaire.cpp +++ b/src/solver/optimisation/opt_appel_solveur_lineaire.cpp @@ -103,8 +103,7 @@ static SimplexResult OPT_TryToCallSimplex( const int optimizationNumber, const OptPeriodStringGenerator& optPeriodStringGenerator, bool PremierPassage, - IResultWriter& writer - ) + IResultWriter& writer) { const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; auto ProbSpx @@ -306,6 +305,7 @@ bool OPT_AppelDuSimplexe(const OptimizationOptions& options, const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; Optimization::PROBLEME_SIMPLEXE_NOMME Probleme(ProblemeAResoudre->NomDesVariables, ProblemeAResoudre->NomDesContraintes, + ProblemeAResoudre->VariablesEntieres, ProblemeAResoudre->StatutDesVariables, ProblemeAResoudre->StatutDesContraintes, problemeHebdo->NamedProblems); diff --git a/src/solver/optimisation/opt_construction_contraintes_couts_demarrage.cpp b/src/solver/optimisation/opt_construction_contraintes_couts_demarrage.cpp index 600cbe71d2..2c0c6f66b6 100644 --- a/src/solver/optimisation/opt_construction_contraintes_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_construction_contraintes_couts_demarrage.cpp @@ -51,7 +51,6 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireCoutsDeDemarrage( = problemeHebdo->NombreDePasDeTempsPourUneOptimisation; ConstraintNamer constraintNamer(ProblemeAResoudre->NomDesContraintes); - int nbTermesContraintesPourLesCoutsDeDemarrage = 0; for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) { const PALIERS_THERMIQUES& PaliersThermiquesDuPays @@ -67,12 +66,7 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireCoutsDeDemarrage( for (int pdt = 0; pdt < nombreDePasDeTempsPourUneOptimisation; pdt++) { pMaxDispatchableGeneration.add(pays, palier, index, pdt, Simulation); - nbTermesContraintesPourLesCoutsDeDemarrage - += pMaxDispatchableGeneration.nbTermesContraintesPourLesCoutsDeDemarrage; - pMinDispatchableGeneration.add(pays, palier, index, pdt, Simulation); - nbTermesContraintesPourLesCoutsDeDemarrage - += pMinDispatchableGeneration.nbTermesContraintesPourLesCoutsDeDemarrage; } } } @@ -92,9 +86,6 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireCoutsDeDemarrage( ConsistenceNumberOfDispatchableUnits consistenceNumberOfDispatchableUnits( problemeHebdo); consistenceNumberOfDispatchableUnits.add(pays, palier, index, pdt, Simulation); - nbTermesContraintesPourLesCoutsDeDemarrage - += consistenceNumberOfDispatchableUnits - .nbTermesContraintesPourLesCoutsDeDemarrage; } } } @@ -114,8 +105,6 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireCoutsDeDemarrage( for (int pdt = 0; pdt < nombreDePasDeTempsPourUneOptimisation; pdt++) { nbUnitsOutageLessThanNbUnitsStop.add(pays, palier, index, pdt, Simulation); - nbTermesContraintesPourLesCoutsDeDemarrage - += nbUnitsOutageLessThanNbUnitsStop.nbTermesContraintesPourLesCoutsDeDemarrage; } } } @@ -136,8 +125,6 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireCoutsDeDemarrage( for (int pdt = 0; pdt < nombreDePasDeTempsPourUneOptimisation; pdt++) { nbDispUnitsMinBoundSinceMinUpTime.add(pays, palier, index, pdt, Simulation); - nbTermesContraintesPourLesCoutsDeDemarrage - += nbDispUnitsMinBoundSinceMinUpTime.nbTermesContraintesPourLesCoutsDeDemarrage; } } } @@ -155,15 +142,9 @@ void OPT_ConstruireLaMatriceDesContraintesDuProblemeLineaireCoutsDeDemarrage( for (int pdt = 0; pdt < nombreDePasDeTempsPourUneOptimisation; pdt++) { minDownTime.add(pays, palier, index, pdt, Simulation); - nbTermesContraintesPourLesCoutsDeDemarrage - += minDownTime.nbTermesContraintesPourLesCoutsDeDemarrage; } } } - if (Simulation) - problemeHebdo->NbTermesContraintesPourLesCoutsDeDemarrage - = nbTermesContraintesPourLesCoutsDeDemarrage; - return; } diff --git a/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp b/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp index b7b1658fec..ebb51aa5ae 100644 --- a/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp +++ b/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp @@ -42,8 +42,9 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarra int nombreDePasDeTempsPourUneOptimisation = problemeHebdo->NombreDePasDeTempsPourUneOptimisation; - int nombreDeVariables = ProblemeAResoudre->NombreDeVariables; + int& nombreDeVariables = ProblemeAResoudre->NombreDeVariables; VariableNamer variableNamer(ProblemeAResoudre->NomDesVariables); + const bool intVariables = problemeHebdo->OptimisationAvecVariablesEntieres; for (uint32_t pays = 0; pays < problemeHebdo->NombreDePays; pays++) { variableNamer.UpdateArea(problemeHebdo->NomsDesPays[pays]); @@ -71,6 +72,8 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarra = nombreDeVariables; ProblemeAResoudre->TypeDeVariable[nombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; + + ProblemeAResoudre->VariablesEntieres[nombreDeVariables] = intVariables; variableNamer.NODU(nombreDeVariables, clusterName); nombreDeVariables++; @@ -80,6 +83,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarra ProblemeAResoudre->TypeDeVariable[nombreDeVariables] = VARIABLE_BORNEE_INFERIEUREMENT; + ProblemeAResoudre->VariablesEntieres[nombreDeVariables] = intVariables; variableNamer.NumberStartingDispatchableUnits(nombreDeVariables, clusterName); nombreDeVariables++; @@ -88,6 +92,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarra = nombreDeVariables; ProblemeAResoudre->TypeDeVariable[nombreDeVariables] = VARIABLE_BORNEE_INFERIEUREMENT; + ProblemeAResoudre->VariablesEntieres[nombreDeVariables] = intVariables; variableNamer.NumberStoppingDispatchableUnits(nombreDeVariables, clusterName); nombreDeVariables++; @@ -96,13 +101,11 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarra = nombreDeVariables; ProblemeAResoudre->TypeDeVariable[nombreDeVariables] = VARIABLE_BORNEE_DES_DEUX_COTES; + + ProblemeAResoudre->VariablesEntieres[nombreDeVariables] = intVariables; variableNamer.NumberBreakingDownDispatchableUnits(nombreDeVariables, clusterName); nombreDeVariables++; } } } - - ProblemeAResoudre->NombreDeVariables = nombreDeVariables; - - return; } diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index d68868d347..17738e7b1d 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -214,7 +214,8 @@ int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO* } if (!Pump && !TurbEntreBornes && MonitorHourlyLev) { - throw FatalError("Level explicit modeling requires flexible generation"); + const std::string areaName(problemeHebdo->NomsDesPays[pays]); + throw FatalError("Level explicit modeling requires flexible generation in area " + areaName); } } diff --git a/src/solver/optimisation/opt_nombre_min_groupes_demarres_couts_demarrage.cpp b/src/solver/optimisation/opt_nombre_min_groupes_demarres_couts_demarrage.cpp index eb050f39d6..59742b94f6 100644 --- a/src/solver/optimisation/opt_nombre_min_groupes_demarres_couts_demarrage.cpp +++ b/src/solver/optimisation/opt_nombre_min_groupes_demarres_couts_demarrage.cpp @@ -176,35 +176,44 @@ void OPT_AjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage(PROBLEME_HEBDO* pro NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo] = (int)ceil(X); } - OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage( - problemeHebdo, NombreMinDeGroupesEnMarcheDuPalierThermique, pays, index); + if (!problemeHebdo->OptimisationAvecVariablesEntieres) + { + OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage( + problemeHebdo, NombreMinDeGroupesEnMarcheDuPalierThermique, pays, index); - for (int pdtHebdo = 0; pdtHebdo < NombreDePasDeTempsProblemeHebdo; pdtHebdo++) + for (int pdtHebdo = 0; pdtHebdo < NombreDePasDeTempsProblemeHebdo; pdtHebdo++) + { + if (NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo] + < NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo]) + NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo] + = NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo]; + + if (pminDUnGroupeDuPalierThermique + * NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo] + > PuissanceDisponibleDuPalierThermique[pdtHebdo]) + PuissanceDisponibleDuPalierThermique[pdtHebdo] + = pminDUnGroupeDuPalierThermique + * NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo]; + } + } + else { - if (NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo] - < NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo]) + for (int pdtHebdo = 0; pdtHebdo < NombreDePasDeTempsProblemeHebdo; pdtHebdo++) + { NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo] = NombreMinDeGroupesEnMarcheDuPalierThermique[pdtHebdo]; - - if (pminDUnGroupeDuPalierThermique - * NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo] - > PuissanceDisponibleDuPalierThermique[pdtHebdo]) - PuissanceDisponibleDuPalierThermique[pdtHebdo] - = pminDUnGroupeDuPalierThermique - * NombreMaxDeGroupesEnMarcheDuPalierThermique[pdtHebdo]; + } } } } } - - return; } void OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage( PROBLEME_HEBDO* problemeHebdo, std::vector& NbMinOptDeGroupesEnMarche, int Pays, - int Index) + int index) { int NombreDePasDeTemps = problemeHebdo->NombreDePasDeTemps; @@ -212,12 +221,12 @@ void OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage( = problemeHebdo->PaliersThermiquesDuPays[Pays]; const std::vector& NombreMaxDeGroupesEnMarcheDuPalierThermique - = PaliersThermiquesDuPays.PuissanceDisponibleEtCout[Index] + = PaliersThermiquesDuPays.PuissanceDisponibleEtCout[index] .NombreMaxDeGroupesEnMarcheDuPalierThermique; const int DureeMinimaleDeMarcheDUnGroupeDuPalierThermique - = PaliersThermiquesDuPays.DureeMinimaleDeMarcheDUnGroupeDuPalierThermique[Index]; + = PaliersThermiquesDuPays.DureeMinimaleDeMarcheDUnGroupeDuPalierThermique[index]; const int DureeMinimaleDArretDUnGroupeDuPalierThermique - = PaliersThermiquesDuPays.DureeMinimaleDArretDUnGroupeDuPalierThermique[Index]; + = PaliersThermiquesDuPays.DureeMinimaleDArretDUnGroupeDuPalierThermique[index]; std::vector& ProductionThermique = problemeHebdo->ResultatsHoraires[Pays].ProductionThermique; @@ -233,40 +242,40 @@ void OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage( if (NbMinOptDeGroupesEnMarche[t1] - NbMinOptDeGroupesEnMarche[t1moins1] < 0) { - ProductionThermique[t1].NombreDeGroupesQuiDemarrentDuPalier[Index] = 0; - ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[Index] + ProductionThermique[t1].NombreDeGroupesQuiDemarrentDuPalier[index] = 0; + ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[index] = NbMinOptDeGroupesEnMarche[t1moins1] - NbMinOptDeGroupesEnMarche[t1]; - ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[Index] = 0; + ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[index] = 0; if (NombreMaxDeGroupesEnMarcheDuPalierThermique[t1] < NombreMaxDeGroupesEnMarcheDuPalierThermique[t1moins1]) { if (NombreMaxDeGroupesEnMarcheDuPalierThermique[t1moins1] - NombreMaxDeGroupesEnMarcheDuPalierThermique[t1] - < ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[Index]) + < ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[index]) { - ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[Index] + ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[index] = NombreMaxDeGroupesEnMarcheDuPalierThermique[t1moins1] - NombreMaxDeGroupesEnMarcheDuPalierThermique[t1]; } else { - ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[Index] - = ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[Index]; + ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[index] + = ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[index]; } } } else if (NbMinOptDeGroupesEnMarche[t1] - NbMinOptDeGroupesEnMarche[t1moins1] > 0) { - ProductionThermique[t1].NombreDeGroupesQuiDemarrentDuPalier[Index] + ProductionThermique[t1].NombreDeGroupesQuiDemarrentDuPalier[index] = NbMinOptDeGroupesEnMarche[t1] - NbMinOptDeGroupesEnMarche[t1moins1]; - ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[Index] = 0; - ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[Index] = 0; + ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[index] = 0; + ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[index] = 0; } else { - ProductionThermique[t1].NombreDeGroupesQuiDemarrentDuPalier[Index] = 0; - ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[Index] = 0; - ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[Index] = 0; + ProductionThermique[t1].NombreDeGroupesQuiDemarrentDuPalier[index] = 0; + ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[index] = 0; + ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[index] = 0; } } @@ -283,8 +292,8 @@ void OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage( if (k < 0) t1 = NombreDePasDeTemps + k; SMarche - += ProductionThermique[t1].NombreDeGroupesQuiDemarrentDuPalier[Index] - - ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[Index]; + += ProductionThermique[t1].NombreDeGroupesQuiDemarrentDuPalier[index] + - ProductionThermique[t1].NombreDeGroupesQuiTombentEnPanneDuPalier[index]; } if (NbMinOptDeGroupesEnMarche[t1] < SMarche) { @@ -315,7 +324,7 @@ void OPT_PbLineairePourAjusterLeNombreMinDeGroupesDemarresCoutsDeDemarrage( SArret += NombreMaxDeGroupesEnMarcheDuPalierThermique[t1] - NombreMaxDeGroupesEnMarcheDuPalierThermique[t1moins1]; } - SArret -= ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[Index]; + SArret -= ProductionThermique[t1].NombreDeGroupesQuiSArretentDuPalier[index]; } if (NbMinOptDeGroupesEnMarche[t1] > SArret) { diff --git a/src/solver/optimisation/opt_optimisation_lineaire.cpp b/src/solver/optimisation/opt_optimisation_lineaire.cpp index ea64560372..b124098e98 100644 --- a/src/solver/optimisation/opt_optimisation_lineaire.cpp +++ b/src/solver/optimisation/opt_optimisation_lineaire.cpp @@ -63,10 +63,10 @@ void OPT_EcrireResultatFonctionObjectiveAuFormatTXT( } bool runWeeklyOptimization(const OptimizationOptions& options, - PROBLEME_HEBDO* problemeHebdo, - const AdqPatchParams& adqPatchParams, - Solver::IResultWriter& writer, - int optimizationNumber) + PROBLEME_HEBDO* problemeHebdo, + const AdqPatchParams& adqPatchParams, + Solver::IResultWriter& writer, + int optimizationNumber) { const int NombreDePasDeTempsPourUneOptimisation = problemeHebdo->NombreDePasDeTempsPourUneOptimisation; @@ -164,7 +164,10 @@ bool OPT_OptimisationLineaire(const OptimizationOptions& options, bool ret = runWeeklyOptimization( options, problemeHebdo, adqPatchParams, writer, PREMIERE_OPTIMISATION); - if (ret && !problemeHebdo->Expansion) + // We only need the 2nd optimization when NOT solving with integer variables + // We also skip the 2nd optimization in the hidden 'Expansion' mode + // and if the 1st one failed. + if (ret && !problemeHebdo->Expansion && !problemeHebdo->OptimisationAvecVariablesEntieres) { // We need to adjust some stuff before running the 2nd optimisation runThermalHeuristic(problemeHebdo); diff --git a/src/solver/optimisation/opt_structure_probleme_a_resoudre.h b/src/solver/optimisation/opt_structure_probleme_a_resoudre.h index b46b659140..8743810af1 100644 --- a/src/solver/optimisation/opt_structure_probleme_a_resoudre.h +++ b/src/solver/optimisation/opt_structure_probleme_a_resoudre.h @@ -115,6 +115,8 @@ struct PROBLEME_ANTARES_A_RESOUDRE std::vector NomDesVariables; std::vector NomDesContraintes; + std::vector VariablesEntieres; // true = int, false = continuous + std::vector StatutDesVariables; std::vector StatutDesContraintes; diff --git a/src/solver/optimisation/post_process_commands.cpp b/src/solver/optimisation/post_process_commands.cpp index a1206fe740..9c6c3f5d9d 100644 --- a/src/solver/optimisation/post_process_commands.cpp +++ b/src/solver/optimisation/post_process_commands.cpp @@ -35,7 +35,7 @@ void DispatchableMarginPostProcessCmd::execute(const optRuntimeData& opt_runtime for (auto i = area.thermal.list.begin(); i != end; ++i) { auto& cluster = *(i->second); - const auto& availableProduction = cluster.series->getAvailablePowerYearly(year); + const auto& availableProduction = cluster.series.getColumn(year); for (uint h = 0; h != nbHoursInWeek; ++h) { double production = hourlyResults.ProductionThermique[h] diff --git a/src/solver/simulation/CMakeLists.txt b/src/solver/simulation/CMakeLists.txt index ab20e592d2..1e95d30615 100644 --- a/src/solver/simulation/CMakeLists.txt +++ b/src/solver/simulation/CMakeLists.txt @@ -62,4 +62,5 @@ target_link_libraries(antares-solver-simulation PRIVATE yuni-static-core Antares::study Antares::result_writer + Antares::concurrency ) diff --git a/src/solver/simulation/common-eco-adq.cpp b/src/solver/simulation/common-eco-adq.cpp index a3f2099ce9..4d8f4a1f11 100644 --- a/src/solver/simulation/common-eco-adq.cpp +++ b/src/solver/simulation/common-eco-adq.cpp @@ -36,7 +36,6 @@ #include #include #include "simulation.h" -#include "../aleatoire/alea_fonctions.h" using namespace Yuni; @@ -139,10 +138,10 @@ void PrepareDataFromClustersInMustrunMode(Data::Study& study, uint numSpace, uin for (auto i = area.thermal.mustrunList.begin(); i != end; ++i) { auto& cluster = *(i->second); - const auto& availableProduction = cluster.series->getAvailablePowerYearly(year); + const auto& availableProduction = cluster.series.getColumn(year); if (inAdequacy && cluster.mustrunOrigin) { - for (uint h = 0; h != cluster.series->timeSeries.height; ++h) + for (uint h = 0; h != cluster.series.timeSeries.height; ++h) { mrs[h] += availableProduction[h]; adq[h] += availableProduction[h]; @@ -150,7 +149,7 @@ void PrepareDataFromClustersInMustrunMode(Data::Study& study, uint numSpace, uin } else { - for (uint h = 0; h != cluster.series->timeSeries.height; ++h) + for (uint h = 0; h != cluster.series.timeSeries.height; ++h) mrs[h] += availableProduction[h]; } } @@ -165,8 +164,8 @@ void PrepareDataFromClustersInMustrunMode(Data::Study& study, uint numSpace, uin if (!cluster.mustrunOrigin) continue; - const auto& availableProduction = cluster.series->getAvailablePowerYearly(year); - for (uint h = 0; h != cluster.series->timeSeries.height; ++h) + const auto& availableProduction = cluster.series.getColumn(year); + for (uint h = 0; h != cluster.series.timeSeries.height; ++h) adq[h] += availableProduction[h]; } } @@ -394,7 +393,7 @@ void BuildThermalPartOfWeeklyProblem(Data::Study& study, + thermalNoises[areaIdx][cluster.areaWideIndex]; Pt.PuissanceDisponibleDuPalierThermique[hourInWeek] - = cluster.series->getAvailablePower(hourInYear, year); + = cluster.series.getCoefficient(year, hourInYear); Pt.PuissanceMinDuPalierThermique[hourInWeek] = (Pt.PuissanceDisponibleDuPalierThermique[hourInWeek] < cluster.PthetaInf[hourInYear]) diff --git a/src/solver/simulation/common-hydro-remix.cpp b/src/solver/simulation/common-hydro-remix.cpp index e2de5f9517..e843baaa0c 100644 --- a/src/solver/simulation/common-hydro-remix.cpp +++ b/src/solver/simulation/common-hydro-remix.cpp @@ -96,11 +96,7 @@ static bool Remix(const Data::AreaList& areas, PROBLEME_HEBDO& problem, uint num double bottom = std::numeric_limits::max(); double top = 0; - uint loadTS = area.load.series->getIndex(problem.year); - auto& load = area.load.series->timeSeries; - assert(load.width > 0); - - auto& L = (loadTS < load.width) ? load[loadTS] : load[0]; + auto* L = area.load.series.getColumn(problem.year); const double* M = area.scratchpad[numSpace].dispatchableGenerationMargin; @@ -109,7 +105,6 @@ static bool Remix(const Data::AreaList& areas, PROBLEME_HEBDO& problem, uint num double h_d = H[i] + D[i]; if (h_d > 0. && Math::Zero(S[i] + M[i])) { - assert(i + hourInYear < load.height); double Li = L[i + hourInYear]; remix[i] = true; diff --git a/src/solver/simulation/sim_allocation_tableaux.cpp b/src/solver/simulation/sim_allocation_tableaux.cpp index 3967b0fbd5..862d8c5898 100644 --- a/src/solver/simulation/sim_allocation_tableaux.cpp +++ b/src/solver/simulation/sim_allocation_tableaux.cpp @@ -44,12 +44,5 @@ static void AllocateResultsForEconomicMode(const Data::Study& study) void SIM_AllocationTableaux(const Data::Study& study) { - NumeroChroniquesTireesParInterconnexion.resize(study.maxNbYearsInParallel); - - const uint intercoCount = study.areas.areaLinkCount(); - for (uint numSpace = 0; numSpace < study.maxNbYearsInParallel; numSpace++) - NumeroChroniquesTireesParInterconnexion[numSpace].resize(intercoCount); - - NumeroChroniquesTireesParGroup.resize(study.maxNbYearsInParallel); AllocateResultsForEconomicMode(study); } diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 60fe4aa9cd..14133c06f1 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -120,6 +120,10 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, problem.exportMPSOnError = Data::exportMPS(parameters.include.unfeasibleProblemBehavior); problem.OptimisationAvecCoutsDeDemarrage + = (study.parameters.unitCommitment.ucMode + != Antares::Data::UnitCommitmentMode::ucHeuristicFast); + + problem.OptimisationAvecVariablesEntieres = (study.parameters.unitCommitment.ucMode == Antares::Data::UnitCommitmentMode::ucMILP); problem.OptimisationAuPasHebdomadaire @@ -314,8 +318,10 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, problem.LeProblemeADejaEteInstancie = false; } -void preparerBindingConstraint(const PROBLEME_HEBDO &problem, uint numSpace, int PasDeTempsDebut, - const BindingConstraintsRepository &bindingConstraints, const uint weekFirstDay, int pasDeTemps) +void preparerBindingConstraint(const PROBLEME_HEBDO &problem, int PasDeTempsDebut, + const BindingConstraintsRepository &bindingConstraints, + const BindingConstraintGroupRepository &bcgroups, + const uint weekFirstDay, int pasDeTemps) { auto activeContraints = bindingConstraints.activeContraints(); const auto constraintCount = activeContraints.size(); @@ -323,8 +329,15 @@ void preparerBindingConstraint(const PROBLEME_HEBDO &problem, uint numSpace, int { auto bc = activeContraints[constraintIndex]; assert(bc->RHSTimeSeries().width && "Invalid constraint data width"); + + uint tsIndexForBc = 0; + auto* group = bcgroups[bc->group()]; + if (group) + tsIndexForBc = group->timeseriesNumbers[0][problem.year]; + //If there is only one TS, always select it. - const auto ts_number = bc->RHSTimeSeries().width == 1 ? 0 : NumeroChroniquesTireesParGroup[numSpace][bc->group()]; + const auto ts_number = bc->RHSTimeSeries().width == 1 ? 0 : tsIndexForBc; + auto& timeSeries = bc->RHSTimeSeries(); double const* column = timeSeries[ts_number]; switch (bc->type()) @@ -549,8 +562,7 @@ void SIM_RenseignementProblemeHebdo(const Study& study, for (uint k = 0; k != linkCount; ++k) { auto& lnk = *(studyruntime.areaLink[k]); - const int tsIndex - = NumeroChroniquesTireesParInterconnexion[numSpace][k].TransmissionCapacities; + const int tsIndex = (lnk.directCapacities.width != 1) ? lnk.timeseriesNumbers[0][year] : 0; assert((uint)hourInYear < lnk.directCapacities.height); assert((uint)tsIndex < lnk.directCapacities.width); @@ -561,7 +573,9 @@ void SIM_RenseignementProblemeHebdo(const Study& study, ntc.ValeurDeLoopFlowOrigineVersExtremite[k] = lnk.parameters[fhlLoopFlow][hourInYear]; } } - preparerBindingConstraint(problem, numSpace, PasDeTempsDebut, study.bindingConstraints, weekFirstDay, hourInWeek); + preparerBindingConstraint(problem, PasDeTempsDebut, + study.bindingConstraints, study.bindingConstraintsGroups, + weekFirstDay, hourInWeek); const uint dayInTheYear = study.calendar.hours[hourInYear].dayYear; @@ -569,33 +583,31 @@ void SIM_RenseignementProblemeHebdo(const Study& study, { auto& area = *(study.areas.byIndex[k]); auto& scratchpad = area.scratchpad[numSpace]; - auto& ror = area.hydro.series->ror; - auto loadSeries = area.load.series->getCoefficient(year, hourInYear); - auto windSeries = area.wind.series->getCoefficient(year, hourInYear); - auto solarSeries = area.solar.series->getCoefficient(year, hourInYear); - auto hydroSeriesIndex = area.hydro.series->getIndex(year); + double loadSeries = area.load.series.getCoefficient(year, hourInYear); + double windSeries = area.wind.series.getCoefficient(year, hourInYear); + double solarSeries = area.solar.series.getCoefficient(year, hourInYear); + double rorSeries = area.hydro.series->ror.getCoefficient(year, hourInYear); assert(&scratchpad); - uint tsFatalIndex = hydroSeriesIndex < ror.width ? hydroSeriesIndex : 0; double& mustRunGen = problem.AllMustRunGeneration[hourInWeek].AllMustRunGenerationOfArea[k]; if (parameters.renewableGeneration.isAggregated()) { - mustRunGen = windSeries - + solarSeries - + scratchpad.miscGenSum[hourInYear] + ror[tsFatalIndex][hourInYear] + mustRunGen = windSeries + solarSeries + + scratchpad.miscGenSum[hourInYear] + + rorSeries + scratchpad.mustrunSum[hourInYear]; } // Renewable if (parameters.renewableGeneration.isClusters()) { - mustRunGen = scratchpad.miscGenSum[hourInYear] + ror[tsFatalIndex][hourInYear] + mustRunGen = scratchpad.miscGenSum[hourInYear] + rorSeries + scratchpad.mustrunSum[hourInYear]; area.renewable.list.each([&](const RenewableCluster& cluster) { - assert(cluster.series->timeSeries.jit == NULL && "No JIT data from the solver"); - mustRunGen += cluster.valueAtTimeStep((uint)hourInYear, year); + assert(cluster.series.timeSeries.jit == nullptr && "No JIT data from the solver"); + mustRunGen += cluster.valueAtTimeStep(year, hourInYear); }); } @@ -633,12 +645,9 @@ void SIM_RenseignementProblemeHebdo(const Study& study, { auto& area = *study.areas.byIndex[k]; auto& hydroSeries = area.hydro.series; - uint tsIndex = hydroSeries->getIndex(year); - auto& inflowsmatrix = hydroSeries->storage; - auto const& srcinflows = inflowsmatrix[tsIndex < inflowsmatrix.width ? tsIndex : 0]; - auto& mingenmatrix = hydroSeries->mingen; - auto const& srcmingen = mingenmatrix[tsIndex < mingenmatrix.width ? tsIndex : 0]; + auto const& srcinflows = hydroSeries->storage.getColumn(year); + auto const& srcmingen = hydroSeries->mingen.getColumn(year); for (uint j = 0; j < problem.NombreDePasDeTemps; ++j) { problem.CaracteristiquesHydrauliques[k].MingenHoraire[j] diff --git a/src/solver/simulation/sim_extern_variables_globales.h b/src/solver/simulation/sim_extern_variables_globales.h index 421e8db76e..0c79e71b1a 100644 --- a/src/solver/simulation/sim_extern_variables_globales.h +++ b/src/solver/simulation/sim_extern_variables_globales.h @@ -31,8 +31,6 @@ #include "sim_structure_probleme_economique.h" /* Valeurs generees de maniere aleatoire */ -extern std::vector> NumeroChroniquesTireesParInterconnexion; -extern std::vector> NumeroChroniquesTireesParGroup; /* Resultats */ /*-Economique-*/ diff --git a/src/solver/simulation/sim_structure_donnees.h b/src/solver/simulation/sim_structure_donnees.h index 6b3431a735..35486dd592 100644 --- a/src/solver/simulation/sim_structure_donnees.h +++ b/src/solver/simulation/sim_structure_donnees.h @@ -27,23 +27,11 @@ #ifndef __SOLVER_SIMULATION_DATA_STRUCTS_H__ #define __SOLVER_SIMULATION_DATA_STRUCTS_H__ -#include - -typedef struct -{ - int TransmissionCapacities; -} NUMERO_CHRONIQUES_TIREES_PAR_INTERCONNEXION; - typedef struct { double* Horaire; } PRODUCTION_THERMIQUE; -typedef struct -{ - double* ParLigne; -} MATRICE_2D; - /* Old define */ #define DEFINITION_STRUCTURES_DONNEES diff --git a/src/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/sim_structure_probleme_economique.h index 5a94273a9b..e935899904 100644 --- a/src/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/sim_structure_probleme_economique.h @@ -487,6 +487,7 @@ struct PROBLEME_HEBDO char TypeDeLissageHydraulique = PAS_DE_LISSAGE_HYDRAULIQUE; bool WaterValueAccurate = false; bool OptimisationAvecCoutsDeDemarrage = false; + bool OptimisationAvecVariablesEntieres = false; uint32_t NombreDePays = 0; std::vector NomsDesPays; uint32_t NombreDePaliersThermiques = 0; diff --git a/src/solver/simulation/sim_variables_globales.cpp b/src/solver/simulation/sim_variables_globales.cpp index e5fe936dc6..7c20c0ad7f 100644 --- a/src/solver/simulation/sim_variables_globales.cpp +++ b/src/solver/simulation/sim_variables_globales.cpp @@ -28,8 +28,4 @@ #include "sim_structure_donnees.h" #include "sim_structure_probleme_economique.h" -std::vector> NumeroChroniquesTireesParInterconnexion; - std::vector> transitMoyenInterconnexionsRecalculQuadratique; - -std::vector> NumeroChroniquesTireesParGroup; //Vector size = num_parallel_year diff --git a/src/solver/simulation/solver.hxx b/src/solver/simulation/solver.hxx index a46781556f..8a33ad50b5 100644 --- a/src/solver/simulation/solver.hxx +++ b/src/solver/simulation/solver.hxx @@ -34,7 +34,6 @@ #include #include "../variable/print.h" #include -#include "../aleatoire/alea_fonctions.h" #include "timeseries-numbers.h" #include "apply-scenario.h" #include @@ -45,11 +44,13 @@ #include #include +#include "antares/concurrency/concurrency.h" + namespace Antares::Solver::Simulation { template -class yearJob final : public Yuni::Job::IJob +class yearJob { public: yearJob(ISimulation* simulation, @@ -133,7 +134,8 @@ private: } } - virtual void onExecute() override +public: + void operator()() { Progression::Task progression(study, y, Solver::Progression::sectYear); @@ -153,8 +155,7 @@ private: randomReservoirLevel = randomForCurrentYear.pReservoirLevels; // 2 - Preparing the Time-series numbers - // We want to draw lots of numbers for time-series - ApplyRandomTSnumbers(study, y, numSpace); + // removed // 3 - Preparing data related to Clusters in 'must-run' mode simulation_->prepareClustersInMustRunMode(numSpace, y); @@ -941,13 +942,7 @@ void ISimulation::loopThroughYears(uint firstYear, allocateMemoryForRandomNumbers(randomForParallelYears); // Number of threads to perform the jobs waiting in the queue - { - int numThreads = pNbMaxPerformedYearsInParallel; - // If the result writer uses the job queue, add one more thread for it - if (pResultWriter.needsTheJobQueue()) - numThreads++; - pQueueService->maximumThreadCount(numThreads); - } + pQueueService->maximumThreadCount(pNbMaxPerformedYearsInParallel); // Loop over sets of parallel years std::vector::iterator set_it; @@ -964,6 +959,7 @@ void ISimulation::loopThroughYears(uint firstYear, std::vector::iterator year_it; bool yearPerformed = false; + Concurrency::FutureSet results; for (year_it = set_it->yearsIndices.begin(); year_it != set_it->yearsIndices.end(); ++year_it) { @@ -983,21 +979,20 @@ void ISimulation::loopThroughYears(uint firstYear, // have to be rerun (meaning : they must be run once). if(!set_it->yearFailed[y]) // continue; - pQueueService->add( - new yearJob(this, - y, - set_it->yearFailed, - set_it->isFirstPerformedYearOfASet, - pFirstSetParallelWithAPerformedYearWasRun, - numSpace, - randomForParallelYears, - performCalculations, - study, - state, - pYearByYear, - pDurationCollector, - pResultWriter)); - + Concurrency::Task task = yearJob(this, + y, + set_it->yearFailed, + set_it->isFirstPerformedYearOfASet, + pFirstSetParallelWithAPerformedYearWasRun, + numSpace, + randomForParallelYears, + performCalculations, + study, + state, + pYearByYear, + pDurationCollector, + pResultWriter); + results.add(Concurrency::AddTask(*pQueueService, task)); } // End loop over years of the current set of parallel years logPerformedYearsInAset(*set_it); @@ -1006,6 +1001,8 @@ void ISimulation::loopThroughYears(uint firstYear, pQueueService->wait(Yuni::qseIdle); pQueueService->stop(); + results.join(); + pResultWriter.flush(); // At this point, the first set of parallel year(s) was run with at least one year performed if (!pFirstSetParallelWithAPerformedYearWasRun && yearPerformed) diff --git a/src/solver/simulation/timeseries-numbers.cpp b/src/solver/simulation/timeseries-numbers.cpp index ba8b00e5b5..a85da87f83 100644 --- a/src/solver/simulation/timeseries-numbers.cpp +++ b/src/solver/simulation/timeseries-numbers.cpp @@ -89,21 +89,21 @@ static bool GenerateDeratedMode(Study& study) logs.warning() << "The derated mode is enabled. The custom building mode will be ignored"; study.areas.each([&](Area& area) { - area.load.series->timeseriesNumbers.zero(); - area.solar.series->timeseriesNumbers.zero(); - area.wind.series->timeseriesNumbers.zero(); + area.load.series.timeseriesNumbers.zero(); + area.solar.series.timeseriesNumbers.zero(); + area.wind.series.timeseriesNumbers.zero(); area.hydro.series->timeseriesNumbers.zero(); for (uint i = 0; i != area.thermal.clusterCount(); ++i) { auto& cluster = *(area.thermal.clusters[i]); - cluster.series->timeseriesNumbers.zero(); + cluster.series.timeseriesNumbers.zero(); } for (uint i = 0; i != area.renewable.clusterCount(); ++i) { auto& cluster = *(area.renewable.clusters[i]); - cluster.series->timeseriesNumbers.zero(); + cluster.series.timeseriesNumbers.zero(); } }); @@ -131,7 +131,7 @@ class loadAreaNumberOfTSretriever : public areaNumberOfTSretriever } std::vector getAreaTimeSeriesNumber(const Area& area) { - std::vector to_return = {area.load.series->timeSeries.width}; + std::vector to_return = {area.load.series.timeSeries.width}; return to_return; } uint getGeneratedTimeSeriesNumber() @@ -148,7 +148,7 @@ class hydroAreaNumberOfTSretriever : public areaNumberOfTSretriever } std::vector getAreaTimeSeriesNumber(const Area& area) { - std::vector to_return = {area.hydro.series->count}; + std::vector to_return = {area.hydro.series->TScount()}; return to_return; } uint getGeneratedTimeSeriesNumber() @@ -165,7 +165,7 @@ class windAreaNumberOfTSretriever : public areaNumberOfTSretriever } std::vector getAreaTimeSeriesNumber(const Area& area) { - std::vector to_return = {area.wind.series->timeSeries.width}; + std::vector to_return = {area.wind.series.timeSeries.width}; return to_return; } uint getGeneratedTimeSeriesNumber() @@ -182,7 +182,7 @@ class solarAreaNumberOfTSretriever : public areaNumberOfTSretriever } std::vector getAreaTimeSeriesNumber(const Area& area) { - std::vector to_return = {area.solar.series->timeSeries.width}; + std::vector to_return = {area.solar.series.timeSeries.width}; return to_return; } uint getGeneratedTimeSeriesNumber() @@ -204,7 +204,7 @@ class thermalAreaNumberOfTSretriever : public areaNumberOfTSretriever for (uint i = 0; i != clusterCount; ++i) { auto& cluster = *(area.thermal.clusters[i]); - to_return.push_back(cluster.series->timeSeries.width); + to_return.push_back(cluster.series.timeSeries.width); } return to_return; } @@ -227,7 +227,7 @@ class renewClustersAreaNumberOfTSretriever : public areaNumberOfTSretriever for (uint i = 0; i != clusterCount; ++i) { auto& cluster = *(area.renewable.clusters[i]); - to_return.push_back(cluster.series->timeSeries.width); + to_return.push_back(cluster.series.timeSeries.width); } return to_return; } @@ -393,7 +393,7 @@ bool checkInterModalConsistencyForArea(Area& area, if (isTSintermodal[indexTS]) { uint nbTimeSeries - = isTSgenerated[indexTS] ? parameters.nbTimeSeriesLoad : area.load.series->timeSeries.width; + = isTSgenerated[indexTS] ? parameters.nbTimeSeriesLoad : area.load.series.timeSeries.width; listNumberTsOverArea.push_back(nbTimeSeries); } @@ -402,7 +402,7 @@ bool checkInterModalConsistencyForArea(Area& area, if (isTSintermodal[indexTS]) { uint nbTimeSeries - = isTSgenerated[indexTS] ? parameters.nbTimeSeriesSolar : area.solar.series->timeSeries.width; + = isTSgenerated[indexTS] ? parameters.nbTimeSeriesSolar : area.solar.series.timeSeries.width; listNumberTsOverArea.push_back(nbTimeSeries); } @@ -411,7 +411,7 @@ bool checkInterModalConsistencyForArea(Area& area, if (isTSintermodal[indexTS]) { uint nbTimeSeries - = isTSgenerated[indexTS] ? parameters.nbTimeSeriesWind : area.wind.series->timeSeries.width; + = isTSgenerated[indexTS] ? parameters.nbTimeSeriesWind : area.wind.series.timeSeries.width; listNumberTsOverArea.push_back(nbTimeSeries); } @@ -420,7 +420,7 @@ bool checkInterModalConsistencyForArea(Area& area, if (isTSintermodal[indexTS]) { uint nbTimeSeries - = isTSgenerated[indexTS] ? parameters.nbTimeSeriesHydro : area.hydro.series->count; + = isTSgenerated[indexTS] ? parameters.nbTimeSeriesHydro : area.hydro.series->TScount(); listNumberTsOverArea.push_back(nbTimeSeries); } @@ -433,7 +433,7 @@ bool checkInterModalConsistencyForArea(Area& area, { auto& cluster = *(area.thermal.clusters[j]); uint nbTimeSeries = isTSgenerated[indexTS] ? parameters.nbTimeSeriesThermal - : cluster.series->timeSeries.width; + : cluster.series.timeSeries.width; listNumberTsOverArea.push_back(nbTimeSeries); } } @@ -446,7 +446,7 @@ bool checkInterModalConsistencyForArea(Area& area, for (uint j = 0; j != clusterCount; ++j) { auto& cluster = *(area.renewable.clusters[j]); - uint nbTimeSeries = cluster.series->timeSeries.width; + uint nbTimeSeries = cluster.series.timeSeries.width; listNumberTsOverArea.push_back(nbTimeSeries); } } @@ -500,29 +500,29 @@ void storeTSnumbersForIntraModal(const array& intramo // ------------- // Load ... // ------------- - assert(year < area.load.series->timeseriesNumbers.height); + assert(year < area.load.series.timeseriesNumbers.height); int indexTS = ts_to_tsIndex.at(timeSeriesLoad); if (isTSintramodal[indexTS]) - area.load.series->timeseriesNumbers[0][year] = intramodal_draws[indexTS]; + area.load.series.timeseriesNumbers[0][year] = intramodal_draws[indexTS]; // ------------- // Solar ... // ------------- - assert(year < area.solar.series->timeseriesNumbers.height); + assert(year < area.solar.series.timeseriesNumbers.height); indexTS = ts_to_tsIndex.at(timeSeriesSolar); if (isTSintramodal[indexTS]) - area.solar.series->timeseriesNumbers[0][year] = intramodal_draws[indexTS]; + area.solar.series.timeseriesNumbers[0][year] = intramodal_draws[indexTS]; // ------------- // Wind ... // ------------- - assert(year < area.wind.series->timeseriesNumbers.height); + assert(year < area.wind.series.timeseriesNumbers.height); indexTS = ts_to_tsIndex.at(timeSeriesWind); if (isTSintramodal[indexTS]) - area.wind.series->timeseriesNumbers[0][year] = intramodal_draws[indexTS]; + area.wind.series.timeseriesNumbers[0][year] = intramodal_draws[indexTS]; // ------------- // Hydro ... @@ -545,7 +545,7 @@ void storeTSnumbersForIntraModal(const array& intramo { ThermalClusterList::SharedPtr cluster = i->second; if (cluster->enabled) - cluster->series->timeseriesNumbers[0][year] = intramodal_draws[indexTS]; + cluster->series.timeseriesNumbers[0][year] = intramodal_draws[indexTS]; } } @@ -561,7 +561,7 @@ void storeTSnumbersForIntraModal(const array& intramo { RenewableClusterList::SharedPtr cluster = j->second; if (cluster->enabled) - cluster->series->timeseriesNumbers[0][year] = intramodal_draws[indexTS]; + cluster->series.timeseriesNumbers[0][year] = intramodal_draws[indexTS]; } } @@ -596,8 +596,8 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (!isTSintramodal[indexTS]) { uint nbTimeSeries = isTSgenerated[indexTS] ? nbTimeseriesByMode[indexTS] - : area.load.series->timeSeries.width; - area.load.series->timeseriesNumbers[0][year] + : area.load.series.timeSeries.width; + area.load.series.timeseriesNumbers[0][year] = (uint32_t)(floor(study.runtime->random[seedTimeseriesNumbers].next() * nbTimeSeries)); } @@ -609,8 +609,8 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (!isTSintramodal[indexTS]) { uint nbTimeSeries = isTSgenerated[indexTS] ? nbTimeseriesByMode[indexTS] - : area.solar.series->timeSeries.width; - area.solar.series->timeseriesNumbers[0][year] + : area.solar.series.timeSeries.width; + area.solar.series.timeseriesNumbers[0][year] = (uint32_t)(floor(study.runtime->random[seedTimeseriesNumbers].next() * nbTimeSeries)); } @@ -622,8 +622,8 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (!isTSintramodal[indexTS]) { uint nbTimeSeries = isTSgenerated[indexTS] ? nbTimeseriesByMode[indexTS] - : area.wind.series->timeSeries.width; - area.wind.series->timeseriesNumbers[0][year] + : area.wind.series.timeSeries.width; + area.wind.series.timeseriesNumbers[0][year] = (uint32_t)(floor(study.runtime->random[seedTimeseriesNumbers].next() * nbTimeSeries)); } @@ -635,7 +635,7 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (!isTSintramodal[indexTS]) { uint nbTimeSeries - = isTSgenerated[indexTS] ? nbTimeseriesByMode[indexTS] : area.hydro.series->ror.width; + = isTSgenerated[indexTS] ? nbTimeseriesByMode[indexTS] : area.hydro.series->ror.timeSeries.width; area.hydro.series->timeseriesNumbers[0][year] = (uint32_t)(floor(study.runtime->random[seedTimeseriesNumbers].next() * nbTimeSeries)); } @@ -656,8 +656,8 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (!isTSintramodal[indexTS]) { uint nbTimeSeries = isTSgenerated[indexTS] ? nbTimeseriesByMode[indexTS] - : cluster->series->timeSeries.width; - cluster->series->timeseriesNumbers[0][year] = (uint32_t)( + : cluster->series.timeSeries.width; + cluster->series.timeseriesNumbers[0][year] = (uint32_t)( floor(study.runtime->random[seedTimeseriesNumbers].next() * nbTimeSeries)); } } @@ -679,8 +679,8 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (!isTSintramodal[indexTS]) { // There is no TS generation for renewable clusters - uint nbTimeSeries = cluster->series->timeSeries.width; - cluster->series->timeseriesNumbers[0][year] = (uint32_t)( + uint nbTimeSeries = cluster->series.timeSeries.width; + cluster->series.timeseriesNumbers[0][year] = (uint32_t)( floor(study.runtime->random[seedTimeseriesNumbers].next() * nbTimeSeries)); } } @@ -734,21 +734,21 @@ Matrix* getFirstTSnumberInterModalMatrixFoundInArea( { Matrix* tsNumbersMtx = nullptr; if (isTSintermodal[ts_to_tsIndex.at(timeSeriesLoad)]) - tsNumbersMtx = &(area.load.series->timeseriesNumbers); + tsNumbersMtx = &(area.load.series.timeseriesNumbers); else { if (isTSintermodal[ts_to_tsIndex.at(timeSeriesSolar)]) - tsNumbersMtx = &(area.solar.series->timeseriesNumbers); + tsNumbersMtx = &(area.solar.series.timeseriesNumbers); else if (isTSintermodal[ts_to_tsIndex.at(timeSeriesWind)]) - tsNumbersMtx = &(area.wind.series->timeseriesNumbers); + tsNumbersMtx = &(area.wind.series.timeseriesNumbers); else if (isTSintermodal[ts_to_tsIndex.at(timeSeriesHydro)]) tsNumbersMtx = &(area.hydro.series->timeseriesNumbers); else if (isTSintermodal[ts_to_tsIndex.at(timeSeriesThermal)] && area.thermal.clusterCount() > 0) - tsNumbersMtx = &(area.thermal.clusters[0]->series->timeseriesNumbers); + tsNumbersMtx = &(area.thermal.clusters[0]->series.timeseriesNumbers); else if (isTSintermodal[ts_to_tsIndex.at(timeSeriesRenewable)] && area.renewable.clusterCount() > 0) - tsNumbersMtx = &(area.renewable.clusters[0]->series->timeseriesNumbers); + tsNumbersMtx = &(area.renewable.clusters[0]->series.timeseriesNumbers); } assert(tsNumbersMtx); @@ -765,17 +765,17 @@ void applyMatrixDrawsToInterModalModesInArea(Matrix* tsNumbersMtx, const uint draw = tsNumbersMtx->entry[0][year]; assert(draw < 100000); - assert(year < area.load.series->timeseriesNumbers.height); + assert(year < area.load.series.timeseriesNumbers.height); if (isTSintermodal[ts_to_tsIndex.at(timeSeriesLoad)]) - area.load.series->timeseriesNumbers[0][year] = draw; + area.load.series.timeseriesNumbers[0][year] = draw; - assert(year < area.solar.series->timeseriesNumbers.height); + assert(year < area.solar.series.timeseriesNumbers.height); if (isTSintermodal[ts_to_tsIndex.at(timeSeriesSolar)]) - area.solar.series->timeseriesNumbers[0][year] = draw; + area.solar.series.timeseriesNumbers[0][year] = draw; - assert(year < area.wind.series->timeseriesNumbers.height); + assert(year < area.wind.series.timeseriesNumbers.height); if (isTSintermodal[ts_to_tsIndex.at(timeSeriesWind)]) - area.wind.series->timeseriesNumbers[0][year] = draw; + area.wind.series.timeseriesNumbers[0][year] = draw; assert(year < area.hydro.series->timeseriesNumbers.height); if (isTSintermodal[ts_to_tsIndex.at(timeSeriesHydro)]) @@ -787,8 +787,8 @@ void applyMatrixDrawsToInterModalModesInArea(Matrix* tsNumbersMtx, for (uint i = 0; i != clusterCount; ++i) { auto& cluster = *(area.thermal.clusters[i]); - assert(year < cluster.series->timeseriesNumbers.height); - cluster.series->timeseriesNumbers[0][year] = draw; + assert(year < cluster.series.timeseriesNumbers.height); + cluster.series.timeseriesNumbers[0][year] = draw; } } if (isTSintermodal[ts_to_tsIndex.at(timeSeriesRenewable)]) @@ -797,8 +797,8 @@ void applyMatrixDrawsToInterModalModesInArea(Matrix* tsNumbersMtx, for (uint i = 0; i != clusterCount; ++i) { auto& cluster = *(area.renewable.clusters[i]); - assert(year < cluster.series->timeseriesNumbers.height); - cluster.series->timeseriesNumbers[0][year] = draw; + assert(year < cluster.series.timeseriesNumbers.height); + cluster.series.timeseriesNumbers[0][year] = draw; } } } @@ -823,34 +823,34 @@ static void fixTSNumbersWhenWidthIsOne(Study& study) study.areas.each([&years](Area& area) { // Load fixTSNumbersSingleAreaSingleMode( - area.load.series->timeseriesNumbers, area.load.series->timeSeries.width, years); + area.load.series.timeseriesNumbers, area.load.series.timeSeries.width, years); // Solar fixTSNumbersSingleAreaSingleMode( - area.solar.series->timeseriesNumbers, area.solar.series->timeSeries.width, years); + area.solar.series.timeseriesNumbers, area.solar.series.timeSeries.width, years); // Wind fixTSNumbersSingleAreaSingleMode( - area.wind.series->timeseriesNumbers, area.wind.series->timeSeries.width, years); + area.wind.series.timeseriesNumbers, area.wind.series.timeSeries.width, years); // Hydro fixTSNumbersSingleAreaSingleMode( - area.hydro.series->timeseriesNumbers, area.hydro.series->count, years); + area.hydro.series->timeseriesNumbers, area.hydro.series->TScount(), years); // Thermal std::for_each(area.thermal.clusters.cbegin(), area.thermal.clusters.cend(), - [&years](const Data::ThermalCluster* cluster) { - fixTSNumbersSingleAreaSingleMode(cluster->series->timeseriesNumbers, - cluster->series->timeSeries.width, + [&years](Data::ThermalCluster* cluster) { + fixTSNumbersSingleAreaSingleMode(cluster->series.timeseriesNumbers, + cluster->series.timeSeries.width, years); }); // Renewables std::for_each(area.renewable.clusters.cbegin(), area.renewable.clusters.cend(), - [&years](const Data::RenewableCluster* cluster) + [&years](Data::RenewableCluster* cluster) { - fixTSNumbersSingleAreaSingleMode(cluster->series->timeseriesNumbers, - cluster->series->timeSeries.width, + fixTSNumbersSingleAreaSingleMode(cluster->series.timeseriesNumbers, + cluster->series.timeSeries.width, years); }); diff --git a/src/solver/ts-generator/generator.hxx b/src/solver/ts-generator/generator.hxx index acf699e4b7..a143ff0d29 100644 --- a/src/solver/ts-generator/generator.hxx +++ b/src/solver/ts-generator/generator.hxx @@ -27,7 +27,6 @@ #ifndef __ANTARES_SOLVER_timeSeries_GENERATOR_HXX__ #define __ANTARES_SOLVER_timeSeries_GENERATOR_HXX__ -#include "../aleatoire/alea_fonctions.h" #include namespace Antares diff --git a/src/solver/ts-generator/hydro.cpp b/src/solver/ts-generator/hydro.cpp index c554de8852..db025fe650 100644 --- a/src/solver/ts-generator/hydro.cpp +++ b/src/solver/ts-generator/hydro.cpp @@ -27,7 +27,6 @@ #include #include "../simulation/sim_extern_variables_globales.h" -#include "../aleatoire/alea_fonctions.h" #include #include #include @@ -50,11 +49,7 @@ namespace TSGenerator static void PreproHydroInitMatrices(Data::Study& study, uint tsCount) { study.areas.each([&](Data::Area& area) { - auto& hydroseries = *(area.hydro.series); - - hydroseries.ror.resize(tsCount, HOURS_PER_YEAR); - hydroseries.storage.resize(tsCount, DAYS_PER_YEAR); - hydroseries.count = tsCount; + area.hydro.series->resizeRORandSTORAGE(tsCount); }); } @@ -184,7 +179,7 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, IResultWriter auto& area = *(study.areas.byIndex[i / 12]); auto& prepro = *area.hydro.prepro; auto& series = *area.hydro.series; - auto& ror = series.ror[l]; + auto ror = series.ror[l]; auto& colExpectation = prepro.data[Data::PreproHydro::expectation]; auto& colStdDeviation = prepro.data[Data::PreproHydro::stdDeviation]; @@ -196,7 +191,7 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, IResultWriter uint realmonth = calendar.months[month].realmonth; uint daysPerMonth = calendar.months[month].days; - assert(l < series.ror.width); + assert(l < series.ror.timeSeries.width); assert(not Math::NaN(colPOW[realmonth])); if (month == 0) @@ -300,14 +295,14 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, IResultWriter { std::string buffer; - area.hydro.series->ror.saveToBuffer(buffer, precision); + area.hydro.series->ror.timeSeries.saveToBuffer(buffer, precision); output.clear() << study.buffer << SEP << "ror.txt"; writer.addEntryFromBuffer(output.c_str(), buffer); } { std::string buffer; - area.hydro.series->storage.saveToBuffer(buffer, precision); + area.hydro.series->storage.timeSeries.saveToBuffer(buffer, precision); output.clear() << study.buffer << SEP << "storage.txt"; writer.addEntryFromBuffer(output.c_str(), buffer); } diff --git a/src/solver/ts-generator/thermal.cpp b/src/solver/ts-generator/thermal.cpp index 9196cfe489..e11d4a056c 100644 --- a/src/solver/ts-generator/thermal.cpp +++ b/src/solver/ts-generator/thermal.cpp @@ -39,7 +39,6 @@ #include "../simulation/sim_structure_donnees.h" #include "../simulation/sim_structure_probleme_economique.h" #include "../simulation/sim_extern_variables_globales.h" -#include "../aleatoire/alea_fonctions.h" using namespace Yuni; @@ -146,14 +145,13 @@ void GeneratorTempData::writeResultsToDisk(const Data::Area& area, pTempFilename.clear() << "ts-generator" << SEP << "thermal" << SEP << "mc-" << currentYear << SEP << area.id << SEP << cluster.id() << ".txt"; - assert(cluster.series); enum { precision = 0 }; std::string buffer; - cluster.series->timeSeries.saveToBuffer(buffer, precision); + cluster.series.timeSeries.saveToBuffer(buffer, precision); pWriter.addEntryFromBuffer(pTempFilename.c_str(), buffer); } @@ -249,19 +247,18 @@ void GeneratorTempData::operator()(Data::Area& area, Data::ThermalCluster& clust return; } - assert(cluster.series); assert(cluster.prepro); if (0 == cluster.unitCount or 0 == cluster.nominalCapacity) { - cluster.series->timeSeries.reset(1, nbHoursPerYear); + cluster.series.timeSeries.reset(1, nbHoursPerYear); if (archive) writeResultsToDisk(area, cluster); return; } - cluster.series->timeSeries.resize(nbThermalTimeseries, nbHoursPerYear); + cluster.series.timeSeries.resize(nbThermalTimeseries, nbHoursPerYear); const auto& preproData = *(cluster.prepro); @@ -356,7 +353,7 @@ void GeneratorTempData::operator()(Data::Area& area, Data::ThermalCluster& clust auto& modulation = cluster.modulation[Data::thermalModulationCapacity]; - Antares::Data::DataSeriesCommon::SingleYear dstSeries = nullptr; + double* dstSeries = nullptr; const uint tsCount = nbThermalTimeseries + 2; for (uint tsIndex = 0; tsIndex != tsCount; ++tsIndex) @@ -364,7 +361,7 @@ void GeneratorTempData::operator()(Data::Area& area, Data::ThermalCluster& clust uint hour = 0; if (tsIndex > 1) - dstSeries = cluster.series->timeSeries[tsIndex - 2]; + dstSeries = cluster.series.timeSeries[tsIndex - 2]; for (uint dayInTheYear = 0; dayInTheYear < daysPerYear; ++dayInTheYear) { @@ -604,7 +601,7 @@ void GeneratorTempData::operator()(Data::Area& area, Data::ThermalCluster& clust } if (derated) - cluster.series->timeSeries.averageTimeseries(); + cluster.series.timeSeries.averageTimeseries(); if (archive) writeResultsToDisk(area, cluster); diff --git a/src/solver/ts-generator/xcast/predicate.hxx b/src/solver/ts-generator/xcast/predicate.hxx index 6a78b7da1d..fe8ee799f8 100644 --- a/src/solver/ts-generator/xcast/predicate.hxx +++ b/src/solver/ts-generator/xcast/predicate.hxx @@ -27,6 +27,7 @@ #ifndef __SOLVER_TS_GENERATOR_XCAST_PREDICATE_HXX__ #define __SOLVER_TS_GENERATOR_XCAST_PREDICATE_HXX__ +#include #include #include #include @@ -59,10 +60,9 @@ public: return !Yuni::Math::Zero(area.wind.prepro->xcast.capacity); } - Matrix& matrix(Data::Area& area) const + Data::TimeSeries::TS& matrix(Data::Area& area) const { - assert(area.wind.series != NULL); - return area.wind.series->timeSeries; + return area.wind.series.timeSeries; } Data::XCast& xcastData(Data::Area& area) const @@ -102,10 +102,9 @@ public: return !Yuni::Math::Zero(area.load.prepro->xcast.capacity); } - Matrix& matrix(Data::Area& area) const + Data::TimeSeries::TS& matrix(Data::Area& area) const { - assert(area.load.series != NULL); - return area.load.series->timeSeries; + return area.load.series.timeSeries; } Data::XCast& xcastData(Data::Area& area) const @@ -145,10 +144,9 @@ public: return !Yuni::Math::Zero(area.solar.prepro->xcast.capacity); } - Matrix& matrix(Data::Area& area) const + Data::TimeSeries::TS& matrix(Data::Area& area) const { - assert(area.solar.series != NULL); - return area.solar.series->timeSeries; + return area.solar.series.timeSeries; } Data::XCast& xcastData(Data::Area& area) const diff --git a/src/solver/ts-generator/xcast/xcast.cpp b/src/solver/ts-generator/xcast/xcast.cpp index 2cffb5235e..9a5c1f0659 100644 --- a/src/solver/ts-generator/xcast/xcast.cpp +++ b/src/solver/ts-generator/xcast/xcast.cpp @@ -610,10 +610,9 @@ bool XCast::runWithPredicate(PredicateT& predicate, Progression::Task& progressi { auto& area = *(study.areas.byIndex[s]); - assert(area.load.series); assert(static_cast(Data::fhrDSM) < area.reserves.width); - auto& matrix = area.load.series->timeSeries; + auto& matrix = area.load.series.timeSeries; auto& dsmvalues = area.reserves.column(Data::fhrDSM); assert(matrix.width > 0); diff --git a/src/solver/utils/mps_utils.cpp b/src/solver/utils/mps_utils.cpp index 3a40854431..fe702b2f65 100644 --- a/src/solver/utils/mps_utils.cpp +++ b/src/solver/utils/mps_utils.cpp @@ -64,8 +64,9 @@ class ProblemConverter dest->NbVar = src->NombreDeVariables; mVariableType.resize(src->NombreDeVariables); - // TODO[FOM] use actual variable types when MIP resolution is integrated - std::fill(mVariableType.begin(), mVariableType.end(), SRS_CONTINUOUS_VAR); + for (int var = 0; var < src->NombreDeVariables; var++) + mVariableType[var] = src->VariablesEntieres[var] ? SRS_INTEGER_VAR : SRS_CONTINUOUS_VAR; + dest->TypeDeVariable = mVariableType.data(); dest->TypeDeBorneDeLaVariable = src->TypeDeVariable; // VARIABLE_BORNEE_DES_DEUX_COTES, // VARIABLE_BORNEE_INFERIEUREMENT, etc. diff --git a/src/solver/utils/named_problem.cpp b/src/solver/utils/named_problem.cpp index 984e678bc6..7553a729cc 100644 --- a/src/solver/utils/named_problem.cpp +++ b/src/solver/utils/named_problem.cpp @@ -1,6 +1,5 @@ #include "named_problem.h" #include -#include namespace Antares { @@ -9,12 +8,14 @@ namespace Optimization PROBLEME_SIMPLEXE_NOMME::PROBLEME_SIMPLEXE_NOMME(const std::vector& NomDesVariables, const std::vector& NomDesContraintes, + const std::vector& VariablesEntieres, std::vector& StatutDesVariables, std::vector& StatutDesContraintes, bool UseNamedProblems) : NomDesVariables(NomDesVariables), NomDesContraintes(NomDesContraintes), + VariablesEntieres(VariablesEntieres), StatutDesVariables(StatutDesVariables), StatutDesContraintes(StatutDesContraintes), useNamedProblems_(UseNamedProblems) @@ -23,9 +24,8 @@ PROBLEME_SIMPLEXE_NOMME::PROBLEME_SIMPLEXE_NOMME(const std::vector& bool PROBLEME_SIMPLEXE_NOMME::isMIP() const { - // TODO replace implementation when MIP is introduced - // For now, no problem is MIP. - return false; + return std::any_of( + VariablesEntieres.cbegin(), VariablesEntieres.cend(), [](bool x) { return x; }); } bool PROBLEME_SIMPLEXE_NOMME::basisExists() const diff --git a/src/solver/utils/named_problem.h b/src/solver/utils/named_problem.h index 7e749e29ee..f8d68a1f10 100644 --- a/src/solver/utils/named_problem.h +++ b/src/solver/utils/named_problem.h @@ -17,6 +17,7 @@ struct PROBLEME_SIMPLEXE_NOMME : public PROBLEME_SIMPLEXE public: PROBLEME_SIMPLEXE_NOMME(const std::vector& NomDesVariables, const std::vector& NomDesContraintes, + const std::vector& VariablesEntieres, std::vector& StatutDesVariables, std::vector& StatutDesContraintes, bool UseNamedProblems); @@ -29,6 +30,7 @@ struct PROBLEME_SIMPLEXE_NOMME : public PROBLEME_SIMPLEXE public: std::vector& StatutDesVariables; std::vector& StatutDesContraintes; + const std::vector& VariablesEntieres; bool isMIP() const; bool basisExists() const; diff --git a/src/solver/utils/ortools_utils.cpp b/src/solver/utils/ortools_utils.cpp index 068087589f..6d3911f76c 100644 --- a/src/solver/utils/ortools_utils.cpp +++ b/src/solver/utils/ortools_utils.cpp @@ -49,7 +49,7 @@ MPSolver* ProblemSimplexeNommeConverter::Convert() TuneSolverSpecificOptions(solver); // Create the variables and set objective cost. - CopyVariables(solver); + CopyObjective(solver); // Create constraints and set coefs CopyRows(solver); @@ -100,7 +100,7 @@ void ProblemSimplexeNommeConverter::UpdateCoefficient(unsigned idxVar, MPObjective* const objective) { double min_l = 0.0; - if (problemeSimplexe_->Xmin != NULL) + if (problemeSimplexe_->Xmin != NULL) // TODO[FOM] Remove enclosing if ? { min_l = problemeSimplexe_->Xmin[idxVar]; } @@ -109,11 +109,10 @@ void ProblemSimplexeNommeConverter::UpdateCoefficient(unsigned idxVar, objective->SetCoefficient(var, problemeSimplexe_->CoutLineaire[idxVar]); } -void ProblemSimplexeNommeConverter::CopyVariables(MPSolver* solver) +void ProblemSimplexeNommeConverter::CopyObjective(MPSolver* solver) { MPObjective* const objective = solver->MutableObjective(); - for (int idxVar = 0; idxVar < problemeSimplexe_->NombreDeVariables; ++idxVar) { UpdateCoefficient(idxVar, solver, objective); @@ -150,26 +149,65 @@ void ProblemSimplexeNommeConverter::CopyRows(MPSolver* solver) } // namespace Optimization } // namespace Antares -static void extract_from_MPSolver(const MPSolver* solver, +static void extractSolutionValues(const std::vector& variables, Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe) { - auto& variables = solver->variables(); int nbVar = problemeSimplexe->NombreDeVariables; - - // Extracting variable values and reduced costs for (int idxVar = 0; idxVar < nbVar; ++idxVar) { auto& var = variables[idxVar]; problemeSimplexe->X[idxVar] = var->solution_value(); + } +} + +static void extractReducedCosts(const std::vector& variables, + Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe) +{ + int nbVar = problemeSimplexe->NombreDeVariables; + for (int idxVar = 0; idxVar < nbVar; ++idxVar) + { + auto& var = variables[idxVar]; problemeSimplexe->CoutsReduits[idxVar] = var->reduced_cost(); } +} - auto& constraints = solver->constraints(); - int nbRow = problemeSimplexe->NombreDeContraintes; - for (int idxRow = 0; idxRow < nbRow; ++idxRow) +static void extractDualValues(const std::vector& constraints, + Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe) +{ + int nbRows = problemeSimplexe->NombreDeContraintes; + for (int idxRow = 0; idxRow < nbRows; ++idxRow) + { + auto& row = constraints[idxRow]; + problemeSimplexe->CoutsMarginauxDesContraintes[idxRow] = row->dual_value(); + } +} + +static void extract_from_MPSolver(MPSolver* solver, + Antares::Optimization::PROBLEME_SIMPLEXE_NOMME* problemeSimplexe) +{ + assert(solver); + assert(problemeSimplexe); + + const bool isMIP = problemeSimplexe->isMIP(); + + extractSolutionValues(solver->variables(), + problemeSimplexe); + + if (isMIP) + { + const int nbVar = problemeSimplexe->NombreDeVariables; + std::fill(problemeSimplexe->CoutsReduits, problemeSimplexe->CoutsReduits + nbVar, 0.); + + const int nbRows = problemeSimplexe->NombreDeContraintes; + std::fill(problemeSimplexe->CoutsMarginauxDesContraintes, + problemeSimplexe->CoutsMarginauxDesContraintes + nbRows, + 0.); + } + else { - auto& row = constraints[idxRow]; - problemeSimplexe->CoutsMarginauxDesContraintes[idxRow] = row->dual_value(); + extractReducedCosts(solver->variables(), problemeSimplexe); + + extractDualValues(solver->constraints(), problemeSimplexe); } } @@ -241,7 +279,8 @@ MPSolver* ORTOOLS_ConvertIfNeeded(const std::string& solverName, { if (solver == nullptr) { - return Antares::Optimization::ProblemSimplexeNommeConverter(solverName, Probleme).Convert(); + Antares::Optimization::ProblemSimplexeNommeConverter converter(solverName, Probleme); + return converter.Convert(); } else { diff --git a/src/solver/utils/ortools_utils.h b/src/solver/utils/ortools_utils.h index 3ec59ef13d..3ea49adce9 100644 --- a/src/solver/utils/ortools_utils.h +++ b/src/solver/utils/ortools_utils.h @@ -92,7 +92,7 @@ class ProblemSimplexeNommeConverter Nomenclature constraintNameManager_ = Nomenclature('c'); void UpdateCoefficient(unsigned idxVar, MPSolver* solver, MPObjective* const objective); - void CopyVariables(MPSolver* solver); + void CopyObjective(MPSolver* solver); void UpdateContraints(unsigned idxRow, MPSolver* solver); void CopyRows(MPSolver* solver); void TuneSolverSpecificOptions(MPSolver* solver) const; diff --git a/src/solver/variable/commons/hydro.h b/src/solver/variable/commons/hydro.h index c1b446b8a3..56a4d78fae 100644 --- a/src/solver/variable/commons/hydro.h +++ b/src/solver/variable/commons/hydro.h @@ -199,9 +199,8 @@ class TimeSeriesValuesHydro { // The current time-series auto& ror = pArea->hydro.series->ror; - const unsigned int nbchro - = pArea->hydro.series->getIndex(year); - pFatalValues[numSpace] = &(ror.entry[(nbchro < ror.width ? nbchro : 0)]); + const unsigned int nbchro = ror.getSeriesIndex(year); + pFatalValues[numSpace] = &(ror.timeSeries.entry[nbchro]); // Next variable NextType::yearBegin(year, numSpace); diff --git a/src/solver/variable/commons/load.h b/src/solver/variable/commons/load.h index 174e94624a..c1b9e2db1c 100644 --- a/src/solver/variable/commons/load.h +++ b/src/solver/variable/commons/load.h @@ -201,8 +201,8 @@ class TimeSeriesValuesLoad // (void)::memcpy( pValuesForTheCurrentYear[numSpace].hour, - pArea->load.series->getColumn(year), - sizeof(double) * pArea->load.series->timeSeries.height); + pArea->load.series.getColumn(year), + sizeof(double) * pArea->load.series.timeSeries.height); // Next variable NextType::yearBegin(year, numSpace); diff --git a/src/solver/variable/commons/solar.h b/src/solver/variable/commons/solar.h index 0887f9f7f9..80b0397852 100644 --- a/src/solver/variable/commons/solar.h +++ b/src/solver/variable/commons/solar.h @@ -199,8 +199,8 @@ class TimeSeriesValuesSolar { // The current solar time-series (void)::memcpy(pValuesForTheCurrentYear[numSpace].hour, - pArea->solar.series->getColumn(year), - sizeof(double) * pArea->solar.series->timeSeries.height); + pArea->solar.series.getColumn(year), + sizeof(double) * pArea->solar.series.timeSeries.height); } // Next variable diff --git a/src/solver/variable/commons/wind.h b/src/solver/variable/commons/wind.h index 369086aeee..786d5572ea 100644 --- a/src/solver/variable/commons/wind.h +++ b/src/solver/variable/commons/wind.h @@ -198,8 +198,8 @@ class TimeSeriesValuesWind { // The current wind time-series (void)::memcpy(pValuesForTheCurrentYear[numSpace].hour, - pArea->wind.series->getColumn(year), - sizeof(double) * pArea->wind.series->timeSeries.height); + pArea->wind.series.getColumn(year), + sizeof(double) * pArea->wind.series.timeSeries.height); } // Next variable diff --git a/src/solver/variable/economy/avail-dispatchable-generation.h b/src/solver/variable/economy/avail-dispatchable-generation.h index 2df9c4fb60..80e3356055 100644 --- a/src/solver/variable/economy/avail-dispatchable-generation.h +++ b/src/solver/variable/economy/avail-dispatchable-generation.h @@ -196,8 +196,8 @@ class AvailableDispatchGen { for (auto& [name, cluster] : list) { - const auto& availableProduction = cluster->series->getAvailablePowerYearly(year); - for (unsigned int hour = 0; hour != cluster->series->timeSeries.height; ++hour) + const auto& availableProduction = cluster->series.getColumn(year); + for (unsigned int hour = 0; hour != cluster->series.timeSeries.height; ++hour) pValuesForTheCurrentYear[numSpace].hour[hour] += availableProduction[hour]; } } diff --git a/src/solver/variable/economy/links/congestionProbability.h b/src/solver/variable/economy/links/congestionProbability.h index 6e81772f41..72f560d7b4 100644 --- a/src/solver/variable/economy/links/congestionProbability.h +++ b/src/solver/variable/economy/links/congestionProbability.h @@ -278,8 +278,7 @@ class CongestionProbability assert(state.link != NULL); const auto& linkDirectCapa = state.link->directCapacities; const auto& linkIndirectCapa = state.link->indirectCapacities; - const int tsIndex = NumeroChroniquesTireesParInterconnexion[numSpace][state.link->index] - .TransmissionCapacities; + const int tsIndex = (linkDirectCapa.width != 1) ? state.link->timeseriesNumbers[0][state.year] : 0; // CONG. PROB + if (state.ntc.ValeurDuFlux[state.link->index] > +linkDirectCapa.entry[tsIndex][state.hourInTheYear] - 10e-6) diff --git a/src/solver/variable/economy/productionByRenewablePlant.h b/src/solver/variable/economy/productionByRenewablePlant.h index f0ab02e886..2f7ed60eac 100644 --- a/src/solver/variable/economy/productionByRenewablePlant.h +++ b/src/solver/variable/economy/productionByRenewablePlant.h @@ -280,7 +280,7 @@ class ProductionByRenewablePlant : public Variable::IVariablerenewable.clusterCount(); ++clusterIndex) { const auto* renewableCluster = state.area->renewable.clusters[clusterIndex]; - double renewableClusterProduction = renewableCluster->valueAtTimeStep(state.hourInTheYear, state.year); + double renewableClusterProduction = renewableCluster->valueAtTimeStep(state.year, state.hourInTheYear); pValuesForTheCurrentYear[numSpace][renewableCluster->areaWideIndex].hour[state.hourInTheYear] += renewableClusterProduction; diff --git a/src/solver/variable/economy/profitByPlant.h b/src/solver/variable/economy/profitByPlant.h index 3438b8b387..bf8c7eca6e 100644 --- a/src/solver/variable/economy/profitByPlant.h +++ b/src/solver/variable/economy/profitByPlant.h @@ -277,7 +277,7 @@ class ProfitByPlant : public Variable::IVariable, NextT, VC auto* cluster = state.area->thermal.clusters[clusterIndex]; double hourlyClusterProduction = thermal[area->index].thermalClustersProductions[clusterIndex]; - uint tsIndex = cluster->series->timeseriesNumbers[0][state.year]; + uint tsIndex = cluster->series.timeseriesNumbers[0][state.year]; // Thermal cluster profit pValuesForTheCurrentYear[numSpace][cluster->areaWideIndex].hour[hourInTheYear] = (hourlyClusterProduction - cluster->PthetaInf[hourInTheYear]) diff --git a/src/solver/variable/economy/renewableGeneration.h b/src/solver/variable/economy/renewableGeneration.h index 631a85c038..93d92b96be 100644 --- a/src/solver/variable/economy/renewableGeneration.h +++ b/src/solver/variable/economy/renewableGeneration.h @@ -272,7 +272,7 @@ class RenewableGeneration { const auto* renewableCluster = state.area->renewable.clusters[clusterIndex]; double renewableClusterProduction - = renewableCluster->valueAtTimeStep(state.hourInTheYear, state.year); + = renewableCluster->valueAtTimeStep(state.year, state.hourInTheYear); pValuesForTheCurrentYear[numSpace][renewableCluster->groupID][state.hourInTheYear] += renewableClusterProduction; diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index 726cb1b478..3dc8ee3635 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -85,7 +85,7 @@ void State::initFromThermalClusterIndex(const uint clusterAreaWideIndex) // alias to the current thermal cluster thermalCluster = area->thermal.clusters[clusterAreaWideIndex]; double thermalClusterAvailableProduction - = thermalCluster->series->getAvailablePower(hourInTheYear, this->year); + = thermalCluster->series.getCoefficient(this->year, hourInTheYear); // Minimum power of a group of the cluster for the current hour in the year double thermalClusterPMinOfAGroup = 0.; @@ -95,8 +95,7 @@ void State::initFromThermalClusterIndex(const uint clusterAreaWideIndex) // When the cluster is in must-run mode, the production value // directly comes from the time-series // it doen't exist from the solver perspective - assert(thermalCluster->series); - assert(hourInTheYear < thermalCluster->series->timeSeries.height); + assert(hourInTheYear < thermalCluster->series.timeSeries.height); thermal[area->index].thermalClustersProductions[clusterAreaWideIndex] = thermalClusterAvailableProduction; @@ -130,15 +129,20 @@ void State::initFromThermalClusterIndex(const uint clusterAreaWideIndex) = hourlyResults->ProductionThermique[hourInTheWeek] .ProductionThermiqueDuPalier[thermalCluster->index]; - if (unitCommitmentMode == Antares::Data::UnitCommitmentMode::ucMILP) // Economy accurate + switch (unitCommitmentMode) + { + using ucMode = Antares::Data::UnitCommitmentMode; + case ucMode::ucHeuristicAccurate: + case ucMode::ucMILP: thermal[area->index].numberOfUnitsONbyCluster[clusterAreaWideIndex] = static_cast(hourlyResults->ProductionThermique[hourInTheWeek] .NombreDeGroupesEnMarcheDuPalier[thermalCluster->index]); - else + break; + default: // Economy Fast or Adequacy -- will be calculated during the smoothing thermal[area->index].numberOfUnitsONbyCluster[clusterAreaWideIndex] = 0; + } } - initFromThermalClusterIndexProduction(clusterAreaWideIndex); if (studyMode != Data::stdmAdequacy) @@ -155,7 +159,7 @@ void State::initFromThermalClusterIndex(const uint clusterAreaWideIndex) void State::initFromThermalClusterIndexProduction(const uint clusterAreaWideIndex) { - uint serieIndex = thermalCluster->series->timeseriesNumbers[0][this->year]; + uint serieIndex = thermalCluster->series.timeseriesNumbers[0][this->year]; if (thermal[area->index].thermalClustersProductions[clusterAreaWideIndex] > 0.) { @@ -242,9 +246,8 @@ void State::yearEndBuildFromThermalClusterIndex(const uint clusterAreaWideIndex) Data::ThermalCluster* currentCluster = area->thermal.clusters[clusterAreaWideIndex]; assert(endHourForCurrentYear <= Variable::maxHoursInAYear); - assert(endHourForCurrentYear <= currentCluster->series->timeSeries.height); + assert(endHourForCurrentYear <= currentCluster->series.timeSeries.height); assert(currentCluster); - assert(currentCluster->series); if (currentCluster->fixedCost > 0.) { @@ -257,7 +260,7 @@ void State::yearEndBuildFromThermalClusterIndex(const uint clusterAreaWideIndex) maxDurationON = endHourForCurrentYear; // min, and max unit ON calculation - const auto& availableProduction = currentCluster->series->getAvailablePowerYearly(this->year); + const auto& availableProduction = currentCluster->series.getColumn(this->year); for (uint h = startHourForCurrentYear; h < endHourForCurrentYear; ++h) { maxUnitNeeded = 0u; @@ -284,13 +287,13 @@ void State::yearEndBuildFromThermalClusterIndex(const uint clusterAreaWideIndex) if (thermalClusterProduction <= 0.) continue; - uint serieIndex = currentCluster->series->timeseriesNumbers[0][this->year]; + uint serieIndex = currentCluster->series.timeseriesNumbers[0][this->year]; thermalClusterOperatingCostForYear[h] = thermalClusterProduction * currentCluster->getOperatingCost(serieIndex, h); switch (unitCommitmentMode) { - case Antares::Data::UnitCommitmentMode::ucHeuristic: + case Antares::Data::UnitCommitmentMode::ucHeuristicFast: { // ON_min[h] = static_cast(Math::Ceil(thermalClusterProduction / // currentCluster->nominalCapacityWithSpinning)); // code 5.0.3b<7 @@ -313,6 +316,7 @@ void State::yearEndBuildFromThermalClusterIndex(const uint clusterAreaWideIndex) break; } case Antares::Data::UnitCommitmentMode::ucMILP: + case Antares::Data::UnitCommitmentMode::ucHeuristicAccurate: { ON_min[h] = Math::Max( static_cast(Math::Ceil(thermalClusterProduction / currentCluster->nominalCapacityWithSpinning)), diff --git a/src/tests/end-to-end/binding_constraints/CMakeLists.txt b/src/tests/end-to-end/binding_constraints/CMakeLists.txt index c65327c73f..900a781d59 100644 --- a/src/tests/end-to-end/binding_constraints/CMakeLists.txt +++ b/src/tests/end-to-end/binding_constraints/CMakeLists.txt @@ -17,7 +17,6 @@ target_link_libraries(tests-binding_constraints antares-solver-simulation antares-solver-hydro antares-solver-ts-generator - antares-solver-aleatoire ) target_include_directories(tests-binding_constraints @@ -29,5 +28,3 @@ target_include_directories(tests-binding_constraints add_test(NAME end-to-end-binding_constraints COMMAND tests-binding_constraints) set_property(TEST end-to-end-binding_constraints PROPERTY LABELS end-to-end) set_target_properties(tests-binding_constraints PROPERTIES FOLDER Unit-tests/end_to_end) - -copy_dependency(sirius_solver tests-binding_constraints) diff --git a/src/tests/end-to-end/binding_constraints/test_binding_constraints.cpp b/src/tests/end-to-end/binding_constraints/test_binding_constraints.cpp index a9ddebe59d..16c3a9046d 100644 --- a/src/tests/end-to-end/binding_constraints/test_binding_constraints.cpp +++ b/src/tests/end-to-end/binding_constraints/test_binding_constraints.cpp @@ -31,11 +31,11 @@ StudyForBCTest::StudyForBCTest() Area* area1 = addAreaToStudy("Area 1"); Area* area2 = addAreaToStudy("Area 2"); - TimeSeriesConfigurer(area1->load.series->timeSeries) + TimeSeriesConfigurer(area1->load.series.timeSeries) .setColumnCount(1) .fillColumnWith(0, 0); - TimeSeriesConfigurer(area2->load.series->timeSeries) + TimeSeriesConfigurer(area2->load.series.timeSeries) .setColumnCount(1) .fillColumnWith(0, 100); diff --git a/src/tests/end-to-end/simple_study/CMakeLists.txt b/src/tests/end-to-end/simple_study/CMakeLists.txt index ac29766275..e25387cbeb 100644 --- a/src/tests/end-to-end/simple_study/CMakeLists.txt +++ b/src/tests/end-to-end/simple_study/CMakeLists.txt @@ -16,7 +16,6 @@ target_link_libraries(tests-simple-study antares-solver-main-economy antares-solver-main-adequacy antares-solver-hydro - antares-solver-aleatoire antares-solver-variable antares-solver-simulation antares-solver-ts-generator @@ -34,9 +33,6 @@ add_test(NAME end-to-end-simple-study COMMAND tests-simple-study) set_property(TEST end-to-end-simple-study PROPERTY LABELS end-to-end) set_target_properties(tests-simple-study PROPERTIES FOLDER Unit-tests/end_to_end) - -copy_dependency(sirius_solver tests-simple-study) - # Storing tests-simple-study under the folder Unit-tests in the IDE #---------------------------------------------------------- diff --git a/src/tests/end-to-end/simple_study/simple-study.cpp b/src/tests/end-to-end/simple_study/simple-study.cpp index ee2a3a94cd..2152402d87 100644 --- a/src/tests/end-to-end/simple_study/simple-study.cpp +++ b/src/tests/end-to-end/simple_study/simple-study.cpp @@ -24,7 +24,7 @@ struct StudyFixture : public StudyBuilder double loadInArea = 0.; double clusterCost = 0.; ThermalClusterConfig clusterConfig; - TimeSeriesConfigurer> loadTSconfig; + TimeSeriesConfigurer loadTSconfig; }; StudyFixture::StudyFixture() @@ -34,7 +34,7 @@ StudyFixture::StudyFixture() cluster = addClusterToArea(area, "some cluster"); loadInArea = 7.0; - loadTSconfig = std::move(TimeSeriesConfigurer(area->load.series->timeSeries)); + loadTSconfig = std::move(TimeSeriesConfigurer(area->load.series.timeSeries)); loadTSconfig.setColumnCount(1) .fillColumnWith(0, loadInArea); @@ -140,4 +140,75 @@ BOOST_AUTO_TEST_CASE(two_mc_years_with_different_weight__two_ts) BOOST_TEST(output.overallCost(area).hour(0) == averageLoad * clusterCost, tt::tolerance(0.001)); } +BOOST_AUTO_TEST_CASE(milp_two_mc_single_unit_single_scenario) +{ + setNumberMCyears(1); + + // Arbitrary large number, only characteristic is : larger than all + // other marginal costs + area->thermal.unsuppliedEnergyCost = 1000; + + // Use OR-Tools / COIN for MILP + auto& p = study->parameters; + p.unitCommitment.ucMode = ucMILP; + p.ortoolsUsed = true; + p.ortoolsSolver = "coin"; + + simulation->create(); + simulation->run(); + + OutputRetriever output(simulation->rawSimu()); + + BOOST_TEST(output.thermalGeneration(cluster.get()).hour(10) == loadInArea, + tt::tolerance(0.001)); + BOOST_TEST(output.thermalNbUnitsON(cluster.get()).hour(10) == 1, tt::tolerance(0.001)); + BOOST_TEST(output.overallCost(area).hour(0) == loadInArea * clusterCost, tt::tolerance(0.001)); +} + +BOOST_AUTO_TEST_CASE(milp_two_mc_two_unit_single_scenario) +{ + setNumberMCyears(1); + + clusterConfig.setAvailablePower(0, 150.).setUnitCount(2); + + loadInArea = 150; + loadTSconfig.setColumnCount(1).fillColumnWith(0, loadInArea); + // Arbitrary large number, only characteristic is : larger than all + // other marginal costs + area->thermal.unsuppliedEnergyCost = 1000; + + // Use OR-Tools / COIN for MILP + auto& p = study->parameters; + p.unitCommitment.ucMode = ucMILP; + p.ortoolsUsed = true; + p.ortoolsSolver = "coin"; + + simulation->create(); + simulation->run(); + + OutputRetriever output(simulation->rawSimu()); + + BOOST_TEST(output.thermalGeneration(cluster.get()).hour(10) == loadInArea, + tt::tolerance(0.001)); + BOOST_TEST(output.thermalNbUnitsON(cluster.get()).hour(10) == 2, tt::tolerance(0.001)); +} +BOOST_AUTO_TEST_SUITE_END() + + +BOOST_AUTO_TEST_SUITE(error_cases) +BOOST_AUTO_TEST_CASE(error_on_wrong_hydro_data) +{ + StudyBuilder builder; + builder.simulationBetweenDays(0, 7); + builder.setNumberMCyears(1); + Area& area = *builder.addAreaToStudy("A"); + PartHydro& hydro = area.hydro; + TimeSeriesConfigurer(hydro.series->storage.timeSeries) + .setColumnCount(1) + .fillColumnWith(0, -1.0); //Negative inflow will cause a consistency error with mingen + + auto simulation = builder.simulation; + simulation->create(); + BOOST_CHECK_THROW(simulation->run(), Antares::FatalError); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/end-to-end/utils/utils.cpp b/src/tests/end-to-end/utils/utils.cpp index d4dc34ac54..70920b7ca3 100644 --- a/src/tests/end-to-end/utils/utils.cpp +++ b/src/tests/end-to-end/utils/utils.cpp @@ -40,32 +40,47 @@ void addScratchpadToEachArea(Study& study) } } +TimeSeriesConfigurer& TimeSeriesConfigurer::setColumnCount(unsigned int columnCount) +{ + ts_->resize(columnCount, HOURS_PER_YEAR); + return *this; +} -ThermalClusterConfig::ThermalClusterConfig(ThermalCluster* cluster) : cluster_(cluster) +TimeSeriesConfigurer& TimeSeriesConfigurer::fillColumnWith(unsigned int column, double value) { - tsAvailablePowerConfig_ = std::move(TimeSeriesConfigurer(cluster_->series->timeSeries)); + ts_->fillColumn(column, value); + return *this; } + +ThermalClusterConfig::ThermalClusterConfig(ThermalCluster* cluster) : cluster_(cluster), tsAvailablePowerConfig_(cluster_->series.timeSeries) +{ +} + ThermalClusterConfig& ThermalClusterConfig::setNominalCapacity(double nominalCapacity) { cluster_->nominalCapacity = nominalCapacity; return *this; } + ThermalClusterConfig& ThermalClusterConfig::setUnitCount(unsigned int unitCount) { cluster_->unitCount = unitCount; return *this; } + ThermalClusterConfig& ThermalClusterConfig::setCosts(double cost) { cluster_->marginalCost = cost; cluster_->marketBidCost = cost; // Must define market bid cost otherwise all production is used return *this; } + ThermalClusterConfig& ThermalClusterConfig::setAvailablePowerNumberOfTS(unsigned int columnCount) { tsAvailablePowerConfig_.setColumnCount(columnCount); return *this; -}; +} + ThermalClusterConfig& ThermalClusterConfig::setAvailablePower(unsigned int column, double value) { tsAvailablePowerConfig_.fillColumnWith(column, value); @@ -108,6 +123,12 @@ averageResults OutputRetriever::thermalGeneration(ThermalCluster* cluster) return averageResults((*result)[cluster->areaWideIndex].avgdata); } +averageResults OutputRetriever::thermalNbUnitsON(ThermalCluster* cluster) +{ + auto result = retrieveResultsForThermalCluster(cluster); + return averageResults((*result)[cluster->areaWideIndex].avgdata); +} + ScenarioBuilderRule::ScenarioBuilderRule(Study& study) { study.scenarioRulesCreate(); diff --git a/src/tests/end-to-end/utils/utils.h b/src/tests/end-to-end/utils/utils.h index 1781b2f54c..15c7ae065f 100644 --- a/src/tests/end-to-end/utils/utils.h +++ b/src/tests/end-to-end/utils/utils.h @@ -15,32 +15,17 @@ void initializeStudy(Study::Ptr study); void configureLinkCapacities(AreaLink* link); -template class TimeSeriesConfigurer { public: TimeSeriesConfigurer() = default; - TimeSeriesConfigurer(MatrixType& matrix) : ts_(&matrix) {} + TimeSeriesConfigurer(Matrix<>& matrix) : ts_(&matrix) {} TimeSeriesConfigurer& setColumnCount(unsigned int columnCount); TimeSeriesConfigurer& fillColumnWith(unsigned int column, double value); private: - MatrixType* ts_ = nullptr; + Matrix<>* ts_ = nullptr; }; -template -TimeSeriesConfigurer& TimeSeriesConfigurer::setColumnCount(unsigned int columnCount) -{ - ts_->resize(columnCount, HOURS_PER_YEAR); - return *this; -} - -template -TimeSeriesConfigurer& TimeSeriesConfigurer::fillColumnWith(unsigned int column, double value) -{ - ts_->fillColumn(column, value); - return *this; -} - class ThermalClusterConfig { @@ -55,7 +40,7 @@ class ThermalClusterConfig private: ThermalCluster* cluster_ = nullptr; - TimeSeriesConfigurer> tsAvailablePowerConfig_; + TimeSeriesConfigurer tsAvailablePowerConfig_; }; std::shared_ptr addClusterToArea(Area* area, const std::string& clusterName); @@ -87,6 +72,7 @@ class OutputRetriever averageResults load(Area* area); averageResults flow(AreaLink* link); averageResults thermalGeneration(ThermalCluster* cluster); + averageResults thermalNbUnitsON(ThermalCluster* cluster); private: template diff --git a/src/tests/src/libs/antares/CMakeLists.txt b/src/tests/src/libs/antares/CMakeLists.txt index 63137627ed..a6771db392 100644 --- a/src/tests/src/libs/antares/CMakeLists.txt +++ b/src/tests/src/libs/antares/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(concurrency) +add_subdirectory(writer) add_subdirectory(study) set(src_libs_antares "${CMAKE_SOURCE_DIR}/libs/antares") diff --git a/src/tests/src/libs/antares/concurrency/CMakeLists.txt b/src/tests/src/libs/antares/concurrency/CMakeLists.txt new file mode 100644 index 0000000000..71cc0484c4 --- /dev/null +++ b/src/tests/src/libs/antares/concurrency/CMakeLists.txt @@ -0,0 +1,11 @@ +add_executable(test-concurrency) + +target_sources(test-concurrency PRIVATE test_concurrency.cpp) + +target_link_libraries(test-concurrency + PRIVATE + Boost::unit_test_framework + Antares::concurrency +) + +add_test(NAME concurrency COMMAND test-concurrency) diff --git a/src/tests/src/libs/antares/concurrency/test_concurrency.cpp b/src/tests/src/libs/antares/concurrency/test_concurrency.cpp new file mode 100644 index 0000000000..2e9cffbd1a --- /dev/null +++ b/src/tests/src/libs/antares/concurrency/test_concurrency.cpp @@ -0,0 +1,99 @@ +/* +** 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-concurrency tests +#define BOOST_TEST_DYN_LINK +#include +#include + +#include "antares/concurrency/concurrency.h" + +using namespace Yuni::Job; +using namespace Antares::Concurrency; + +std::unique_ptr createThreadPool(int size) +{ + auto threadPool = std::make_unique(); + threadPool->maximumThreadCount(size); + threadPool->start(); + return threadPool; +} + +BOOST_AUTO_TEST_CASE(test_no_error) +{ + auto threadPool = createThreadPool(1); + int counter = 0; + Task incrementCounter = [&counter]() { + counter++; + }; + TaskFuture future = AddTask(*threadPool, incrementCounter); + future.get(); + BOOST_CHECK(counter == 1); +} + + +template +Task failingTask() { + return []() { + throw Exc(); + }; +} + +class TestException {}; + +BOOST_AUTO_TEST_CASE(test_throw) +{ + auto threadPool = createThreadPool(1); + TaskFuture future = AddTask(*threadPool, failingTask()); + BOOST_CHECK_THROW(future.get(), TestException); +} + +BOOST_AUTO_TEST_CASE(test_future_set) +{ + auto threadPool = createThreadPool(4); + int counter = 0; + Task incrementCounter = [&counter]() { + counter++; + }; + FutureSet futures; + for (int i = 0; i < 10; i++) { + futures.add(AddTask(*threadPool, incrementCounter)); + } + futures.join(); + BOOST_CHECK(counter == 10); +} + +template +class TestExceptionN {}; + +BOOST_AUTO_TEST_CASE(test_future_set_rethrows_first_submitted) +{ + auto threadPool = createThreadPool(2); + FutureSet futures; + futures.add(AddTask(*threadPool, failingTask>())); + futures.add(AddTask(*threadPool, failingTask>())); + BOOST_CHECK_THROW(futures.join(), TestExceptionN<1>); +} diff --git a/src/tests/src/libs/antares/study/CMakeLists.txt b/src/tests/src/libs/antares/study/CMakeLists.txt index dcff0a42fd..d735c1218a 100644 --- a/src/tests/src/libs/antares/study/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/CMakeLists.txt @@ -6,3 +6,14 @@ add_subdirectory(output-folder) add_subdirectory(short-term-storage-input) add_subdirectory(thermal-price-definition) add_subdirectory(constraint) +add_subdirectory(series) + +add_executable(test-study) +target_sources(test-study PRIVATE test_study.cpp) +target_link_libraries(test-study + PRIVATE + Antares::study + Boost::unit_test_framework +) + +add_test(NAME test-study COMMAND test-study) diff --git a/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-read-line.cpp b/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-read-line.cpp index 798b91ab2f..ad39460e08 100644 --- a/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-read-line.cpp +++ b/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-read-line.cpp @@ -34,7 +34,6 @@ std::shared_ptr addClusterToArea(Area* area, const std::string& clu { auto cluster = std::make_shared(area); cluster->setName(clusterName); - cluster->series = new DataSeriesCommon(); addClusterToAreaList(area, cluster); @@ -65,27 +64,27 @@ struct Fixture // Load : set the nb of ready made TS uint nbReadyMadeTS = 13; - area_1->load.series->timeSeries.resize(nbReadyMadeTS, 1); - area_2->load.series->timeSeries.resize(nbReadyMadeTS, 1); - area_3->load.series->timeSeries.resize(nbReadyMadeTS, 1); + area_1->load.series.timeSeries.resize(nbReadyMadeTS, 1); + area_2->load.series.timeSeries.resize(nbReadyMadeTS, 1); + area_3->load.series.timeSeries.resize(nbReadyMadeTS, 1); // Wind : set the nb of ready made TS nbReadyMadeTS = 17; - area_1->wind.series->timeSeries.resize(nbReadyMadeTS, 1); - area_2->wind.series->timeSeries.resize(nbReadyMadeTS, 1); - area_3->wind.series->timeSeries.resize(nbReadyMadeTS, 1); + area_1->wind.series.timeSeries.resize(nbReadyMadeTS, 1); + area_2->wind.series.timeSeries.resize(nbReadyMadeTS, 1); + area_3->wind.series.timeSeries.resize(nbReadyMadeTS, 1); // Solar : set the nb of ready made TS nbReadyMadeTS = 9; - area_1->solar.series->timeSeries.resize(nbReadyMadeTS, 1); - area_2->solar.series->timeSeries.resize(nbReadyMadeTS, 1); - area_3->solar.series->timeSeries.resize(nbReadyMadeTS, 1); + area_1->solar.series.timeSeries.resize(nbReadyMadeTS, 1); + area_2->solar.series.timeSeries.resize(nbReadyMadeTS, 1); + area_3->solar.series.timeSeries.resize(nbReadyMadeTS, 1); // Hydro : set the nb of ready made TS nbReadyMadeTS = 12; - area_1->hydro.series->count = nbReadyMadeTS; - area_2->hydro.series->count = nbReadyMadeTS; - area_3->hydro.series->count = nbReadyMadeTS; + area_1->hydro.series->resizeGenerationTS(nbReadyMadeTS, 1); + area_2->hydro.series->resizeGenerationTS(nbReadyMadeTS, 1); + area_3->hydro.series->resizeGenerationTS(nbReadyMadeTS, 1); // Links link_12 = AreaAddLinkBetweenAreas(area_1, area_2, false); @@ -103,9 +102,9 @@ struct Fixture thCluster_31 = addClusterToArea(area_3, "th-cluster-31"); // Thermal clusters : set the nb of ready made TS - thCluster_11->series->timeSeries.resize(14, 1); - thCluster_12->series->timeSeries.resize(14, 1); - thCluster_31->series->timeSeries.resize(14, 1); + thCluster_11->series.timeSeries.resize(14, 1); + thCluster_12->series.timeSeries.resize(14, 1); + thCluster_31->series.timeSeries.resize(14, 1); // Thermal clusters : update areas local numbering for clusters area_1->thermal.prepareAreaWideIndexes(); @@ -118,9 +117,9 @@ struct Fixture rnCluster_32 = addClusterToArea(area_3, "rn-cluster-32"); // Renewable clusters : set the nb of ready made TS - rnCluster_21->series->timeSeries.resize(9, 1); - rnCluster_31->series->timeSeries.resize(9, 1); - rnCluster_32->series->timeSeries.resize(9, 1); + rnCluster_21->series.timeSeries.resize(9, 1); + rnCluster_31->series.timeSeries.resize(9, 1); + rnCluster_32->series.timeSeries.resize(9, 1); // Renewable clusters : update areas local numbering for clusters area_1->renewable.prepareAreaWideIndexes(); @@ -181,7 +180,7 @@ BOOST_FIXTURE_TEST_CASE(on_area2_and_on_year_18__load_TS_number_11_is_chosen__re BOOST_CHECK_EQUAL(my_rule.load.get_value(yearNumber.to(), area_2->index), tsNumber.to()); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(area_2->load.series->timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); + BOOST_CHECK_EQUAL(area_2->load.series.timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); } // ================= @@ -197,7 +196,7 @@ BOOST_FIXTURE_TEST_CASE(on_area3_and_on_year_7__wind_TS_number_5_is_chosen__read BOOST_CHECK_EQUAL(my_rule.wind.get_value(yearNumber.to(), area_3->index), tsNumber.to()); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(area_3->wind.series->timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); + BOOST_CHECK_EQUAL(area_3->wind.series.timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); } // ================= @@ -213,7 +212,7 @@ BOOST_FIXTURE_TEST_CASE(on_area1_and_on_year_4__solar_TS_number_8_is_chosen__rea BOOST_CHECK_EQUAL(my_rule.solar.get_value(yearNumber.to(), area_1->index), tsNumber.to()); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(area_1->solar.series->timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); + BOOST_CHECK_EQUAL(area_1->solar.series.timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); } // ================= @@ -246,7 +245,7 @@ BOOST_FIXTURE_TEST_CASE(on_th_cluster11_of_area1_and_on_year_6__solar_TS_number_ BOOST_CHECK_EQUAL(my_rule.thermal[area_1->index].get(thCluster_11.get(), yearNumber.to()), tsNumber.to()); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(thCluster_11->series->timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); + BOOST_CHECK_EQUAL(thCluster_11->series.timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); } BOOST_FIXTURE_TEST_CASE(on_th_cluster12_of_area1_and_on_year_13__solar_TS_number_5_is_chosen__reading_OK, Fixture) @@ -259,7 +258,7 @@ BOOST_FIXTURE_TEST_CASE(on_th_cluster12_of_area1_and_on_year_13__solar_TS_number BOOST_CHECK_EQUAL(my_rule.thermal[area_1->index].get(thCluster_12.get(), yearNumber.to()), tsNumber.to()); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(thCluster_12->series->timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); + BOOST_CHECK_EQUAL(thCluster_12->series.timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); } BOOST_FIXTURE_TEST_CASE(on_th_cluster31_of_area3_and_on_year_10__solar_TS_number_7_is_chosen__reading_OK, Fixture) @@ -272,7 +271,7 @@ BOOST_FIXTURE_TEST_CASE(on_th_cluster31_of_area3_and_on_year_10__solar_TS_number BOOST_CHECK_EQUAL(my_rule.thermal[area_3->index].get(thCluster_31.get(), yearNumber.to()), tsNumber.to()); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(thCluster_31->series->timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); + BOOST_CHECK_EQUAL(thCluster_31->series.timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); } @@ -291,7 +290,7 @@ BOOST_FIXTURE_TEST_CASE(on_rn_cluster21_of_area2_and_on_year_16__solar_TS_number BOOST_CHECK_EQUAL(my_rule.renewable[area_2->index].get(rnCluster_21.get(), yearNumber.to()), tsNumber.to()); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(rnCluster_21->series->timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); + BOOST_CHECK_EQUAL(rnCluster_21->series.timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); } BOOST_FIXTURE_TEST_CASE(on_rn_cluster32_of_area3_and_on_year_2__solar_TS_number_4_is_chosen__reading_OK, Fixture) @@ -306,7 +305,7 @@ BOOST_FIXTURE_TEST_CASE(on_rn_cluster32_of_area3_and_on_year_2__solar_TS_number_ BOOST_CHECK_EQUAL(my_rule.renewable[area_3->index].get(rnCluster_32.get(), yearNumber.to()), tsNumber.to()); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(rnCluster_32->series->timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); + BOOST_CHECK_EQUAL(rnCluster_32->series.timeseriesNumbers[0][yearNumber.to()], tsNumber.to() - 1); } diff --git a/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-save.cpp b/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-save.cpp index 592ece1694..0fef661c93 100644 --- a/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-save.cpp +++ b/src/tests/src/libs/antares/study/scenario-builder/test-sc-builder-file-save.cpp @@ -75,7 +75,6 @@ std::shared_ptr addClusterToArea(Area* area, const std::string& clu { auto cluster = std::make_shared(area); cluster->setName(clusterName); - cluster->series = new DataSeriesCommon(); addClusterToAreaList(area, cluster); @@ -96,8 +95,7 @@ struct commonFixture study = std::make_shared(); // Set study parameters study->parameters.nbYears = 20; - study->parameters.timeSeriesToGenerate - = 0; // No generated time-series, only ready made time-series + study->parameters.timeSeriesToGenerate = 0; // No generated time-series, only ready made time-series // Add areas area_1 = study->areaAdd("Area 1"); @@ -107,27 +105,27 @@ struct commonFixture // Load : set the nb of ready made TS uint nbReadyMadeTS = 13; - area_1->load.series->timeSeries.resize(nbReadyMadeTS, 1); - area_2->load.series->timeSeries.resize(nbReadyMadeTS, 1); - area_3->load.series->timeSeries.resize(nbReadyMadeTS, 1); + area_1->load.series.timeSeries.resize(nbReadyMadeTS, 1); + area_2->load.series.timeSeries.resize(nbReadyMadeTS, 1); + area_3->load.series.timeSeries.resize(nbReadyMadeTS, 1); // Wind : set the nb of ready made TS nbReadyMadeTS = 17; - area_1->wind.series->timeSeries.resize(nbReadyMadeTS, 1); - area_2->wind.series->timeSeries.resize(nbReadyMadeTS, 1); - area_3->wind.series->timeSeries.resize(nbReadyMadeTS, 1); + area_1->wind.series.timeSeries.resize(nbReadyMadeTS, 1); + area_2->wind.series.timeSeries.resize(nbReadyMadeTS, 1); + area_3->wind.series.timeSeries.resize(nbReadyMadeTS, 1); // Solar : set the nb of ready made TS nbReadyMadeTS = 9; - area_1->solar.series->timeSeries.resize(nbReadyMadeTS, 1); - area_2->solar.series->timeSeries.resize(nbReadyMadeTS, 1); - area_3->solar.series->timeSeries.resize(nbReadyMadeTS, 1); + area_1->solar.series.timeSeries.resize(nbReadyMadeTS, 1); + area_2->solar.series.timeSeries.resize(nbReadyMadeTS, 1); + area_3->solar.series.timeSeries.resize(nbReadyMadeTS, 1); // Hydro : set the nb of ready made TS nbReadyMadeTS = 12; - area_1->hydro.series->count = nbReadyMadeTS; - area_2->hydro.series->count = nbReadyMadeTS; - area_3->hydro.series->count = nbReadyMadeTS; + area_1->hydro.series->resizeGenerationTS(nbReadyMadeTS, 1); + area_2->hydro.series->resizeGenerationTS(nbReadyMadeTS, 1); + area_3->hydro.series->resizeGenerationTS(nbReadyMadeTS, 1); // Links link_12 = AreaAddLinkBetweenAreas(area_1, area_2, false); @@ -145,9 +143,9 @@ struct commonFixture thCluster_31 = addClusterToArea(area_3, "th-cluster-31"); // Thermal clusters : set the nb of ready made TS - thCluster_11->series->timeSeries.resize(14, 1); - thCluster_12->series->timeSeries.resize(14, 1); - thCluster_31->series->timeSeries.resize(14, 1); + thCluster_11->series.timeSeries.resize(14, 1); + thCluster_12->series.timeSeries.resize(14, 1); + thCluster_31->series.timeSeries.resize(14, 1); // Thermal clusters : update areas local numbering for clusters area_1->thermal.prepareAreaWideIndexes(); @@ -160,9 +158,9 @@ struct commonFixture rnCluster_32 = addClusterToArea(area_3, "rn-cluster-32"); // Renewable clusters : set the nb of ready made TS - rnCluster_21->series->timeSeries.resize(9, 1); - rnCluster_31->series->timeSeries.resize(9, 1); - rnCluster_32->series->timeSeries.resize(9, 1); + rnCluster_21->series.timeSeries.resize(9, 1); + rnCluster_31->series.timeSeries.resize(9, 1); + rnCluster_32->series.timeSeries.resize(9, 1); // Renewable clusters : update areas local numbering for clusters area_1->renewable.prepareAreaWideIndexes(); diff --git a/src/tests/src/libs/antares/study/series/CMakeLists.txt b/src/tests/src/libs/antares/study/series/CMakeLists.txt new file mode 100644 index 0000000000..0afbfe34ef --- /dev/null +++ b/src/tests/src/libs/antares/study/series/CMakeLists.txt @@ -0,0 +1,20 @@ +# ==================================== +# Tests on TimeSeries class +# ==================================== +set(SRC_TIMESERIES_TESTS + timeseries-tests.cpp +) +add_executable(timeseries-tests ${SRC_TIMESERIES_TESTS}) + +target_link_libraries(timeseries-tests + PRIVATE + Boost::unit_test_framework + Antares::series +) + +# Storing timeseries-tests under the folder Unit-tests in the IDE +set_target_properties(timeseries-tests PROPERTIES FOLDER Unit-tests/timeseries-tests) + +add_test(NAME timeseries-tests COMMAND timeseries-tests) + +set_property(TEST timeseries-tests PROPERTY LABELS unit) diff --git a/src/tests/src/libs/antares/study/series/timeseries-tests.cpp b/src/tests/src/libs/antares/study/series/timeseries-tests.cpp new file mode 100644 index 0000000000..7f7410267e --- /dev/null +++ b/src/tests/src/libs/antares/study/series/timeseries-tests.cpp @@ -0,0 +1,153 @@ +#define BOOST_TEST_MODULE "test time series" +#define BOOST_TEST_DYN_LINK + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +using namespace Antares::Data; + +// ================= +// The fixture +// ================= +struct Fixture +{ + Fixture(const Fixture& f) = delete; + Fixture(const Fixture&& f) = delete; + Fixture& operator=(const Fixture& f) = delete; + Fixture& operator=(const Fixture&& f) = delete; + Fixture() : ts(tsnum) + { + ts.resize(1, HOURS_PER_YEAR); + tsnum.resize(1, 1); + } + TimeSeries ts; + TimeSeries::numbers tsnum; + std::string folder; + + void fillColumn(unsigned int idx); + void fillColumnReverse(unsigned int idx); + + void fillTsnum(); + +}; + +void Fixture::fillColumn(unsigned int idx) +{ + for (unsigned int i = 0; i < ts.timeSeries.height; i++) + ts.timeSeries[idx][i] = i; +} + +void Fixture::fillColumnReverse(unsigned int idx) +{ + for (unsigned int i = 0; i < ts.timeSeries.height; i++) + ts.timeSeries[idx][i] = HOURS_PER_YEAR - i; +} + +void Fixture::fillTsnum() +{ + tsnum.resize(1, ts.timeSeries.width); + for (unsigned int i = 0; i < ts.timeSeries.width; i++) + tsnum[0][i] = i; +} + +// ================== +// Tests section +// ================== + +BOOST_AUTO_TEST_SUITE(timeseries_tests) + +BOOST_FIXTURE_TEST_CASE(getSeriesIndex, Fixture) +{ + tsnum.resize(1, 10); + for (unsigned int i = 0; i < 10; i++) + tsnum[0][i] = i; + + //timeSeries.width == 1 so returns 0 + BOOST_CHECK_EQUAL(ts.getSeriesIndex(5), 0); + + ts.resize(2, HOURS_PER_YEAR); + for (unsigned int i = 0; i < 10; i++) + BOOST_CHECK_EQUAL(ts.getSeriesIndex(i), i); +} + +BOOST_FIXTURE_TEST_CASE(getCoefficientWidth1, Fixture) +{ + fillColumn(0); + BOOST_CHECK_EQUAL(ts.getCoefficient(0, 12), 12); + BOOST_CHECK_EQUAL(ts.getCoefficient(0, 8750), 8750); +} + +BOOST_FIXTURE_TEST_CASE(getCoefficientWidth0, Fixture) +{ + ts.resize(0, HOURS_PER_YEAR); + BOOST_CHECK_EQUAL(ts.getCoefficient(0, 12), 0); + BOOST_CHECK_EQUAL(ts.getCoefficient(0, 8750), 0); +} + +BOOST_FIXTURE_TEST_CASE(getCoefficientNotInitialized, Fixture) +{ + ts.resize(4, HOURS_PER_YEAR); + fillTsnum(); + BOOST_CHECK_EQUAL(ts.getCoefficient(3, 12), 0); + BOOST_CHECK_EQUAL(ts.getCoefficient(3, 8750), 0); +} + +BOOST_FIXTURE_TEST_CASE(getCoefficientWidthMoreThan1, Fixture) +{ + ts.resize(5, HOURS_PER_YEAR); + fillTsnum(); + + fillColumn(3); + BOOST_CHECK_EQUAL(ts.getCoefficient(3, 12), 12); + BOOST_CHECK_EQUAL(ts.getCoefficient(3, 4858), 4858); + + fillColumnReverse(2); + BOOST_CHECK_EQUAL(ts.getCoefficient(2, 20), 8740); + BOOST_CHECK_EQUAL(ts.getCoefficient(2, 4567), HOURS_PER_YEAR - 4567); +} + +BOOST_FIXTURE_TEST_CASE(getColumn, Fixture) +{ + ts.resize(0, HOURS_PER_YEAR); + auto col = ts.getColumn(3); //emptyColumn + BOOST_CHECK_EQUAL(col[38], 0); + BOOST_CHECK_EQUAL(col[7463], 0); + + ts.resize(4, HOURS_PER_YEAR); + fillTsnum(); + fillColumn(2); + + col = ts.getColumn(2); + BOOST_CHECK_EQUAL(col[38], 38); + BOOST_CHECK_EQUAL(col[7463], 7463); +} + +BOOST_FIXTURE_TEST_CASE(operatorArray, Fixture) +{ + ts.resize(4, HOURS_PER_YEAR); + fillTsnum(); + auto* col = ts[2]; + col[27] = 12; + BOOST_CHECK_EQUAL(ts.getCoefficient(2, 27), 12); +} + +BOOST_FIXTURE_TEST_CASE(getCoefficientSpecificData, Fixture) +{ + ts.resize(2, 2); + fillTsnum(); + tsnum[0][0] = 1; + tsnum[0][1] = 0; + ts.timeSeries[0][0] = 12.5; + ts.timeSeries[0][1] = 74.74; + ts.timeSeries[1][0] = -57; + ts.timeSeries[1][1] = 29; + + BOOST_CHECK_EQUAL(ts.getCoefficient(1, 1), 74.74); + BOOST_CHECK_EQUAL(ts.getCoefficient(0, 0), -57); + BOOST_CHECK_EQUAL(ts.getCoefficient(1, 0), 12.5); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/libs/antares/study/test_study.cpp b/src/tests/src/libs/antares/study/test_study.cpp new file mode 100644 index 0000000000..91c8718140 --- /dev/null +++ b/src/tests/src/libs/antares/study/test_study.cpp @@ -0,0 +1,178 @@ +/* +** 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 study +#define BOOST_TEST_DYN_LINK +#define WIN32_LEAN_AND_MEAN +#include + +#include "antares/study/study.h" + +using namespace Antares::Data; + +/*! + * Study with one area named "A" + */ +struct OneAreaStudy +{ + OneAreaStudy() + { + areaA = study.areaAdd("A"); + } + + Study study; + Area* areaA; +}; + +BOOST_AUTO_TEST_SUITE(areas_operations) + +BOOST_AUTO_TEST_CASE(area_add) +{ + Study study; + Area* areaA = study.areaAdd("A"); + BOOST_CHECK(areaA != nullptr); + BOOST_CHECK(areaA->name == "A"); + BOOST_CHECK(areaA->id == "a"); +} + +BOOST_FIXTURE_TEST_CASE(area_rename, OneAreaStudy) +{ + BOOST_CHECK(study.areaRename(areaA, "B")); + BOOST_CHECK(areaA->name == "B"); + BOOST_CHECK(areaA->id == "b"); +} + +BOOST_FIXTURE_TEST_CASE(area_delete, OneAreaStudy) +{ + BOOST_CHECK(study.areas.size() == 1); + BOOST_CHECK(study.areaDelete(areaA)); + BOOST_CHECK(study.areas.empty()); +} + +BOOST_AUTO_TEST_SUITE_END() //areas + +BOOST_AUTO_TEST_SUITE(thermal_clusters_operations) + +BOOST_FIXTURE_TEST_CASE(thermal_cluster_add, OneAreaStudy) +{ + Study study; + Area& area = *study.areaAdd("A"); + auto newCluster = std::make_shared(&area); + newCluster->setName("Cluster"); + BOOST_CHECK(newCluster->name() == "Cluster"); + BOOST_CHECK(newCluster->id() == "cluster"); + + area.thermal.list.add(newCluster); + BOOST_CHECK(area.thermal.list.find("cluster") == newCluster.get()); + BOOST_CHECK(area.thermal.list.find("Cluster") == nullptr); +} + +/*! + * Study with: + * - one area named "A" + * - one thermal cluster named "Cluster" + */ +struct ThermalClusterStudy: public OneAreaStudy +{ + ThermalClusterStudy() + { + auto newCluster = std::make_shared(areaA); + newCluster->setName("Cluster"); + areaA->thermal.list.add(newCluster); + cluster = newCluster.get(); + } + + ThermalCluster* cluster; +}; + +BOOST_FIXTURE_TEST_CASE(thermal_cluster_rename, ThermalClusterStudy) +{ + BOOST_CHECK(study.clusterRename(cluster, "Renamed")); + BOOST_CHECK(cluster->name() == "Renamed"); + BOOST_CHECK(cluster->id() == "renamed"); +} + +BOOST_FIXTURE_TEST_CASE(thermal_cluster_delete, ThermalClusterStudy) +{ + BOOST_CHECK(areaA->thermal.list.find("cluster") == cluster); + areaA->thermal.list.remove("cluster"); + BOOST_CHECK(areaA->thermal.list.find("cluster") == nullptr); + BOOST_CHECK(areaA->thermal.list.empty()); +} + +BOOST_AUTO_TEST_SUITE_END() // thermal clusters + +BOOST_AUTO_TEST_SUITE(renewable_clusters_operations) + +BOOST_FIXTURE_TEST_CASE(renewable_cluster_add, OneAreaStudy) +{ + auto newCluster = std::make_shared(areaA); + newCluster->setName("WindCluster"); + BOOST_CHECK(newCluster->name() == "WindCluster"); + BOOST_CHECK(newCluster->id() == "windcluster"); + + areaA->renewable.list.add(newCluster); + BOOST_CHECK(areaA->renewable.list.find("windcluster") == newCluster.get()); + BOOST_CHECK(areaA->renewable.list.find("WindCluster") == nullptr); +} + + +/*! + * Study with: + * - one area named "A" + * - one renewable cluster named "WindCluster" + */ +struct RenewableClusterStudy : public OneAreaStudy +{ + RenewableClusterStudy() + { + areaA = study.areaAdd("A"); + auto newCluster = std::make_shared(areaA); + newCluster->setName("WindCluster"); + areaA->renewable.list.add(newCluster); + cluster = newCluster.get(); + } + + RenewableCluster* cluster; +}; + +BOOST_FIXTURE_TEST_CASE(renewable_cluster_rename, RenewableClusterStudy) +{ + BOOST_CHECK(study.clusterRename(cluster, "Renamed")); + BOOST_CHECK(cluster->name() == "Renamed"); + BOOST_CHECK(cluster->id() == "renamed"); +} + +BOOST_FIXTURE_TEST_CASE(renewable_cluster_delete, RenewableClusterStudy) +{ + BOOST_CHECK(areaA->renewable.list.find("windcluster") == cluster); + BOOST_CHECK(areaA->renewable.list.remove("windcluster")); + BOOST_CHECK(areaA->renewable.list.find("windcluster") == nullptr); + BOOST_CHECK(areaA->renewable.list.empty()); +} + +BOOST_AUTO_TEST_SUITE_END() //renewable clusters diff --git a/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp b/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp index 7748e7466d..8fb7c49d18 100644 --- a/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp +++ b/src/tests/src/libs/antares/study/thermal-price-definition/thermal-price-definition.cpp @@ -164,8 +164,7 @@ BOOST_FIXTURE_TEST_CASE(checkCo2_checkCO2CostColumnNumber_OK, FixtureFull) area->thermal.list.loadFromFolder(*study, folder, area); auto cluster = area->thermal.list.mapping["some cluster"]; - cluster->series = new DataSeriesCommon; - cluster->series->timeSeries.reset(3, 8760); + cluster->series.timeSeries.reset(3, 8760); area->thermal.prepareAreaWideIndexes(); @@ -180,8 +179,7 @@ BOOST_FIXTURE_TEST_CASE(checkCo2_checkCO2CostColumnNumber_KO, FixtureFull) area->thermal.list.loadFromFolder(*study, folder, area); auto cluster = area->thermal.list.mapping["some cluster"]; - cluster->series = new DataSeriesCommon; - cluster->series->timeSeries.reset(3, 8760); + cluster->series.timeSeries.reset(3, 8760); area->thermal.prepareAreaWideIndexes(); @@ -197,8 +195,7 @@ BOOST_FIXTURE_TEST_CASE(checkFuelAndCo2_checkColumnNumber_OK, FixtureFull) area->thermal.list.loadFromFolder(*study, folder, area); auto cluster = area->thermal.list.mapping["some cluster"]; - cluster->series = new DataSeriesCommon; - cluster->series->timeSeries.reset(3, 8760); + cluster->series.timeSeries.reset(3, 8760); area->thermal.prepareAreaWideIndexes(); diff --git a/src/tests/src/libs/antares/test_utils.cpp b/src/tests/src/libs/antares/test_utils.cpp index a4cb101c9e..d6de5507a2 100644 --- a/src/tests/src/libs/antares/test_utils.cpp +++ b/src/tests/src/libs/antares/test_utils.cpp @@ -18,6 +18,13 @@ T beautify(const T& in) { constexpr auto beautifyStd = beautify; constexpr auto beautifyYuni = beautify; +std::string transformNameToId(const AnyString& name) +{ + std::string res; + Antares::TransformNameIntoID(name, res); + return res; +} + } BOOST_AUTO_TEST_CASE(test_beautify_name_std) @@ -47,3 +54,10 @@ BOOST_AUTO_TEST_CASE(test_string_conversion) Yuni::String yuniConvertedBack = stdStr; BOOST_TEST(yuniConvertedBack == "hello"); } + +BOOST_AUTO_TEST_CASE(test_transform_name_into_id) +{ + BOOST_CHECK(transformNameToId("NA!ME") == "na me"); + BOOST_CHECK(transformNameToId("name!") == "name"); + BOOST_CHECK(transformNameToId("!name") == "name"); +} diff --git a/src/tests/src/libs/antares/writer/CMakeLists.txt b/src/tests/src/libs/antares/writer/CMakeLists.txt new file mode 100644 index 0000000000..5d0e479419 --- /dev/null +++ b/src/tests/src/libs/antares/writer/CMakeLists.txt @@ -0,0 +1,13 @@ +add_executable(test-writer) + +target_sources(test-writer PRIVATE test_zip_writer.cpp) + +target_link_libraries(test-writer + PRIVATE + Boost::unit_test_framework + Antares::result_writer + test_utils_unit + MINIZIP::minizip +) + +add_test(NAME writer COMMAND test-writer) 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..c934b0d316 --- /dev/null +++ b/src/tests/src/libs/antares/writer/test_zip_writer.cpp @@ -0,0 +1,128 @@ +/* +** 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 +#define BOOST_TEST_DYN_LINK +#include +#include + +#include "yuni/job/queue/service.h" +#include "antares/writer/i_writer.h" +#include "antares/writer/writer_factory.h" +#include "antares/benchmarking/DurationCollector.h" +#include "utils.h" + +extern "C" +{ +#include +#include +#include +#include +} + +using namespace Yuni::Job; +using Benchmarking::NullDurationCollector; +using Benchmarking::IDurationCollector; +using Antares::Solver::IResultWriter; + +// 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/simulation/tests-ts-numbers.cpp b/src/tests/src/solver/simulation/tests-ts-numbers.cpp index 13cd2a187f..132564294c 100644 --- a/src/tests/src/solver/simulation/tests-ts-numbers.cpp +++ b/src/tests/src/solver/simulation/tests-ts-numbers.cpp @@ -67,7 +67,6 @@ std::shared_ptr addClusterToArea(Area* area, const std::string& clu { auto cluster = std::make_shared(area); cluster->setName(clusterName); - cluster->series = new DataSeriesCommon(); addClusterToAreaList(area, cluster); @@ -120,18 +119,18 @@ BOOST_AUTO_TEST_CASE(two_areas_with_5_ready_made_ts_on_load___check_intra_modal_ // Area 1 Area* area_1 = addAreaToStudy(study, "Area 1"); area_1->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); - area_1->load.series->timeSeries.resize(5, 1); + area_1->load.series.timeSeries.resize(5, 1); // Area 2 Area* area_2 = addAreaToStudy(study, "Area 2"); area_2->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); - area_2->load.series->timeSeries.resize(5, 1); + area_2->load.series.timeSeries.resize(5, 1); BOOST_CHECK(Generate(*study)); // intra-modal for load : drawn TS numbers in all areas must be equal uint year = 0; - BOOST_CHECK_EQUAL(area_1->load.series->timeseriesNumbers[0][year], area_2->load.series->timeseriesNumbers[0][year]); + BOOST_CHECK_EQUAL(area_1->load.series.timeseriesNumbers[0][year], area_2->load.series.timeseriesNumbers[0][year]); } static bool intermodal_load_two_areas(unsigned width_area_1, unsigned width_area_2) @@ -144,12 +143,12 @@ static bool intermodal_load_two_areas(unsigned width_area_1, unsigned width_area // Area 1 Area* area_1 = addAreaToStudy(study, "Area 1"); - area_1->load.series->timeSeries.resize(width_area_1, 1); + area_1->load.series.timeSeries.resize(width_area_1, 1); area_1->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); // Area 2 Area* area_2 = addAreaToStudy(study, "Area 2"); - area_2->load.series->timeSeries.resize(width_area_2, 1); + area_2->load.series.timeSeries.resize(width_area_2, 1); area_2->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); return Generate(*study); @@ -180,10 +179,10 @@ BOOST_AUTO_TEST_CASE(two_areas_3_thermal_clusters_with_same_number_of_ready_made // ... Area 1 : thermal cluster 1 auto thCluster_11 = addClusterToArea(area_1, "th-cluster-11"); - thCluster_11->series->timeSeries.resize(4, 1); + thCluster_11->series.timeSeries.resize(4, 1); // ... Area 1 : thermal cluster 2 auto thCluster_12 = addClusterToArea(area_1, "th-cluster-12"); - thCluster_12->series->timeSeries.resize(4, 1); + thCluster_12->series.timeSeries.resize(4, 1); area_1->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -194,7 +193,7 @@ BOOST_AUTO_TEST_CASE(two_areas_3_thermal_clusters_with_same_number_of_ready_made // ... Area 2 : thermal cluster 1 auto thCluster_21 = addClusterToArea(area_2, "th-cluster-21"); - thCluster_21->series->timeSeries.resize(4, 1); + thCluster_21->series.timeSeries.resize(4, 1); area_2->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -202,8 +201,8 @@ BOOST_AUTO_TEST_CASE(two_areas_3_thermal_clusters_with_same_number_of_ready_made // TS number checks uint year = 0; - BOOST_CHECK_EQUAL(thCluster_12->series->timeseriesNumbers[0][year], thCluster_11->series->timeseriesNumbers[0][year]); - BOOST_CHECK_EQUAL(thCluster_21->series->timeseriesNumbers[0][year], thCluster_11->series->timeseriesNumbers[0][year]); + BOOST_CHECK_EQUAL(thCluster_12->series.timeseriesNumbers[0][year], thCluster_11->series.timeseriesNumbers[0][year]); + BOOST_CHECK_EQUAL(thCluster_21->series.timeseriesNumbers[0][year], thCluster_11->series.timeseriesNumbers[0][year]); } BOOST_AUTO_TEST_CASE(two_areas_2_thermal_clusters_with_respectively_4_4_ready_made_ts___check_intra_modal_consistency_OK) @@ -221,7 +220,7 @@ BOOST_AUTO_TEST_CASE(two_areas_2_thermal_clusters_with_respectively_4_4_ready_ma // ... Area 1 : thermal cluster 1 auto thCluster_11 = addClusterToArea(area_1, "th-cluster-11"); - thCluster_11->series->timeSeries.resize(4, 1); + thCluster_11->series.timeSeries.resize(4, 1); area_1->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -232,7 +231,7 @@ BOOST_AUTO_TEST_CASE(two_areas_2_thermal_clusters_with_respectively_4_4_ready_ma // ... Area 2 : thermal cluster 1 auto thCluster_21 = addClusterToArea(area_2, "th-cluster-21"); - thCluster_21->series->timeSeries.resize(4, 1); + thCluster_21->series.timeSeries.resize(4, 1); area_2->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -240,7 +239,7 @@ BOOST_AUTO_TEST_CASE(two_areas_2_thermal_clusters_with_respectively_4_4_ready_ma // TS number checks uint year = 0; - BOOST_CHECK_EQUAL(thCluster_21->series->timeseriesNumbers[0][year], thCluster_11->series->timeseriesNumbers[0][year]); + BOOST_CHECK_EQUAL(thCluster_21->series.timeseriesNumbers[0][year], thCluster_11->series.timeseriesNumbers[0][year]); } BOOST_AUTO_TEST_CASE(two_areas_3_thermal_clusters_with_different_number_of_ready_made_ts___check_intra_modal_consistency_KO) @@ -258,10 +257,10 @@ BOOST_AUTO_TEST_CASE(two_areas_3_thermal_clusters_with_different_number_of_ready // ... Area 1 : thermal cluster 1 auto thCluster_11 = addClusterToArea(area_1, "th-cluster-11"); - thCluster_11->series->timeSeries.resize(4, 1); + thCluster_11->series.timeSeries.resize(4, 1); // ... Area 1 : thermal cluster 2 auto thCluster_12 = addClusterToArea(area_1, "th-cluster-12"); - thCluster_12->series->timeSeries.resize(4, 1); + thCluster_12->series.timeSeries.resize(4, 1); area_1->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -272,7 +271,7 @@ BOOST_AUTO_TEST_CASE(two_areas_3_thermal_clusters_with_different_number_of_ready // ... Area 2 : thermal cluster 1 auto thCluster_21 = addClusterToArea(area_2, "th-cluster-21"); - thCluster_21->series->timeSeries.resize(3, 1); + thCluster_21->series.timeSeries.resize(3, 1); area_2->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -296,10 +295,10 @@ BOOST_AUTO_TEST_CASE(two_areas_3_renew_clusters_with_same_number_of_ready_made_t // ... Area 1 : renewable cluster 1 auto rnCluster_11 = addClusterToArea(area_1, "rn-cluster-11"); - rnCluster_11->series->timeSeries.resize(4, 1); + rnCluster_11->series.timeSeries.resize(4, 1); // ... Area 1 : renewable cluster 2 auto rnCluster_12 = addClusterToArea(area_1, "rn-cluster-12"); - rnCluster_12->series->timeSeries.resize(4, 1); + rnCluster_12->series.timeSeries.resize(4, 1); area_1->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -309,7 +308,7 @@ BOOST_AUTO_TEST_CASE(two_areas_3_renew_clusters_with_same_number_of_ready_made_t Area* area_2 = addAreaToStudy(study, "Area 2"); // ... Area 2 : renewable cluster 1 auto rnCluster_21 = addClusterToArea(area_2, "rn-cluster-21"); - rnCluster_21->series->timeSeries.resize(4, 1); + rnCluster_21->series.timeSeries.resize(4, 1); area_2->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -317,8 +316,8 @@ BOOST_AUTO_TEST_CASE(two_areas_3_renew_clusters_with_same_number_of_ready_made_t // TS number checks uint year = 0; - BOOST_CHECK_EQUAL(rnCluster_12->series->timeseriesNumbers[0][year], rnCluster_11->series->timeseriesNumbers[0][year]); - BOOST_CHECK_EQUAL(rnCluster_21->series->timeseriesNumbers[0][year], rnCluster_11->series->timeseriesNumbers[0][year]); + BOOST_CHECK_EQUAL(rnCluster_12->series.timeseriesNumbers[0][year], rnCluster_11->series.timeseriesNumbers[0][year]); + BOOST_CHECK_EQUAL(rnCluster_21->series.timeseriesNumbers[0][year], rnCluster_11->series.timeseriesNumbers[0][year]); } @@ -338,10 +337,10 @@ BOOST_AUTO_TEST_CASE(two_areas_2_renew_clusters_with_respectively_4_4_ready_made // ... Area 1 : renewable cluster 1 auto rnCluster_11 = addClusterToArea(area_1, "rn-cluster-11"); - rnCluster_11->series->timeSeries.resize(4, 1); + rnCluster_11->series.timeSeries.resize(4, 1); // ... Area 1 : renewable cluster 2 auto rnCluster_12 = addClusterToArea(area_1, "rn-cluster-12"); - rnCluster_12->series->timeSeries.resize(4, 1); + rnCluster_12->series.timeSeries.resize(4, 1); area_1->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -356,7 +355,7 @@ BOOST_AUTO_TEST_CASE(two_areas_2_renew_clusters_with_respectively_4_4_ready_made // TS number checks uint year = 0; - BOOST_CHECK_EQUAL(rnCluster_12->series->timeseriesNumbers[0][year], rnCluster_11->series->timeseriesNumbers[0][year]); + BOOST_CHECK_EQUAL(rnCluster_12->series.timeseriesNumbers[0][year], rnCluster_11->series.timeseriesNumbers[0][year]); } BOOST_AUTO_TEST_CASE(two_areas_3_renew_clusters_with_different_number_of_ready_made_ts___check_intra_modal_consistency_KO) @@ -375,10 +374,10 @@ BOOST_AUTO_TEST_CASE(two_areas_3_renew_clusters_with_different_number_of_ready_m // ... Area 1 : renewable cluster 1 auto rnCluster_11 = addClusterToArea(area_1, "rn-cluster-11"); - rnCluster_11->series->timeSeries.resize(4, 1); + rnCluster_11->series.timeSeries.resize(4, 1); // ... Area 1 : renewable cluster 2 auto rnCluster_12 = addClusterToArea(area_1, "rn-cluster-12"); - rnCluster_12->series->timeSeries.resize(3, 1); // Caution : number of TS different from previous cluster + rnCluster_12->series.timeSeries.resize(3, 1); // Caution : number of TS different from previous cluster area_1->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -389,7 +388,7 @@ BOOST_AUTO_TEST_CASE(two_areas_3_renew_clusters_with_different_number_of_ready_m // ... Area 2 : renewable cluster 1 auto rnCluster_21 = addClusterToArea(area_2, "rn-cluster-21"); - rnCluster_21->series->timeSeries.resize(4, 1); + rnCluster_21->series.timeSeries.resize(4, 1); area_2->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -414,10 +413,10 @@ BOOST_AUTO_TEST_CASE(one_area__load_wind_thermal_are_turned_to_inter_modal__same Area* area = addAreaToStudy(study, "Area"); // ... Load - area->load.series->timeSeries.resize(5, 1); // Ready made TS for load + area->load.series.timeSeries.resize(5, 1); // Ready made TS for load // ... Wind - area->wind.series->timeSeries.resize(5, 1); // Ready made TS for wind + area->wind.series.timeSeries.resize(5, 1); // Ready made TS for wind // ... Thermal study->parameters.timeSeriesToRefresh |= timeSeriesThermal; // Generated TS for thermal @@ -432,10 +431,10 @@ BOOST_AUTO_TEST_CASE(one_area__load_wind_thermal_are_turned_to_inter_modal__same // TS number checks uint year = 0; - uint drawnTsNbForLoad = area->load.series->timeseriesNumbers[0][year]; - BOOST_CHECK_EQUAL(area->wind.series->timeseriesNumbers[0][year], drawnTsNbForLoad); - BOOST_CHECK_EQUAL(thCluster_1->series->timeseriesNumbers[0][year], drawnTsNbForLoad); - BOOST_CHECK_EQUAL(thCluster_2->series->timeseriesNumbers[0][year], drawnTsNbForLoad); + uint drawnTsNbForLoad = area->load.series.timeseriesNumbers[0][year]; + BOOST_CHECK_EQUAL(area->wind.series.timeseriesNumbers[0][year], drawnTsNbForLoad); + BOOST_CHECK_EQUAL(thCluster_1->series.timeseriesNumbers[0][year], drawnTsNbForLoad); + BOOST_CHECK_EQUAL(thCluster_2->series.timeseriesNumbers[0][year], drawnTsNbForLoad); } BOOST_AUTO_TEST_CASE(one_area__load_wind_thermal_are_turned_to_inter_modal__same_nb_of_ts_except_1_for_load_check_inter_modal_consistency_OK) @@ -452,10 +451,10 @@ BOOST_AUTO_TEST_CASE(one_area__load_wind_thermal_are_turned_to_inter_modal__same Area* area = addAreaToStudy(study, "Area"); // ... Load - area->load.series->timeSeries.resize(1, 1); // Ready made TS for load + area->load.series.timeSeries.resize(1, 1); // Ready made TS for load // ... Wind - area->wind.series->timeSeries.resize(5, 1); // Ready made TS for wind + area->wind.series.timeSeries.resize(5, 1); // Ready made TS for wind // ... Thermal study->parameters.timeSeriesToRefresh |= timeSeriesThermal; // Generated TS for thermal @@ -470,10 +469,10 @@ BOOST_AUTO_TEST_CASE(one_area__load_wind_thermal_are_turned_to_inter_modal__same // TS number checks uint year = 0; - uint drawnTsNbForLoad = area->load.series->timeseriesNumbers[0][year]; - BOOST_CHECK_EQUAL(area->wind.series->timeseriesNumbers[0][year], drawnTsNbForLoad); - BOOST_CHECK_EQUAL(thCluster_1->series->timeseriesNumbers[0][year], drawnTsNbForLoad); - BOOST_CHECK_EQUAL(thCluster_2->series->timeseriesNumbers[0][year], drawnTsNbForLoad); + uint drawnTsNbForLoad = area->load.series.timeseriesNumbers[0][year]; + BOOST_CHECK_EQUAL(area->wind.series.timeseriesNumbers[0][year], drawnTsNbForLoad); + BOOST_CHECK_EQUAL(thCluster_1->series.timeseriesNumbers[0][year], drawnTsNbForLoad); + BOOST_CHECK_EQUAL(thCluster_2->series.timeseriesNumbers[0][year], drawnTsNbForLoad); } BOOST_AUTO_TEST_CASE(one_area__load_wind_thermal_are_turned_to_inter_modal__different_nb_of_ts____check_inter_modal_consistency_KO) @@ -490,10 +489,10 @@ BOOST_AUTO_TEST_CASE(one_area__load_wind_thermal_are_turned_to_inter_modal__diff Area* area = addAreaToStudy(study, "Area"); // ... Load - area->load.series->timeSeries.resize(5, 1); // Ready made TS for load + area->load.series.timeSeries.resize(5, 1); // Ready made TS for load // ... Wind - area->wind.series->timeSeries.resize(5, 1); // Ready made TS for wind + area->wind.series.timeSeries.resize(5, 1); // Ready made TS for wind // ... Thermal study->parameters.timeSeriesToRefresh |= timeSeriesThermal; // Generated TS for thermal @@ -523,12 +522,12 @@ BOOST_AUTO_TEST_CASE(one_area__load_renewable_are_turned_to_inter_modal__same_nb Area* area = addAreaToStudy(study, "Area"); // ... Load - area->load.series->timeSeries.resize(5, 1); // Ready made TS for load + area->load.series.timeSeries.resize(5, 1); // Ready made TS for load // ... Renewable // ... ... clusters auto rnCluster_1 = addClusterToArea(area, "rn-cluster-1"); - rnCluster_1->series->timeSeries.resize(5, 1); + rnCluster_1->series.timeSeries.resize(5, 1); area->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -536,7 +535,7 @@ BOOST_AUTO_TEST_CASE(one_area__load_renewable_are_turned_to_inter_modal__same_nb // TS number checks uint year = 0; - BOOST_CHECK_EQUAL(rnCluster_1->series->timeseriesNumbers[0][year], area->load.series->timeseriesNumbers[0][year]); + BOOST_CHECK_EQUAL(rnCluster_1->series.timeseriesNumbers[0][year], area->load.series.timeseriesNumbers[0][year]); } BOOST_AUTO_TEST_CASE(one_area__load_renewable_are_turned_to_inter_modal__different_nb_of_ts____check_inter_modal_consistency_KO) @@ -554,12 +553,12 @@ BOOST_AUTO_TEST_CASE(one_area__load_renewable_are_turned_to_inter_modal__differe Area* area = addAreaToStudy(study, "Area"); // ... Load - area->load.series->timeSeries.resize(5, 1); // Ready made TS for load + area->load.series.timeSeries.resize(5, 1); // Ready made TS for load // ... Renewable // ... ... clusters auto rnCluster_1 = addClusterToArea(area, "rn-cluster-1"); - rnCluster_1->series->timeSeries.resize(4, 1); + rnCluster_1->series.timeSeries.resize(4, 1); area->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -581,12 +580,12 @@ BOOST_AUTO_TEST_CASE(one_area__load_renewable_are_turned_to_inter_modal_with_res Area* area = addAreaToStudy(study, "Area"); // ... Load - area->load.series->timeSeries.resize(5, 1); // Ready made TS for load + area->load.series.timeSeries.resize(5, 1); // Ready made TS for load // ... Renewable // ... ... clusters auto rnCluster_1 = addClusterToArea(area, "rn-cluster-1"); - rnCluster_1->series->timeSeries.resize(1, 1); + rnCluster_1->series.timeSeries.resize(1, 1); area->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); @@ -622,9 +621,9 @@ BOOST_AUTO_TEST_CASE(load_wind_thermal_in_intra_and_inter_modal____check_all_ts_ // =============== Area* area_1 = addAreaToStudy(study, "Area 1"); // ... Load - area_1->load.series->timeSeries.resize(5, 1); // Ready made TS for load + area_1->load.series.timeSeries.resize(5, 1); // Ready made TS for load // ... Wind - area_1->wind.series->timeSeries.resize(5, 1); // Ready made TS for wind + area_1->wind.series.timeSeries.resize(5, 1); // Ready made TS for wind // ... Thermal auto thCluster_area_1 = addClusterToArea(area_1, "th-cluster-area-1"); @@ -635,9 +634,9 @@ BOOST_AUTO_TEST_CASE(load_wind_thermal_in_intra_and_inter_modal____check_all_ts_ // =============== Area* area_2 = addAreaToStudy(study, "Area 2"); // ... Load - area_2->load.series->timeSeries.resize(5, 1); // Ready made TS for load + area_2->load.series.timeSeries.resize(5, 1); // Ready made TS for load // ... Wind - area_2->wind.series->timeSeries.resize(5, 1); // Ready made TS for wind + area_2->wind.series.timeSeries.resize(5, 1); // Ready made TS for wind // ... Thermal auto thCluster_area_2 = addClusterToArea(area_2, "th-cluster-area-2"); @@ -649,12 +648,12 @@ BOOST_AUTO_TEST_CASE(load_wind_thermal_in_intra_and_inter_modal____check_all_ts_ // - inside an area // - for all areas uint year = 0; - uint referenceLoadTsNumber = area_1->load.series->timeseriesNumbers[0][year]; - BOOST_CHECK_EQUAL(area_2->load.series->timeseriesNumbers[0][year], referenceLoadTsNumber); - BOOST_CHECK_EQUAL(area_1->wind.series->timeseriesNumbers[0][year], referenceLoadTsNumber); - BOOST_CHECK_EQUAL(area_2->wind.series->timeseriesNumbers[0][year], referenceLoadTsNumber); - BOOST_CHECK_EQUAL(thCluster_area_1->series->timeseriesNumbers[0][year], referenceLoadTsNumber); - BOOST_CHECK_EQUAL(thCluster_area_2->series->timeseriesNumbers[0][year], referenceLoadTsNumber); + uint referenceLoadTsNumber = area_1->load.series.timeseriesNumbers[0][year]; + BOOST_CHECK_EQUAL(area_2->load.series.timeseriesNumbers[0][year], referenceLoadTsNumber); + BOOST_CHECK_EQUAL(area_1->wind.series.timeseriesNumbers[0][year], referenceLoadTsNumber); + BOOST_CHECK_EQUAL(area_2->wind.series.timeseriesNumbers[0][year], referenceLoadTsNumber); + BOOST_CHECK_EQUAL(thCluster_area_1->series.timeseriesNumbers[0][year], referenceLoadTsNumber); + BOOST_CHECK_EQUAL(thCluster_area_2->series.timeseriesNumbers[0][year], referenceLoadTsNumber); } BOOST_AUTO_TEST_CASE(check_all_drawn_ts_numbers_are_bounded_between_0_and_nb_of_ts) @@ -700,11 +699,11 @@ BOOST_AUTO_TEST_CASE(check_all_drawn_ts_numbers_are_bounded_between_0_and_nb_of_ // TS number checks : each energy drawn ts numbers are up-bounded with the number of TS of the related energy uint year = 0; - uint loadTsNumber = area->load.series->timeseriesNumbers[0][year]; - uint windTsNumber = area->wind.series->timeseriesNumbers[0][year]; - uint solarTsNumber = area->solar.series->timeseriesNumbers[0][year]; + uint loadTsNumber = area->load.series.timeseriesNumbers[0][year]; + uint windTsNumber = area->wind.series.timeseriesNumbers[0][year]; + uint solarTsNumber = area->solar.series.timeseriesNumbers[0][year]; uint hydroTsNumber = area->hydro.series->timeseriesNumbers[0][year]; - uint thermalTsNumber = thCluster->series->timeseriesNumbers[0][year]; + uint thermalTsNumber = thCluster->series.timeseriesNumbers[0][year]; auto binding_constraints_TS_number = study->bindingConstraintsGroups["dummy"]->timeseriesNumbers[0][year]; BOOST_CHECK(loadTsNumber < loadNumberOfTs); @@ -713,4 +712,4 @@ BOOST_AUTO_TEST_CASE(check_all_drawn_ts_numbers_are_bounded_between_0_and_nb_of_ BOOST_CHECK(hydroTsNumber < hydroNumberOfTs); BOOST_CHECK(thermalTsNumber < thermalNumberOfTs); BOOST_CHECK_LT(binding_constraints_TS_number, binding_constraints_number_of_TS); -} \ No newline at end of file +} diff --git a/src/tools/batchrun/CMakeLists.txt b/src/tools/batchrun/CMakeLists.txt index b0957b354a..3656f3d28d 100644 --- a/src/tools/batchrun/CMakeLists.txt +++ b/src/tools/batchrun/CMakeLists.txt @@ -39,6 +39,7 @@ set(BATCHRUN_LIBS antares-core #local.h yuni-static-core ${CMAKE_THREADS_LIBS_INIT} + Antares::args_helper Antares::study ) diff --git a/src/tools/batchrun/main.cpp b/src/tools/batchrun/main.cpp index 0f0000b9f5..8cf5a97261 100644 --- a/src/tools/batchrun/main.cpp +++ b/src/tools/batchrun/main.cpp @@ -35,7 +35,7 @@ #include #include #include -#include "../../ui/common/winmain.hxx" +#include #include #include #ifdef YUNI_OS_WINDOWS @@ -78,8 +78,8 @@ int main(int argc, char* argv[]) InitializeDefaultLocale(); logs.applicationName("batchrun"); - argv = AntaresGetUTF8Arguments(argc, argv); - + IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); + std::tie(argc, argv) = toUTF8ArgsTranslator.convert(); // Initializing the toolbox Antares::Resources::Initialize(argc, argv, true); diff --git a/src/tools/cleaner/CMakeLists.txt b/src/tools/cleaner/CMakeLists.txt index da5694f626..ea87db4a79 100644 --- a/src/tools/cleaner/CMakeLists.txt +++ b/src/tools/cleaner/CMakeLists.txt @@ -26,6 +26,7 @@ INSTALL(EXPORT antares-study-cleaner set(CLEANER_LIBS yuni-static-core + Antares::args_helper Antares::study Antares::sys antares-core #version.h diff --git a/src/tools/cleaner/main.cpp b/src/tools/cleaner/main.cpp index 3282ccbd8b..729bdb760f 100644 --- a/src/tools/cleaner/main.cpp +++ b/src/tools/cleaner/main.cpp @@ -28,7 +28,7 @@ #include #include #include -#include "../../ui/common/winmain.hxx" +#include #include #include #include @@ -97,8 +97,8 @@ int main(int argc, char* argv[]) InitializeDefaultLocale(); Antares::logs.applicationName("cleaner"); - argv = AntaresGetUTF8Arguments(argc, argv); - + IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); + std::tie(argc, argv) = toUTF8ArgsTranslator.convert(); String::Vector optInput; bool optPrintOnly = false; bool optMrProper = false; diff --git a/src/tools/config/CMakeLists.txt b/src/tools/config/CMakeLists.txt index c85d140d5b..f2d2a49add 100644 --- a/src/tools/config/CMakeLists.txt +++ b/src/tools/config/CMakeLists.txt @@ -30,6 +30,7 @@ INSTALL(EXPORT antares-config set(CONFIG_LIBS yuni-static-core + Antares::args_helper ${CMAKE_THREADS_LIBS_INIT} ) diff --git a/src/tools/config/main.cpp b/src/tools/config/main.cpp index 17a85efb8b..c4f34aecbc 100644 --- a/src/tools/config/main.cpp +++ b/src/tools/config/main.cpp @@ -29,7 +29,7 @@ #include #include #include -#include "../../ui/common/winmain.hxx" +#include #include #include #include @@ -44,8 +44,8 @@ int main(int argc, char* argv[]) InitializeDefaultLocale(); logs.applicationName("config"); - argv = AntaresGetUTF8Arguments(argc, argv); - + IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); + std::tie(argc, argv) = toUTF8ArgsTranslator.convert(); // Initializing the toolbox Antares::Resources::Initialize(argc, argv, true); diff --git a/src/tools/finder/CMakeLists.txt b/src/tools/finder/CMakeLists.txt index ef8b1ae4db..7d58acaf2f 100644 --- a/src/tools/finder/CMakeLists.txt +++ b/src/tools/finder/CMakeLists.txt @@ -28,6 +28,7 @@ INSTALL(EXPORT antares-study-finder set(FINDER_LIBS antares-core yuni-static-core + Antares::args_helper ${CMAKE_THREADS_LIBS_INIT} ) diff --git a/src/tools/finder/main.cpp b/src/tools/finder/main.cpp index 10dafea6bc..2b3e04c2b7 100644 --- a/src/tools/finder/main.cpp +++ b/src/tools/finder/main.cpp @@ -28,7 +28,7 @@ #include #include #include -#include "../../ui/common/winmain.hxx" +#include #include #include #include @@ -73,8 +73,8 @@ int main(int argc, char* argv[]) InitializeDefaultLocale(); logs.applicationName("finder"); - argv = AntaresGetUTF8Arguments(argc, argv); - + IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); + std::tie(argc, argv) = toUTF8ArgsTranslator.convert(); Yuni::String::Vector optInput; bool optExtra = false; bool optCSV = false; diff --git a/src/tools/updater/CMakeLists.txt b/src/tools/updater/CMakeLists.txt index ec70330b8e..6fd814588a 100644 --- a/src/tools/updater/CMakeLists.txt +++ b/src/tools/updater/CMakeLists.txt @@ -26,6 +26,7 @@ INSTALL(EXPORT antares-study-updater set(UPDATER_LIBS yuni-static-core + Antares::args_helper Antares::study Antares::sys antares-core #version.h diff --git a/src/tools/updater/main.cpp b/src/tools/updater/main.cpp index af67d4c190..4650493f7d 100644 --- a/src/tools/updater/main.cpp +++ b/src/tools/updater/main.cpp @@ -29,7 +29,7 @@ #include #include #include -#include "../../ui/common/winmain.hxx" +#include #include #include #include @@ -170,7 +170,8 @@ int main(int argc, char* argv[]) InitializeDefaultLocale(); logs.applicationName("updater"); - argv = AntaresGetUTF8Arguments(argc, argv); + IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); + std::tie(argc, argv) = toUTF8ArgsTranslator.convert(); String::Vector optInput; bool optCleanup = false; diff --git a/src/tools/vacuum/CMakeLists.txt b/src/tools/vacuum/CMakeLists.txt index b9c01826c0..34e4142e49 100644 --- a/src/tools/vacuum/CMakeLists.txt +++ b/src/tools/vacuum/CMakeLists.txt @@ -36,6 +36,7 @@ set(VACUUM_LIBS antares-fswalker yuni-static-core ${CMAKE_THREADS_LIBS_INIT} + Antares::args_helper Antares::study ) diff --git a/src/tools/vacuum/main.cpp b/src/tools/vacuum/main.cpp index c6ffd6bd5f..e88cc3ffe7 100644 --- a/src/tools/vacuum/main.cpp +++ b/src/tools/vacuum/main.cpp @@ -35,7 +35,7 @@ #include #include #include -#include "../../ui/common/winmain.hxx" +#include #include #include #include "modified-inode.h" @@ -247,7 +247,8 @@ int main(int argc, char** argv) InitializeDefaultLocale(); logs.applicationName("vacuum"); - argv = AntaresGetUTF8Arguments(argc, argv); + IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); + std::tie(argc, argv) = toUTF8ArgsTranslator.convert(); String::Vector optInput; String::Vector optEachFolderIn; uint optMaxDays = 90; // days diff --git a/src/tools/yby-aggregator/CMakeLists.txt b/src/tools/yby-aggregator/CMakeLists.txt index 3824b7ef1f..0c60a5cc33 100644 --- a/src/tools/yby-aggregator/CMakeLists.txt +++ b/src/tools/yby-aggregator/CMakeLists.txt @@ -48,6 +48,7 @@ INSTALL(EXPORT antares-ybyaggregator set(YBY_AGGREGATOR_LIBS antares-core #version.h + Antares::args_helper Antares::date Antares::logs yuni-static-core diff --git a/src/tools/yby-aggregator/main.cpp b/src/tools/yby-aggregator/main.cpp index 31664f797d..d44095d34e 100644 --- a/src/tools/yby-aggregator/main.cpp +++ b/src/tools/yby-aggregator/main.cpp @@ -28,7 +28,7 @@ #include #include #include -#include "../../ui/common/winmain.hxx" +#include #include #include #include @@ -602,8 +602,8 @@ int main(int argc, char* argv[]) if (not memory.initializeTemporaryFolder()) return EXIT_FAILURE; - argv = AntaresGetUTF8Arguments(argc, argv); - + IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); + std::tie(argc, argv) = toUTF8ArgsTranslator.convert(); // Load the local policy settings LocalPolicy::Open(); LocalPolicy::CheckRootPrefix(argv[0]); diff --git a/src/ui/action/handler/antares-study/area/timeseries.cpp b/src/ui/action/handler/antares-study/area/timeseries.cpp index a1070c0d4c..eebedab74a 100644 --- a/src/ui/action/handler/antares-study/area/timeseries.cpp +++ b/src/ui/action/handler/antares-study/area/timeseries.cpp @@ -137,42 +137,33 @@ bool DataTimeseries::performWL(Context& ctx) { case Data::timeSeriesLoad: { - ctx.area->load.series->timeSeries = source->load.series->timeSeries; - source->load.series->timeSeries.unloadFromMemory(); + ctx.area->load.series.timeSeries = source->load.series.timeSeries; + source->load.series.timeSeries.unloadFromMemory(); break; } case Data::timeSeriesSolar: { - ctx.area->solar.series->timeSeries = source->solar.series->timeSeries; - source->solar.series->timeSeries.unloadFromMemory(); + ctx.area->solar.series.timeSeries = source->solar.series.timeSeries; + source->solar.series.timeSeries.unloadFromMemory(); break; } case Data::timeSeriesWind: { - ctx.area->wind.series->timeSeries = source->wind.series->timeSeries; - source->wind.series->timeSeries.unloadFromMemory(); + ctx.area->wind.series.timeSeries = source->wind.series.timeSeries; + source->wind.series.timeSeries.unloadFromMemory(); break; } case Data::timeSeriesHydro: { - ctx.area->hydro.series->ror = source->hydro.series->ror; - ctx.area->hydro.series->storage = source->hydro.series->storage; - ctx.area->hydro.series->mingen = source->hydro.series->mingen; - - ctx.area->hydro.series->count = source->hydro.series->count; - - source->hydro.series->ror.unloadFromMemory(); - source->hydro.series->storage.unloadFromMemory(); - source->hydro.series->mingen.unloadFromMemory(); - + ctx.area->hydro.series->copyGenerationTS(*source->hydro.series); break; } case Data::timeSeriesThermal: { if (ctx.cluster && ctx.originalPlant && ctx.cluster != ctx.originalPlant) { - ctx.cluster->series->timeSeries = ctx.originalPlant->series->timeSeries; - ctx.originalPlant->series->timeSeries.unloadFromMemory(); + ctx.cluster->series.timeSeries = ctx.originalPlant->series.timeSeries; + ctx.originalPlant->series.timeSeries.unloadFromMemory(); } break; } diff --git a/src/ui/action/handler/antares-study/area/ts-node.cpp b/src/ui/action/handler/antares-study/area/ts-node.cpp index b9d3d81dfb..7906856692 100644 --- a/src/ui/action/handler/antares-study/area/ts-node.cpp +++ b/src/ui/action/handler/antares-study/area/ts-node.cpp @@ -110,7 +110,7 @@ bool NodeTimeseries::performWL(Context& ctx) case Data::timeSeriesThermal: if (ctx.cluster) { - ctx.cluster->series->timeSeries.reset(1, HOURS_PER_YEAR); + ctx.cluster->series.timeSeries.reset(1, HOURS_PER_YEAR); ctx.cluster->prepro->reset(); ctx.cluster->ecoInput.reset(); } diff --git a/src/ui/common/winmain.hxx b/src/ui/common/winmain.hxx deleted file mode 100644 index fc6fb3baf7..0000000000 --- a/src/ui/common/winmain.hxx +++ /dev/null @@ -1,71 +0,0 @@ -/* -** 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 - -#ifdef YUNI_OS_WINDOWS -#include -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN 1 -#endif -#include -#include -#include -#include -#endif - -#ifdef YUNI_OS_WINDOWS -char** AntaresGetUTF8Arguments(int argc, char**) -{ - wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc); - char** argvUTF8 = (char**)malloc(argc * sizeof(char*)); - for (int i = 0; i != argc; ++i) - { - const uint len = (uint)wcslen(wargv[i]); - const uint newLen = WideCharToMultiByte(CP_UTF8, 0, wargv[i], len, NULL, 0, NULL, NULL); - argvUTF8[i] = (char*)malloc((newLen + 1) * sizeof(char)); - memset(argvUTF8[i], 0, (newLen + 1) * sizeof(char)); - WideCharToMultiByte(CP_UTF8, 0, wargv[i], len, argvUTF8[i], newLen, NULL, NULL); - argvUTF8[i][newLen] = '\0'; - } - return argvUTF8; -} - -void FreeUTF8Arguments(int argc, char** argv) -{ - for (int i = 0; i != argc; ++i) - free(argv[i]); - free(argv); -} - -#else - -#define AntaresGetUTF8Arguments(ARGC, ARGV) ARGV - -#define FreeUTF8Arguments(ARGC, ARGV) - -#endif diff --git a/src/ui/simulator/cmake/application.cmake b/src/ui/simulator/cmake/application.cmake index b4d394621f..012acba2fb 100644 --- a/src/ui/simulator/cmake/application.cmake +++ b/src/ui/simulator/cmake/application.cmake @@ -54,8 +54,6 @@ SET(SRC_APPLICATION application/study.h application/study.cpp - # The main - ../common/winmain.hxx main.cpp ) @@ -72,7 +70,8 @@ target_link_libraries(antares-ui-application PRIVATE ${wxWidgets_LIBRARIES} antares-ui-common - antares-core + antares-core + Antares::args_helper Antares::sys Antares::study ) diff --git a/src/ui/simulator/main.cpp b/src/ui/simulator/main.cpp index 3780e5253e..bf36e9564a 100644 --- a/src/ui/simulator/main.cpp +++ b/src/ui/simulator/main.cpp @@ -29,7 +29,7 @@ #include "application/application.h" #include "application/main.h" #include -#include "../common/winmain.hxx" +#include #include #include #include @@ -54,7 +54,7 @@ int main(int argc, char* argv[]) return EXIT_FAILURE; // We have one or several arguments - argv = AntaresGetUTF8Arguments(argc, argv); + IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); // locale InitializeDefaultLocale(); @@ -76,7 +76,6 @@ int main(int argc, char* argv[]) // An error has occured if (options(argc, argv) == GetOpt::ReturnCode::error) { - FreeUTF8Arguments(argc, argv); return options.errors() ? 1 : 0; } @@ -84,7 +83,6 @@ int main(int argc, char* argv[]) if (optVersion) { std::cout << ANTARES_VERSION_STR << "\n"; - FreeUTF8Arguments(argc, argv); return 0; } } @@ -105,7 +103,6 @@ int main(int argc, char* argv[]) const int ret = wxEntry(argc, argv); LocalPolicy::Close(); - FreeUTF8Arguments(argc, argv); return ret; } diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/area/timeseries.h b/src/ui/simulator/toolbox/components/datagrid/renderer/area/timeseries.h index b9ed6f3576..17e0e62d2a 100644 --- a/src/ui/simulator/toolbox/components/datagrid/renderer/area/timeseries.h +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/area/timeseries.h @@ -42,10 +42,10 @@ namespace Datagrid { namespace Renderer { -class ATimeSeries : public Renderer::Matrix, public Renderer::ARendererArea +class ATimeSeries : public Renderer::Matrix, public Renderer::ARendererArea { public: - using AncestorType = Renderer::Matrix; + using AncestorType = Renderer::Matrix; public: ATimeSeries(wxWindow* control, Toolbox::InputSelector::Area* notifier); @@ -117,7 +117,7 @@ class ATimeSeries : public Renderer::Matrix, public Renderer::A class TimeSeriesLoad final : public ATimeSeries { public: - using AncestorType = Renderer::Matrix; + using AncestorType = Renderer::Matrix; public: TimeSeriesLoad(wxWindow* control, Toolbox::InputSelector::Area* notifier) : @@ -147,7 +147,7 @@ class TimeSeriesLoad final : public ATimeSeries protected: virtual void internalAreaChanged(Antares::Data::Area* area) { - matrix((area && CurrentStudyIsValid()) ? &(area->load.series->timeSeries) : NULL); + matrix((area && CurrentStudyIsValid()) ? &(area->load.series.timeSeries) : NULL); Renderer::ARendererArea::internalAreaChanged(area); } }; @@ -155,7 +155,7 @@ class TimeSeriesLoad final : public ATimeSeries class TimeSeriesSolar final : public ATimeSeries { public: - using AncestorType = Renderer::Matrix; + using AncestorType = Renderer::Matrix; public: TimeSeriesSolar(wxWindow* control, Toolbox::InputSelector::Area* notifier) : @@ -185,7 +185,7 @@ class TimeSeriesSolar final : public ATimeSeries protected: virtual void internalAreaChanged(Antares::Data::Area* area) { - matrix((area && CurrentStudyIsValid()) ? &(area->solar.series->timeSeries) : NULL); + matrix((area && CurrentStudyIsValid()) ? &(area->solar.series.timeSeries) : NULL); Renderer::ARendererArea::internalAreaChanged(area); } }; @@ -193,7 +193,7 @@ class TimeSeriesSolar final : public ATimeSeries class TimeSeriesWind final : public ATimeSeries { public: - using AncestorType = Renderer::Matrix; + using AncestorType = Renderer::Matrix; public: TimeSeriesWind(wxWindow* control, Toolbox::InputSelector::Area* notifier) : @@ -223,7 +223,7 @@ class TimeSeriesWind final : public ATimeSeries protected: virtual void internalAreaChanged(Antares::Data::Area* area) { - matrix((area && CurrentStudyIsValid()) ? &(area->wind.series->timeSeries) : NULL); + matrix((area && CurrentStudyIsValid()) ? &(area->wind.series.timeSeries) : NULL); Renderer::ARendererArea::internalAreaChanged(area); } }; @@ -231,7 +231,7 @@ class TimeSeriesWind final : public ATimeSeries class TimeSeriesHydroFatal final : public ATimeSeries { public: - using AncestorType = Renderer::Matrix; + using AncestorType = Renderer::Matrix; public: TimeSeriesHydroFatal(wxWindow* control, Toolbox::InputSelector::Area* notifier) : @@ -256,7 +256,7 @@ class TimeSeriesHydroFatal final : public ATimeSeries protected: virtual void internalAreaChanged(Antares::Data::Area* area) { - matrix((area && CurrentStudyIsValid()) ? &(area->hydro.series->ror) : NULL); + matrix((area && CurrentStudyIsValid()) ? &(area->hydro.series->ror.timeSeries) : NULL); Renderer::ARendererArea::internalAreaChanged(area); } }; @@ -264,7 +264,7 @@ class TimeSeriesHydroFatal final : public ATimeSeries class TimeSeriesHydroMod final : public ATimeSeries { public: - using AncestorType = Renderer::Matrix; + using AncestorType = Renderer::Matrix; public: TimeSeriesHydroMod(wxWindow* control, Toolbox::InputSelector::Area* notifier) : @@ -294,7 +294,7 @@ class TimeSeriesHydroMod final : public ATimeSeries protected: virtual void internalAreaChanged(Antares::Data::Area* area) { - matrix((area && CurrentStudyIsValid()) ? &(area->hydro.series->storage) : NULL); + matrix((area && CurrentStudyIsValid()) ? &(area->hydro.series->storage.timeSeries) : NULL); Renderer::ARendererArea::internalAreaChanged(area); } }; @@ -303,7 +303,7 @@ class TimeSeriesHydroMod final : public ATimeSeries class TimeSeriesHydroMinGen final : public ATimeSeries { public: - using AncestorType = Renderer::Matrix; + using AncestorType = Renderer::Matrix; TimeSeriesHydroMinGen(wxWindow* control, Toolbox::InputSelector::Area* notifier) : ATimeSeries(control, notifier) @@ -327,7 +327,7 @@ class TimeSeriesHydroMinGen final : public ATimeSeries private: void internalAreaChanged(Antares::Data::Area* area) override { - matrix((area && CurrentStudyIsValid()) ? &(area->hydro.series->mingen) : NULL); + matrix((area && CurrentStudyIsValid()) ? &(area->hydro.series->mingen.timeSeries) : NULL); Renderer::ARendererArea::internalAreaChanged(area); } }; @@ -419,7 +419,7 @@ class TimeSeriesThermalCluster final : public TimeSeriesCluster protected: void internalThermalClusterChanged(Antares::Data::ThermalCluster* cluster) { - matrix((CurrentStudyIsValid() && cluster) ? &(cluster->series->timeSeries) : NULL); + matrix((CurrentStudyIsValid() && cluster) ? &(cluster->series.timeSeries) : NULL); } void onStudyClosed() override; @@ -468,7 +468,7 @@ class TimeSeriesRenewableCluster final : public TimeSeriesCluster private: void internalRenewableClusterChanged(Antares::Data::RenewableCluster* cluster) { - matrix((CurrentStudyIsValid() && cluster) ? &(cluster->series->timeSeries) : NULL); + matrix((CurrentStudyIsValid() && cluster) ? &(cluster->series.timeSeries) : NULL); } void onStudyClosed() override; diff --git a/src/ui/simulator/windows/options/advanced/advanced.cpp b/src/ui/simulator/windows/options/advanced/advanced.cpp index 3b925d47ef..fa670c5ce1 100644 --- a/src/ui/simulator/windows/options/advanced/advanced.cpp +++ b/src/ui/simulator/windows/options/advanced/advanced.cpp @@ -338,7 +338,7 @@ void AdvancedParameters::onResetToDefault(void*) parameters.hydroPricing.hpMode = Data::hpHeuristic; parameters.power.fluctuations = Data::lssFreeModulations; parameters.shedding.policy = Data::shpShavePeaks; - parameters.unitCommitment.ucMode = Data::ucHeuristic; + parameters.unitCommitment.ucMode = Data::ucHeuristicFast; parameters.nbCores.ncMode = Data::ncAvg; parameters.renewableGeneration.rgModelling = Data::rgAggregated; @@ -806,52 +806,63 @@ void AdvancedParameters::onUnitCommitmentMode(Component::Button&, wxMenu& menu, wxMenuItem* it; wxString text; - text = wxStringFromUTF8(UnitCommitmentModeToCString(Data::ucHeuristic)); // Fast + text = wxStringFromUTF8(UnitCommitmentModeToCString(Data::ucHeuristicFast)); // Fast text << wxT(" [default]"); it = Menu::CreateItem(&menu, wxID_ANY, text, "images/16x16/tag.png"); menu.Connect(it->GetId(), wxEVT_COMMAND_MENU_SELECTED, - wxCommandEventHandler(AdvancedParameters::onSelectUCHeuristic), + wxCommandEventHandler(AdvancedParameters::onSelectUCHeuristicFast), nullptr, this); text.clear(); - text = wxStringFromUTF8(UnitCommitmentModeToCString(Data::ucMILP)); // Accurate + text = wxStringFromUTF8(UnitCommitmentModeToCString(Data::ucHeuristicAccurate)); // Accurate text << wxT(" (slow)"); it = Menu::CreateItem(&menu, wxID_ANY, text, "images/16x16/tag.png"); menu.Connect(it->GetId(), wxEVT_COMMAND_MENU_SELECTED, - wxCommandEventHandler(AdvancedParameters::onSelectUCMixedIntegerLinearProblem), + wxCommandEventHandler(AdvancedParameters::onSelectUCHeuristicAccurate), + nullptr, + this); + + text.clear(); + text = wxStringFromUTF8(UnitCommitmentModeToCString(Data::ucMILP)); // Accurate + text << wxT(" "); + it = Menu::CreateItem(&menu, wxID_ANY, text, "images/16x16/tag.png"); + menu.Connect(it->GetId(), + wxEVT_COMMAND_MENU_SELECTED, + wxCommandEventHandler(AdvancedParameters::onSelectUCMILP), nullptr, this); } -void AdvancedParameters::onSelectUCHeuristic(wxCommandEvent& /* evt */) +void AdvancedParameters::onSelectUCMode(Antares::Data::UnitCommitmentMode mode) { - auto& study = *GetCurrentStudy(); if (not CurrentStudyIsValid()) return; + auto study = GetCurrentStudy(); - if (study.parameters.unitCommitment.ucMode != Data::ucHeuristic) + if (study->parameters.unitCommitment.ucMode != mode) { - study.parameters.unitCommitment.ucMode = Data::ucHeuristic; + study->parameters.unitCommitment.ucMode = mode; MarkTheStudyAsModified(); refresh(); } } -void AdvancedParameters::onSelectUCMixedIntegerLinearProblem(wxCommandEvent& /* evt */) +void AdvancedParameters::onSelectUCHeuristicFast(wxCommandEvent& /* evt */) { - if (not CurrentStudyIsValid()) - return; - auto& study = *GetCurrentStudy(); + onSelectUCMode(Data::ucHeuristicFast); +} - if (study.parameters.unitCommitment.ucMode != Data::ucMILP) - { - study.parameters.unitCommitment.ucMode = Data::ucMILP; - MarkTheStudyAsModified(); - refresh(); - } +void AdvancedParameters::onSelectUCHeuristicAccurate(wxCommandEvent& /* evt */) +{ + onSelectUCMode(Data::ucHeuristicAccurate); +} + +void AdvancedParameters::onSelectUCMILP(wxCommandEvent& /* evt */) +{ + onSelectUCMode(Data::ucMILP); } void AdvancedParameters::onNumberOfCores(Component::Button&, wxMenu& menu, void*) diff --git a/src/ui/simulator/windows/options/advanced/advanced.h b/src/ui/simulator/windows/options/advanced/advanced.h index 15e274fae5..d888492400 100644 --- a/src/ui/simulator/windows/options/advanced/advanced.h +++ b/src/ui/simulator/windows/options/advanced/advanced.h @@ -98,8 +98,11 @@ class AdvancedParameters final : public wxDialog void onSelectSHPMinimizeDuration(wxCommandEvent& evt); void onUnitCommitmentMode(Component::Button&, wxMenu& menu, void*); - void onSelectUCHeuristic(wxCommandEvent& evt); - void onSelectUCMixedIntegerLinearProblem(wxCommandEvent& evt); + + void onSelectUCMode(Antares::Data::UnitCommitmentMode mode); + void onSelectUCHeuristicFast(wxCommandEvent& evt); + void onSelectUCHeuristicAccurate(wxCommandEvent& evt); + void onSelectUCMILP(wxCommandEvent& evt); void onNumberOfCores(Component::Button&, wxMenu& menu, void*); template