diff --git a/.github/ISSUE_TEMPLATE/support_request.md b/.github/ISSUE_TEMPLATE/support_request.md new file mode 100644 index 0000000000..9760b940dc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/support_request.md @@ -0,0 +1,14 @@ +--- +name: Request for support +about: Ask any question +title: '' +labels: help wanted + +--- + +**Your identity** +Your name, company, why you are interested in Antares-Simulator... +Any information that can help us understand the context of your request! + +**Question** +Your question, remark... \ No newline at end of file diff --git a/.github/workflows/centos7.yml b/.github/workflows/centos7.yml index b43fde4cd1..330df8e719 100644 --- a/.github/workflows/centos7.yml +++ b/.github/workflows/centos7.yml @@ -7,7 +7,6 @@ on: branches: - develop - dependabot/* - schedule: - cron: '21 2 * * *' workflow_call: @@ -24,6 +23,7 @@ env: IS_RELEASE: ${{ github.event_name == 'workflow_dispatch' }} IS_PUSH: ${{ github.event_name == 'push' }} REF: ${{ inputs.target_branch =='' && github.ref_name || inputs.target_branch}} + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true jobs: @@ -43,26 +43,50 @@ jobs: - name: Install gcc 10 run: | + # update mirrors, official centos7 is deprecated + sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo &&\ + sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo &&\ + sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo &&\ + yum update -y + + # not a typo, centos-release-scl is needed to install devtoolset-10 but introduce deprecated mirror + sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo &&\ + sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo &&\ + sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo + yum install -y centos-release-scl - yum install -y devtoolset-10-gcc* + yum install -y devtoolset-11-gcc* - - uses: ./.github/workflows/install-cmake-328 + - name: Install cmake 3.28 + run: pip3 install cmake==3.28.4 - - name: Init submodule + - name: Install VCPKG + # Note: we need to use environment variables instead of workflow variables + # because github messes up path variables when running in container, + # see https://github.com/actions/runner/issues/2058 run: | - git submodule update --init --remote src/antares-deps src/tests/resources/Antares_Simulator_Tests + git submodule update --init vcpkg && ./vcpkg/bootstrap-vcpkg.sh -disableMetrics + echo "VCPKG_ROOT=$GITHUB_WORKSPACE/vcpkg" >> $GITHUB_ENV + echo "VCPKG_CACHE_DIR=$GITHUB_WORKSPACE/vcpkg_cache" >> $GITHUB_ENV + echo "VCPKG_BINARY_SOURCES=clear;files,$GITHUB_WORKSPACE/vcpkg_cache,readwrite" >> $GITHUB_ENV + + - name: Restore vcpkg binary dir from cache + id: cache-vcpkg-binary + # Note: we are stuck with v3, because v4 is not compatible with oracle8 image + uses: actions/cache/restore@v3 + with: + path: ${{ env.VCPKG_CACHE_DIR }} + key: vcpkg-cache-centos7-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} + # Allows to restore a cache when deps have only partially changed (like adding a dependency) + restore-keys: vcpkg-cache-centos7- - - name: Download & extract precompiled deps at root + - name: Init submodule run: | - ANTARES_DEPS_VERSION=$(cut -d'"' -f4 antares-deps-version.json | grep -Ev '\{|\}') - cd / - wget https://github.com/AntaresSimulatorTeam/antares-deps/releases/download/v${ANTARES_DEPS_VERSION}/rte-antares-deps-centos7-Release.tar.gz - tar -xvf rte-antares-deps-centos7-Release.tar.gz - rm -rf rte-antares-deps-centos7-Release.tar.gz + git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests - name: Config OR-Tools URL run: | - echo "URL_ORTOOLS=https://github.com/rte-france/or-tools/releases/download/$(cat ortools_tag)/ortools_cxx_centos7_static_sirius.zip" >> $GITHUB_ENV + echo "URL_ORTOOLS=https://github.com/rte-france/or-tools-rte/releases/download/$(cat ortools_tag)/ortools_cxx_centos7_static_sirius.zip" >> $GITHUB_ENV - name: Download OR-Tools id: ortools @@ -75,29 +99,29 @@ jobs: - name: Install gh if needed if: ${{ env.IS_RELEASE == 'true' }} run: | - yum -y install dnf - dnf -y install 'dnf-command(config-manager)' - dnf -y config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo - dnf -y install gh - + wget https://github.com/cli/cli/releases/download/v2.52.0/gh_2.52.0_linux_amd64.rpm + rpm -i gh_2.52.0_linux_amd64.rpm + gh --version - name: Configure run: | - source /opt/rh/devtoolset-10/enable - cmake -B _build -S src \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DDEPS_INSTALL_DIR=/rte-antares-deps-Release \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_TESTING=ON \ - -DBUILD_not_system=OFF \ - -DBUILD_TOOLS=ON \ - -DBUILD_UI=OFF \ - -DCMAKE_PREFIX_PATH=${{ env.ORTOOLSDIR }}/install \ + source /opt/rh/devtoolset-11/enable + source /opt/rh/rh-git227/enable + cmake -B _build -S src \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/vcpkg/scripts/buildsystems/vcpkg.cmake \ + -DVCPKG_TARGET_TRIPLET=x64-linux-release \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=ON \ + -DBUILD_TOOLS=ON \ + -DBUILD_UI=OFF \ + -DCMAKE_PREFIX_PATH=${{ env.ORTOOLSDIR }}/install \ + - name: Build run: | - source /opt/rh/devtoolset-10/enable + source /opt/rh/devtoolset-11/enable source /opt/rh/rh-git227/enable cmake --build _build --config Release -j$(nproc) ccache -s @@ -122,16 +146,6 @@ jobs: cd _build cpack -G TGZ - - name: Installer TGZ push - uses: actions/upload-artifact@v3 - with: - path: _build/*.tar.gz - - - name: Installer RPM push - uses: actions/upload-artifact@v3 - with: - path: _build/*.rpm - - name: Publish assets if: ${{ env.IS_RELEASE == 'true' }} env: @@ -140,4 +154,10 @@ jobs: run: | gh release upload "$tag" _build/*.tar.gz _build/*.rpm - + - name: Cache vcpkg binary dir + if: always() + id: save-cache-vcpkg-binary + uses: actions/cache/save@v3 + with: + path: ${{ env.VCPKG_CACHE_DIR }} + key: vcpkg-cache-centos7-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 0000000000..8232f319c7 --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,31 @@ +name: Check cpp formatting using clang 18.1.3 + +on: + pull_request: + +jobs: + build: + name: clang-format + + runs-on: ubuntu-24.04 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Print version + run: clang-format --version + + - name: clang-format + run: cd src && ./format-code.sh + + - name: git diff + run: | + DIFF=`git status --porcelain` + if [[ $DIFF ]]; then + echo "The following files are not well formatted, please make sure to use clang-format 18.1.3" + echo "$DIFF" + exit 1 + else + echo "Code is well formatted, congrats !" + fi diff --git a/.github/workflows/cucumber-tests/action.yml b/.github/workflows/cucumber-tests/action.yml new file mode 100644 index 0000000000..475d3310b3 --- /dev/null +++ b/.github/workflows/cucumber-tests/action.yml @@ -0,0 +1,23 @@ +name: "Run cucumber tests" +description: "Run cucumber tests" +inputs: + feature: + description: 'Feature file or folder to run (default runs all features in "features" folder)' + required: false + default: 'features' + tags: + description: 'Tags to run (default skips tests marked @flaky)' + required: false + default: '~@flaky' +runs: + using: "composite" + steps: + - name: Install Python requirements + shell: bash + run: python3 -m pip install -r src/tests/cucumber/requirements.txt + + - name: Run tests + shell: bash + run: | + cd src/tests/cucumber + behave --tags ${{ inputs.tags }} ${{ inputs.feature }} diff --git a/.github/workflows/download-extract-precompiled-libraries-tgz/action.yml b/.github/workflows/download-extract-precompiled-libraries-tgz/action.yml index 00852138af..d6b87bcaa5 100644 --- a/.github/workflows/download-extract-precompiled-libraries-tgz/action.yml +++ b/.github/workflows/download-extract-precompiled-libraries-tgz/action.yml @@ -1,9 +1,6 @@ name: "Download extract .tgz precompiled libraries" description: "Download and extract .tgz precompiled libraries from antares-deps and antares-simulator repository" inputs: - antares-deps-version: - description: 'antares-deps version' - required: true os: description: 'operational system used for github action' required: true @@ -21,12 +18,6 @@ inputs: runs: using: "composite" steps: - - name: Download & extract antares-deps - shell: bash - run: | - wget https://github.com/AntaresSimulatorTeam/antares-deps/releases/download/v${{inputs.antares-deps-version}}/rte-antares-deps-${{inputs.os}}-${{inputs.buildtype}}.tar.gz - tar -xvf rte-antares-deps-${{inputs.os}}-${{inputs.buildtype}}.tar.gz - rm -rf rte-antares-deps-${{inputs.os}}-${{inputs.buildtype}}.tar.gz - name: Download & extract OR-Tools shell: bash diff --git a/.github/workflows/download-extract-precompiled-libraries-zip/action.yml b/.github/workflows/download-extract-precompiled-libraries-zip/action.yml index 745b76236c..52eec0beea 100644 --- a/.github/workflows/download-extract-precompiled-libraries-zip/action.yml +++ b/.github/workflows/download-extract-precompiled-libraries-zip/action.yml @@ -1,9 +1,6 @@ name: "Download extract .zip precompiled libraries" description: "Download and extract .zip precompiled libraries from antares-deps and antares-simulator repository" inputs: - antares-deps-version: - description: 'antares-deps version' - required: true os: description: 'operational system used for github action' required: true @@ -20,15 +17,7 @@ inputs: runs: using: "composite" - steps: - - name: Download & extract antares-deps - shell: bash - run: | - wget https://github.com/AntaresSimulatorTeam/antares-deps/releases/download/v${{inputs.antares-deps-version}}/rte-antares-deps-${{inputs.os}}-${{inputs.buildtype}}.zip - unzip rte-antares-deps-${{inputs.os}}-${{inputs.buildtype}}.zip - rm -rf rte-antares-deps-${{inputs.os}}-${{inputs.buildtype}}.zip - echo "${GITHUB_WORKSPACE}/rte-antares-deps-Release/bin" >> $GITHUB_PATH - + steps: - name: Download & extract OR-Tools shell: bash run: | diff --git a/.github/workflows/install-cmake-328/action.yml b/.github/workflows/install-cmake-328/action.yml index a6f111746c..1cf045dbee 100644 --- a/.github/workflows/install-cmake-328/action.yml +++ b/.github/workflows/install-cmake-328/action.yml @@ -1,4 +1,4 @@ -name: "Install cmake 3.28 using devtoolset 10" +name: "Install cmake 3.28 using devtoolset 10 if possible" description: "Download and install system wide cmake 3.28" runs: @@ -7,7 +7,7 @@ runs: - name: Build cmake shell: bash run: | - source /opt/rh/devtoolset-10/enable + source /opt/rh/devtoolset-10/enable || true # Ignore error if devtoolset-10 is not available yum -y install openssl-devel wget https://github.com/Kitware/CMake/releases/download/v3.28.2/cmake-3.28.2.tar.gz tar -xvf cmake-3.28.2.tar.gz diff --git a/.github/workflows/oracle8.yml b/.github/workflows/oracle8.yml index 82666b7876..e026b4246a 100644 --- a/.github/workflows/oracle8.yml +++ b/.github/workflows/oracle8.yml @@ -25,7 +25,6 @@ env: IS_PUSH: ${{ github.event_name == 'push' }} REF: ${{ inputs.target_branch =='' && github.ref_name || inputs.target_branch}} - jobs: build: @@ -50,11 +49,31 @@ jobs: - name: Checkout run: | - git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git -b ${{ env.REF }} . + git clone $GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git -b ${{ env.REF }} . + git config --global safe.directory '*' + + - name: Install VCPKG + # Note: we need to use environment variables instead of workflow variables + # because github messes up path variables when running in container, + # see https://github.com/actions/runner/issues/2058 + run: | + git submodule update --init vcpkg && ./vcpkg/bootstrap-vcpkg.sh -disableMetrics + echo "VCPKG_ROOT=$GITHUB_WORKSPACE/vcpkg" >> $GITHUB_ENV + echo "VCPKG_CACHE_DIR=$GITHUB_WORKSPACE/vcpkg_cache" >> $GITHUB_ENV + echo "VCPKG_BINARY_SOURCES=clear;files,$GITHUB_WORKSPACE/vcpkg_cache,readwrite" >> $GITHUB_ENV + + - name: Restore vcpkg binary dir from cache + id: cache-vcpkg-binary + uses: actions/cache/restore@v4 + with: + path: ${{ env.VCPKG_CACHE_DIR }} + key: vcpkg-cache-oracle8-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} + # Allows to restore a cache when deps have only partially changed (like adding a dependency) + restore-keys: vcpkg-cache-oracle8- - name: Config OR-Tools URL run: | - echo "ORTOOLS_URL=https://github.com/rte-france/or-tools/releases/download/$(cat ortools_tag)/ortools_cxx_oraclelinux-8_static_sirius.zip" >> $GITHUB_ENV + echo "ORTOOLS_URL=https://github.com/rte-france/or-tools-rte/releases/download/$(cat ortools_tag)/ortools_cxx_oraclelinux-8_static_sirius.zip" >> $GITHUB_ENV - name: Download & extract OR-Tools run: | @@ -65,9 +84,7 @@ jobs: rm ortools.zip - name: Init submodule - run: | - git config --global safe.directory '*' - git submodule update --init --remote src/antares-deps src/tests/resources/Antares_Simulator_Tests + run: git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests - name: Install dependencies run: | @@ -82,13 +99,15 @@ jobs: - name: Configure run: | - source /opt/rh/gcc-toolset-11/enable - cmake -B _build -S src \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_TESTING=OFF \ - -DBUILD_TOOLS=ON \ - -DBUILD_UI=OFF \ - -DCMAKE_PREFIX_PATH=${{ env.ORTOOLS_DIR }}/install + source /opt/rh/gcc-toolset-11/enable + cmake -B _build -S src \ + -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/vcpkg/scripts/buildsystems/vcpkg.cmake \ + -DVCPKG_TARGET_TRIPLET=x64-linux-release \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=ON \ + -DBUILD_TOOLS=ON \ + -DBUILD_UI=OFF \ + -DCMAKE_PREFIX_PATH=${{ env.ORTOOLS_DIR }}/install - name: Build run: | @@ -122,13 +141,15 @@ jobs: cpack -G TGZ - name: Installer TGZ push - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: + name: oracle-targz path: _build/*.tar.gz - name: Installer RPM push - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: + name: oracle-rpm path: _build/*.rpm - name: Publish assets @@ -138,3 +159,11 @@ jobs: tag: ${{ github.event.inputs.release_tag }} run: | gh release upload "$tag" _build/*.tar.gz _build/*.rpm + + - name: Cache vcpkg binary dir + if: always() + id: save-cache-vcpkg-binary + uses: actions/cache/save@v4 + with: + path: ${{ env.VCPKG_CACHE_DIR }} + key: vcpkg-cache-oracle8-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 9c061abe15..e6f1cf608f 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -1,7 +1,10 @@ name: SonarCloud on: - pull_request: + pull_request: + push: + branches: + - develop jobs: sonarcloud: @@ -15,18 +18,45 @@ jobs: env: SONAR_SERVER_URL: "https://sonarcloud.io" ORTOOLS_DIR: ${{ github.workspace }}/or-tools + # Caching strategy of VCPKG dependencies + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/vcpkg_cache,readwrite" + BUILD_WRAPPER_OUT_DIR: ${{ github.workspace }}/_build/output # Directory where build-wrapper output will be placed steps: + # Disk space on / is insufficient, leading to errors + # We use this 'hack' to remove unused stuff (android, dotnet, etc.) and change partition layout + - name: Maximize build space + uses: easimon/maximize-build-space@v10 + with: + root-reserve-mb: 5120 + swap-size-mb: 1024 + remove-dotnet: true + remove-android: true + remove-haskell: true + remove-codeql: true + - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Install VCPKG + run: git submodule update --init vcpkg && ./vcpkg/bootstrap-vcpkg.sh -disableMetrics + + - name: Restore vcpkg binary dir from cache + id: cache-vcpkg-binary + uses: actions/cache/restore@v4 + with: + path: ${{ github.workspace }}/vcpkg_cache + key: vcpkg-cache-ubuntu-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} + # Allows to restore a cache when deps have only partially changed (like adding a dependency) + restore-keys: vcpkg-cache-ubuntu- + - name: Config OR-Tools URL run: | - echo "ORTOOLS_URL=https://github.com/rte-france/or-tools/releases/download/$(cat ortools_tag)/ortools_cxx_ubuntu-20.04_static_sirius.zip" >> $GITHUB_ENV + echo "ORTOOLS_URL=https://github.com/rte-france/or-tools-rte/releases/download/$(cat ortools_tag)/ortools_cxx_ubuntu-20.04_static_sirius.zip" >> $GITHUB_ENV - name: Install sonar-scanner and build-wrapper - uses: SonarSource/sonarcloud-github-c-cpp@v2 + uses: SonarSource/sonarcloud-github-c-cpp@v3 - name: ccache uses: hendrikmuhs/ccache-action@v1.2 @@ -40,17 +70,9 @@ jobs: sudo apt-get install libboost-test-dev sudo apt-get install g++-10 gcc-10 - - 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}} @@ -69,9 +91,18 @@ jobs: python -m pip install --upgrade pip pip3 install -r src/tests/examples/requirements.txt + - name: Read simtest version + run: | + echo 'SIMTEST_JSON<> $GITHUB_ENV + cat ./simtest.json >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + + - name: Export simtest version + run: | + echo "SIMTEST=${{ fromJson(env.SIMTEST_JSON).version }}" >> $GITHUB_ENV + - name: Init submodule run: | - git submodule update --init src/antares-deps git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests - name: Configure @@ -81,18 +112,19 @@ jobs: -DCMAKE_C_COMPILER=/usr/bin/gcc-10 \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER=/usr/bin/g++-10 \ - -DDEPS_INSTALL_DIR=./rte-antares-deps-Debug \ + -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake \ + -DVCPKG_TARGET_TRIPLET=x64-linux-release \ -DCODE_COVERAGE=ON \ - -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="../install;${{ env.ORTOOLS_DIR }}/install" \ -DBUILD_TESTING=ON \ -DMZ_CODE_COVERAGE=ON \ - -DBUILD_not_system=OFF \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DPython3_EXECUTABLE='${{ steps.setup-python.outputs.python-path }}' - name: Build run: | - build-wrapper-linux-x86-64 --out-dir $GITHUB_WORKSPACE/_build/output cmake --build _build --config release -j$(nproc) + build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build _build --config Release -j$(nproc) - name: Test and generate coverage continue-on-error: true @@ -100,6 +132,14 @@ jobs: cd $GITHUB_WORKSPACE/_build ctest -C Release --output-on-failure -L "unit" + - name: Run short-tests + continue-on-error: true + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: short-tests + os: ${{ matrix.os }} + - name: Collect coverage into one XML report run: | gcovr --sonarqube --output coverage.xml @@ -108,4 +148,12 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: sonar-scanner --define sonar.host.url="${{ env.SONAR_SERVER_URL }}" + run: sonar-scanner --define sonar.host.url="${{ env.SONAR_SERVER_URL }}" --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" + + - name: Cache vcpkg binary dir + if: always() + id: save-cache-vcpkg-binary + uses: actions/cache/save@v4 + with: + path: ${{ github.workspace }}/vcpkg_cache + key: vcpkg-cache-ubuntu-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 0ee8848977..2c73097adb 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -29,7 +29,6 @@ env: RUN_EXTENDED_TESTS: ${{ github.event_name == 'schedule' || inputs.run-tests == 'true' }} REF: ${{ inputs.target_branch =='' && github.ref || inputs.target_branch}} VCPKG_ROOT: ${{ github.workspace }}/vcpkg - vcpkgPackages: yaml-cpp antlr4 boost-test triplet: x64-linux WX_CONFIG: /usr/bin/wx-config @@ -40,301 +39,327 @@ jobs: env: ORTOOLS_DIR: ${{ github.workspace }}/or-tools os: ubuntu-20.04 + # Caching strategy of VCPKG dependencies + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/vcpkg_cache,readwrite" runs-on: ubuntu-20.04 if: "!contains(github.event.head_commit.message, '[skip ci]')" steps: - - uses: actions/checkout@v4 - with: - ref: ${{ env.REF }} - - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: + - uses: actions/checkout@v4 + with: + ref: ${{ env.REF }} + + - name: Install VCPKG + run: git submodule update --init vcpkg && ./vcpkg/bootstrap-vcpkg.sh -disableMetrics + + - name: Restore vcpkg binary dir from cache + id: cache-vcpkg-binary + uses: actions/cache/restore@v4 + with: + path: ${{ github.workspace }}/vcpkg_cache + key: vcpkg-cache-ubuntu-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} + # Allows to restore a cache when deps have only partially changed (like adding a dependency) + restore-keys: vcpkg-cache-ubuntu- + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: key: ${{ env.os }} - - - name : Init VCPKG submodule - run: | - git submodule update --init vcpkg - - # Restore both vcpkg and its artifacts from the GitHub cache service. - - name: Restore vcpkg and its artifacts. - uses: actions/cache@v4 - with: - # The first path is the location of vcpkg (it contains the vcpkg executable and data files). - # The other paths starting with '!' are exclusions: they contain termporary files generated during the build of the installed packages. - path: | - ${{ env.VCPKG_ROOT }} - !${{ env.VCPKG_ROOT }}/buildtrees - !${{ env.VCPKG_ROOT }}/packages - !${{ env.VCPKG_ROOT }}/downloads - # The key is composed in a way that it gets properly invalidated: this must happen whenever vcpkg's Git commit id changes, or the list of packages changes. In this case a cache miss must happen and a new entry with a new key with be pushed to GitHub the cache service. - # The key includes: hash of the vcpkg.json file, the hash of the vcpkg Git commit id, and the used vcpkg's triplet. The vcpkg's commit id would suffice, but computing an hash out it does not harm. - # Note: given a key, the cache content is immutable. If a cache entry has been created improperly, in order the recreate the right content the key must be changed as well, and it must be brand new (i.e. not existing already). - key: | - ${{ hashFiles( 'vcpkg_manifest/vcpkg.json' ) }}-${{ hashFiles( '.git/modules/vcpkg/HEAD' )}}-${{ env.triplet }} - - - name: Install libraries - run: | - sudo apt-get update - sudo apt-get install uuid-dev libwxgtk3.0-gtk3-dev - sudo apt-get install g++-10 gcc-10 - - - name: export wxWidgets script - shell: bash - run: | - export WX_CONFIG=${{env.WX_CONFIG}} - - - name : Install deps with VCPKG - run: | - cd vcpkg - ./bootstrap-vcpkg.sh - vcpkg install ${{env.vcpkgPackages}} --triplet ${{env.triplet}} - rm -rf buildtrees packages downloads - shell: bash - - - 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/$(cat ortools_tag)/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: ${{env.os}} - ortools-url: ${{env.ORTOOLS_URL}} - ortools-dir: ${{env.ORTOOLS_DIR}} - - - name: Set up Python - id: setup-python - uses: actions/setup-python@v5 - with: - python-version: '3.12' - - - name: Install dependencies - run: | + - name: Install libraries + run: | + sudo apt-get update + sudo apt-get install uuid-dev libwxgtk3.0-gtk3-dev + sudo apt-get install g++-10 gcc-10 + + - name: Config OR-Tools URL + run: | + echo "ORTOOLS_URL=https://github.com/rte-france/or-tools-rte/releases/download/$(cat ortools_tag)/ortools_cxx_ubuntu-20.04_static_sirius.zip" >> $GITHUB_ENV + + - name: Download pre-compiled librairies + uses: ./.github/workflows/download-extract-precompiled-libraries-tgz + with: + os: ${{env.os}} + ortools-url: ${{env.ORTOOLS_URL}} + ortools-dir: ${{env.ORTOOLS_DIR}} + + - name: Set up Python + id: setup-python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - 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 - run: | - cmake -B _build -S src \ + - name: Configure + run: | + cmake -B _build -S src \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_C_COMPILER=/usr/bin/gcc-10 \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER=/usr/bin/g++-10 \ + -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake \ + -DVCPKG_TARGET_TRIPLET=x64-linux-release \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=ON \ + -DBUILD_TOOLS=ON \ + -DCMAKE_PREFIX_PATH=${{ env.ORTOOLS_DIR }}/install \ + -DPython3_EXECUTABLE="${{ env.Python3_ROOT_DIR }}/bin/python" + + - name: Build + run: | + cmake --build _build -j$(nproc) + + - name: Run API tests + run: | + cmake --install _build --prefix antares_install + cd src/api_client_example + cmake -B _build -S . \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DVCPKG_ROOT="${{env.VCPKG_ROOT}}" \ - -DVCPKG_TARGET_TRIPLET=${{ env.triplet }} \ -DCMAKE_C_COMPILER=/usr/bin/gcc-10 \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER=/usr/bin/g++-10 \ - -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 \ - -DPython3_EXECUTABLE="${{ env.Python3_ROOT_DIR }}/bin/python" - - - name: Build - run: | - cmake --build _build -j$(nproc) - - - # 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.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-named-mps - os: ${{ env.os }} - variant: "named-mps" - - - name: Run unfeasibility-related tests - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - run: | + -DCMAKE_TOOLCHAIN_FILE=${{github.workspace}}/vcpkg/scripts/buildsystems/vcpkg.cmake \ + -DVCPKG_TARGET_TRIPLET=x64-linux-release \ + -DCMAKE_PREFIX_PATH="${{github.workspace}}/rte-antares-deps-Release;${{github.workspace}}/install;${{ env.ORTOOLS_DIR }}/install;${{github.workspace}}/antares_install;${{github.workspace}}/rte-antares-deps-Release;${{github.workspace}}/_build/vcpkg_installed/x64-linux-release" + cmake --build _build -j$(nproc) cd _build - ctest -C Release --output-on-failure -R "^unfeasible$" + ctest -C Release --output-on-failure - - name: Run unit and end-to-end tests - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - run: | - cd _build - ctest -C Release --output-on-failure -L "unit|end-to-end" - - - name: Upload logs for failed tests - if: ${{ failure() }} - uses: actions/upload-artifact@v4 - with: - name: test-log - path: ${{ github.workspace }}/_build/Testing/Temporary/LastTest.log - - - name: Run tests about infinity on BCs RHS - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v830 - os: ${{ env.os }} - - - name: Run MILP with CBC - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-milp - variant: "milp-cbc" - os: ${{ env.os }} - - - name: Run tests introduced in v860 - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v860 - os: ${{ env.os }} - - - name: Run tests introduced in v870 - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v870 - os: ${{ env.os }} - - - name: Run tests introduced in v910 - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v910 - os: ${{ env.os }} - - - name: Run short-tests - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: short-tests - os: ${{ env.os }} - - - name: Run mps tests - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-mps - os: ${{ env.os }} - - - name: Run tests for adequacy patch (CSR) - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: adequacy-patch-CSR - os: ${{ env.os }} - - - name: Run parallel tests - if: ${{ env.RUN_EXTENDED_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-parallel - os: ${{ env.os }} - variant: "parallel" - - - name: Run 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: ${{ env.os }} - - - 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: ${{ env.os }} - - - 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: ${{ env.os }} - - - 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: ${{ env.os }} - - - name: Installer .deb creation - run: | - cd _build - cpack -G DEB + - name: Read simtest version + run: | + echo 'SIMTEST_JSON<> $GITHUB_ENV + cat ./simtest.json >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV - - name: .tar.gz creation - run: | - cd _build - cpack -G TGZ + - name: Export simtest version + run: | + echo "SIMTEST=${{ fromJson(env.SIMTEST_JSON).version }}" >> $GITHUB_ENV - - 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@v4 - with: - name: targz - path: _build/*.tar.gz - - - name: Installer deb upload push - uses: actions/upload-artifact@v4 - with: - name: deb - path: _build/*.deb - - - - name: Publish assets - if: ${{ env.IS_RELEASE == 'true' }} - env: - GITHUB_TOKEN: ${{ github.token }} - tag: ${{ github.event.inputs.release_tag }} - run: | - gh release upload "$tag" _build/*.tar.gz _build/*.deb + - name: Init submodule Antares_Simulator_Tests + run: | + git submodule update --init --remote --recursive src/tests/resources/Antares_Simulator_Tests + + - name: Init submodule Antares_Simulator_Tests_NR + run: | + git submodule update --init --remote --recursive src/tests/resources/Antares_Simulator_Tests_NR + + - name: Run named mps tests + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-named-mps + os: ${{ env.os }} + variant: "named-mps" + + - name: Run unfeasibility-related tests + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + run: | + cd _build + ctest -C Release --output-on-failure -R "^unfeasible$" + + - name: Run unit and end-to-end tests + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + run: | + cd _build + ctest -C Release --output-on-failure -L "unit|end-to-end" + + - name: Upload logs for failed tests + if: ${{ failure() }} + uses: actions/upload-artifact@v4 + with: + name: test-log + path: ${{ github.workspace }}/_build/Testing/Temporary/LastTest.log + + - name: Run tests about infinity on BCs RHS + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-v830 + os: ${{ env.os }} + + - name: Run MILP with CBC + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-milp + variant: "milp-cbc" + os: ${{ env.os }} + + - name: Run tests introduced in 8.6.0 + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-v860 + os: ${{ env.os }} + + - name: Run tests introduced in 8.7.0 + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-v870 + os: ${{ env.os }} + + - name: Run tests introduced in 9.1.0 + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-v910 + os: ${{ env.os }} + + - name: Run tests introduced in 9.2.0 + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-v920 + os: ${{ env.os }} + + - name: Run short-tests + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: short-tests + os: ${{ env.os }} + + - name: Run cucumber on short-tests + uses: ./.github/workflows/cucumber-tests + with: + feature: "features/short_tests.feature" + + - name: Run mps tests + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-mps + os: ${{ env.os }} + + - name: Run tests for adequacy patch (CSR) + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: adequacy-patch-CSR + os: ${{ env.os }} + + - name: Run parallel tests + if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-parallel + os: ${{ env.os }} + variant: "parallel" + + - name: Run tests for time series generator tool + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: ts-generator + os: ${{ env.os }} + variant: "tsgenerator" + + - name: Run medium-tests + if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: medium-tests + os: ${{ env.os }} + + - name: Run cucumber on medium-tests + uses: ./.github/workflows/cucumber-tests + with: + feature: "features/medium_tests.feature" + + - name: Run long-tests-1 + if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: long-tests-1 + os: ${{ env.os }} + + - name: Run long-tests-2 + if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: long-tests-2 + os: ${{ env.os }} + + - name: Run long-tests-3 + if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: long-tests-3 + os: ${{ env.os }} + + - name: Barrier + if: ${{ !success() }} + run: exit 1 + + - 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@v4 + with: + name: targz + path: _build/*.tar.gz + + - name: Installer deb upload push + uses: actions/upload-artifact@v4 + with: + name: deb + path: _build/*.deb + + + - name: Publish assets + if: ${{ env.IS_RELEASE == 'true' }} + env: + GITHUB_TOKEN: ${{ github.token }} + tag: ${{ github.event.inputs.release_tag }} + run: | + gh release upload "$tag" _build/*.tar.gz _build/*.deb + + - name: Cache vcpkg binary dir + if: always() + id: save-cache-vcpkg-binary + uses: actions/cache/save@v4 + with: + path: ${{ github.workspace }}/vcpkg_cache + key: vcpkg-cache-ubuntu-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} diff --git a/.github/workflows/windows-vcpkg.yml b/.github/workflows/windows-vcpkg.yml index e9bda8e410..05bafe3520 100644 --- a/.github/workflows/windows-vcpkg.yml +++ b/.github/workflows/windows-vcpkg.yml @@ -37,309 +37,332 @@ jobs: # Indicates the location of the vcpkg as a Git submodule of the project repository. VCPKG_ROOT: ${{ github.workspace }}/vcpkg ORTOOLS_DIR: ${{ github.workspace }}/or-tools - os: windows-latest - test-platform: windows-2022 - vcpkgPackages: wxwidgets boost-test yaml-cpp antlr4 - triplet: x64-windows + os: windows-2022 + vcpkgPackages: wxwidgets boost-test + triplet: x64-windows-release + # Caching strategy of VCPKG dependencies + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/vcpkg_cache,readwrite" runs-on: windows-latest steps: - - uses: actions/checkout@v4 - with: - ref: ${{ env.REF }} + - uses: actions/checkout@v4 + with: + ref: ${{ env.REF }} - - name: Config OR-Tools URL - run: | - echo "ORTOOLS_URL=https://github.com/rte-france/or-tools/releases/download/$(cat ortools_tag)/ortools_cxx_windows-latest_static_sirius.zip" >> $GITHUB_ENV - shell: bash + - name: Config OR-Tools URL + run: | + echo "ORTOOLS_URL=https://github.com/rte-france/or-tools-rte/releases/download/$(cat ortools_tag)/ortools_cxx_windows-latest_static_sirius.zip" >> $GITHUB_ENV + shell: bash - - name: Pre-requisites - shell: cmd - run: | + - name: Pre-requisites + shell: cmd + run: | choco install wget unzip zip --no-progress - # Downloads ccache, and copies it to "cl.exe" in order to trick cmake into using it, - # see ccache wiki for background on using it with MSVC: - # https://github.com/ccache/ccache/wiki/MS-Visual-Studio - - name: Install ccache - shell: bash - run: | - wget https://github.com/ccache/ccache/releases/download/v4.8.3/ccache-4.8.3-windows-x86_64.zip -O ccache.zip - unzip ccache.zip - rm ccache.zip - mv ccache-4.8.3-windows-x86_64 ccache - cp ccache/ccache.exe ccache/cl.exe - echo "${GITHUB_WORKSPACE}/ccache" >> $GITHUB_PATH - - - name: ccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: windows - - - name : Init VCPKG submodule - run: | - git submodule update --init vcpkg - - # Restore both vcpkg and its artifacts from the GitHub cache service. - - name: Restore vcpkg and its artifacts. - uses: actions/cache@v4 - with: - # The first path is the location of vcpkg (it contains the vcpkg executable and data files). - # The other paths starting with '!' are exclusions: they contain temporary files generated during the build of the installed packages. - path: | - ${{ env.VCPKG_ROOT }} - !${{ env.VCPKG_ROOT }}/buildtrees - !${{ env.VCPKG_ROOT }}/packages - !${{ env.VCPKG_ROOT }}/downloads - # The key is composed in a way that it gets properly invalidated: this must happen whenever vcpkg's Git commit id changes, or the list of packages changes. In this case a cache miss must happen and a new entry with a new key with be pushed to GitHub the cache service. - # The key includes: hash of the vcpkg.json file, the hash of the vcpkg Git commit id, and the used vcpkg's triplet. The vcpkg's commit id would suffice, but computing an hash out it does not harm. - # Note: given a key, the cache content is immutable. If a cache entry has been created improperly, in order the recreate the right content the key must be changed as well, and it must be brand new (i.e. not existing already). - key: | - ${{ hashFiles( 'vcpkg_manifest/vcpkg.json' ) }}-${{ hashFiles( '.git/modules/vcpkg/HEAD' )}}-${{ env.triplet }} - - - name : Install deps with VCPKG - run: | - cd vcpkg - ./bootstrap-vcpkg.sh - vcpkg install ${{env.vcpkgPackages}} --triplet ${{env.triplet}} - rm -rf buildtrees packages downloads - shell: bash - - - 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-zip - with: - antares-deps-version: ${{steps.antares-deps-version.outputs.prop}} - os: ${{env.os}} - ortools-url: ${{env.ORTOOLS_URL}} - ortools-dir: ${{env.ORTOOLS_DIR}} - - - name: Setup Python 3.12 - uses: actions/setup-python@v5 - id: setup-python - with: - architecture: 'x64' - python-version: '3.12' - - - name: Install pip dependencies if necessary - run: pip 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: Enable git longpaths - run: git config --system core.longpaths true - - - name: Configure - shell: bash - run: | - cmake -B _build -S src \ - -DDEPS_INSTALL_DIR=rte-antares-deps-Release \ - -DCMAKE_PREFIX_PATH="${{ env.ORTOOLS_DIR }}/install" \ - -DVCPKG_ROOT="${{env.VCPKG_ROOT}}" \ - -DVCPKG_TARGET_TRIPLET=${{ env.triplet }} \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_TESTING=OFF \ - -DBUILD_TOOLS=ON \ - -DBUILD_not_system=OFF \ - -DPython3_EXECUTABLE="${{ env.Python3_ROOT_DIR }}/python.exe" \ - -DCMAKE_VS_GLOBALS="CLToolExe=cl.exe;CLToolPath=${GITHUB_WORKSPACE}/ccache;TrackFileAccess=false;UseMultiToolTask=true;DebugInformationFormat=OldStyle" - - - name: Build - shell: bash - run: | - cmake --build _build --config Release -j$(nproc) - # 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.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-named-mps - os: ${{ env.test-platform }} - variant: "named-mps" - - - name: Run unfeasibility-related tests - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - run: | - cd _build - ctest -C Release --output-on-failure -R "^unfeasible$" - - - name: Run unit and end-to-end tests - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - run: | - cd _build - ctest -C Release --output-on-failure -L "unit|end-to-end" -LE ortools - - - name: Upload build on failure - if: ${{ failure() }} - uses: actions/upload-artifact@v4 - with: - name: MPS-diff - path: ${{ github.workspace }}/src/tests/mps - - - - name: Run tests for adequacy patch (CSR) - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: adequacy-patch-CSR - os: ${{ env.test-platform }} - - - name: Run tests about infinity on BCs RHS - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v830 - os: ${{ env.test-platform }} - - - name: Run MILP with CBC - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-milp - variant: "milp-cbc" - os: ${{ env.test-platform }} - - - name: Run tests introduced in v860 - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v860 - os: ${{ env.test-platform }} - - - name: Run tests introduced in v870 - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v870 - os: ${{ env.test-platform }} - - - name: Run tests introduced in v910 - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-v910 - os: ${{ env.test-platform }} - - - name: Run short-tests - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: short-tests - os: ${{ env.test-platform }} - - - name: Run mps tests - if: ${{ env.RUN_SIMPLE_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-mps - os: ${{ env.test-platform }} - - - name: Run parallel tests - if: ${{ env.RUN_EXTENDED_TESTS == 'true' }} - uses: ./.github/workflows/run-tests - with: - simtest-tag: ${{steps.simtest-version.outputs.prop}} - batch-name: valid-parallel - os: ${{ env.test-platform }} - variant: "parallel" - - - 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: ${{ env.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: ${{ env.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: ${{ env.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: ${{ env.test-platform }} - - - name: Solver archive creation - shell: bash - run: | - cd _build - zip -r antares-solver_windows.zip solver/Release/antares-solver.exe solver/Release/*.dll - - - name: NSIS Installer creation - shell: bash - run: | - rm -rf src/tests/resources/Antares_Simulator_Tests - cd _build - cpack -GNSIS - export NSIS_NAME=$(ls *.exe) - echo "NSIS_NAME=$NSIS_NAME" >> $GITHUB_ENV - - - name: Upload NSIS log on failure - if: ${{ failure() }} - uses: actions/upload-artifact@v4 - with: - name: NSISError.log - path: _build/_CPack_Packages/win64/NSIS/NSISOutput.log - - - name: .zip creation - run: | - cd _build - cpack -G ZIP - - - name: Installer upload - uses: actions/upload-artifact@v4 - with: - name: installer - path: _build/${{env.NSIS_NAME}} - - - name: Publish assets - if: ${{ env.IS_RELEASE == 'true' }} - env: - GITHUB_TOKEN: ${{ github.token }} - tag: ${{ github.event.inputs.release_tag }} - run: | - gh release upload "$tag" _build/*.zip _build/*.exe - shell: bash + # Downloads ccache, and copies it to "cl.exe" in order to trick cmake into using it, + # see ccache wiki for background on using it with MSVC: + # https://github.com/ccache/ccache/wiki/MS-Visual-Studio + - name: Install ccache + shell: bash + run: | + wget https://github.com/ccache/ccache/releases/download/v4.8.3/ccache-4.8.3-windows-x86_64.zip -O ccache.zip + unzip ccache.zip + rm ccache.zip + mv ccache-4.8.3-windows-x86_64 ccache + cp ccache/ccache.exe ccache/cl.exe + echo "${GITHUB_WORKSPACE}/ccache" >> $GITHUB_PATH + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: windows + + - name: Install VCPKG + shell: bash + run: | + git submodule update --init vcpkg && ./vcpkg/bootstrap-vcpkg.bat -disableMetrics + + - name: Restore vcpkg binary dir from cache + id: cache-vcpkg-binary + uses: actions/cache/restore@v4 + with: + path: ${{ github.workspace }}/vcpkg_cache + key: vcpkg-cache-windows-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} + # Allows to restore a cache when deps have only partially changed (like adding a dependency) + restore-keys: vcpkg-cache-windows- + + - name: Download pre-compiled librairies + uses: ./.github/workflows/download-extract-precompiled-libraries-zip + with: + os: windows-latest + ortools-url: ${{env.ORTOOLS_URL}} + ortools-dir: ${{env.ORTOOLS_DIR}} + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + id: setup-python + with: + architecture: 'x64' + python-version: '3.12' + + - name: Install pip dependencies if necessary + run: pip install -r src/tests/examples/requirements.txt + + - name: Init submodule Antares_Simulator_Tests + run: | + git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests + + - name: Init submodule Antares_Simulator_Tests_NR + run: | + git submodule update --init --remote src/tests/resources/Antares_Simulator_Tests_NR + + - name: Enable git longpaths + run: git config --system core.longpaths true + + - name: Configure + shell: bash + run: | + cmake -B _build -S src \ + -DCMAKE_PREFIX_PATH="${{ env.ORTOOLS_DIR }}/install" \ + -DVCPKG_ROOT="${{env.VCPKG_ROOT}}" \ + -DVCPKG_TARGET_TRIPLET=${{ env.triplet }} \ + -DCMAKE_TOOLCHAIN_FILE="${{ env.VCPKG_ROOT }}/scripts/buildsystems/vcpkg.cmake" \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_TESTING=ON \ + -DBUILD_TOOLS=ON \ + -DPython3_EXECUTABLE="${{ env.Python3_ROOT_DIR }}/python.exe" \ + -DCMAKE_VS_GLOBALS="CLToolExe=cl.exe;CLToolPath=${GITHUB_WORKSPACE}/ccache;TrackFileAccess=false;UseMultiToolTask=true;DebugInformationFormat=OldStyle" + + - name: Build + shell: bash + run: | + cmake --build _build --config Release -j$(nproc) + + - name: Read simtest version + shell: bash + run: | + echo 'SIMTEST_JSON<> $GITHUB_ENV + cat ./simtest.json >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + + - name: Export simtest version + shell: bash + run: | + echo "SIMTEST=${{ fromJson(env.SIMTEST_JSON).version }}" >> $GITHUB_ENV + + - name: Run named mps tests + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && ! cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-named-mps + os: ${{ env.os }} + variant: "named-mps" + + - name: Run unfeasibility-related tests + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && ! cancelled() }} + run: | + cd _build + ctest -C Release --output-on-failure -R "^unfeasible$" + + - name: Run unit and end-to-end tests + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && ! cancelled() }} + run: | + cd _build + ctest -C Release --output-on-failure -L "unit|end-to-end" -LE ortools + + - name: Upload build on failure + if: ${{ failure() }} + uses: actions/upload-artifact@v4 + with: + name: MPS-diff + path: ${{ github.workspace }}/src/tests/mps + + - name: Run tests for adequacy patch (CSR) + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && ! cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: adequacy-patch-CSR + os: ${{ env.os }} + + - name: Run tests about infinity on BCs RHS + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-v830 + os: ${{ env.os }} + + - name: Run MILP with CBC + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-milp + variant: "milp-cbc" + os: ${{ env.os }} + + - name: Run tests introduced in 8.6.0 + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-v860 + os: ${{ env.os }} + + - name: Run tests introduced in 8.7.0 + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-v870 + os: ${{ env.os }} + + - name: Run tests introduced in 9.1.0 + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-v910 + os: ${{ env.os }} + + - name: Run tests introduced in 9.2.0 + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-v920 + os: ${{ env.os }} + + - name: Run short-tests + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: short-tests + os: ${{ env.os }} + + - name: Run cucumber on short-tests + uses: ./.github/workflows/cucumber-tests + with: + feature: "features/short_tests.feature" + + - name: Run mps tests + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-mps + os: ${{ env.os }} + + - name: Run parallel tests + if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: valid-parallel + os: ${{ env.os }} + variant: "parallel" + + - name: Run tests for time series generator tool + if: ${{ env.RUN_SIMPLE_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: ts-generator + os: ${{ env.os }} + variant: "tsgenerator" + + - name: Run medium-tests + if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: medium-tests + os: ${{ env.os }} + + - name: Run cucumber on medium-tests + uses: ./.github/workflows/cucumber-tests + with: + feature: "features/medium_tests.feature" + + - name: Run long-tests-1 + if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: long-tests-1 + os: ${{ env.os }} + + - name: Run long-tests-2 + if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: long-tests-2 + os: ${{ env.os }} + + - name: Run long-tests-3 + if: ${{ env.RUN_EXTENDED_TESTS == 'true' && !cancelled() }} + uses: ./.github/workflows/run-tests + with: + simtest-tag: ${{ env.SIMTEST }} + batch-name: long-tests-3 + os: ${{ env.os }} + + - name: Barrier + if: ${{ !success() }} + run: exit 1 + + - name: Solver archive creation + shell: bash + run: | + cd _build + zip -r antares-solver_windows.zip solver/Release/antares-solver.exe solver/Release/*.dll + + - name: NSIS Installer creation + shell: bash + run: | + rm -rf src/tests/resources/Antares_Simulator_Tests + cd _build + cpack -GNSIS + export NSIS_NAME=$(ls *.exe) + echo "NSIS_NAME=$NSIS_NAME" >> $GITHUB_ENV + + - name: Upload NSIS log on failure + if: ${{ failure() }} + uses: actions/upload-artifact@v4 + with: + name: NSISError.log + path: _build/_CPack_Packages/win64/NSIS/NSISOutput.log + + - name: .zip creation + run: | + cd _build + cpack -G ZIP + + - name: Installer upload + uses: actions/upload-artifact@v4 + with: + name: installer + path: _build/${{env.NSIS_NAME}} + + - name: Publish assets + if: ${{ env.IS_RELEASE == 'true' }} + env: + GITHUB_TOKEN: ${{ github.token }} + tag: ${{ github.event.inputs.release_tag }} + run: | + gh release upload "$tag" _build/*.zip _build/*.exe + shell: bash + + - name: Cache vcpkg binary dir + if: always() + id: save-cache-vcpkg-binary + uses: actions/cache/save@v4 + with: + path: ${{ github.workspace }}/vcpkg_cache + key: vcpkg-cache-windows-${{ hashFiles('src/vcpkg.json', '.git/modules/vcpkg/HEAD') }} diff --git a/.gitmodules b/.gitmodules index 9bee42d242..16639d0fb1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ -[submodule "src/antares-deps"] - path = src/antares-deps - url = https://github.com/AntaresSimulatorTeam/antares-deps.git - branch = v2.0.2b [submodule "src/tests/resources/Antares_Simulator_Tests"] path = src/tests/resources/Antares_Simulator_Tests url = https://github.com/AntaresSimulatorTeam/Antares_Simulator_Tests.git @@ -9,3 +5,6 @@ [submodule "vcpkg"] path = vcpkg url = https://github.com/microsoft/vcpkg.git +[submodule "src/tests/resources/Antares_Simulator_Tests_NR"] + path = src/tests/resources/Antares_Simulator_Tests_NR + url = https://github.com/AntaresSimulatorTeam/Antares_Simulator_Tests_NR.git diff --git a/AUTHORS.txt b/AUTHORS.txt index 6c7df3d9cb..d7681f43e1 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -7,16 +7,20 @@ Michael Boulade V4-V6 Michel Doquet V1-V7 Damien Gerard V2-V5 Robert Gonzalez V2-V5 -Jean-Marie Kerloch V7-V8 +Jean-Marie Kerloch V7-V8 Sylvain Marandon V6-V7 Eric Momot V1-V2 Papa Ndiaye V5-V7 -Florian Omnes V7-V8 -Guillaume Pierre V5-V8 +Florian Omnes V7-* +Guillaume Pierre V5-* Andrea Sgattoni V6-V8 Frederique Verrier V1-V2 Li Wu V5 - +Vincent Payet V8-* +Jason Marechal V8-* +Abdoulbari Zakir V8-* +Sylvain Leclerc V8-* + Artwork ======= diff --git a/README.md b/README.md index df15f52b86..bc31a675f0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Antares Simulator + [![Status][ubuntu_ci_svg]][ubuntu_ci_link] [![Status][windows_ci_svg]][windows_ci_link] [![Status][centos_ci_svg]][centos_ci_link] @@ -42,43 +43,47 @@ The GUI is deprecated in favor of [Antares Web](https://antares-web.readthedocs. This software suite has been tested under: -* Ubuntu 20.04 [![Status][ubuntu_ci_svg]][ubuntu_ci_link] -* Microsoft Windows with Visual Studio 2022 (64-bit) [![Status][windows_ci_svg]][windows_ci_link] -* Centos7 [![Status][centos_ci_svg]][centos_ci_link] -* Oracle Linux [![Status][oraclelinux_ci_svg]][oraclelinux_ci_link] +* Ubuntu 20.04 [![Status][ubuntu_ci_svg]][ubuntu_ci_link] +* Microsoft Windows with Visual Studio 2022 (64-bit) [![Status][windows_ci_svg]][windows_ci_link] +* Centos7 [![Status][centos_ci_svg]][centos_ci_link] +* Oracle Linux [![Status][oraclelinux_ci_svg]][oraclelinux_ci_link] Antares Simulator is built using CMake. -For installation instructions, please visit the [documentation website](https://antares-simulator.readthedocs.io/) +For installation instructions, please visit the [documentation website](https://antares-simulator.readthedocs.io/) or [its sources](docs/developer-guide/0-Introduction.md). # Source Code Content -* [AUTHORS](AUTHORS.txt) - Antares Simulator authors -* [CERTIFICATE](CERTIFICATE.txt) - A standard DCO that has to be signed by every contributor -* [CONTRIBUTING](CONTRIBUTING.md) - How to submit patches and discuss code evolutions +* [AUTHORS](AUTHORS.txt) - Antares Simulator authors +* [CERTIFICATE](CERTIFICATE.txt) - A standard DCO that has to be signed by every contributor +* [CONTRIBUTING](CONTRIBUTING.md) - How to submit patches and discuss code evolutions * [COPYING](COPYING.txt) - The MPL v2 license. * [NEWS](NEWS.md) - Important modifications between the releases. * [README](README.md) - This file. * [ROADMAP](ROADMAP.txt) - Main orientations for further developments * [THANKS](THANKS.txt) - Attribution notices for external libraries and contributors. -* [resources/](resources) - Free sample data sets. +* [resources/](resources) - Free sample data sets. * [src/analyzer/](src/analyzer) - source code for the statistical analysis of historical time-series. * [src/cmake/](src/cmake) - files for initializing a solution ready for compilation. -* [src/distrib/](src/distrib) - system redistributable libraries Win(x64,x86),unix. -* [src/ext/](src/ext) - third party libraries used by Antares_Simulator: libYuni, Sirius_Solver. -* [src/libs/](src/libs) - miscellaneous Antares_Simulator libraries. +* [src/distrib/](src/distrib) - system redistributable libraries Win(x64,x86),unix. +* [src/ext/](src/ext) - third party libraries used by Antares_Simulator: libYuni, Sirius_Solver. +* [src/libs/](src/libs) - miscellaneous Antares_Simulator libraries. * [src/solver/](src/solver) - simulation and optimization part. * [src/tools/](src/tools) - miscellaneous tools for dataset management. * [src/ui/](src/ui) - Graphic user interface. [ubuntu_ci_svg]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/workflows/Ubuntu%20CI%20(push%20and/or%20release)/badge.svg -[ubuntu_ci_link]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions?query=workflow%3A"Ubuntu%20CI%20(push%20and/or%20release)" + +[ubuntu_ci_link]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions/workflows/ubuntu.yml [windows_ci_svg]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/workflows/Windows%20CI%20(VCPKG%20and%20pre-compiled)/badge.svg -[windows_ci_link]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions?query=workflow%3A"Windows%20CI%20(VCPKG%20and%20pre-compiled)" + +[windows_ci_link]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions/workflows/windows-vcpkg.yml [centos_ci_svg]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/workflows/Centos7%20CI%20(push%20and/or%20release)/badge.svg -[centos_ci_link]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions?query=workflow%3A"Centos7%20CI%20(push%20and/or%20release)" + +[centos_ci_link]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions/workflows/centos7.yml [oraclelinux_ci_svg]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/workflows/Oracle%208%20CI%20(push%20and/or%20release)/badge.svg -[oraclelinux_ci_link]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions?query=workflow%3A"Oracle%208%20CI%20(push%20and/or%20release)" + +[oraclelinux_ci_link]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions/workflows/oracle8.yml diff --git a/antares-deps-version.json b/antares-deps-version.json deleted file mode 100644 index ced7f5add0..0000000000 --- a/antares-deps-version.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "antares_deps_version": "2.0.2b" -} diff --git a/docs/Architecture_Decision_Records/Expose_cpp_API.md b/docs/Architecture_Decision_Records/Expose_cpp_API.md index bae68cd5b4..fcc11c8a93 100644 --- a/docs/Architecture_Decision_Records/Expose_cpp_API.md +++ b/docs/Architecture_Decision_Records/Expose_cpp_API.md @@ -4,11 +4,11 @@ ## Context -Some clients (e.g. Xpansion) would prefer to use a library than a CLI tool. Exposing a library require exposing a public API. -The API can be exposed either as pure C or as C++. -A C API can always be developped as a facade on top of a C++ API. -C++ API will not have to care about ABI compatibility because Simulator lib will be provided as static, meaning a client -upgrading would need to be recompiled and relink with the new lib version. +Several clients, such as Xpansion, express a preference for utilizing a library over a command-line interface (CLI) tool. Exposing a library necessitates the exposure of a public API. + +This API can be presented in either pure C or C++. It's worth noting that a C API can always serve as a facade atop a C++ API. + +In the case of a C++ API, concerns regarding ABI compatibility are alleviated, as the Simulator library is provided in a static form. Consequently, when a client upgrades, they would simply need to recompile and relink with the new version of the library. ## Decision diff --git a/docs/Architecture_Decision_Records/separate_install_exe_api.md b/docs/Architecture_Decision_Records/separate_install_exe_api.md new file mode 100644 index 0000000000..3a9662ec1d --- /dev/null +++ b/docs/Architecture_Decision_Records/separate_install_exe_api.md @@ -0,0 +1,25 @@ +# Expose public C++ API + +## Status: Rejected [2024/04/11] + +## Context + +Originally, there exists a single install target designated to deploy the diverse Antares executables, predominantly packaged within the release assets. However, there's a rationale behind avoiding the creation of a unified package containing both executables and libraries, given that they cater to distinct user demographics. This mirrors the flexibility offered by package managers such as apt, where users can opt to install binary packages and separate development (devel) packages according to their requirements. + +## Decision + +Split installation into two targets + +Produce different assets/packages for each install targets. + + +## Consequences + +* Mutltiplication of assets +* Two install targets to manage +* Users of executable not "polluted" by libraries + +## Reason for rejection + +The decision was rejected because it was deemed unnecessary to split the installation targets. It adds +some difficulties for few benefits at the moment \ No newline at end of file diff --git a/docs/developer-guide/1-Development-requirements.md b/docs/developer-guide/1-Development-requirements.md index 7378d198cc..02c0896f33 100644 --- a/docs/developer-guide/1-Development-requirements.md +++ b/docs/developer-guide/1-Development-requirements.md @@ -11,13 +11,17 @@ The compilation of *Antares Simulator* requires C++17 support. === "Centos" By default, GCC version on Centos is old. - Some external repositories must be enabled depedning on your version of the OS: + Some external repositories must be enabled depending on your version of the OS: #### Centos 7 You must enable the EPEL repository: ``` sudo yum install epel-release - sudo yum install centos-release-scl + sudo yum install git redhat-lsb-core make wget centos-release-scl scl-utils rpm-build + sudo yum install devtoolset-10-gcc* + + scl enable devtoolset-10 bash + source /opt/rh/rh-git227/enable ``` #### Centos 8 @@ -25,8 +29,8 @@ The compilation of *Antares Simulator* requires C++17 support. ``` sudo yum install dnf-plugins-core sudo yum config-manager --set-enabled PowerTools - sudo yum install devtoolset-9 - scl enable devtoolset-9 bash + sudo yum install devtoolset-10 + scl enable devtoolset-10 bash ``` === "Ubuntu/Debian" diff --git a/docs/developer-guide/2-Dependencies-install.md b/docs/developer-guide/2-Dependencies-install.md index 45a96e08f0..1177228e6a 100644 --- a/docs/developer-guide/2-Dependencies-install.md +++ b/docs/developer-guide/2-Dependencies-install.md @@ -10,94 +10,61 @@ toc_depth: 2 - [OR-Tools](https://github.com/rte-france.com/or-tools) (fork from [Google](https://github.com/google/or-tools)) - [wxWidgets](https://github.com/wxWidgets/wxWidgets) (Only for the complete Antares Simulator solution with GUI) -- [Boost](https://www.boost.org/) libraries: test (Only for unit tests) +- [minizip](https://github.com/zlib-ng/minizip-ng) library, with its dependency zlib +- [Boost](https://www.boost.org/) libraries: header libraries and boost-test library +- [libuuid](https://linux.die.net/man/3/libuuid) on Linux systems -These third-party libraries can be installed: -- by building them from sources (see [here](3-Build.md) for more information) -- or using a package manager. +We favor using [vcpkg](https://github.com/microsoft/vcpkg) for building and installing most of those dependencies, +see [build instructions](3-Build.md) which explain how it integrates with CMake build. +However, we still have a few exceptions that must be installed in a different way, see next sections. -## Install with package manager +Although not encouraged, it's still possible to install those dependencies yourself and add +their installation path to your `CMAKE_PREFIX_PATH`. -=== "Windows" +## OR-Tools - For Windows we will use [vcpkg](https://github.com/microsoft/vcpkg) to download and compile the libraries. vcpkg is available as a submodule in *ANTARES*. - - You must install the corresponding [vcpkg-triplet](https://vcpkg.readthedocs.io/en/latest/users/integration/#triplet-selection) depending on Antares version and libraries load: - - - ``x64-windows`` : 64 bits version with dynamic libraries load - - ``x86-windows`` : 32 bits version with dynamic libraries load - - ``x64-windows-static``: 64 bits version with static libraries load - - ``x86-windows-static``: 32 bits version with static libraries load - - The vcpkg-triplet used will be named [vcpg-triplet] later in this document. - - - Init submodule and install vcpkg - - ``` - git submodule update --init vcpkg - cd vcpkg - .\bootstrap-vcpkg.bat - ``` - - Note: - > all vcpkg command further described must be run from vcpkg folder. This folder will be named [vcpkg_root] later in this document. +OR-Tools may be installed in one of 2 ways: + +1. **As a pre-compiled dependency** + + You can [download](https://github.com/rte-france/or-tools/releases) a precompiled OR-Tools archive that contains headers & static libraries. + Please note that dynamic linking with OR-Tools is only supported in Linux. - - Install dependencies - ``` - cd vcpkg - vcpkg install wxwidgets boost-test --triplet [vcpg-triplet] - ``` + Decompress the archive, and provide its path as a `CMAKE_PREFIX_PATH`. + +2. **As part of the build** + + You may enable the `BUILD_ORTOOLS` configuration option to build it from source during Antares build, + as documented in [build instructions](3-Build.md). + + The drawback of this second approach is that OR-Tools may need to be built again when you + run again a cmake configure step, therefore it's not advised for developers. + + +## Linux: libuuid and wxWidgets + +On Linux systems, libuuid development packages need to be installed with your +OS package manager. +You will also need to install wxWidgets if you want to build the GUI. + === "Centos" ``` - sudo yum install git redhat-lsb-core gcc gcc-c++ make wget centos-release-scl scl-utils rpm-build - sudo yum install cmake3 devtoolset-9 - sudo yum install libuuid-devel unzip wxGTK3-devel boost-test boost-devel + sudo yum install libuuid-devel + sudo yum install wxGTK3-devel ``` + === "Ubuntu 20.04 or 22.04 / Debian 11" ``` - sudo apt install uuid-dev libwxgtk3.0-gtk3-dev - sudo apt install libboost-test-dev + sudo apt install uuid-dev + sudo apt install libwxgtk3.0-gtk3-dev ``` === "Ubuntu 23.04 / Debian 12" ``` - sudo apt install uuid-dev libwxgtk3.2-dev libboost-test-dev + sudo apt install uuid-dev + sudo apt install libwxgtk3.2-dev ``` - -## Automatic libraries compilation from sources -[The Antares dependencies compilation repository](https://github.com/AntaresSimulatorTeam/antares-deps) is a submodule that can be used for automatic libraries compilation from sources. - -Apart from OR-Tools, all dependencies can be built at configure time using the option `-DBUILD_ALL=ON` (`OFF` by default). -For a list of available options, see [the Antares dependencies compilation repository](https://github.com/AntaresSimulatorTeam/antares-deps). - -You can set `-DBUILD_ORTOOLS=ON` to download & build OR-Tools. It is also possible to use a precompiled archive, see below. - -For compiling the package yourself from git, additional build dependencies are needed (see [here](1-Development-requirements.md)). - -### Pre-compiled OR-Tools: release+static only -You can [download](https://github.com/rte-france/or-tools/releases) a precompiled OR-Tools archive that contains headers & static libraries. - -Please note that dynamic linking with OR-Tools is only supported in Linux. - -Decompress the archive, and provide its path as a `CMAKE_PREFIX_PATH`. If you use XPRESS, you may need also to specify `XPRESS_ROOT`. - -### Defining dependency install directory -When using multiple directories for Antares development with multiple branches, it can be useful to have a common dependency install directory. - -Dependency install directory can be specified with `DEPS_INSTALL_DIR`. By default, install directory is `/../rte-antares-deps-` - -Note: -> `DEPS_INSTALL_DIR` is added to `CMAKE_PREFIX_PATH` - -### Pre-compiled libraries download: release version only -You can download a pre-compiled antares-deps archive from [Antares dependencies compilation repository][antares-deps-url]. Only release versions are available. - -Note: -> For Windows, you must you use a MSVC version compatible with the MSVC version used in the GitHub Action that made the release. - -[antares-deps-url]: https://github.com/AntaresSimulatorTeam/antares-deps/releases - diff --git a/docs/developer-guide/3-Build.md b/docs/developer-guide/3-Build.md index 14f7ccdbe3..860c9f47cb 100644 --- a/docs/developer-guide/3-Build.md +++ b/docs/developer-guide/3-Build.md @@ -1,69 +1,77 @@ # Build -Before build, make sure that dependencies are [installed](2-Dependencies-install.md). -## Environment settings -On CentOS, enable `devtoolset-9` and `rh-git227`: -``` -scl enable devtoolset-9 bash -source /opt/rh/rh-git227/enable -``` -## Update git submodule -``` -git submodule update --init src/antares-deps -``` -> 💡 **Ignore submodules to make git operations faster** -> Antares_Simulator is quite a large project, with a few large submodules. In file .git/config, you can add this line to all [submodule] sections -> ``` -> ignore = all -> ``` -> This way git won't waste time computing diff on these when checking out, diffing commits, etc. git operations should be a lot faster. -> Keep in mind that your submodules won't be updated. +Before building, make sure that dependencies are [installed](2-Dependencies-install.md). + +## Install VCPKG + +Although you may install third party dependencies yourself, the preferred way is +to rely on [vcpkg](https://github.com/microsoft/vcpkg) and its CMake integration +to build and install most of them. + +The first step will be to install VCPKG using its bootstrap script: -## Configure build with CMake === "Windows" ``` - cmake -B _build -S [antares_src] -DVCPKG_ROOT=[vcpkg_root] -DVCPKG_TARGET_TRIPLET=[vcpkg-triplet] -DCMAKE_BUILD_TYPE=release + git submodule update --init vcpkg + cd vcpkg + .\bootstrap-vcpkg.bat ``` - > **Note:** cpack NSIS installer creation needs an 'out-of-source build'. The build directory must be outside `[antares_src]` directory -=== "CentOS" +=== "Linux" ``` - cmake3 -B _build -S [antares_src] -DCMAKE_BUILD_TYPE=release + git submodule update --init vcpkg + cd vcpkg + ./bootstrap-vcpkg.sh ``` -=== "Ubuntu/Debian" + +## Configure build with CMake + +The preferred way of building the project is to use a pre-compiled version of OR-Tools and to install +other dependencies using vcpkg. To achieve this, you will need to define VCPKG-related variables, +and add your OR-tools install path to `CMAKE_PREFIX_PATH`: + + +=== "Windows" ``` - cmake -B _build -S [antares_src] -DCMAKE_BUILD_TYPE=release + cmake -B _build -S src -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake \ + -DVCPKG_TARGET_TRIPLET=x64-windows-antares \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH= + ``` + + > **Note:** cpack NSIS installer creation needs an 'out-of-source build'. The build directory must be outside `src` directory + + +=== "Linux" + + ``` + cmake -B _build -S src -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake \ + -DVCPKG_TARGET_TRIPLET=x64-linux-antares \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_PREFIX_PATH= ``` Here is a list of mandatory or optional CMake configuration options: -| Option | Mandatory | Description | Expected value | Default value | -|:----------------------|-----------|----------------------------------------------------------------------------------|----------------------------------------|-----------------------------------------------------------| -| `CMAKE_C_COMPILER` | **yes** | Select C compiler | `gcc_-10` | | -| `CMAKE_CXX_COMPILER` | **yes** | Select C++ compiler | `g++-10` | | -| `CMAKE_BUILD_TYPE` | **yes** | Define build type | `Release` / `Debug` / `RelWithDebInfo` | | -| `BUILD_UI` | no | Enable or disable Antares Simulator UI[^1] compilation | `ON` / `OFF` | `ON` | -| `BUILD_ALL` | no | Enable build of ALL external libraries | `ON` / `OFF` | `OFF` | -| `DEPS_INSTALL_DIR` | no | Define dependencies libraries install directory | absolute path to an existing directory | `/../rte-antares-deps-` | -| `USE_PRECOMPILED_EXT` | no | This option must be set if you use wxWidget as precompiled external library | `ON` / `OFF` | `OFF` | -| `BUILD_TESTING` | no | Enable build for unit tests | `ON` / `OFF` | `OFF` | -| `BUILD_ORTOOLS` | no | Enable build for OR-Tools and its dependencies (requires an Internet connection) | `ON` / `OFF` | `OFF` | +| Option | Mandatory | Description | Expected value | Default value | +|:-----------------------|--------------|----------------------------------------------------------------------------------|---------------------------------------------|-----------------------------------------------------------| +| `CMAKE_C_COMPILER` | OS-dependent | Select C compiler | `gcc-10` | | +| `CMAKE_CXX_COMPILER` | OS-dependent | Select C++ compiler | `g++-10` | | +| `CMAKE_BUILD_TYPE` | **yes** | Define build type | `Release` / `Debug` / `RelWithDebInfo` | | +| `BUILD_UI` | no | Enable or disable Antares Simulator UI[^1] compilation | `ON` / `OFF` | `ON` | +| `BUILD_TESTING` | no | Enable build for unit tests | `ON` / `OFF` | `OFF` | +| `BUILD_ORTOOLS` | no | Enable build for OR-Tools and its dependencies (requires an Internet connection) | `ON` / `OFF` | `OFF` | +| `CMAKE_TOOLCHAIN_FILE` | no | Path to VCPKG toolchain file, allows to integrate VCPKG with cmake build | `../vcpkg/scripts/buildsystems/vcpkg.cmake` | | +| `VCPKG_TARGET_TRIPLET` | no | Define VCPKG triplet (build type for dependencies etc.) | `x64-windows-antares` / `x64-linux-antares` | | > 💡 **Disable the UI build to make builds faster** > The UI takes up a good chunk of compilation time. It is enabled by default, but you can disable it by turning off `BUILD_UI` -Additional options for Windows: - -| Option | Description | -|:-----------------------|------------------------| -| `VCPKG_ROOT` | Define vcpkg directory | -| `VCPKG_TARGET_TRIPLET` | Define [vcpkg-triplet] | - > 💡 **Use Ninja to speed up target generation by CMake** -> At configure time, you may specify Ninja for generation instead of traditional Make. This will speed up the update +> At configure time, you may specify Ninja for generation instead of traditional Make. This will speed up the update > step after you make small changes to the code. > ``` > cmake -S src [...] -G Ninja @@ -74,17 +82,17 @@ Additional options for Windows: === "Windows" ``` - cmake --build _build --config release -j8 + cmake --build _build --config Release -j8 ``` === "CentOS" ``` - cmake3 --build _build --config release -j8 + cmake3 --build _build -j8 ``` === "Ubuntu/Debian" ``` - cmake --build _build --config release -j8 + cmake --build _build -j8 ``` > 💡 Compilation can be done on several processors with `-j` option. @@ -92,4 +100,24 @@ Additional options for Windows: The final GUI file can be executed at `_build/ui/simulator/antares-X.Y-ui-simulator` +## Developer tips + +### Use a compiler cache +In order to avoid unnecessary rebuilds, for example when you switch branches, you may use a compiler cache +such as ccache. Using it under Linux systems is pretty easy with CMake, you only need to specify it +as the compiler launcher at configure time: +``` +cmake ... -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache ... +``` + +### Ignore submodules to make git operations faster +Antares_Simulator is quite a large project, with a few large submodules. In file .git/config, you can add this line to all [submodule] sections +``` +ignore = all +``` +This way git won't waste time computing diff on these when checking out, diffing commits, etc. git operations should be a lot faster. +Keep in mind that your submodules won't be updated. + + + [^1]: GUI support has been dropped in favor of [Antares Web](https://antares-web.readthedocs.io) \ No newline at end of file diff --git a/docs/developer-guide/CHANGELOG.md b/docs/developer-guide/CHANGELOG.md index 67aa64da57..880f5dc220 100644 --- a/docs/developer-guide/CHANGELOG.md +++ b/docs/developer-guide/CHANGELOG.md @@ -3,6 +3,12 @@ toc_depth: 2 --- # Antares Changelog + +## Branch 9.2.x +### 9.2.0 + +* Changed the formula for the number of cores [details](../user-guide/solver/optional-features/multi-threading.md) + ## Branch 9.1.x ### 9.1.0 (06/2024) @@ -10,51 +16,8 @@ toc_depth: 2 * Scenarized & hourly values for hydro pumping and hydro generation. Previously this data was not scenarized and daily. * STS groups are now "dynamic" : group names are no longer fixed by code, user is free to define these groups. * Add optimization options from command line in OR-Tools / XPRESS (#1837) -#### TODO - -## Branch 9.0.x - -### 9.0.0 -#### License -* Use licence MPL 2.0 instead of GPL3_WITH_RTE-Exceptions (#1812) - -#### Improvements -* Include overflow variable in HydroPower constraint (#1903) -* Add total time logging at the end of the simulation (#1908) -* Add STS level constraint to suspect list for infeasible problem analysis (#1891) - -#### For developers -* Use precompiled OR-Tools for Oracle Linux 8 CI (#1893) -* Change version behavior to allow more flexibility (#1898) - -#### Code quality -* Use std::shared_ptr instead of indices for active binding constraints in results (#1887) -* Fix a few compilation warnings (#1880) -* Scratchpad numspace (#1749) - -#### Tests -* Fix invalid index causing segfault in `test-study` test (#1902) - -## Branch 8.8.x (end of support 12/2025) - -### 8.8.5 (05/2024) -#### Bugfix -- [UI] Fix opening a study from the file browser -- Fix crash occurring when duplicate thermal clusters are present in a study (same name) -- Fix formula for "PROFIT BY PLANT" - -### 8.8.4 (03/2024) -#### Bugfix -* Adequacy patch CSR - fix DTG MRG (#1982) -* Fix ts numbers for no gen clusters (#1969) -* Remove unitcount limit for time series generation (#1960) - -### 8.8.3 (02/2024) -#### Bugfix -* Fix an issue where depending on the platform the output archive could contain several entries of the same area and inrco files #### Improvements -* Remove sc-builder prefix "hgp", use "h" instead for max hydro pumping & generation timeseries. * Rationalize consistency checks on the number of columns (#2073) * Documentation reorganization and improvement (#2024) (#2023) (#2022) * Add doc for thermal heuristic (#2048) @@ -102,6 +65,59 @@ toc_depth: 2 * Remove deps-build Actions (#2043) * Remove unused logs.hxx (#2026) +## Branch 9.0.x + +### 9.0.0 +#### License +* Use licence MPL 2.0 instead of GPL3_WITH_RTE-Exceptions (#1812) + +#### Improvements +* Include overflow variable in HydroPower constraint (#1903) +* Add total time logging at the end of the simulation (#1908) +* Add STS level constraint to suspect list for infeasible problem analysis (#1891) + +#### For developers +* Use precompiled OR-Tools for Oracle Linux 8 CI (#1893) +* Change version behavior to allow more flexibility (#1898) + +#### Code quality +* Use std::shared_ptr instead of indices for active binding constraints in results (#1887) +* Fix a few compilation warnings (#1880) +* Scratchpad numspace (#1749) + +#### Tests +* Fix invalid index causing segfault in `test-study` test (#1902) + +## Branch 8.8.x (end of support 12/2025) +### 8.8.7 (07/2024) +#### Improvements +- Add OR-Tools solver option for batchrun tool (#1981) + +#### Bugfix +- Adequacy Patch regression [ANT-1845] #2235 + +### 8.8.6 (07/2024) +#### Bugfix +- Fix missing synthesis results for links (#2115) +#### Dependencies +- Update vcpkg (fix Boost) + +### 8.8.5 (05/2024) +#### Bugfix +- [UI] Fix opening a study from the file browser +- Fix crash occurring when duplicate thermal clusters are present in a study (same name) +- Fix formula for "PROFIT BY PLANT" + +### 8.8.4 (03/2024) +#### Bugfix +* Adequacy patch CSR - fix DTG MRG (#1982) +* Fix ts numbers for no gen clusters (#1969) +* Remove unitcount limit for time series generation (#1960) + +### 8.8.3 (02/2024) +#### Bugfix +* Fix an issue where depending on the platform the output archive could contain several entries of the same area and interco files + ### 8.8.2 #### Bugfix * Fix segfault caused by uninitialized `cluster.series.timeseriesNumbers` (#1876). This bug was introduced in v8.8.1 by #1752 @@ -320,6 +336,12 @@ toc_depth: 2 * Array, logs jit and correlation in makefile (#1410) ## Branch 8.6.x (end of support 06/2025) +### 8.6.8 (07/2024) +#### Bugfix +- [UI] Remove propery storagecycle for short term storage added when saving a study (#2037) +#### Dependencies +- Update vcpkg (fix Boost) + ### 8.6.7 (05/2024) #### Bugfixes * Fix formula use in output var Profit by plant [ANT-1719] (https://github.com/AntaresSimulatorTeam/Antares_Simulator/pull/2097) diff --git a/docs/developer-guide/continuous-integration.md b/docs/developer-guide/continuous-integration.md index 6414c531a6..0f5a47fff3 100644 --- a/docs/developer-guide/continuous-integration.md +++ b/docs/developer-guide/continuous-integration.md @@ -26,8 +26,9 @@ Here is a description of workflows with their associated status. | `download-extract-precompiled-libraries-zip/action.yml` | Download and extract .zip precompiled libraries from antares-deps repository | | | `install-cmake-328/action.yml` | Installs cmake 3.28 using devtoolset 10 | | | `run-tests/action.yml` | Runs tests on the simulator using reference study batches [here](https://github.com/AntaresSimulatorTeam/SimTest) | | - +| `clang-format.yml` | Check formatting using clang-format 18.1.3 through bash script src/format-code.sh[^2] | | [^1]: all branch names must start with `feature/`, `features/`, `fix/`, `release/`, `doc/`, `issue-`, or `dependabot/`; otherwise the workflows are not run +[^2]: please note that this job must succeed in order to merge PRs [ubuntu_ci_svg]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/workflows/Ubuntu%20CI%20(push%20and/or%20release)/badge.svg [ubuntu_ci_link]: https://github.com/AntaresSimulatorTeam/Antares_Simulator/actions?query=workflow%3A"Ubuntu%20CI%20(push%20and/or%20release)" diff --git a/docs/pdf-doc-generation-with-sphinx/source/conf.py b/docs/pdf-doc-generation-with-sphinx/source/conf.py index 9c84a4fc3b..9226aefac1 100644 --- a/docs/pdf-doc-generation-with-sphinx/source/conf.py +++ b/docs/pdf-doc-generation-with-sphinx/source/conf.py @@ -18,8 +18,8 @@ # -- Project information ----------------------------------------------------- project = 'Antares Simulator User Guide' -release = 'v8.8' -copyright = '2023, RTE' +release = 'v9.1' +copyright = '2024, RTE' author = 'RTE' diff --git a/docs/user-guide/03-getting_started.md b/docs/user-guide/03-getting_started.md index 6ceab3315b..ba4ca923a8 100644 --- a/docs/user-guide/03-getting_started.md +++ b/docs/user-guide/03-getting_started.md @@ -62,9 +62,9 @@ These steps most often involve: 2. Defining the simulation contexts (definition of the "Monte-Carlo years" to simulate) 3. *(Optional)* If some time-series are supposed to be [automatically generated](18-parameters.md#generate), running a simulation to produce actual numeric scenarios, following the directives defined in (2). - *In this step, the [ts-generator](ts-generator/01-overview.md) tool should be used.* + *In this step, the [ts-generator](ts-generator/01-overview-tsgenerator.md) tool should be used.* 4. Running the optimization, to solve all the optimization problems associated with each of the scenarios produced in (3). - *In this step, the main [solver](solver/01-overview.md) tool should be used.* + *In this step, the main [solver](solver/01-overview-solver.md) tool should be used.* 5. Exploiting the detailed [results](solver/03-outputs.md) yielded by (4). *In this step, we recommend using [Antares Web](https://antares-web.readthedocs.io) or [Antares Extensions](#using-extensions).* diff --git a/docs/user-guide/04-migration-guides.md b/docs/user-guide/04-migration-guides.md index 2fda042306..eca0ef0fbe 100644 --- a/docs/user-guide/04-migration-guides.md +++ b/docs/user-guide/04-migration-guides.md @@ -1,9 +1,41 @@ # Migration guides 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. + +## v9.2.0 +### Adequacy Patch LMR +Removed following properties from **settings/generaldata.ini**. +- enable-first-step +- set-to-null-ntc-between-physical-out-for-first-step + +### (TS-generator only) TS generation for link capacities +In files input/links//properties.ini, add the following properties +- tsgen_direct_XXX, +- tsgen_indirect_XXX +with XXX in +- unitcount (unsigned int, default 1) +- nominalcapacity (float) +- law.planned (string "uniform"/"geometric") +- law.forced (same) +- volatility.planned (double in [0,1]) +- volatility.forced (same) + +- "prepro" timeseries => input/links//prepro/_{direct, indirect}.txt, 365x6 values, respectively "forced outage duration", "planned outage duration", "forced outage rate", "planned outage rate", "minimum of groups in maintenance", "maximum of groups in maintenance". +- "modulation" timeseries => input/links//prepro/_mod_{direct, indirect}.txt, 8760x1 values each in [0, 1] +- number of TS to generate => generaldata.ini/General/nbtimeserieslinks (unsigned int, default value 1) + + +### Input +#### Short term storage: efficiency for withdrawal +In input/st-storage/area/list.ini add property: `efficiencywithdrawal` [double] in range 0-1 + +### Output +- Remove column SPIL ENRG CSR (adequacy patch) +- Add DTG MRG CSR and UNSP ENRG CSR variables + ## v9.1.0 ### Input #### Hydro Maximum Generation/Pumping Power -* For time series ![Migration diagram](migration.png "Migration diagram"), for more details, see [this Python script](migration.py) +* For time series ![Migration diagram](img/migration.png "Migration diagram"), for more details, see [this Python script](img/migration.py) Regarding Hydro time-series, the scenario builder allows the user to choose, for a given year and area, a different time series whether we consider : - inflows, ROR and minimum generation, max pumping & generation (prefix "h") @@ -109,6 +141,10 @@ For each thermal cluster, in existing file **input/thermal/clusters/<area> For each thermal cluster, new files added **input/thermal/series/<area>/<cluster>/CO2Cost.txt** and **input/thermal/series/<area>/<cluster>/fuelCost.txt**. **fuelCost.txt** and **CO2Cost.txt** must either have one column, or the same number of columns as existing file **series.txt** (availability). The number of rows for these new matrices is 8760. +#### Hydro Final Reservoir Level +In the existing file **settings/scenariobuilder.dat**, under **<ruleset>** section following properties added (if final reservoir level specified, different from `init`): +* **hfl,<area>,<year> = <hfl-value>** + ### Output #### Scenarized RHS for binding constraints Add directory **bindingconstraints** to output directory **ts-numbers**. For every binding constraint group, add a file **ts-numbers/bindingconstraints/<group>.txt** containing the TS numbers used for that group. diff --git a/docs/user-guide/other-features/analyzer.md b/docs/user-guide/other-features/analyzer.md index 877b423332..89f79928c7 100644 --- a/docs/user-guide/other-features/analyzer.md +++ b/docs/user-guide/other-features/analyzer.md @@ -5,9 +5,12 @@ hide: # Time-Series Analyzer ---- + +**Executable**: antares-analyzer (currently released for Windows & Ubuntu only) + + > _**WARNING:**_ this feature is deprecated and will be removed in a future release. If you are still using it, > please [get in touch](https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues) with us. ---- -**Executable**: antares-analyzer (currently released for Windows & Ubuntu only) \ No newline at end of file + + diff --git a/docs/user-guide/other-features/batchrun.md b/docs/user-guide/other-features/batchrun.md index eb6c4ead58..97e973501c 100644 --- a/docs/user-guide/other-features/batchrun.md +++ b/docs/user-guide/other-features/batchrun.md @@ -5,10 +5,10 @@ hide: # Batch Runner ---- + > _**WARNING:**_ this feature is deprecated and will be removed in a future release. If you are still using it, > please [get in touch](https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues) with us. ---- + **Executable**: antares-batchrun (currently released for Windows & Ubuntu only) diff --git a/docs/user-guide/other-features/config.md b/docs/user-guide/other-features/config.md index b9acd22cca..6d06b1bea4 100644 --- a/docs/user-guide/other-features/config.md +++ b/docs/user-guide/other-features/config.md @@ -5,10 +5,8 @@ hide: # Config Checker ---- > _**WARNING:**_ this feature is deprecated and will be removed in a future release. If you are still using it, > please [get in touch](https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues) with us. ---- **Executable**: antares-config (currently released for Windows & Ubuntu only) diff --git a/docs/user-guide/other-features/kirchhoff-constraints-builder.md b/docs/user-guide/other-features/kirchhoff-constraints-builder.md index e0c11c66b8..5aecd43e30 100644 --- a/docs/user-guide/other-features/kirchhoff-constraints-builder.md +++ b/docs/user-guide/other-features/kirchhoff-constraints-builder.md @@ -1,9 +1,7 @@ # Kirchhoff's constraint generator ---- > _**WARNING:**_ this feature is deprecated and will be removed in a future release. If you are still using it, > please [get in touch](https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues) with us. ---- **Executable**: antares-kirchhoff-constraints-builder (currently released for Windows & Ubuntu only) diff --git a/docs/user-guide/other-features/study-cleaner.md b/docs/user-guide/other-features/study-cleaner.md index ad2049afc6..ff67c59f24 100644 --- a/docs/user-guide/other-features/study-cleaner.md +++ b/docs/user-guide/other-features/study-cleaner.md @@ -5,10 +5,9 @@ hide: # Study Cleaner ---- + > _**WARNING:**_ this feature is deprecated and will be removed in a future release. If you are still using it, > please [get in touch](https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues) with us. ---- **Executable**: antares-study-cleaner (currently released for Windows & Ubuntu only) diff --git a/docs/user-guide/other-features/study-finder.md b/docs/user-guide/other-features/study-finder.md index d7e21a09f8..d681ff07a1 100644 --- a/docs/user-guide/other-features/study-finder.md +++ b/docs/user-guide/other-features/study-finder.md @@ -5,10 +5,8 @@ hide: # Study Finder ---- > _**WARNING:**_ this feature is deprecated and will be removed in a future release. If you are still using it, > please [get in touch](https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues) with us. ---- **Executable**: antares-study-finder (currently released for Windows & Ubuntu only) diff --git a/docs/user-guide/other-features/study-updater.md b/docs/user-guide/other-features/study-updater.md index 0f6bafd87b..70b51873c3 100644 --- a/docs/user-guide/other-features/study-updater.md +++ b/docs/user-guide/other-features/study-updater.md @@ -5,10 +5,8 @@ hide: # Study Updater ---- > _**WARNING:**_ this feature is deprecated and will be removed in a future release. If you are still using it, > please [get in touch](https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues) with us. ---- **Executable**: antares-study-updater (currently released for Windows & Ubuntu only) diff --git a/docs/user-guide/other-features/ui-simulator.md b/docs/user-guide/other-features/ui-simulator.md index f79bab5c42..2987c7f095 100644 --- a/docs/user-guide/other-features/ui-simulator.md +++ b/docs/user-guide/other-features/ui-simulator.md @@ -5,10 +5,8 @@ hide: # GUI ---- > _**WARNING:**_ this feature is deprecated and will be removed in a future release. If you are still using it, > please [get in touch](https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues) with us. ---- **Executable**: antares-study-ui-simulator (currently released for Windows & Ubuntu only) diff --git a/docs/user-guide/other-features/vacuum.md b/docs/user-guide/other-features/vacuum.md index 42af2f9f25..25db8dacb4 100644 --- a/docs/user-guide/other-features/vacuum.md +++ b/docs/user-guide/other-features/vacuum.md @@ -5,9 +5,7 @@ hide: # Vacuum ---- > _**WARNING:**_ this feature is deprecated and will be removed in a future release. If you are still using it, > please [get in touch](https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues) with us. ---- **Executable**: antares-vacuum (currently released for Windows & Ubuntu only) diff --git a/docs/user-guide/other-features/ybyaggregator.md b/docs/user-guide/other-features/ybyaggregator.md index 0ca3630116..aa885301d5 100644 --- a/docs/user-guide/other-features/ybyaggregator.md +++ b/docs/user-guide/other-features/ybyaggregator.md @@ -5,9 +5,7 @@ hide: # Year-by-Year Aggregator ---- > _**WARNING:**_ this feature is deprecated and will be removed in a future release. If you are still using it, > please [get in touch](https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues) with us. ---- **Executable**: antares-ybyaggregator (currently released for Windows & Ubuntu only) diff --git a/docs/user-guide/solver/00-index.md b/docs/user-guide/solver/00-index.md index d9a519183b..4ef21bd614 100644 --- a/docs/user-guide/solver/00-index.md +++ b/docs/user-guide/solver/00-index.md @@ -4,7 +4,7 @@ ```{toctree} :hidden: -01-overview.md +01-overview-solver.md 02-inputs.md 03-outputs.md 04-parameters.md diff --git a/docs/user-guide/solver/01-overview.md b/docs/user-guide/solver/01-overview-solver.md similarity index 100% rename from docs/user-guide/solver/01-overview.md rename to docs/user-guide/solver/01-overview-solver.md diff --git a/docs/user-guide/solver/02-inputs.md b/docs/user-guide/solver/02-inputs.md index cf3768b7d2..8f497e8b34 100644 --- a/docs/user-guide/solver/02-inputs.md +++ b/docs/user-guide/solver/02-inputs.md @@ -157,7 +157,7 @@ The user may pick any area appearing in the list and is then given access to dif - The "local data" tab is used to set the parameters of the stochastic generator. These parameters are presented in four sub-tabs whose content is presented in - [Time-series analysis and generation](../ts-generator/01-overview.md). + [Time-series analysis and generation](../ts-generator/01-overview-tsgenerator.md). - The "digest" tab displays for all areas a short account of the local data @@ -286,6 +286,7 @@ The user may pick any area appearing in the area list and is then given access t - Injection (MW): the maximum injection power for the storage - withdrawal refers to the flow from the power system to the storage - Stock (MWh): the capacity of the storage in MWh - Efficiency (%): the energy efficiency of the storage, i.e. the ratio for a given volume between the energy taken from the system to be injected into the storage and the energy returned to the system during its withdrawal. This efficiency factor is applied when injecting energy into the storage. + - Efficiency Withdrawal (%): Same behavior as the previous efficiency, this factor is applied when withdrawing energy from the storage. - Initial level (%): the imposed initial filling rate of the storage at the beginning of each optimisation period. - Initial level optimal: if the parameter is activated, the "Initial level" parameter is ignored and the initial storage level is optimized by Antares for each optimization period to minimize its objective function. _Note: setting this parameter to "True" implies that there is no guarantee that the initial storage level of week N is the same as the final storage level of week N-1. However, the final level of week N is always equal to the initial level of the same week N plus/minus the injections/withdrawals occuring at the last hour of week N._ diff --git a/docs/user-guide/solver/03-outputs.md b/docs/user-guide/solver/03-outputs.md index cd79b2fdb4..367340cc3e 100644 --- a/docs/user-guide/solver/03-outputs.md +++ b/docs/user-guide/solver/03-outputs.md @@ -117,12 +117,13 @@ The area files that belong to the "values" class display fields corresponding to | SPIL. ENRG | Spilled energy (energy produced that cannot be used and has to be wasted) | | LOLD | Loss of load duration: adequacy indicator (length of shortfalls) | | LOLP | Loss of Load probability: adequacy indicator (probability of at least one hour of shortfall within the considered period, without normalization by the duration of the considered period) | -| AVL. DTG | Available dispatchable thermal generation (sum of av. power over all plants) | -| DTG. MRG | Disp. Ther. Gen. (AVL DTG – sum of all dispatched thermal generation) | +| AVL DTG | Available dispatchable thermal generation (sum of av. power over all plants) | +| DTG MRG | Disp. Ther. Gen. (AVL DTG – sum of all dispatched thermal generation) | | MAX. MRG | Maximum margin: operational margin obtained if the hydro storage energy of the week were used to maximise margins instead of minimizing costs | | DENS | Domestic Energy Not Supplied: the difference between the local production capabilities of an area and its local load[^adqp] | | LMR. VIOL | Local Matching Rule Violation after the Antares Simulation as defined by the adequacy patch[^adqp] | -| SPIL. ENRG. CSR | Spilled Energy after the Curtailment Sharing Rule step of the dequacy patch[^adqp] | +| UNSP. ENRG. CSR | Unsupplied enery after CSR (demand that cannot be satisfied)[^adqp] | +| DTG MRG CSR | DTG MRG after CSR[^adqp] | | _injection | Injection of energy from the area into each short-term storage group | | _withdrawal | Withdrawal of energy from each short-term storage group into the area | | _level | Average level of each short-term storage group | diff --git a/docs/user-guide/solver/04-parameters.md b/docs/user-guide/solver/04-parameters.md index 7c0515c420..5ca79193a0 100644 --- a/docs/user-guide/solver/04-parameters.md +++ b/docs/user-guide/solver/04-parameters.md @@ -12,7 +12,7 @@ These parameters are listed under the `[general]` section in the `.ini` file. --- ### Study mode ---- + #### mode [//]: # (TODO: verify if required, remove default value) [//]: # (TODO: add details 'expansion' behavior) @@ -36,7 +36,7 @@ These parameters are listed under the `[general]` section in the `.ini` file. --- ### Study horizon ---- + #### horizon [//]: # (TODO: verify if required, remove default value) - **Expected value:** year (string) @@ -48,7 +48,7 @@ These parameters are listed under the `[general]` section in the `.ini` file. ### Calendar parameters ---- + #### nbyears [//]: # (TODO: verify if required, verify default value) - **Expected value:** unsigned integer @@ -122,7 +122,7 @@ These parameters are listed under the `[general]` section in the `.ini` file. --- ### Additional parameters ---- + #### year-by-year - **Expected value:** `true` or `false` - **Required:** no @@ -219,7 +219,7 @@ These parameters are listed under the `[general]` section in the `.ini` file. --- ### Pre-processor parameters ---- + #### readonly [//]: # (TODO: add usage details) - **Expected value:** `true` or `false` @@ -503,16 +503,6 @@ These parameters are listed under the `[adequacy patch]` section in the `.ini` f inside adequacy patch (area type 2). NTC is set to null (if true) only in the first step of adequacy patch local matching rule. NTC from physical areas outside to physical areas inside adequacy patch (set to null / local values) ---- -#### set-to-null-ntc-between-physical-out-for-first-step -[//]: # (TODO: usage is not clear) -- **Expected value:** `true` or `false` -- **Required:** no -- **Default value:** `true` -- **Usage:** Transmission capacities between physical areas outside adequacy patch (area type 1). - NTC is set to null (if true) only in the first step of adequacy patch local matching rule. - NTC between physical areas outside adequacy patch (set to null / local values) - --- #### price-taking-order [//]: # (TODO: document this parameter) @@ -543,16 +533,6 @@ _**This section is under construction**_ - **Default value:** - **Usage:** Check CSR cost function value prior and after CSR (false / true) ---- -#### enable-first-step -[//]: # (TODO: document this parameter) -_**This section is under construction**_ - -- **Expected value:** -- **Required:** **yes** -- **Default value:** -- **Usage:** - --- #### threshold-initiate-curtailment-sharing-rule [//]: # (TODO: document this parameter) @@ -588,8 +568,7 @@ _**This section is under construction**_ These parameters are listed under the `[other preferences]` section in the `.ini` file. --- -#### initial-reservoir-levels -[//]: # (TODO: complete the usage paragraph) +#### initial-reservoir-levels (DEPRECATED since 9.2: cold start is default behavior) - **Expected value:** one of the following (case-insensitive): - `cold start` - `hot start` @@ -792,13 +771,15 @@ They are **required** if [user-playlist](#user-playlist) is set to `true`. --- #### playlist_year - **Expected value:** `+ =` or `- =`, followed by a positive integer (example: `playlist_year + = 5`) -- **Required:** **yes**, if [user-playlist](#user-playlist) is set to `true`. +- **Required:** **yes**, if [user-playlist](#user-playlist) is set to `true`, ignored otherwise. - **Usage:** - for every Monte-Carlo year that you want the Antares Simulator to **study**, add the parameter entry `playlist_year + = i`, where `i` is the index of the year. - for every Monte-Carlo year that you want the Antares Simulator to **skip**, add the parameter entry `playlist_year - = i`, where `i` is the index of the year. +_Please note that by convention, the first year has index 0._ + --- #### playlist_year_weight [//]: # (TODO: document this parameter) diff --git a/docs/user-guide/solver/05-model.md b/docs/user-guide/solver/05-model.md index 29816befd2..9f37c2ac9a 100644 --- a/docs/user-guide/solver/05-model.md +++ b/docs/user-guide/solver/05-model.md @@ -178,6 +178,21 @@ Note: Almost all variables of the system are defined twice (one value per state) | $R\_\lambda \in \mathbb{R}^T_+$ | stored energy level in reservoir $\lambda$ | | $\mathfrak{R}\_{\lambda_q} \in \mathbb{R}_+$ | filling level of reservoir layer $q$ at time $T$ (end of the week) | +### Short-term storages +| Notation | Explanation | +|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| $s\in \mathcal{S}$ | A single short-term storge reservoir. There is one set of short-term storage per area. | +| $L_s \in \mathbb{R}_+^T$ | Level for storage $s$ | +| $\underline{L}_s \in \mathbb{R}^T$, $\overline{L}_s \in \mathbb{R}^T$ | Minimum (resp. maximum) level for storage $s$ also known as "rule-curves" | +| $L_s^0 \in \mathbb{R}_+$ | Initial level for storage $s$ (optional) | +| $P^w_s \in \mathbb{R}_+^T$ | Withdrawal for storage $s$. Note that this is from the storage's perspective : the amount of power withdrawn from the storage | +| $\underline{P}^i_s \in \mathbb{R}^T$, $\overline{P}^i_s \in \mathbb{R}^T$ | Minimum (resp. maximum) injection for storage $s$ | +| $\eta^i_s \in [0, 1]$ | Injection efficiency for storage $s$ | +| $P^i_s \in \mathbb{R}_+^T$ | Injection for storage $s$. Note that this is from the storage's perspective : the amount of power injected into the storage | +| $\underline{P}^w_s \in \mathbb{R}^T$, $\overline{P}^w_s \in \mathbb{R}^T$ | Minimum (resp. maximum) withdrawal for storage $s$ | +| $\eta^w_s \in [0, 1]$ | Withdrawal efficiency for storage $s$ | +| $I_s \in \mathbb{R}^T$ | Inflows for storage $s$. Energy that is injected into the storage over time | + ### Binding constraints In problems $\mathcal{P}^k$, the need for a versatile modelling of the power system calls for the introduction of an arbitrary number of linear binding constraints between system's variables throughout the grid, expressed either in terms of hourly power, daily energies or weekly energies. @@ -261,12 +276,45 @@ $\Omega\_{\mathrm{unit com}}$ is the expression derived from $\Omega\_{\mathrm{d ## Constraints related to the nominal system state +### Short-term storage +Level equation. For each short-term storage $s\in\mathcal{S}$, + +$$ +L_s(t) - L_s(t-1) = \eta^i_s * P^i_s(t) - \eta^w_s * P^w_s(t) + I_s(t) +$$ + +Note that in this equation, time-steps are cycled. From now on, time indices are omitted for simplicity. + +Bounded level + +$$ +0 \leq \underline{L}_s \leq L_s \leq \overline{L}_s +$$ + +Bounded injection + +$$ +\underline{P}^i_s \leq P^i_s \leq \overline{P^i}_s +$$ + +Bounded withdrawal + +$$ +\underline{P}^w_s \leq P^w_s \leq \overline{P^w}_s +$$ + +Initial level (optional) + +$$ +L_s(0) = L_s^0 +$$ + ### Balance between load and generation: First Kirchhoff's law: $$ -\forall n \in N, \sum\_{l \in L\_n^+} F_l - \sum\_{l \in L\_n^-} F_l = \left( G\_n^+ + \sum\_{\lambda \in \Lambda\_n}(H\_\lambda - \Pi\_\lambda) + \sum\_{\theta \ \in \Theta\_n} P\_\theta\right)-(G\_n^-+D\_n) +\forall n \in N, \sum\_{l \in L\_n^+} F_l - \sum\_{l \in L\_n^-} F_l = \left( G\_n^+ + \sum\_{\lambda \in \Lambda\_n}(H\_\lambda - \Pi\_\lambda) + \sum\_{\theta \ \in \Theta\_n} P\_\theta + \sum_{s \in \mathcal{S}} \left(P^w_s - P^i_s\right)\right)-(G\_n^-+D\_n) $$ diff --git a/docs/user-guide/solver/06-hydro-heuristics.md b/docs/user-guide/solver/06-hydro-heuristics.md index 4d4de31f48..78ff065933 100644 --- a/docs/user-guide/solver/06-hydro-heuristics.md +++ b/docs/user-guide/solver/06-hydro-heuristics.md @@ -188,6 +188,6 @@ $$V_t^- + S_t \geq \underline{S_t}$$ $$Y - V_t^- \geq 0$$ -[^monthly_allocation]: In the first equation, $S_{t-1}$ is either the initial stock $S_0$ or the final stock of the previous year (hydro hot start) +[^monthly_allocation]: In the first equation, $S_{t-1}$ is equal to initial stock $S_0$ [^daily_allocation]: In the first equation, $S_{t-1}$ is either the initial stock used in M or the final stock of the previous month ($D(m-1)$) diff --git a/docs/user-guide/solver/07-thermal-heuristic.md b/docs/user-guide/solver/07-thermal-heuristic.md index 67670a36ca..372ceb8bed 100644 --- a/docs/user-guide/solver/07-thermal-heuristic.md +++ b/docs/user-guide/solver/07-thermal-heuristic.md @@ -35,33 +35,33 @@ The way steps 1 and 2 are performed depends on a parameter set by the user in th ### Fast mode #### Step 1: first problem resolution -The general idea of the fast mode is to completely remove the constraints and costs involving integers (the \\(M_\theta\\), \\(M_\theta^+\\) and \\(M_\theta^-\\) variables) in step 1. This means that the first resolution of the weekly problem does not consider constraints (17) to (23) in the [optimisation problem formulation](01-modeling.md). Constraint (16) related to the minimum/maximum output of the thermal cluster is kept. In addition, costs related to integer variables (start-up and hourly fixed costs) are not included in the objective function. +The general idea of the fast mode is to completely remove the constraints and costs involving integers (the $M_\theta$, $M_\theta^+$ and $M_\theta^-$ variables) in step 1. This means that the first resolution of the weekly problem does not consider constraints (17) to (23) in the [optimisation problem formulation](01-modeling.md). Constraint (16) related to the minimum/maximum output of the thermal cluster is kept. In addition, costs related to integer variables (start-up and hourly fixed costs) are not included in the objective function. -The first resolution of the problem is then run, and provides hourly power outputs for each thermal cluster \\(P_{\theta,t}^{optim1}\\). At each hour, an initial value of the NODU of each cluster in then calculated: \\(M_\{\theta, t}^{guide} = ceil(\frac{P_{\theta,t}^{optim1}}{\overline{P_{\theta}}})\\). +The first resolution of the problem is then run, and provides hourly power outputs for each thermal cluster $P_{\theta,t}^{optim1}$. At each hour, an initial value of the NODU of each cluster in then calculated: $M_{\theta,t}^{guide}$ = $ceil(\frac{P_{\theta,t}^{optim1}}{\overline{P_{\theta} } }) $. #### Step 2: fast mode heuristic -In step 2, for each cluster, a parameter \\(\Delta_{adjust,\theta} = max(\Delta_\theta^+, \Delta_\theta^-)\\) is then calculated, which is the maximum of the minimum on and off durations. Hence, they are approximated to be of the same duration. For each week and each thermal cluster, the week is then divided in intervals of length \\(\Delta_{adjust,\theta}\\). The week is supposed to be cyclic (hour 1 is the timestep followin hour 168), just like in the weekly optimization problem solved by Antares. Within each interval, the NODU of the cluster is increased to the maximum value of \\(M_\{\theta, t}^{guide}\\) during this period. This process is run several time by shifting the intervals timestep by timestep until all the possible week splits have been performed. Finally, the solution which minimizes the number of adjustments of the NODU is used as the solution of step 2 \\(M_{\theta,t}^{heuristic}\\). +In step 2, for each cluster, a parameter $\Delta_{adjust,\theta} = max(\Delta_\theta^+, \Delta_\theta^-)$ is then calculated, which is the maximum of the minimum on and off durations. Hence, they are approximated to be of the same duration. For each week and each thermal cluster, the week is then divided in intervals of length $\Delta_{adjust,\theta}$. The week is supposed to be cyclic (hour 1 is the timestep followin hour 168), just like in the weekly optimization problem solved by Antares. Within each interval, the NODU of the cluster is increased to the maximum value of $M_{\theta, t}^{guide}$ during this period. This process is run several time by shifting the intervals timestep by timestep until all the possible week splits have been performed. Finally, the solution which minimizes the number of adjustments of the NODU is used as the solution of step 2 $M_{\theta,t}^{heuristic}$. ![Step 2 of the "fast" thermal mode](img/thermal_heuristic_fast_step_2.png){ .add-padding-and-white-bg }

Illustration of step 2 of the fast mode, with $\Delta_{adjust,\theta}$ equal to 2. Here, both solutions are acceptable as they involve 3 NODU adjustments.

#### Step 3: second resolution -Finally, the result of the heuristic \\(M_{\theta,t}^{heuristic}\\) is converted into a lower bound of the power output of each thermal cluster in step 3: \\(P_{\theta,t}^{min}=\underline{P_\theta}*M_{\theta,t}^{heuristic}\\). The second resolution of the problem is then run considering this lower bound, and still excluding integer variables and constraints (17) to (23) of the [optimisation problem formulation](01-modeling.md). In particular, this means that startup and fixed costs are not considered in the formulation of the optimisation problem in any of the two resolutions. However, they are added ex-post and visible in the output variables. +Finally, the result of the heuristic $M_{\theta,t}^{heuristic}$ is converted into a lower bound of the power output of each thermal cluster in step 3: $P_{\theta,t}^{min}=\underline{P_\theta}*M_{\theta,t}^{heuristic}$. The second resolution of the problem is then run considering this lower bound, and still excluding integer variables and constraints (17) to (23) of the [optimisation problem formulation](01-modeling.md). In particular, this means that startup and fixed costs are not considered in the formulation of the optimisation problem in any of the two resolutions. However, they are added ex-post and visible in the output variables. ### Accurate mode #### Step 1: first problem resolution -The accurate mode aims at taking into account integer variables in both resolutions of the optimisation problem (steps 1 and 3), but considering them as continuous variables in step 1, and fixing them as parameters in step 3. Contrary to the fast mode, constraints (17) to (23) of the [optimisation problem formulation](01-modeling.md) are taken into account in both resolutions, as well as the start-up and fixed costs in the objective function, but the integer variables \\(M_\theta\\) are considered continuous. +The accurate mode aims at taking into account integer variables in both resolutions of the optimisation problem (steps 1 and 3), but considering them as continuous variables in step 1, and fixing them as parameters in step 3. Contrary to the fast mode, constraints (17) to (23) of the [optimisation problem formulation](01-modeling.md) are taken into account in both resolutions, as well as the start-up and fixed costs in the objective function, but the integer variables $M_\theta$ are considered continuous. -The first resolution of the problem is then run. As an output, the integer NODU for each thermal cluster is calculed by rounding up the continuous NODUs which are the output of this resolution: \\(M_{\theta,t}^{guide}=ceil(M_{\theta,t}^{optim1})\\). The variables counting the number of units being started-up or shut-down at any time step \\(M_{\theta,t}^{+}\\) and \\(M_{\theta,t}^{-}\\) are also calculated at that stage. +The first resolution of the problem is then run. As an output, the integer NODU for each thermal cluster is calculed by rounding up the continuous NODUs which are the output of this resolution: $M_{\theta,t}^{guide}=ceil(M_{\theta,t}^{optim1})$. The variables counting the number of units being started-up or shut-down at any time step $M_{\theta,t}^{+}$ and $M_{\theta,t}^{-}$ are also calculated at that stage. #### Step 2: accurate mode heuristic -Step 2 of the accurate mode starts by checking for each cluster and for each week whether any constraint of minimum time up or down (constraints (22) and (23) of the [weekly optimisation problem](01-modeling.md)) is violated. If no constraint is violated for a given thermal cluster at a given week, no further action is performed and the output variable of this step \\(M_{\theta,t}^{heuristic}=M_{\theta,t}^{guide}\\). +Step 2 of the accurate mode starts by checking for each cluster and for each week whether any constraint of minimum time up or down (constraints (22) and (23) of the [weekly optimisation problem](01-modeling.md)) is violated. If no constraint is violated for a given thermal cluster at a given week, no further action is performed and the output variable of this step $M_{\theta,t}^{heuristic}=M_{\theta,t}^{guide}$. -For a given cluster and a given week, if any of these constraints is violated, a small optimisation problem is run, which aims at minimizing the changes to the NODU of the cluster while respecting constraints (22) and (23). The output of this optimisation problem is then \\(M_{\theta,t}^{heuristic}\\). +For a given cluster and a given week, if any of these constraints is violated, a small optimisation problem is run, which aims at minimizing the changes to the NODU of the cluster while respecting constraints (22) and (23). The output of this optimisation problem is then $M_{\theta,t}^{heuristic}$. #### Step 3: second resolution -Finally, the output of step 2 \\(M_{\theta,t}^{heuristic}\\) is converted into a lower bound of the NODU of each thermal cluster for the second resolution: \\(M_{\theta,t} \geq M_{\theta,t}^{heuristic}\\). The second resolution of the problem is then run considering this lower bound, and still including integer variables (as continuous variables) and constraints (17) to (23) of the [optimisation problem formulation](01-modeling.md), and start-up and fixed costs in the objective function. +Finally, the output of step 2 $M_{\theta,t}^{heuristic}$ is converted into a lower bound of the NODU of each thermal cluster for the second resolution: $M_{\theta,t} \geq M_{\theta,t}^{heuristic}$. The second resolution of the problem is then run considering this lower bound, and still including integer variables (as continuous variables) and constraints (17) to (23) of the [optimisation problem formulation](01-modeling.md), and start-up and fixed costs in the objective function. ## Annual smoothing heuristic (step 4) @@ -71,11 +71,11 @@ As a final step of the resolution of a Monte-Carlo year, an annual smoothing heu The general principle of this heuristic is that while respecting the production plan determined at the end of the second resolution and the minimum power output of each unit, we calculate a minimum duration below which it is more economically interesting to leave a group on rather than shutting it down and restarting it at a later stage. This duration is defined as follows: -$$𝑑=\frac{\sigma_\theta^+}{\tau_\theta}$$ -with \\(\sigma_\theta^+\\) the startup cost of a unit of cluster \\(\theta\\), and \\({\tau_\theta}\\) the fixed cost of a unit of cluster \\(\theta\\) when it is on. +$$d=\frac{\sigma_\theta^+}{\tau_\theta}$$ +with $\sigma_\theta^+$ the startup cost of a unit of cluster $\theta$, and ${\tau_\theta}$ the fixed cost of a unit of cluster $\theta$ when it is on. -The smoothing heuristic may then choose to increase the NODU in certain clusters when it identifies that a shut-down/start-up sequence lasted shorter than duration d. The new NODU cannot exceed the maximum accepted NODU to respect the production plan, which is equal to \\(floor(\frac{P_\theta}{\underline{P_\theta}})\\). +The smoothing heuristic may then choose to increase the NODU in certain clusters when it identifies that a shut-down/start-up sequence lasted shorter than duration d. The new NODU cannot exceed the maximum accepted NODU to respect the production plan, which is equal to $floor(\frac{P_\theta}{\underline{P_\theta}})$. ![Step 4: smoothing heuristic](img/thermal_smoothing_heuristic.png). diff --git a/docs/user-guide/solver/08-command-line.md b/docs/user-guide/solver/08-command-line.md index 0aa433c33c..8ef88dfd23 100644 --- a/docs/user-guide/solver/08-command-line.md +++ b/docs/user-guide/solver/08-command-line.md @@ -41,7 +41,7 @@ hide: | --optimization-range | Force the [simplex optimization range](04-parameters.md#simplex-range) ('day' or 'week') | | --no-constraints | Ignore all binding constraints | | --no-ts-import | Do not import timeseries into the input folder (this option may be useful for running old studies without upgrade) | -| -m, --mps-export | Export anonymous MPS, weekly or daily optimal UC+dispatch linear | +| -m, --mps-export | Export anonymous MPS, weekly or daily optimal UC+dispatch linear (MPS will be named if the problem is infeasible) | | -s, --named-mps-problems | Export named MPS, weekly or daily optimal UC+dispatch linear | | --solver-logs | Print solver logs | | --solver-parameters | Set solver-specific parameters, for instance `--solver-parameters="THREADS 1 PRESOLVE 1"` for XPRESS or `--solver-parameters="parallel/maxnthreads 1, lp/presolving TRUE"` for SCIP. Syntax is solver-dependent, and only supported for SCIP & XPRESS. | @@ -54,4 +54,4 @@ hide: | -p, --pid=VALUE | Specify the file where to write the process ID | | --list-solvers | Display a list of LP solvers available through OR-Tools and exit | | -v, --version | Print the version of the solver and exit | -| -h, --help | Display this help and exit | \ No newline at end of file +| -h, --help | Display this help and exit | diff --git a/docs/user-guide/solver/09-appendix.md b/docs/user-guide/solver/09-appendix.md index 3ab1b49f6d..1f8e24673d 100644 --- a/docs/user-guide/solver/09-appendix.md +++ b/docs/user-guide/solver/09-appendix.md @@ -64,9 +64,9 @@ With `..._MPS` options, the full expression of the faulty problem(s) is printed thus allowing further analysis of the infeasibility issue. -## Details on the "initial-reservoir-levels" parameter -[//]: # (TODO: update this paragraph) -_**This section is under construction**_ +## Details on the "initial-reservoir-levels" parameter (DEPRECATED since 9.2) + +### version 9.2: The reservoir level is now always determined with cold start behavior. This parameter can take the two values "cold start" or "hot start". [default: cold start]. Simulations results may in some circumstances be heavily impacted by this setting, hence proper attention should be paid to its meaning before considering changing the default value. diff --git a/docs/user-guide/solver/optional-features/multi-threading.md b/docs/user-guide/solver/optional-features/multi-threading.md index c2c13bee46..5d126a6672 100644 --- a/docs/user-guide/solver/optional-features/multi-threading.md +++ b/docs/user-guide/solver/optional-features/multi-threading.md @@ -24,21 +24,9 @@ This parameter can take five different values (Minimum, Low, Medium, High, Maxim The number of independent processes resulting from the combination (local hardware + study settings) is given in the following table, which shows the CPU allowances granted in the different configurations. -| _Available CPU Cores_ | _Minimum_ | _Low_ | _Medium_ | _Large_ | _Maximum_ | -|:---------------------:|:---------:|:---------:|:---------:|:----------:|:---------:| -| _1_ | 1 | 1 | 1 | 1 | 1 | -| _2_ | 1 | 1 | 1 | 2 | 2 | -| _3_ | 1 | 2 | 2 | 2 | 3 | -| _4_ | 1 | 2 | 2 | 3 | 4 | -| _5_ | 1 | 2 | 3 | 4 | 5 | -| _6_ | 1 | 2 | 3 | 4 | 6 | -| _7_ | 1 | 2 | 3 | 5 | 7 | -| _8_ | 1 | 2 | 4 | 6 | 8 | -| _9_ | 1 | 3 | 5 | 7 | 8 | -| _10_ | 1 | 3 | 5 | 8 | 9 | -| _11_ | 1 | 3 | 6 | 8 | 10 | -| _12_ | 1 | 3 | 6 | 9 | 11 | -| _S > 12_ | 1 | Ceil(S/4) | Ceil(S/2) | Ceil(3S/4) | S-1 | +| _Minimum_ | _Low_ | _Medium_ | _High_ | _Maximum_ | +|:---------:|:---------:|:---------:|:----------:|:---------:| +| 1 | Ceil(S/4) | Ceil(S/2) | Ceil(3S/4) | S | **Note**: The number of independent threads actually launched by Antares in parallel mode may appear smaller than that shown in the table above. In this case, the resources monitor menu and the dashboard displayed on starting the simulation indicates: @@ -54,6 +42,45 @@ Examples of reduction from an initial allowance of 12 cores are given hereafter. The Table indicates either the refresh status (No) or the refresh span (the associated refresh status "yes" is implicit). +## Formula for CPU cores + +Starting from 9.2 we changed the formula for the number of cores to simplify. Here's the old values and the new ones. + +### Starting from 9.2 + +-| _Available CPU Cores_ | _Minimum_ | _Low_ | _Medium_ | _High_ | _Maximum_ | +-|:---------------------:|:---------:|:---------:|:---------:|:----------:|:---------:| +-| _1_ | 1 | 1 | 1 | 1 | 1 | +-| _2_ | 1 | 1 | 1 | 2 | 2 | +-| _3_ | 1 | 1 | 2 | 3 | 3 | +-| _4_ | 1 | 1 | 2 | 3 | 4 | +-| _5_ | 1 | 2 | 3 | 4 | 5 | +-| _6_ | 1 | 2 | 3 | 5 | 6 | +-| _7_ | 1 | 2 | 4 | 6 | 7 | +-| _8_ | 1 | 2 | 4 | 6 | 8 | +-| _9_ | 1 | 3 | 5 | 7 | 9 | +-| _10_ | 1 | 3 | 5 | 8 | 10 | +-| _11_ | 1 | 3 | 6 | 9 | 11 | +-| _12_ | 1 | 3 | 6 | 9 | 12 | +-| _S > 12_ | 1 | Ceil(S/4) | Ceil(S/2) | Ceil(3S/4) | S | + +### Before 9.2 + +-| _Available CPU Cores_ | _Minimum_ | _Low_ | _Medium_ | _High_ | _Maximum_ | +-|:---------------------:|:---------:|:---------:|:---------:|:----------:|:---------:| +-| _1_ | 1 | 1 | 1 | 1 | 1 | +-| _2_ | 1 | 1 | 1 | 2 | 2 | +-| _3_ | 1 | 2 | 2 | 2 | 3 | +-| _4_ | 1 | 2 | 2 | 3 | 4 | +-| _5_ | 1 | 2 | 3 | 4 | 5 | +-| _6_ | 1 | 2 | 3 | 4 | 6 | +-| _7_ | 1 | 2 | 3 | 5 | 7 | +-| _8_ | 1 | 2 | 4 | 6 | 8 | +-| _9_ | 1 | 3 | 5 | 7 | 8 | +-| _10_ | 1 | 3 | 5 | 8 | 9 | +-| _11_ | 1 | 3 | 6 | 8 | 10 | +-| _12_ | 1 | 3 | 6 | 9 | 11 | +-| _S > 12_ | 1 | Ceil(S/4) | Ceil(S/2) | Ceil(3S/4) | S-1 | [^23]: When the number of MC years to run is smaller than the allowance, the parallel run includes all of these years in a single bundle and there is no "reduced allowance" message diff --git a/docs/user-guide/ts-generator/00-index.md b/docs/user-guide/ts-generator/00-index.md index 264054542c..d4ead75883 100644 --- a/docs/user-guide/ts-generator/00-index.md +++ b/docs/user-guide/ts-generator/00-index.md @@ -3,7 +3,7 @@ ```{toctree} :hidden: -01-overview.md +01-overview-tsgenerator.md 02-inputs.md 03-outputs.md 04-parameters.md diff --git a/docs/user-guide/ts-generator/01-overview.md b/docs/user-guide/ts-generator/01-overview-tsgenerator.md similarity index 100% rename from docs/user-guide/ts-generator/01-overview.md rename to docs/user-guide/ts-generator/01-overview-tsgenerator.md diff --git a/docs/user-guide/ts-generator/04-parameters.md b/docs/user-guide/ts-generator/04-parameters.md index 2fac490989..debe1465cc 100644 --- a/docs/user-guide/ts-generator/04-parameters.md +++ b/docs/user-guide/ts-generator/04-parameters.md @@ -12,7 +12,7 @@ These parameters are listed under the `[general]` section in the `.ini` file. --- ### Time-series parameters ---- + #### generate - **Expected value:** comma-seperated list of 0 to N elements among the following (case-insensitive): `load`, `wind`, `hydro`, `thermal`, `solar`, `renewables`, `max-power` (ex: `generate = load, hydro, wind`) diff --git a/mkdocs.yml b/mkdocs.yml index 23187934c1..cf71684518 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -84,6 +84,7 @@ nav: - 'Antares ecosystem': 'https://antares-doc.readthedocs.io' - 'Antares website': 'https://antares-simulator.org' - 'RTE website': 'http://www.rte-france.com/' + - 'Contact': 'https://github.com/AntaresSimulatorTeam/Antares_Simulator/issues/new?template=support_request.md' plugins: diff --git a/ortools_tag b/ortools_tag index fdaa0174f8..ef2956ed2d 100644 --- a/ortools_tag +++ b/ortools_tag @@ -1 +1 @@ -v9.8-rte1.0 \ No newline at end of file +v9.10-rte1.0 \ No newline at end of file diff --git a/simtest.json b/simtest.json index 9029e0c9bb..c1478f4703 100644 --- a/simtest.json +++ b/simtest.json @@ -1,3 +1,3 @@ { - "version": "v9.1.0-rc5" + "version": "v9.2.0d" } diff --git a/sonar-project.properties b/sonar-project.properties index 5065cb1141..2a76f458da 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,7 +1,7 @@ sonar.projectName=Antares_Simulator sonar.projectKey=AntaresSimulatorTeam_Antares_Simulator sonar.organization=antaressimulatorteam -sonar.projectVersion=9.0.0 +sonar.projectVersion=9.1.0 # ===================================================== # Properties that will be shared amongst all modules @@ -15,6 +15,5 @@ sonar.sourceEncoding=UTF-8 sonar.exclusions=src/ext/**,src/tests/**,src/ui/** sonar.coverage.exclusions=src/ext/**,src/tests/**,src/analyzer/**,src/distrib/**,src/tools/**,src/ui/** -sonar.cfamily.build-wrapper-output=_build/output sonar.coverageReportPaths=coverage.xml sonar.cfamily.threads=4 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97137c04e0..6422fe62f1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,12 +2,13 @@ cmake_minimum_required(VERSION 3.14) # FetchContent_MakeAvailable # Version set(ANTARES_VERSION_HI 9) -set(ANTARES_VERSION_LO 1) +set(ANTARES_VERSION_LO 2) set(ANTARES_VERSION_REVISION 0) + # Beta release set(ANTARES_BETA 0) -set(ANTARES_RC 0) +set(ANTARES_RC 3) set(ANTARES_VERSION_YEAR 2024) @@ -182,9 +183,6 @@ message(STATUS "Build antares tools: ${BUILD_TOOLS}") option(BUILD_ORTOOLS "Build OR-Tools" OFF) message(STATUS "Build OR-Tools: ${BUILD_ORTOOLS}") -option(BUILD_MINIZIP "Build minizip" OFF) -message(STATUS "Build minizip: ${BUILD_MINIZIP}") - option(WITH_ANTLR4 "With antlr4" OFF) message(STATUS "With antlr4: ${WITH_ANTLR4}") @@ -240,37 +238,18 @@ set(Boost_DEBUG 1) #Boost header libraries find_package(Boost REQUIRED) -#TODO : Add ZLIB if VCPKG used why is this needed -if (VCPKG_TOOLCHAIN) - #zlib - find_package(ZLIB REQUIRED) -endif() - #Sirius solver if(POLICY CMP0074) cmake_policy(SET CMP0074 NEW) endif() -if (VCPKG_TOOLCHAIN) - list(APPEND CMAKE_PREFIX_PATH "${sirius_solver_ROOT}") - list(APPEND CMAKE_PREFIX_PATH "${ortools_ROOT}") -endif() - -find_package(sirius_solver) - -if (NOT sirius_solver_FOUND) - message (FATAL_ERROR "Sirius solver not found. Sirius solver can be compiled with -DBUILD_sirius=ON or you can specify previous dependency install directory with -DCMAKE_PREFIX_PATH or -DDEPS_INSTALL_DIR") -endif() - -#gflags needed for ortools -set(GFLAGS_USE_TARGET_NAMESPACE TRUE) -find_package(gflags) +find_package(sirius_solver REQUIRED) find_package(ortools) if(NOT ortools_FOUND OR BUILD_ORTOOLS) message(STATUS "OR-Tools tag ${ORTOOLS_TAG}") FetchContent_Declare(ortools - GIT_REPOSITORY "https://github.com/rte-france/or-tools" + GIT_REPOSITORY "https://github.com/rte-france/or-tools-rte" GIT_TAG ${ORTOOLS_TAG} GIT_SHALLOW TRUE ) @@ -292,37 +271,17 @@ message(STATUS "OR-Tools tag ${ORTOOLS_TAG}") FetchContent_MakeAvailable(ortools) endif() -find_package(minizip QUIET) - -if(NOT minizip_FOUND OR BUILD_MINIZIP) - if (NOT minizip_FOUND) - message("minizip not found, downloading") +find_package(minizip-ng QUIET) +if (minizip-ng_FOUND) + add_library(MINIZIP::minizip ALIAS MINIZIP::minizip-ng) +else () + find_package(minizip) + if (minizip_FOUND) + message (STATUS "Found minizip (not minizip-ng).") + else () + message (FATAL_ERROR "Minizip not found.") endif () - if (BUILD_MINIZIP) - message("BUILD_MINIZIP set, downloading") - endif () - # Repository + tag - set(MZ_REPOSITORY "https://github.com/zlib-ng/minizip-ng.git") - set(MZ_TAG "4.0.1") - # CMake flags - set(MZ_LZMA "OFF" CACHE INTERNAL "") - set(MZ_ZSTD "OFF" CACHE INTERNAL "") - set(MZ_BZIP2 "OFF" CACHE INTERNAL "") - set(MZ_PKCRYPT "OFF" CACHE INTERNAL "") - set(MZ_WZAES "OFF" CACHE INTERNAL "") - set(MZ_OPENSSL "OFF" CACHE INTERNAL "") - set(MZ_ICONV "OFF" CACHE INTERNAL "") - - FetchContent_Declare(minizip - GIT_REPOSITORY ${MZ_REPOSITORY} - GIT_TAG ${MZ_TAG} - OVERRIDE_FIND_PACKAGE - ) - - FetchContent_MakeAvailable(minizip) -endif() -find_package(minizip REQUIRED) - +endif () #wxWidget not needed for all library find is done in ui CMakeLists.txt if (VCPKG_TOOLCHAIN AND NOT BUILD_wxWidgets) @@ -346,6 +305,7 @@ add_subdirectory("ext/yuni/src") OMESSAGE("") # empty line # Sub Directories +add_subdirectory(api) add_subdirectory(libs) #antares-core fswalker if(BUILD_UI) diff --git a/src/analyzer/atsp/cache.cpp b/src/analyzer/atsp/cache.cpp index 312dafe442..07ecd37803 100644 --- a/src/analyzer/atsp/cache.cpp +++ b/src/analyzer/atsp/cache.cpp @@ -37,7 +37,7 @@ void ATSP::cacheCreate() void ATSP::cacheDestroy() { delete[] pCacheMatrix; - pCacheMatrix = NULL; + pCacheMatrix = nullptr; } void ATSP::cacheClear() diff --git a/src/analyzer/atsp/correlations.cpp b/src/analyzer/atsp/correlations.cpp index af3c800d5c..120d9d8465 100644 --- a/src/analyzer/atsp/correlations.cpp +++ b/src/analyzer/atsp/correlations.cpp @@ -71,7 +71,7 @@ bool ATSP::computeMonthlyCorrelations() Matrix<> tmpNDP; tmpNDP.reset(realAreaCount, realAreaCount); - double* tmpArray = new double[realAreaCount + 1]; + std::vector tmpArray(realAreaCount + 1); // Initialize mapping, to skip areas which has been disabled // the real number of items is `realAreaCount` @@ -342,7 +342,7 @@ bool ATSP::computeMonthlyCorrelations() resultNDP.entry, ID.entry, ID.width, - tmpArray); + tmpArray.data()); if (shrink < 1.) { if (shrink <= -1.) @@ -381,7 +381,7 @@ bool ATSP::computeMonthlyCorrelations() resultNDP.entry, CORR_MNPZ.entry, CORR_MNPZ.width, - tmpArray); + tmpArray.data()); if (shrink < 1.) { if (shrink <= -1.) // CORR_MNPZ is too close to sdp boundary, shrink CORR_MNP instead @@ -393,7 +393,7 @@ bool ATSP::computeMonthlyCorrelations() resultNDP.entry, ID.entry, ID.width, - tmpArray); + tmpArray.data()); if (shrink <= -1.) { logs.error() << "invalid data, can not be processed"; @@ -505,7 +505,7 @@ bool ATSP::computeMonthlyCorrelations() resultNDP.entry, ID.entry, ID.width, - tmpArray); + tmpArray.data()); if (shrink < 1.) { if (shrink <= -1.) @@ -542,7 +542,7 @@ bool ATSP::computeMonthlyCorrelations() resultNDP.entry, CORR_YNPZ.entry, CORR_YNPZ.width, - tmpArray); + tmpArray.data()); if (shrink < 1.) { if (shrink <= -1.) // CORR_YNP is too close to sdp boundary, shrink CORR_YNP instead @@ -554,7 +554,7 @@ bool ATSP::computeMonthlyCorrelations() resultNDP.entry, ID.entry, ID.width, - tmpArray); + tmpArray.data()); if (shrink <= -1.) { logs.error() << "invalid data, can not be processed"; diff --git a/src/analyzer/atsp/load.cpp b/src/analyzer/atsp/load.cpp index f7a08f4d1a..b23f86f551 100644 --- a/src/analyzer/atsp/load.cpp +++ b/src/analyzer/atsp/load.cpp @@ -54,12 +54,12 @@ bool ATSP::loadFromINIFile(const String& filename) CString<50, false> key; CString<50, false> value; - for (section = ini.firstSection; section != NULL; section = section->next) + for (section = ini.firstSection; section; section = section->next) { if (section->name == ".general") { IniFile::Property* p = section->firstProperty; - for (; p != NULL; p = p->next) + for (; p; p = p->next) { key = p->key; key.toLower(); @@ -180,7 +180,7 @@ bool ATSP::loadFromINIFile(const String& filename) info->distribution = Data::XCast::dtBeta; IniFile::Property* p = section->firstProperty; - for (; p != NULL; p = p->next) + for (; p; p = p->next) { key = p->key; key.toLower(); diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index 65d9a81e95..201a61f9b2 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -101,7 +101,7 @@ static void NotEnoughMemory() exit(42); } -int main(int argc, char* argv[]) +int main(int argc, const char* argv[]) { // Dealing with the lack of memory std::set_new_handler(&NotEnoughMemory); diff --git a/src/antares-deps b/src/antares-deps deleted file mode 160000 index 0d6bebfb90..0000000000 --- a/src/antares-deps +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0d6bebfb901e47ec6ac1c73cb61a522803c81b98 diff --git a/src/api/API.cpp b/src/api/API.cpp new file mode 100644 index 0000000000..3580f34752 --- /dev/null +++ b/src/api/API.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include "API.h" + +#include + +#include +#include "antares/benchmarking/DurationCollector.h" +#include "antares/exception/LoadingError.hpp" +#include "antares/infoCollection/StudyInfoCollector.h" +#include "antares/solver/misc/options.h" +#include "antares/solver/simulation/simulation-run.h" + +namespace Antares::API +{ +SimulationResults APIInternal::run(const IStudyLoader& study_loader) +{ + try + { + study_ = study_loader.load(); + } + catch (const ::Antares::Error::StudyFolderDoesNotExist& e) + { + Antares::API::Error err{.reason = e.what()}; + return {.simulationPath = "", .antares_problems = {}, .error = err}; + } + return execute(); +} + +/** + * @brief The execute method is used to execute the simulation. + * @return SimulationResults object which contains the results of the simulation. + * + * This method is initialy a copy of Application::execute with some modifications hence the apparent + * dupllication + */ +SimulationResults APIInternal::execute() const +{ + // study_ == nullptr e.g when the -h flag is given + if (!study_) + { + using namespace std::string_literals; + Antares::API::Error err{.reason = "Couldn't create study"s}; + return {.simulationPath{}, .antares_problems{}, .error = err}; + } + + // Only those two fields are used un simulation + Settings settings; + settings.tsGeneratorsOnly = false; + settings.noOutput = false; + + Benchmarking::DurationCollector durationCollector; + Benchmarking::OptimizationInfo optimizationInfo; + auto ioQueueService = std::make_shared(); + ioQueueService->maximumThreadCount(1); + ioQueueService->start(); + auto resultWriter = Solver::resultWriterFactory(study_->parameters.resultFormat, + study_->folderOutput, + ioQueueService, + durationCollector); + SimulationObserver simulationObserver; + + optimizationInfo = simulationRun(*study_, + settings, + durationCollector, + *resultWriter, + simulationObserver); + + // Importing Time-Series if asked + study_->importTimeseriesIntoInput(); + + return {.simulationPath = study_->folderOutput.c_str(), + .antares_problems = simulationObserver.acquireLps(), + .error{}}; +} +} // namespace Antares::API diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt new file mode 100644 index 0000000000..109c640578 --- /dev/null +++ b/src/api/CMakeLists.txt @@ -0,0 +1,42 @@ +add_library(solver_api) +add_library(Antares::solver_api ALIAS solver_api) + +set(PUBLIC_HEADERS + include/antares/api/SimulationResults.h + include/antares/api/solver.h +) + +set(PRIVATE_HEADERS + private/API.h + private/SimulationObserver.h +) + +target_sources(solver_api + PRIVATE + solver.cpp + API.cpp + SimulationObserver.cpp + SimulationResults.cpp + ${PUBLIC_HEADERS} + ${PRIVATE_HEADERS} +) + +target_include_directories(solver_api + PUBLIC + $ + PRIVATE + $ +) + +target_link_libraries(solver_api + PRIVATE + Antares::study + Antares::study-loader + Antares::file-tree-study-loader + antares-solver-simulation + PUBLIC + Antares::lps +) +install(DIRECTORY include/antares + DESTINATION "include" +) \ No newline at end of file diff --git a/src/api/SimulationObserver.cpp b/src/api/SimulationObserver.cpp new file mode 100644 index 0000000000..2291702082 --- /dev/null +++ b/src/api/SimulationObserver.cpp @@ -0,0 +1,74 @@ + +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include "SimulationObserver.h" + +#include "antares/solver/optimisation/HebdoProblemToLpsTranslator.h" + +namespace Antares::API +{ +namespace +{ +auto translate(const PROBLEME_HEBDO& problemeHebdo, + std::string_view name, + const Solver::HebdoProblemToLpsTranslator& translator, + std::once_flag& flag) +{ + auto weekly_data = translator.translate(problemeHebdo.ProblemeAResoudre.get(), name); + std::optional common_data; + bool translateCommonData = false; + std::call_once(flag, [&translateCommonData]() { translateCommonData = true; }); + if (translateCommonData) + { + common_data = translator.commonProblemData(problemeHebdo.ProblemeAResoudre.get()); + } + return std::make_pair(common_data, weekly_data); +} +} // namespace + +void SimulationObserver::notifyHebdoProblem(const PROBLEME_HEBDO& problemeHebdo, + int optimizationNumber, + std::string_view name) +{ + if (optimizationNumber != 1) + { + return; // We only care about first optimization + } + Solver::HebdoProblemToLpsTranslator translator; + const unsigned int year = problemeHebdo.year + 1; + const unsigned int week = problemeHebdo.weekInTheYear + 1; + // common_data and weekly_data computed before the mutex lock to prevent blocking the thread + auto [common_data, weekly_data] = translate(problemeHebdo, name, translator, flag_); + std::lock_guard lock(lps_mutex_); + if (common_data) + { + lps_.setConstantData(common_data.value()); + } + lps_.addWeeklyData({year, week}, weekly_data); +} + +Solver::LpsFromAntares&& SimulationObserver::acquireLps() noexcept +{ + std::lock_guard lock(lps_mutex_); + return std::move(lps_); +} +} // namespace Antares::API diff --git a/src/api/SimulationResults.cpp b/src/api/SimulationResults.cpp new file mode 100644 index 0000000000..63c5127a49 --- /dev/null +++ b/src/api/SimulationResults.cpp @@ -0,0 +1,22 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include "antares/api/SimulationResults.h" diff --git a/src/api/include/antares/api/SimulationResults.h b/src/api/include/antares/api/SimulationResults.h new file mode 100644 index 0000000000..5a5e93982a --- /dev/null +++ b/src/api/include/antares/api/SimulationResults.h @@ -0,0 +1,62 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once +#include +#include +#include +#include "antares/solver/lps/LpsFromAntares.h" + +namespace Antares::API +{ +/** + * @struct Error + * @brief The Error structure is used to represent an error that occurred during the simulation. + */ +struct Error { + /** + * @brief The reason for the error. + */ + std::string reason; +}; + +/** + * @struct SimulationResults + * @brief The SimulationResults structure is used to represent the results of a simulation. + * @details It contains the path to the simulation, weekly problems, and an optional error. + */ +struct [[nodiscard("Contains results and potential error")]] SimulationResults +{ + /** + * @brief The path to the simulation (output). + */ + std::filesystem::path simulationPath; + /** + * @brief weekly problems + */ + Antares::Solver::LpsFromAntares antares_problems; + /** + * @brief An optional error that occurred during the simulation. + */ + std::optional error; +}; + +} \ No newline at end of file diff --git a/src/api/include/antares/api/solver.h b/src/api/include/antares/api/solver.h new file mode 100644 index 0000000000..d016a9a08a --- /dev/null +++ b/src/api/include/antares/api/solver.h @@ -0,0 +1,35 @@ + +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once +#include "SimulationResults.h" + +namespace Antares::API +{ +/** + * @brief The PerformSimulation function is used to perform a simulation. + * @param study_path The path to the study to be simulated. + * @return SimulationResults object which contains the results of the simulation. + * @exception noexcept This function does not throw exceptions. + */ +SimulationResults PerformSimulation(const std::filesystem::path& study_path) noexcept; +} // namespace Antares::API diff --git a/src/api/private/API.h b/src/api/private/API.h new file mode 100644 index 0000000000..91f8a4e2d3 --- /dev/null +++ b/src/api/private/API.h @@ -0,0 +1,56 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once +#include + +#include +#include "antares/api/SimulationResults.h" + +namespace Antares::Data +{ +class Study; +} + +namespace Antares::API +{ + +/** + * @class APIInternal + * @brief The APIInternal class is used to run simulations. + */ +class APIInternal +{ +public: + /** + * @brief The run method is used to run the simulation. + * @param study_loader A pointer to an IStudyLoader object. The IStudyLoader object is used to + * load the study that will be simulated. + * @return SimulationResults object which contains the results of the simulation. + */ + SimulationResults run(const IStudyLoader& study_loader); + +private: + std::shared_ptr study_; + SimulationResults execute() const; +}; + +} // namespace Antares::API diff --git a/src/api/private/SimulationObserver.h b/src/api/private/SimulationObserver.h new file mode 100644 index 0000000000..30a69b3bae --- /dev/null +++ b/src/api/private/SimulationObserver.h @@ -0,0 +1,62 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once +#include +#include + +namespace Antares::API +{ + +/** + * @class SimulationObserver + * @brief The SimulationObserver class is used to observe the simulation. + * @details It inherits from the ISimulationObserver interface and overrides the notifyHebdoProblem + * method. + */ +class SimulationObserver: public Solver::Simulation::ISimulationObserver +{ +public: + /** + * @brief Used to notify of a solver HEBDO_PROBLEM. + * HEBDO_PROBLEM is assumed to be properly constructed and valid in order to build + * LpsFromAntares properly + * @param problemeHebdo A pointer to a PROBLEME_HEBDO object representing the problem. + * @param optimizationNumber The number of the optimization. + * @param name The name of the problem. + */ + void notifyHebdoProblem(const PROBLEME_HEBDO& problemeHebdo, + int optimizationNumber, + std::string_view name) override; + + /** + * @brief The acquireLps method is used to take ownership of Antares problems. + * @return An LpsFromAntares object containing the linear programming problems. + */ + Solver::LpsFromAntares&& acquireLps() noexcept; + +private: + Solver::LpsFromAntares lps_; + mutable std::mutex lps_mutex_; + mutable std::once_flag flag_; +}; + +} // namespace Antares::API diff --git a/src/api/solver.cpp b/src/api/solver.cpp new file mode 100644 index 0000000000..6e2f7068ea --- /dev/null +++ b/src/api/solver.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include +#include "antares/file-tree-study-loader/FileTreeStudyLoader.h" +#include "antares/study-loader/IStudyLoader.h" + +#include "private/API.h" + +namespace Antares::API +{ + +SimulationResults PerformSimulation(const std::filesystem::path& study_path) noexcept +{ + try + { + APIInternal api; + FileTreeStudyLoader study_loader(study_path); + return api.run(study_loader); + } + catch (const std::exception& e) + { + Antares::API::Error err{.reason = e.what()}; + return SimulationResults{.simulationPath = study_path, .antares_problems{}, .error = err}; + } +} + +} // namespace Antares::API diff --git a/src/api_client_example/CMakeLists.txt b/src/api_client_example/CMakeLists.txt new file mode 100644 index 0000000000..570ee9341b --- /dev/null +++ b/src/api_client_example/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.5) + +PROJECT(API_client) + +set(CMAKE_CXX_STANDARD 20) + +add_subdirectory(src) + +include(CTest) +if (BUILD_TESTING) + add_subdirectory(tests) +endif () \ No newline at end of file diff --git a/src/api_client_example/README.md b/src/api_client_example/README.md new file mode 100644 index 0000000000..151b1d346b --- /dev/null +++ b/src/api_client_example/README.md @@ -0,0 +1,3 @@ +Client for antares solver API + +To demonstrate as much capabilities as possible this client should stay stand alone this mean not added as a sub_directory for cmake diff --git a/src/api_client_example/src/API_client.cpp b/src/api_client_example/src/API_client.cpp new file mode 100644 index 0000000000..6489806c51 --- /dev/null +++ b/src/api_client_example/src/API_client.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + + +#include "API_client.h" + +#include + +Antares::API::SimulationResults solve(std::filesystem::path study_path) { + return Antares::API::PerformSimulation(std::move(study_path)); +} + diff --git a/src/api_client_example/src/API_client.h b/src/api_client_example/src/API_client.h new file mode 100644 index 0000000000..5d8500649e --- /dev/null +++ b/src/api_client_example/src/API_client.h @@ -0,0 +1,28 @@ + +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include +#include + +Antares::API::SimulationResults solve(std::filesystem::path study_path); diff --git a/src/api_client_example/src/CMakeLists.txt b/src/api_client_example/src/CMakeLists.txt new file mode 100644 index 0000000000..55ebb33579 --- /dev/null +++ b/src/api_client_example/src/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(API_client) + +target_sources(API_client + PRIVATE + API_client.cpp + API_client.h +) + +find_package(Antares REQUIRED) +target_link_libraries(API_client PUBLIC Antares::solver_api) +target_include_directories(API_client + PUBLIC + $ +) \ No newline at end of file diff --git a/src/api_client_example/tests/CMakeLists.txt b/src/api_client_example/tests/CMakeLists.txt new file mode 100644 index 0000000000..1fc9c3cc89 --- /dev/null +++ b/src/api_client_example/tests/CMakeLists.txt @@ -0,0 +1,17 @@ +find_package(Boost COMPONENTS unit_test_framework REQUIRED) + +add_executable(test_client) + +target_sources(test_client + PRIVATE + test.cpp +) + +target_link_libraries(test_client + PRIVATE + API_client + Boost::unit_test_framework +) + +add_test(NAME testclient COMMAND test_client) +set_property(TEST testclient PROPERTY LABELS integ) \ No newline at end of file diff --git a/src/api_client_example/tests/test.cpp b/src/api_client_example/tests/test.cpp new file mode 100644 index 0000000000..4adee7bfd6 --- /dev/null +++ b/src/api_client_example/tests/test.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define BOOST_TEST_MODULE test_client_api + +#include +#include "API_client.h" + +BOOST_AUTO_TEST_CASE(test_run) { + auto results = solve("dummy_study_test_client_api"); + BOOST_CHECK(results.error); + BOOST_CHECK(!results.error->reason.empty()); + auto c = results.error->reason; + std::cout << c << std::endl; + BOOST_CHECK(results.error->reason.find("Study") != std::string::npos); + BOOST_CHECK(results.error->reason.find("folder") != std::string::npos); + BOOST_CHECK(results.error->reason.find("not") != std::string::npos); + BOOST_CHECK(results.error->reason.find("exist") != std::string::npos); +} \ No newline at end of file diff --git a/src/cmake/wxWidgets/FindwxWidgets.cmake b/src/cmake/wxWidgets/FindwxWidgets.cmake index dea003dce6..c174be3ed7 100644 --- a/src/cmake/wxWidgets/FindwxWidgets.cmake +++ b/src/cmake/wxWidgets/FindwxWidgets.cmake @@ -820,7 +820,6 @@ else() find_program(wxWidgets_CONFIG_EXECUTABLE NAMES $ENV{WX_CONFIG} wx-config wx-config-3.1 wx-config-3.0 wx-config-2.9 wx-config-2.8 DOC "Location of wxWidgets library configuration provider binary (wx-config)." - ONLY_CMAKE_FIND_ROOT_PATH ) if(wxWidgets_CONFIG_EXECUTABLE) diff --git a/src/ext/yuni/src/yuni/core/any/any.cpp b/src/ext/yuni/src/yuni/core/any/any.cpp index 47017ed8d1..36e2257c32 100644 --- a/src/ext/yuni/src/yuni/core/any/any.cpp +++ b/src/ext/yuni/src/yuni/core/any/any.cpp @@ -16,7 +16,7 @@ namespace Yuni Any::Any() { pTable = Private::Any::Table::Get(); - pObject = NULL; + pObject = nullptr; } Any::Any(const Any& rhs) @@ -59,7 +59,7 @@ void Any::reset() { pTable->staticDelete(&pObject); pTable = Private::Any::Table::Get(); - pObject = NULL; + pObject = nullptr; } } diff --git a/src/ext/yuni/src/yuni/core/charset/charset.cpp b/src/ext/yuni/src/yuni/core/charset/charset.cpp index 2323581439..30c63e0bd2 100644 --- a/src/ext/yuni/src/yuni/core/charset/charset.cpp +++ b/src/ext/yuni/src/yuni/core/charset/charset.cpp @@ -61,7 +61,7 @@ void Converter::reset() { if (!valid()) return; - iconv((iconv_t)pContext, NULL, NULL, NULL, NULL); + iconv((iconv_t)pContext, nullptr, nullptr, nullptr, nullptr); } const char* Converter::Name(Charset::Type type) diff --git a/src/ext/yuni/src/yuni/core/dynamiclibrary/file.cpp b/src/ext/yuni/src/yuni/core/dynamiclibrary/file.cpp index 54f35580a4..0f673490b3 100644 --- a/src/ext/yuni/src/yuni/core/dynamiclibrary/file.cpp +++ b/src/ext/yuni/src/yuni/core/dynamiclibrary/file.cpp @@ -215,7 +215,7 @@ bool File::loadFromRawFilename(const AnyString& filename, File::Relocation r, Fi bool File::hasSymbol(const AnyString& name) const { return NullHandle != pHandle - and NULL != reinterpret_cast(YUNI_DYNLIB_DLSYM(pHandle, name.c_str())); + && reinterpret_cast(YUNI_DYNLIB_DLSYM(pHandle, name.c_str())); } Symbol File::resolve(const AnyString& name) const diff --git a/src/ext/yuni/src/yuni/core/getopt/parser.cpp b/src/ext/yuni/src/yuni/core/getopt/parser.cpp index c34443c470..909b00a5da 100644 --- a/src/ext/yuni/src/yuni/core/getopt/parser.cpp +++ b/src/ext/yuni/src/yuni/core/getopt/parser.cpp @@ -9,8 +9,9 @@ ** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror) */ #include "parser.h" -#include + #include +#include // The standard error output is not displayed on Windows #ifndef YUNI_OS_WINDOWS @@ -75,7 +76,7 @@ class Context final /*! ** \brief parse the command line */ - GetOpt::ReturnCode operator()(int argc, char* argv[]); + GetOpt::ReturnCode operator()(int argc, const char* argv[]); private: //! An option has not been found @@ -83,7 +84,7 @@ class Context final //! A additional parameter is missing for an option void parameterIsMissing(const char* name); //! Find the additional parameter and add it to the option - bool findNextParameter(IOption* option, int argc, char* argv[]); + bool findNextParameter(IOption* option, int argc, const char* argv[]); private: //! The public class for the parser, where all options are stored @@ -111,14 +112,17 @@ inline Context::TokenType Context::GetTokenType(const char* argv) #endif } -inline Context::Context(Parser& parser) : pParser(parser), pTokenIndex(1), pParameterIndex(1) +inline Context::Context(Parser& parser): + pParser(parser), + pTokenIndex(1), + pParameterIndex(1) { pParser.pErrors = 0; } -bool Context::findNextParameter(IOption* option, int argc, char* argv[]) +bool Context::findNextParameter(IOption* option, int argc, const char* argv[]) { - assert(option != NULL); + assert(option); if (not option->requireAdditionalParameter()) { @@ -160,7 +164,7 @@ void Context::parameterIsMissing(const char* name) STD_CERR << "Error: The parameter for `" << name << "` is missing" << std::endl; } -GetOpt::ReturnCode Context::operator()(int argc, char* argv[]) +GetOpt::ReturnCode Context::operator()(int argc, const char* argv[]) { using namespace GetOpt; while (pTokenIndex < argc) @@ -178,8 +182,10 @@ GetOpt::ReturnCode Context::operator()(int argc, char* argv[]) if (i != pParser.pShortNames.end()) { if (not findNextParameter(i->second, argc, argv)) + { std::cerr << "Error: The parameter is missing for `" << arg << "`" << std::endl; + } } else { @@ -200,7 +206,9 @@ GetOpt::ReturnCode Context::operator()(int argc, char* argv[]) ++arg; ++arg; if ('\0' == *arg) // End of options + { return (0 == pParser.pErrors) ? ReturnCode::ok : ReturnCode::error; + } if ((sub = strchr(arg, '='))) { @@ -239,7 +247,9 @@ GetOpt::ReturnCode Context::operator()(int argc, char* argv[]) if (i != pParser.pLongNames.end()) { if (not findNextParameter(i->second, argc, argv)) + { parameterIsMissing(arg); + } } else { @@ -261,7 +271,9 @@ GetOpt::ReturnCode Context::operator()(int argc, char* argv[]) { pParameterIndex = pTokenIndex; if (pParser.pRemains) + { pParser.pRemains->addValue(arg, static_cast(::strlen(arg))); + } } break; } @@ -295,7 +307,10 @@ static const char* ExtractFilenameOnly(const char* argv) return result; } -Parser::Parser() : pRemains(nullptr), pErrors(0), pIgnoreUnknownArgs(false) +Parser::Parser(): + pRemains(nullptr), + pErrors(0), + pIgnoreUnknownArgs(false) { } @@ -305,7 +320,9 @@ Parser::~Parser() { OptionList::iterator end = pAllOptions.end(); for (OptionList::iterator i = pAllOptions.begin(); i != end; ++i) + { delete *i; + } } delete pRemains; @@ -317,7 +334,9 @@ void Parser::clear() { OptionList::iterator end = pAllOptions.end(); for (OptionList::iterator i = pAllOptions.begin(); i != end; ++i) + { delete *i; + } // clear-and-minimize idiom OptionsOrderedByShortName emptyShort; @@ -335,7 +354,7 @@ void Parser::clear() pRemains = nullptr; } -GetOpt::ReturnCode Parser::operator()(int argc, char* argv[]) +GetOpt::ReturnCode Parser::operator()(int argc, const char* argv[]) { Private::GetOptImpl::Context context(*this); return context(argc, argv); @@ -343,16 +362,20 @@ GetOpt::ReturnCode Parser::operator()(int argc, char* argv[]) void Parser::helpUsage(const char* argv0) { - assert(argv0 != NULL); // just in case + assert(argv0); // just in case// OK std::cout.write("Usage: ", 7); std::cout << ExtractFilenameOnly(argv0); std::cout.write(" [OPTION]...", 12); if (pRemains) + { std::cout.write(" [FILE]...\n", 11); + } else + { std::cout << '\n'; + } if (not pAllOptions.empty()) { @@ -362,21 +385,33 @@ void Parser::helpUsage(const char* argv0) // Add a space if the first option is not a paragraph // In this case the user would do what he wants if (not dynamic_cast(*i)) + { std::cout << '\n'; + } for (; i != end; ++i) + { (*i)->helpUsage(std::cout); + } } // Help if (pLongNames.end() == pLongNames.find("help")) { if (pShortNames.end() == pShortNames.find('h')) - Private::GetOptImpl::DisplayHelpForOption( - std::cout, 'h', "help", "Display this help and exit"); + { + Private::GetOptImpl::DisplayHelpForOption(std::cout, + 'h', + "help", + "Display this help and exit"); + } else - Private::GetOptImpl::DisplayHelpForOption( - std::cout, ' ', "help", "Display this help and exit"); + { + Private::GetOptImpl::DisplayHelpForOption(std::cout, + ' ', + "help", + "Display this help and exit"); + } } std::cout << std::endl; // flush @@ -388,7 +423,9 @@ void Parser::appendShortOption(IOption* option, char shortname) pAllOptions.push_back(option); // The short name if (shortname != ' ' and shortname != '\0') + { pShortNames[shortname] = option; + } } void Parser::appendOption(IOption* option, char shortname) @@ -403,7 +440,9 @@ void Parser::appendOption(IOption* option, char shortname) and "The long name of an option must be igreater than 1 (ambigous on Windows)"); #else if (longname.size() == 1) // ambigous on Windows, must not continue + { return; + } #endif pLongNames[longname.c_str()] = option; @@ -414,7 +453,9 @@ void Parser::appendOption(IOption* option, char shortname) // The short name if (shortname != ' ' and shortname != '\0') + { pShortNames[shortname] = option; + } } } // namespace GetOpt diff --git a/src/ext/yuni/src/yuni/core/getopt/parser.h b/src/ext/yuni/src/yuni/core/getopt/parser.h index e025909c4b..90c490089d 100644 --- a/src/ext/yuni/src/yuni/core/getopt/parser.h +++ b/src/ext/yuni/src/yuni/core/getopt/parser.h @@ -9,12 +9,13 @@ ** gitlab: https://gitlab.com/libyuni/libyuni/ (mirror) */ #pragma once -#include "../validator/text/default.h" -#include "option.h" -#include "../../yuni.h" #include #include +#include "../../yuni.h" +#include "../validator/text/default.h" +#include "option.h" + namespace Yuni { namespace GetOpt @@ -167,7 +168,7 @@ class YUNI_DECL Parser final ** \param argv The list of arguments ** \return False if the program should abort */ - ReturnCode operator()(int argc, char* argv[]); + ReturnCode operator()(int argc, const char* argv[]); //@} //! \name Help usage diff --git a/src/ext/yuni/src/yuni/core/system/environment.cpp b/src/ext/yuni/src/yuni/core/system/environment.cpp index 8f278e971e..cb5a5c9800 100644 --- a/src/ext/yuni/src/yuni/core/system/environment.cpp +++ b/src/ext/yuni/src/yuni/core/system/environment.cpp @@ -45,7 +45,7 @@ inline bool ReadImpl(const AnyString& name, StringT& out, bool emptyBefore) if (size != 0) { int sizeRequired - = WideCharToMultiByte(CP_UTF8, 0, buffer, (int)size - 1, NULL, 0, NULL, NULL); + = WideCharToMultiByte(CP_UTF8, 0, buffer, (int)size - 1, nullptr, 0, nullptr, nullptr); if (sizeRequired > 0) { out.reserve(out.size() + sizeRequired); @@ -55,8 +55,8 @@ inline bool ReadImpl(const AnyString& name, StringT& out, bool emptyBefore) (int)size - 1, out.data() + out.size(), size, - NULL, - NULL); + nullptr, + nullptr); ::free(buffer); out.resize(out.size() + (uint)sizeRequired); return true; diff --git a/src/ext/yuni/src/yuni/core/system/gettimeofday.cpp b/src/ext/yuni/src/yuni/core/system/gettimeofday.cpp index a8d3ec2aee..18ff782ed8 100644 --- a/src/ext/yuni/src/yuni/core/system/gettimeofday.cpp +++ b/src/ext/yuni/src/yuni/core/system/gettimeofday.cpp @@ -19,7 +19,7 @@ namespace Yuni { int gettimeofday(struct timeval* tv, struct timezone* tz) { - if (NULL != tv) + if (tv) { struct _timeb timebuffer; _ftime64_s(&timebuffer); @@ -27,7 +27,7 @@ int gettimeofday(struct timeval* tv, struct timezone* tz) tv->tv_usec = (int64_t)(timebuffer.millitm * 1000); } - if (NULL != tz) + if (tz) { static int tzflag = 0; if (!tzflag) diff --git a/src/ext/yuni/src/yuni/core/system/memory.cpp b/src/ext/yuni/src/yuni/core/system/memory.cpp index a872a46b02..4e1bfbce29 100644 --- a/src/ext/yuni/src/yuni/core/system/memory.cpp +++ b/src/ext/yuni/src/yuni/core/system/memory.cpp @@ -268,7 +268,7 @@ uint64_t Total() int mib[2] = {CTL_HW, HW_MEMSIZE}; uint64_t memory; size_t len = sizeof(uint64_t); - return (!sysctl(mib, 2, &memory, &len, NULL, 0)) ? memory : (uint64_t)defaultTotal; + return (!sysctl(mib, 2, &memory, &len, nullptr, 0)) ? memory : (uint64_t)defaultTotal; } uint64_t Available() @@ -298,7 +298,7 @@ bool Usage::update() int mib[2] = {CTL_HW, HW_MEMSIZE}; size_t len = sizeof(uint64_t); size_t sttotal; - if (sysctl(mib, 2, &sttotal, &len, NULL, 0)) + if (sysctl(mib, 2, &sttotal, &len, nullptr, 0)) { total = (uint64_t)defaultTotal; return false; diff --git a/src/ext/yuni/src/yuni/core/system/username.cpp b/src/ext/yuni/src/yuni/core/system/username.cpp index 9e5b57cf7c..1348b2e02c 100644 --- a/src/ext/yuni/src/yuni/core/system/username.cpp +++ b/src/ext/yuni/src/yuni/core/system/username.cpp @@ -37,12 +37,12 @@ uint WindowsUsername(char* cstring, uint size) // The variable `unwsize` contains the final zero --unwsize; // Getting the size of the buffer into UTF8 - int sizeRequired = WideCharToMultiByte(CP_UTF8, 0, unw, unwsize, NULL, 0, NULL, NULL); + int sizeRequired = WideCharToMultiByte(CP_UTF8, 0, unw, unwsize, nullptr, 0, nullptr, nullptr); if (sizeRequired > 0) { if (static_cast(sizeRequired) > size) sizeRequired = size; - WideCharToMultiByte(CP_UTF8, 0, unw, unwsize, cstring, sizeRequired, NULL, NULL); + WideCharToMultiByte(CP_UTF8, 0, unw, unwsize, cstring, sizeRequired, nullptr, nullptr); return static_cast(sizeRequired); } } diff --git a/src/ext/yuni/src/yuni/datetime/timestamp.cpp b/src/ext/yuni/src/yuni/datetime/timestamp.cpp index 90c1b26496..06c2fa68e9 100644 --- a/src/ext/yuni/src/yuni/datetime/timestamp.cpp +++ b/src/ext/yuni/src/yuni/datetime/timestamp.cpp @@ -97,9 +97,9 @@ char* FormatTimestampToString(const AnyString& format, int64_t timestamp) if (timestamp <= 0) { #ifdef YUNI_OS_MSVC - timestamp = (int64_t)::_time64(NULL); + timestamp = (int64_t)::_time64(nullptr); #else - timestamp = (int64_t)::time(NULL); + timestamp = (int64_t)::time(nullptr); #endif } diff --git a/src/ext/yuni/src/yuni/io/directory/info/platform.cpp b/src/ext/yuni/src/yuni/io/directory/info/platform.cpp index 7a330da911..516a344f41 100644 --- a/src/ext/yuni/src/yuni/io/directory/info/platform.cpp +++ b/src/ext/yuni/src/yuni/io/directory/info/platform.cpp @@ -189,12 +189,12 @@ class DirInfo final : private Yuni::NonCopyable } const int sizeRequired - = WideCharToMultiByte(CP_UTF8, 0, data.name, -1, NULL, 0, NULL, NULL); + = WideCharToMultiByte(CP_UTF8, 0, data.name, -1, nullptr, 0, nullptr, nullptr); if (sizeRequired <= 0) continue; name.reserve((uint)sizeRequired); WideCharToMultiByte( - CP_UTF8, 0, data.name, -1, (char*)name.data(), sizeRequired, NULL, NULL); + CP_UTF8, 0, data.name, -1, (char*)name.data(), sizeRequired, nullptr, nullptr); name.resize(((uint)sizeRequired) - 1); filename.clear(); @@ -341,12 +341,12 @@ IteratorData* IteratorDataCreate(const AnyString& folder, uint flags) data->push(folder); return data; } - return NULL; + return nullptr; } IteratorData* IteratorDataCopy(const IteratorData* data) { - return (data) ? (new IteratorData(*data)) : NULL; + return (data) ? (new IteratorData(*data)) : nullptr; } void IteratorDataFree(const IteratorData* data) @@ -356,52 +356,52 @@ void IteratorDataFree(const IteratorData* data) IteratorData* IteratorDataNext(IteratorData* data) { - assert(data != NULL); + assert(data); if (data->next()) return data; delete data; - return NULL; + return nullptr; } const String& IteratorDataFilename(const IteratorData* data) { - assert(data != NULL); + assert(data); return data->dirinfo.front().filename; } const String& IteratorDataParentName(const IteratorData* data) { - assert(data != NULL); + assert(data); return data->dirinfo.front().parent; } const String& IteratorDataName(const IteratorData* data) { - assert(data != NULL); + assert(data); return data->dirinfo.front().name; } uint64_t IteratorDataSize(const IteratorData* data) { - assert(data != NULL); + assert(data); return data->dirinfo.front().size; } int64_t IteratorDataModified(const IteratorData* data) { - assert(data != NULL); + assert(data); return data->dirinfo.front().modified; } bool IteratorDataIsFolder(const IteratorData* data) { - assert(data != NULL); + assert(data); return data->dirinfo.front().isFolder; } bool IteratorDataIsFile(const IteratorData* data) { - assert(data != NULL); + assert(data); return !data->dirinfo.front().isFolder; } diff --git a/src/ext/yuni/src/yuni/io/directory/iterator/iterator.cpp b/src/ext/yuni/src/yuni/io/directory/iterator/iterator.cpp index 2bcbd5743c..c4ddc8f573 100644 --- a/src/ext/yuni/src/yuni/io/directory/iterator/iterator.cpp +++ b/src/ext/yuni/src/yuni/io/directory/iterator/iterator.cpp @@ -148,7 +148,7 @@ Flow TraverseWindowsFolder(const String& filename, bool files) { // Convertir the filename - assert(opts.wbuffer != NULL); + assert(opts.wbuffer); opts.wbuffer[0] = L'\\'; opts.wbuffer[1] = L'\\'; opts.wbuffer[2] = L'?'; @@ -199,12 +199,12 @@ Flow TraverseWindowsFolder(const String& filename, } const int sizeRequired - = WideCharToMultiByte(CP_UTF8, 0, data.cFileName, -1, NULL, 0, NULL, NULL); + = WideCharToMultiByte(CP_UTF8, 0, data.cFileName, -1, nullptr, 0, nullptr, nullptr); if (sizeRequired <= 0) continue; newName.reserve((uint)sizeRequired); WideCharToMultiByte( - CP_UTF8, 0, data.cFileName, -1, (char*)newName.data(), sizeRequired, NULL, NULL); + CP_UTF8, 0, data.cFileName, -1, (char*)newName.data(), sizeRequired, nullptr, nullptr); newName.resize(((uint)sizeRequired) - 1); newFilename.clear(); diff --git a/src/ext/yuni/src/yuni/io/directory/remove.cpp b/src/ext/yuni/src/yuni/io/directory/remove.cpp index e35f9664f9..e5a936599a 100644 --- a/src/ext/yuni/src/yuni/io/directory/remove.cpp +++ b/src/ext/yuni/src/yuni/io/directory/remove.cpp @@ -73,7 +73,7 @@ static bool RmDirRecursiveInternal(const AnyString& path) buffer.clear() << path << SEP << (const char*)ep->d_name; ::unlink(buffer.c_str()); } - } while (NULL != (ep = ::readdir(dp))); + } while (nullptr != (ep = ::readdir(dp))); } (void)::closedir(dp); } diff --git a/src/ext/yuni/src/yuni/io/file/file.cpp b/src/ext/yuni/src/yuni/io/file/file.cpp index efe0dc80f8..9613b25b1d 100644 --- a/src/ext/yuni/src/yuni/io/file/file.cpp +++ b/src/ext/yuni/src/yuni/io/file/file.cpp @@ -71,7 +71,7 @@ bool Size(const AnyString& filename, uint64_t& value) } HANDLE hndl = CreateFileW( - wstr.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + wstr.c_str(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (hndl == INVALID_HANDLE_VALUE) { value = 0u; @@ -158,7 +158,7 @@ bool GetLastWriteTime(HANDLE hFile) // Convert the last-write time to local time. if (!FileTimeToSystemTime(&ftWrite, &stUTC)) return false; - if (!SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal)) + if (!SystemTimeToTzSpecificLocalTime(nullptr, &stUTC, &stLocal)) return false; return true; diff --git a/src/ext/yuni/src/yuni/io/file/stream.cpp b/src/ext/yuni/src/yuni/io/file/stream.cpp index 8815990c22..6d5c2cf375 100644 --- a/src/ext/yuni/src/yuni/io/file/stream.cpp +++ b/src/ext/yuni/src/yuni/io/file/stream.cpp @@ -121,7 +121,7 @@ bool Stream::open(const AnyString& filename, int mode) pFd = ::fopen(filename.c_str(), OpenMode::ToCString(mode)); #endif - return (NULL != pFd); + return (pFd); } bool Stream::close() @@ -130,7 +130,7 @@ bool Stream::close() { if (0 == ::fclose(pFd)) { - pFd = NULL; + pFd = nullptr; return true; } return false; diff --git a/src/ext/yuni/src/yuni/job/job.cpp b/src/ext/yuni/src/yuni/job/job.cpp index bef4051930..125bae6f51 100644 --- a/src/ext/yuni/src/yuni/job/job.cpp +++ b/src/ext/yuni/src/yuni/job/job.cpp @@ -21,14 +21,14 @@ IJob::IJob() : pThread(nullptr) IJob::~IJob() { - assert(this != NULL and "IJob: Destructor: Oo `this' is null !?"); - assert(pThread == NULL and "A job can not be attached to a thread when destroyed"); + assert(this && "IJob: Destructor: Oo `this' is null !?"); + assert(!pThread && "A job can not be attached to a thread when destroyed"); } bool IJob::suspend(uint delay) const { // This method must only be called from a thread - assert(pThread and "Job: The pointer to the attached thread must not be NULL"); + assert(pThread and "Job: The pointer to the attached thread must not be nullptr"); // We can suspend the job only if it is running if (pState == stateRunning) diff --git a/src/ext/yuni/src/yuni/job/queue/service.cpp b/src/ext/yuni/src/yuni/job/queue/service.cpp index 775f456cd3..18fe860903 100644 --- a/src/ext/yuni/src/yuni/job/queue/service.cpp +++ b/src/ext/yuni/src/yuni/job/queue/service.cpp @@ -37,14 +37,14 @@ static inline uint OptimalCPUCount() return count; } -QueueService::QueueService() : pStatus(sStopped), pThreads(NULL) +QueueService::QueueService() : pStatus(sStopped), pThreads(nullptr) { uint count = OptimalCPUCount(); pMinimumThreadCount = count; pMaximumThreadCount = count; } -QueueService::QueueService(bool autostart) : pStatus(sStopped), pThreads(NULL) +QueueService::QueueService(bool autostart) : pStatus(sStopped), pThreads(nullptr) { uint count = OptimalCPUCount(); pMinimumThreadCount = count; @@ -172,7 +172,7 @@ void QueueService::stop(uint timeout) return; threads = (ThreadArray*)pThreads; - pThreads = NULL; + pThreads = nullptr; pStatus = sStopping; } diff --git a/src/ext/yuni/src/yuni/thread/signal.cpp b/src/ext/yuni/src/yuni/thread/signal.cpp index 335d61fd20..9da95f2dde 100644 --- a/src/ext/yuni/src/yuni/thread/signal.cpp +++ b/src/ext/yuni/src/yuni/thread/signal.cpp @@ -33,10 +33,10 @@ Signal::Signal() // Making sure that our pseudo HANDLE type is valid assert(sizeof(HANDLE) >= sizeof(void*) and "Invalid type for Signal::pHandle"); - pHandle = (void*)CreateEvent(NULL, // default security attributes + pHandle = (void*)CreateEvent(nullptr, // default security attributes TRUE, // manual-reset event FALSE, // initial state is nonsignaled - NULL); // unamed + nullptr); // unamed #else pSignalled = false; @@ -53,10 +53,10 @@ Signal::Signal(const Signal&) // Making sure that our pseudo HANDLE type is valid assert(sizeof(HANDLE) >= sizeof(void*) and "Invalid type for Signal::pHandle"); - pHandle = (void*)CreateEvent(NULL, // default security attributes + pHandle = (void*)CreateEvent(nullptr, // default security attributes TRUE, // manual-reset event FALSE, // initial state is nonsignaled - NULL); // unamed + nullptr); // unamed #else pSignalled = false; @@ -194,7 +194,7 @@ bool Signal::wait(uint timeout) // Set the timespec t at [timeout] milliseconds in the future. assert(timeout < 2147483648u and "Invalid range for timeout (Signal::wait(timeout))"); - YUNI_SYSTEM_GETTIMEOFDAY(&now, NULL); + YUNI_SYSTEM_GETTIMEOFDAY(&now, nullptr); t.tv_nsec = (long)(now.tv_usec * 1000 + (((int)timeout % 1000) * 1000000)); t.tv_sec = (time_t)(now.tv_sec + timeout / 1000 + (t.tv_nsec / 1000000000L)); t.tv_nsec %= 1000000000L; diff --git a/src/ext/yuni/src/yuni/thread/thread.cpp b/src/ext/yuni/src/yuni/thread/thread.cpp index 048455b281..c8eb06dd9f 100644 --- a/src/ext/yuni/src/yuni/thread/thread.cpp +++ b/src/ext/yuni/src/yuni/thread/thread.cpp @@ -89,8 +89,8 @@ extern "C" YUNI_THREAD_FNC_RETURN threadCallbackExecute(void* arg) #ifndef YUNI_OS_WINDOWS // pthread - Adjust cancellation behaviors - // ::pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - ::pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + // ::pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, nullptr); + ::pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr); #endif if (thread.onStarting()) diff --git a/src/ext/yuni/src/yuni/uuid/uuid.cpp b/src/ext/yuni/src/yuni/uuid/uuid.cpp index be2e1cc2db..d151ceca1b 100644 --- a/src/ext/yuni/src/yuni/uuid/uuid.cpp +++ b/src/ext/yuni/src/yuni/uuid/uuid.cpp @@ -69,7 +69,7 @@ void UUID::writeToCString(char cstring[42]) const bool UUID::initializeFromCString(const char* cstring) { - assert(cstring != NULL); + assert(cstring != nullptr); #ifndef YUNI_OS_WINDOWS // Why uuid_parse takes a char* and not a const char* ?? diff --git a/src/format-code.sh b/src/format-code.sh index 30b51bd2e2..abac85a423 100755 --- a/src/format-code.sh +++ b/src/format-code.sh @@ -4,7 +4,7 @@ if [ $# -eq 0 ] then # No arguments: format all SOURCE_DIRS="analyzer/ libs/ solver/ tools/ config/ tests/ packaging/" - SOURCE_FILES=$(find $SOURCE_DIRS -regextype egrep -regex ".*/*\.(c|cxx|cpp|cc|h|hxx|hpp)$") + SOURCE_FILES=$(find $SOURCE_DIRS -regextype egrep -regex ".*/*\.(c|cxx|cpp|cc|h|hxx|hpp)$" ! -path '*/antlr-interface/*') else # Format files provided as arguments SOURCE_FILES="$@" diff --git a/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h b/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h index 6aca93a605..96f83b38af 100644 --- a/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h +++ b/src/libs/antares/InfoCollection/include/antares/infoCollection/StudyInfoCollector.h @@ -69,7 +69,9 @@ class SimulationInfoCollector { public: SimulationInfoCollector(const OptimizationInfo& optInfo): - opt_info_(optInfo){}; + opt_info_(optInfo) + { + } void toFileContent(FileContent& file_content); diff --git a/src/libs/antares/args/args_to_utf8.cpp b/src/libs/antares/args/args_to_utf8.cpp index 522c176565..eb14932f42 100644 --- a/src/libs/antares/args/args_to_utf8.cpp +++ b/src/libs/antares/args/args_to_utf8.cpp @@ -39,25 +39,33 @@ // clang-format on #endif // YUNI_OS_WINDOWS -IntoUTF8ArgsTranslator::IntoUTF8ArgsTranslator(int argc, char** argv): +IntoUTF8ArgsTranslator::IntoUTF8ArgsTranslator(int argc, const char** argv): argc_(argc), argv_(argv) { } -std::pair IntoUTF8ArgsTranslator::convert() +std::pair IntoUTF8ArgsTranslator::convert() { #ifdef YUNI_OS_WINDOWS wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc_); - argv_ = (char**)malloc(argc_ * sizeof(char*)); + auto& argv = const_cast(argv_); + 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'; + const uint newLen = WideCharToMultiByte(CP_UTF8, + 0, + wargv[i], + len, + nullptr, + 0, + nullptr, + nullptr); + 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, nullptr, nullptr); + argv[i][newLen] = '\0'; } #endif return {argc_, argv_}; @@ -66,10 +74,11 @@ std::pair IntoUTF8ArgsTranslator::convert() IntoUTF8ArgsTranslator::~IntoUTF8ArgsTranslator() { #ifdef YUNI_OS_WINDOWS + auto& argv = const_cast(argv_); for (int i = 0; i != argc_; ++i) { - free(argv_[i]); + free(argv[i]); } - free(argv_); + 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 index 8ca9a2e962..9174253fec 100644 --- a/src/libs/antares/args/include/antares/args/args_to_utf8.h +++ b/src/libs/antares/args/include/antares/args/args_to_utf8.h @@ -25,11 +25,11 @@ class IntoUTF8ArgsTranslator { public: - IntoUTF8ArgsTranslator(int argc, char** argv); - std::pair convert(); + IntoUTF8ArgsTranslator(int argc, const char** argv); + std::pair convert(); ~IntoUTF8ArgsTranslator(); private: int argc_; - char** argv_; + const char** argv_; }; diff --git a/src/libs/antares/array/CMakeLists.txt b/src/libs/antares/array/CMakeLists.txt index e2a7e48bf5..bfa3f2e4f8 100644 --- a/src/libs/antares/array/CMakeLists.txt +++ b/src/libs/antares/array/CMakeLists.txt @@ -15,7 +15,7 @@ target_link_libraries(array io #matrix.hxx jit #jit.hxx require logs Antares::memory - Antares::study + Antares::utils ) target_include_directories(array @@ -25,4 +25,4 @@ target_include_directories(array install(DIRECTORY include/antares DESTINATION "include" -) \ No newline at end of file +) diff --git a/src/libs/antares/array/include/antares/array/matrix.h b/src/libs/antares/array/include/antares/array/matrix.h index f1d65c5a43..42432a0ae1 100644 --- a/src/libs/antares/array/include/antares/array/matrix.h +++ b/src/libs/antares/array/include/antares/array/matrix.h @@ -28,9 +28,7 @@ #include #include -#include "antares/antares/antares.h" #include "antares/jit/jit.h" -#include "antares/study/fwd.h" namespace Antares { @@ -339,15 +337,6 @@ class Matrix template void pasteToColumn(uint x, const U* data); - /*! - ** \brief Copy values into a given column in the matrix - ** - ** \param x The column index (zero-based) - ** \param data The data to copy - */ - template - void pasteToColumn(uint x, const Antares::Memory::Array& data); - /*! ** \brief Set a entire column with a given value ** diff --git a/src/libs/antares/array/include/antares/array/matrix.hxx b/src/libs/antares/array/include/antares/array/matrix.hxx index 7fabacba02..c95db1bd93 100644 --- a/src/libs/antares/array/include/antares/array/matrix.hxx +++ b/src/libs/antares/array/include/antares/array/matrix.hxx @@ -488,31 +488,6 @@ void Matrix::pasteToColumn(uint x, const U* data) markAsModified(); } -template -template -void Matrix::pasteToColumn(uint x, const Antares::Memory::Array& data) -{ - assert(x < width and "Invalid column index (bigger than `this->width`)"); - ColumnType& column = entry[x]; - - // if the two types are strictly equal, we can perform some major - // optimisations - if (Yuni::Static::Type::StrictlyEqual::Yes) - { - (void)::memcpy(column, data, sizeof(T) * height); - } - else - { - // ...otherwise we have to copy each item by hand in any cases - for (uint y = 0; y != height; ++y) - { - column[y] = (T)data[y]; - } - } - - markAsModified(); -} - template void Matrix::fillColumn(uint x, const T& value) { @@ -1069,8 +1044,6 @@ bool Matrix::internalLoadCSVFile(const AnyString& filename, uint options, BufferType* buffer) { - using namespace Yuni; - // Status bool result = false; @@ -1082,7 +1055,7 @@ bool Matrix::internalLoadCSVFile(const AnyString& filename, switch (loadFromFileToBuffer(*buffer, filename)) { - case IO::errNone: + case Yuni::IO::errNone: { // Empty files if (buffer->empty()) @@ -1123,7 +1096,7 @@ bool Matrix::internalLoadCSVFile(const AnyString& filename, } break; } - case IO::errNotFound: + case Yuni::IO::errNotFound: { if (not(options & optQuiet)) { @@ -1131,7 +1104,7 @@ bool Matrix::internalLoadCSVFile(const AnyString& filename, } break; } - case IO::errMemoryLimit: + case Yuni::IO::errMemoryLimit: { if (not(options & optQuiet)) { diff --git a/src/libs/antares/benchmarking/DurationCollector.cpp b/src/libs/antares/benchmarking/DurationCollector.cpp index 9d66166bca..83b50d0f53 100644 --- a/src/libs/antares/benchmarking/DurationCollector.cpp +++ b/src/libs/antares/benchmarking/DurationCollector.cpp @@ -36,7 +36,9 @@ void DurationCollector::toFileContent(FileContent& file_content) { for (const auto& [name, durations]: duration_items_) { - const int64_t duration_sum = accumulate(durations.begin(), durations.end(), 0); + const int64_t duration_sum = accumulate(durations.begin(), + durations.end(), + static_cast(0)); file_content.addDurationItem(name, (unsigned int)duration_sum, (int)durations.size()); } @@ -67,7 +69,7 @@ int64_t DurationCollector::getTime(const std::string& name) const { const auto& v = duration_items_.at(name); - return accumulate(v.begin(), v.end(), 0); + return accumulate(v.begin(), v.end(), static_cast(0)); } } // namespace Benchmarking diff --git a/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h b/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h index 113451410f..62352390bc 100644 --- a/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h +++ b/src/libs/antares/checks/include/antares/checks/checkLoadedInputData.h @@ -28,7 +28,6 @@ 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/correlation/correlation.cpp b/src/libs/antares/correlation/correlation.cpp index 84c39b974f..efdf3b3769 100644 --- a/src/libs/antares/correlation/correlation.cpp +++ b/src/libs/antares/correlation/correlation.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/correlation/correlation.h" @@ -212,13 +212,13 @@ int InterAreaCorrelationLoadFromIniFile(Matrix<>* m, AreaList* l, IniFile* ini, if (ini) { IniFile::Section* s; - for (s = ini->firstSection; s != NULL; s = s->next) /* Each section */ + for (s = ini->firstSection; s; s = s->next) /* Each section */ { Area* from = AreaListLFind(l, s->name.c_str()); if (from) { IniFile::Property* p; - for (p = s->firstProperty; p != NULL; p = p->next) /* Each property*/ + for (p = s->firstProperty; p; p = p->next) /* Each property*/ { Area* to = AreaListLFind(l, p->key.c_str()); if (to and to != from) @@ -327,18 +327,10 @@ int InterAreaCorrelationSaveToFile(const Matrix<>* m, const AreaList* l, const c } Correlation::Correlation(): - annual(nullptr), - monthly(nullptr), pMode(modeNone) { } -Correlation::~Correlation() -{ - delete annual; - delete[] monthly; -} - bool Correlation::loadFromFile(Study& study, const AnyString& filename, bool warnings) { #ifndef NDEBUG @@ -397,16 +389,16 @@ void Correlation::internalSaveToINI(Study& study, IO::File::Stream& file) const // mode file << "[general]\nmode = " << ModeToCString(pMode) << "\n\n"; - if (annual) + if (!annual.empty()) { - ExportCorrelationCoefficients(study, *annual, file, "annual"); + ExportCorrelationCoefficients(study, annual, file, "annual"); } else { logs.error() << correlationName << ": the annual correlation coefficients are missing"; } - if (monthly) + if (!monthly.empty()) { for (int month = 0; month < 12; month++) { @@ -428,20 +420,20 @@ bool Correlation::internalLoadFromINITry(Study& study, const IniFile& ini, bool if (JIT::usedFromGUI or pMode == modeAnnual) { - annual = new Matrix<>(); - annual->resize(study.areas.size(), study.areas.size()); - annual->fillUnit(); + annual.clear(); + annual.resize(study.areas.size(), study.areas.size()); + annual.fillUnit(); auto* section = ini.find("annual"); if (section) // the section might be missing { - ReadCorrelationCoefficients(*this, study, *annual, ini, *section, warnings); + ReadCorrelationCoefficients(*this, study, annual, ini, *section, warnings); } } if (JIT::usedFromGUI or pMode == modeMonthly) { - monthly = new Matrix<>[12]; + monthly.resize(12); for (uint i = 0; i < 12; ++i) { monthly[i].resize(study.areas.size(), study.areas.size()); @@ -475,28 +467,18 @@ bool Correlation::internalLoadFromINITry(Study& study, const IniFile& ini, bool void Correlation::reset(Study& study) { - // Clean - if (annual) - { - delete annual; - annual = nullptr; - } - if (monthly) - { - delete[] monthly; - monthly = nullptr; - } + clear(); pMode = modeAnnual; if (JIT::usedFromGUI) { // Reset - annual = new Matrix<>(); - annual->resize(study.areas.size(), study.areas.size()); - annual->fillUnit(); + annual.clear(); + annual.resize(study.areas.size(), study.areas.size()); + annual.fillUnit(); // Preparing the monthly correlation matrices - monthly = new Matrix<>[12]; + monthly.resize(12); for (int i = 0; i < 12; ++i) { monthly[i].resize(study.areas.size(), study.areas.size()); @@ -505,40 +487,21 @@ void Correlation::reset(Study& study) } else { - annual = new Matrix<>(); - annual->resize(study.areas.size(), study.areas.size()); - annual->fillUnit(); + annual.clear(); + annual.resize(study.areas.size(), study.areas.size()); + annual.fillUnit(); } } void Correlation::clear() { - // Clean - if (annual) - { - delete annual; - annual = nullptr; - } - if (monthly) - { - delete[] monthly; - monthly = nullptr; - } + annual.reset(); + monthly.clear(); } bool Correlation::internalLoadFromINI(Study& study, const IniFile& ini, bool warnings) { - // Clean - if (annual) - { - delete annual; - annual = nullptr; - } - if (monthly) - { - delete[] monthly; - monthly = nullptr; - } + clear(); if (!internalLoadFromINITry(study, ini, warnings)) { @@ -546,28 +509,22 @@ bool Correlation::internalLoadFromINI(Study& study, const IniFile& ini, bool war pMode = modeAnnual; if (JIT::usedFromGUI) { - // Reset - annual = new Matrix<>(); - annual->resize(study.areas.size(), study.areas.size()); - annual->fillUnit(); - // Preparing the monthly correlation matrices - monthly = new Matrix<>[12]; + monthly.resize(12); for (int i = 0; i < 12; ++i) { monthly[i].resize(study.areas.size(), study.areas.size()); monthly[i].fillUnit(); } } - else - { - annual = new Matrix<>(); - annual->resize(study.areas.size(), study.areas.size()); - annual->fillUnit(); - } + + annual.clear(); + annual.resize(study.areas.size(), study.areas.size()); + annual.fillUnit(); return false; } + return true; } @@ -600,45 +557,14 @@ void Correlation::set(Matrix<>& m, const Area& from, const Area& to, double v) m[to.index][from.index] = v; } -void Correlation::retrieveMontlyMatrixArray(const Matrix<>* array[12]) const -{ - switch (pMode) - { - case modeAnnual: - { - for (uint i = 0; i != 12; ++i) - { - array[i] = annual; - } - break; - } - case modeMonthly: - { - for (uint i = 0; i != 12; ++i) - { - array[i] = &(monthly[i]); - } - break; - } - default: - { - for (uint i = 0; i != 12; ++i) - { - array[i] = nullptr; - } - return; - } - } -} - uint64_t Correlation::memoryUsage() const { uint64_t r = sizeof(Correlation); - if (annual) + if (!annual.empty()) { - r += annual->memoryUsage(); + r += annual.memoryUsage(); } - if (monthly) + if (!monthly.empty()) { for (uint i = 0; i != 12; ++i) { @@ -651,9 +577,9 @@ uint64_t Correlation::memoryUsage() const bool Correlation::forceReload(bool reload) const { bool ret = true; - if (annual) + if (!annual.empty()) { - ret = annual->forceReload(reload) and ret; + ret = annual.forceReload(reload) and ret; } for (uint i = 0; i != 12; ++i) { @@ -665,9 +591,9 @@ bool Correlation::forceReload(bool reload) const void Correlation::markAsModified() const { - if (annual) + if (!annual.empty()) { - annual->markAsModified(); + annual.markAsModified(); } for (uint i = 0; i != 12; ++i) { @@ -762,8 +688,8 @@ void Correlation::copyFrom(const Correlation& source, // copying the annual correlation matrix std::cout << "ANNUAL\n"; - CopyFromSingleMatrix(*source.annual, - *annual, + CopyFromSingleMatrix(source.annual, + annual, studySource, areaSourceIndex, areaTargetIndex, diff --git a/src/libs/antares/correlation/include/antares/correlation/correlation.h b/src/libs/antares/correlation/include/antares/correlation/correlation.h index 9dc48c5a76..c0ffebe4a0 100644 --- a/src/libs/antares/correlation/include/antares/correlation/correlation.h +++ b/src/libs/antares/correlation/include/antares/correlation/correlation.h @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #ifndef __ANTARES_LIBS_ARRAY_CORRELATION_H__ #define __ANTARES_LIBS_ARRAY_CORRELATION_H__ @@ -62,7 +62,7 @@ class Correlation final /*! ** \brief Destructor */ - ~Correlation(); + ~Correlation() = default; //@} //! \name Mode @@ -123,11 +123,6 @@ class Correlation final const AreaNameMapping& mapping, const Study& study); - /*! - ** \brief - */ - void retrieveMontlyMatrixArray(const Matrix<>* array[12]) const; - /*! ** \brief Get the amount of memory used the correlation matrices */ @@ -145,9 +140,9 @@ class Correlation final public: //! The correlation matrix for the whole year - Matrix<>* annual; + Matrix<> annual; //! All correlation matrices per month (12) - Matrix<>* monthly; // [12] + std::vector> monthly; // [12] //! The name to displays in logs Yuni::CString<30, false> correlationName; diff --git a/src/libs/antares/date/date.cpp b/src/libs/antares/date/date.cpp index 1d309201a2..acec182242 100644 --- a/src/libs/antares/date/date.cpp +++ b/src/libs/antares/date/date.cpp @@ -21,6 +21,8 @@ #include +#include + #include #include #include @@ -32,7 +34,7 @@ using namespace Yuni; namespace Antares::Date { -static const uint StandardDaysPerMonths[12] = { +static const uint StandardDaysPerMonths[MONTHS_PER_YEAR] = { 31, // january 28, // february 31, // march @@ -137,12 +139,13 @@ bool StringToMonth(MonthName& out, AnyString text) return false; } text.trim(); - CString<12, false> t = text; - t.toLower(); + std::string t = text; + boost::algorithm::to_lower(t); + /* t.toLower(); */ if (t.size() == 3) { - for (uint m = 0; m != 12; ++m) + for (uint m = 0; m != MONTHS_PER_YEAR; ++m) { if (monthShortLowerNames[m] == t) { @@ -153,7 +156,7 @@ bool StringToMonth(MonthName& out, AnyString text) } else { - for (uint m = 0; m != 12; ++m) + for (uint m = 0; m != MONTHS_PER_YEAR; ++m) { if (monthNamesLower[m] == t) { @@ -168,22 +171,22 @@ bool StringToMonth(MonthName& out, AnyString text) const char* MonthToString(int m, int offset) { - return monthNames[(m - offset) % 12]; + return monthNames[(m - offset) % MONTHS_PER_YEAR]; } const char* MonthToLowerString(int m, int offset) { - return monthNamesLower[(m - offset) % 12]; + return monthNamesLower[(m - offset) % MONTHS_PER_YEAR]; } const char* MonthToShortString(int m, int offset) { - return monthShortNames[(m - offset) % 12]; + return monthShortNames[(m - offset) % MONTHS_PER_YEAR]; } const char* MonthToUpperShortString(int m, int offset) { - return monthShortUpperNames[(m - offset) % 12]; + return monthShortUpperNames[(m - offset) % MONTHS_PER_YEAR]; } const char* WeekdayToString(int m) @@ -424,7 +427,7 @@ bool Calendar::saveToCSVFile(const AnyString& filename) const line.clear() << "hour begin\thour end\tdays\tday uear begin\tday year end\tfirst weekday"; report.months.push_back(line); - for (uint m = 0; m != 12; ++m) + for (uint m = 0; m != MONTHS_PER_YEAR; ++m) { auto& month = months[m]; line.clear(); @@ -494,10 +497,10 @@ void Calendar::reset() (void)::memset(months, '\0', sizeof(months)); // Reset months relationship - for (uint m = 0; m != 12 + 1; ++m) + for (uint m = 0; m != MONTHS_PER_YEAR + 1; ++m) { - uint realmonth = (m + (uint)settings_.firstMonth) % 12; - if (m < 12) + uint realmonth = (m + (uint)settings_.firstMonth) % MONTHS_PER_YEAR; + if (m < MONTHS_PER_YEAR) { mapping.months[realmonth] = m; } diff --git a/src/libs/antares/exception/LoadingError.cpp b/src/libs/antares/exception/LoadingError.cpp index 499f0ed3f6..4a80591bef 100644 --- a/src/libs/antares/exception/LoadingError.cpp +++ b/src/libs/antares/exception/LoadingError.cpp @@ -192,11 +192,6 @@ IncompatibleHurdleCostCSR::IncompatibleHurdleCostCSR(): { } -AdqPatchDisabledLMR::AdqPatchDisabledLMR(): - LoadingError("Incompatible options LMR disabled and priceTakingOrder equal Dens") -{ -} - IncompatibleOutputOptions::IncompatibleOutputOptions(const std::string& text): LoadingError(text) { diff --git a/src/libs/antares/exception/include/antares/exception/LoadingError.hpp b/src/libs/antares/exception/include/antares/exception/LoadingError.hpp index ab1ae664d8..d70820e5e9 100644 --- a/src/libs/antares/exception/include/antares/exception/LoadingError.hpp +++ b/src/libs/antares/exception/include/antares/exception/LoadingError.hpp @@ -130,13 +130,14 @@ class InvalidSolver: public LoadingError explicit InvalidSolver(const std::string& solver, const std::string& availableSolverList); }; -class InvalidSolverSpecificParameters : public LoadingError +class InvalidSolverSpecificParameters: public LoadingError { public: - explicit InvalidSolverSpecificParameters(const std::string& solver, const std::string& specificParameters); + explicit InvalidSolverSpecificParameters(const std::string& solver, + const std::string& specificParameters); }; -class InvalidStudy : public LoadingError +class InvalidStudy: public LoadingError { public: explicit InvalidStudy(const Yuni::String& study); @@ -193,12 +194,6 @@ class IncompatibleHurdleCostCSR: public LoadingError IncompatibleHurdleCostCSR(); }; -class AdqPatchDisabledLMR: public LoadingError -{ -public: - AdqPatchDisabledLMR(); -}; - class IncompatibleOutputOptions: public LoadingError { public: diff --git a/src/libs/antares/file-tree-study-loader/FileTreeStudyLoader.cpp b/src/libs/antares/file-tree-study-loader/FileTreeStudyLoader.cpp index 5302c19263..92b8691d83 100644 --- a/src/libs/antares/file-tree-study-loader/FileTreeStudyLoader.cpp +++ b/src/libs/antares/file-tree-study-loader/FileTreeStudyLoader.cpp @@ -1,4 +1,3 @@ - /* * Copyright 2007-2024, RTE (https://www.rte-france.com) * See AUTHORS.txt @@ -34,40 +33,15 @@ FileTreeStudyLoader::FileTreeStudyLoader(std::filesystem::path study_path): { } -namespace -{ -/** - * @brief Prepares arguments for the Antares Solver application. - * - * This function prepares the arguments required by the Antares Solver application. - * It takes a span of char pointers and a string_view representing the study path. - * The function creates copies of the required arguments and stores them in a vector. - * The original char pointers in the span are updated to point to the newly created copies. - * Lifetime of values inside argv is determined be the content of the returned vector - * - * @param argv A span of char pointers to be filled with the prepared arguments. - * @param study_path A string_view representing the study path. - * @return std::vector A vector of strings containing the prepared arguments. - */ -[[nodiscard]] std::vector prepareArgs(std::span argv, - std::string_view study_path) -{ - using namespace std::literals::string_literals; - std::string arg0{""s}; - std::string arg1{study_path}; - argv[0] = arg0.data(); - argv[1] = arg1.data(); - return {std::move(arg0), std::move(arg1)}; -} -} // namespace - std::unique_ptr FileTreeStudyLoader::load() const { using namespace std::literals::string_literals; Antares::Solver::Application application; - constexpr unsigned int argc = 2; - std::array argv; - auto keep_alive = prepareArgs(argv, study_path_.string()); + constexpr unsigned int argc = 3; + // On Windows, std::filesystem::path::value_type is wchar_t + std::array argv{"", + reinterpret_cast(study_path_.c_str()), + "--parallel"}; application.prepare(argc, argv.data()); return application.acquireStudy(); diff --git a/src/libs/antares/file-tree-study-loader/include/antares/file-tree-study-loader/FileTreeStudyLoader.h b/src/libs/antares/file-tree-study-loader/include/antares/file-tree-study-loader/FileTreeStudyLoader.h index 687afa12ae..7b46a95c3a 100644 --- a/src/libs/antares/file-tree-study-loader/include/antares/file-tree-study-loader/FileTreeStudyLoader.h +++ b/src/libs/antares/file-tree-study-loader/include/antares/file-tree-study-loader/FileTreeStudyLoader.h @@ -31,6 +31,7 @@ namespace Data { class Study; } + /** * @class FileTreeStudyLoader * @brief A class to load studies from the file tree. diff --git a/src/libs/antares/include/antares/antares/constants.h b/src/libs/antares/include/antares/antares/constants.h index d2bb24bacd..c29e81c1ef 100644 --- a/src/libs/antares/include/antares/antares/constants.h +++ b/src/libs/antares/include/antares/antares/constants.h @@ -51,12 +51,15 @@ #include const unsigned int HOURS_PER_DAY = 24; + +const unsigned int MONTHS_PER_YEAR = 12; +const unsigned int WEEKS_PER_YEAR = 53; const unsigned int DAYS_PER_YEAR = 365; const unsigned int HOURS_PER_YEAR = 8760; namespace Antares::Constants { -extern const std::array daysPerMonth; +extern const std::array daysPerMonth; extern const unsigned int nbHoursInAWeek; } // namespace Antares::Constants diff --git a/src/libs/antares/inifile/CMakeLists.txt b/src/libs/antares/inifile/CMakeLists.txt index a68b3f2786..089591f002 100644 --- a/src/libs/antares/inifile/CMakeLists.txt +++ b/src/libs/antares/inifile/CMakeLists.txt @@ -17,11 +17,11 @@ target_link_libraries(inifile PRIVATE io logs - Boost::boost + Boost::headers ) target_include_directories(inifile - PUBLIC + PUBLIC $ ) diff --git a/src/libs/antares/inifile/include/antares/inifile/inifile.hxx b/src/libs/antares/inifile/include/antares/inifile/inifile.hxx index 64785d1ece..20498c3ee2 100644 --- a/src/libs/antares/inifile/include/antares/inifile/inifile.hxx +++ b/src/libs/antares/inifile/include/antares/inifile/inifile.hxx @@ -32,7 +32,8 @@ inline bool IniFile::empty() const return not firstSection; } -inline IniFile::Section::Section(const AnyString& name): name(name) +inline IniFile::Section::Section(const AnyString& name): + name(name) { } diff --git a/src/libs/antares/inifile/inifile.cpp b/src/libs/antares/inifile/inifile.cpp index e6524920ee..8cfa6b9607 100644 --- a/src/libs/antares/inifile/inifile.cpp +++ b/src/libs/antares/inifile/inifile.cpp @@ -65,7 +65,8 @@ void IniFile::Section::saveToStream(std::ostream& stream_out, uint64_t& written) stream_out << '[' << name << "]\n"; written += 4 /* []\n\n */ + name.size(); - each([&](const IniFile::Property& p) { p.saveToStream(stream_out, written); }); + each([&stream_out, &written](const IniFile::Property& p) + { p.saveToStream(stream_out, written); }); stream_out << '\n'; } @@ -168,9 +169,9 @@ static std::string getSectionName(const std::string& line) return splitLine[1]; } -static bool isProperty(const std::string& line) +static bool isProperty(std::string_view line) { - return std::ranges::count(line.begin(), line.end(), '=') == 1; + return std::ranges::count(line, '=') == 1; } static IniFile::Property getProperty(std::string line) @@ -247,7 +248,7 @@ bool IniFile::open(const fs::path& filename, bool warnings) if (std::ifstream file(filename); file.is_open()) { - if (! readStream(file)) + if (!readStream(file)) { logs.error() << "Invalid INI file : " << filename; return false; @@ -264,7 +265,8 @@ bool IniFile::open(const fs::path& filename, bool warnings) void IniFile::saveToStream(std::ostream& stream_out, uint64_t& written) const { - each([&](const IniFile::Section& s) {s.saveToStream(stream_out, written); }); + each([&stream_out, &written](const IniFile::Section& s) + { s.saveToStream(stream_out, written); }); if (written != 0) { diff --git a/src/libs/antares/io/file.cpp b/src/libs/antares/io/file.cpp index 10bf5b30b9..8ef66b3a3d 100644 --- a/src/libs/antares/io/file.cpp +++ b/src/libs/antares/io/file.cpp @@ -27,13 +27,13 @@ #ifdef YUNI_OS_WINDOWS #include + #include #else #include #include #endif #include - #include #include diff --git a/src/libs/antares/io/include/antares/io/file.h b/src/libs/antares/io/include/antares/io/file.h index e9fd0e91dc..b401b1cece 100644 --- a/src/libs/antares/io/include/antares/io/file.h +++ b/src/libs/antares/io/include/antares/io/file.h @@ -21,10 +21,10 @@ #ifndef __LIBS_ANTARES_IO_FILE_H__ #define __LIBS_ANTARES_IO_FILE_H__ -#include - #include +#include + namespace Antares::IO { /*! diff --git a/src/libs/antares/locale/locale.cpp b/src/libs/antares/locale/locale.cpp index 7fcbc420ba..238331274a 100644 --- a/src/libs/antares/locale/locale.cpp +++ b/src/libs/antares/locale/locale.cpp @@ -31,13 +31,13 @@ namespace Antares void InitializeDefaultLocale() { #ifdef YUNI_OS_WINDOWS - if (NULL == std::setlocale(LC_ALL, "English")) + if (!std::setlocale(LC_ALL, "English")) { std::cerr << "impossible to set locale to English" << std::endl; } #else - if (NULL == std::setlocale(LC_ALL, "en_US.utf8")) + if (!std::setlocale(LC_ALL, "en_US.utf8")) { std::cerr << "impossible to set locale to en_US.utf8" << std::endl; } diff --git a/src/libs/antares/locator/locator.cpp b/src/libs/antares/locator/locator.cpp index fbb4087086..7a3e9436ef 100644 --- a/src/libs/antares/locator/locator.cpp +++ b/src/libs/antares/locator/locator.cpp @@ -31,10 +31,6 @@ using namespace Yuni; -#define SEP \ - Yuni:; \ - IO::Separator - namespace Antares::Solver { bool FindLocation(String& location) diff --git a/src/libs/antares/logs/include/antares/logs/logs.h b/src/libs/antares/logs/include/antares/logs/logs.h index 9bf0181cf4..3aca2ba167 100644 --- a/src/libs/antares/logs/include/antares/logs/logs.h +++ b/src/libs/antares/logs/include/antares/logs/logs.h @@ -63,16 +63,6 @@ #include #include -namespace Antares -{ -namespace Data -{ -// Forward declaration -class Study; - -} // namespace Data -} // namespace Antares - namespace Antares { //! Handlers for logging diff --git a/src/libs/antares/memory/include/antares/memory/memory.h b/src/libs/antares/memory/include/antares/memory/memory.h index 89eb4815f4..42515c5fce 100644 --- a/src/libs/antares/memory/include/antares/memory/memory.h +++ b/src/libs/antares/memory/include/antares/memory/memory.h @@ -33,52 +33,6 @@ namespace Antares class Memory final: public Yuni::Policy::ObjectLevelLockable { public: - template - class Array final - { - public: - //! \name Constructors - //@{ - /*! - ** \brief Default constructor - */ - Array() = default; - - /*! - ** \brief Constructor from null - */ - explicit Array(const Yuni::NullPtr&); - - /*! - ** \brief Constructor with an initial allocation size - */ - explicit Array(size_t size); - - //! Copy constructor (must be empty) - Array(const Array& copy); - - template - Array(const Array&); - - /*! - ** \brief Destructor - */ - ~Array(); - //@} - - /*! - ** \brief - */ - void allocate(size_t size); - - T& operator[](uint i); - const T& operator[](uint i) const; - - private: - T* pPointer = nullptr; - - }; // class Array - template struct Stored final { @@ -101,7 +55,6 @@ class Memory final: public Yuni::Policy::ObjectLevelLockable template static void Assign(uint count, U* array, const U& value); -public: template static void Allocate(T*& out, size_t size); @@ -117,7 +70,6 @@ class Memory final: public Yuni::Policy::ObjectLevelLockable template static void Release(T*& pointer); -public: //! \name Constructor & Destructor //@{ /*! diff --git a/src/libs/antares/memory/include/antares/memory/memory.hxx b/src/libs/antares/memory/include/antares/memory/memory.hxx index 1b575150a5..aeb99b413d 100644 --- a/src/libs/antares/memory/include/antares/memory/memory.hxx +++ b/src/libs/antares/memory/include/antares/memory/memory.hxx @@ -28,54 +28,6 @@ inline uint64_t Memory::processID() const return pProcessID; } -template -Memory::Array::Array(const Yuni::NullPtr&) -{ -} - -template -Memory::Array::Array(const Memory::Array&) -{ -} - -template -template -Memory::Array::Array(const Memory::Array&) -{ -} - -template -inline Memory::Array::Array(size_t size) -{ - allocate(size); -} - -template -inline Memory::Array::~Array() -{ - delete[] pPointer; - pPointer = nullptr; -} - -template -void Memory::Array::allocate(size_t size) -{ - delete[] pPointer; - pPointer = new T[size]; -} - -template -T& Memory::Array::operator[](uint i) -{ - return (T&)pPointer[i]; -} - -template -const T& Memory::Array::operator[](uint i) const -{ - return (const T&)pPointer[i]; -} - template inline void Memory::Release(T*& pointer) { diff --git a/src/libs/antares/resources/include/antares/resources/resources.h b/src/libs/antares/resources/include/antares/resources/resources.h index d7a905cc45..f6aaabeceb 100644 --- a/src/libs/antares/resources/include/antares/resources/resources.h +++ b/src/libs/antares/resources/include/antares/resources/resources.h @@ -52,7 +52,7 @@ bool FindExampleFolder(YString& folder); /*! ** \brief Initialize variables about resource handling */ -void Initialize(int argc, char* argv[], bool initializeSearchPath = false); +void Initialize(int argc, const char* argv[], bool initializeSearchPath = false); /*! ** \brief Copy the root folder diff --git a/src/libs/antares/resources/resources.cpp b/src/libs/antares/resources/resources.cpp index cbd3122d18..b16dafdf29 100644 --- a/src/libs/antares/resources/resources.cpp +++ b/src/libs/antares/resources/resources.cpp @@ -134,9 +134,9 @@ bool FindExampleFolder(Yuni::String& folder) return false; } -void Initialize(int argc, char** argv, bool initializeSearchPath) +void Initialize(int argc, const char** argv, bool initializeSearchPath) { - if (argc < 1 or argv[0] == NULL) + if (argc < 1 or !argv[0]) { logs.error() << "Impossible to find the root folder"; return; diff --git a/src/libs/antares/series/CMakeLists.txt b/src/libs/antares/series/CMakeLists.txt index 5f9da57ab2..570680f4cf 100644 --- a/src/libs/antares/series/CMakeLists.txt +++ b/src/libs/antares/series/CMakeLists.txt @@ -11,7 +11,7 @@ target_sources(series $ ) -target_link_libraries(series PUBLIC Antares::array) +target_link_libraries(series PUBLIC Antares::array antares-core) target_include_directories(series PUBLIC @@ -20,4 +20,4 @@ target_include_directories(series install(DIRECTORY include/antares DESTINATION "include" -) \ No newline at end of file +) diff --git a/src/libs/antares/series/include/antares/series/series.h b/src/libs/antares/series/include/antares/series/series.h index d3dde6d092..939b25e40d 100644 --- a/src/libs/antares/series/include/antares/series/series.h +++ b/src/libs/antares/series/include/antares/series/series.h @@ -83,7 +83,7 @@ class TimeSeries ** \param prefix the prefix for the filename ** \return A non-zero value if the operation succeeded, 0 otherwise */ - int saveToFolder(const AreaName& areaID, + int saveToFolder(const std::string& areaID, const std::string& folder, const std::string& prefix) const; diff --git a/src/libs/antares/series/series.cpp b/src/libs/antares/series/series.cpp index 9116a5b5da..03894a9c50 100644 --- a/src/libs/antares/series/series.cpp +++ b/src/libs/antares/series/series.cpp @@ -29,6 +29,8 @@ #include #include +#include + using namespace Yuni; #define SEP IO::Separator @@ -129,7 +131,7 @@ bool TimeSeries::loadFromFile(const std::string& path, const bool average) return ret; } -int TimeSeries::saveToFolder(const AreaName& areaID, +int TimeSeries::saveToFolder(const std::string& areaID, const std::string& folder, const std::string& prefix) const { diff --git a/src/libs/antares/study-loader/include/antares/study-loader/IStudyLoader.h b/src/libs/antares/study-loader/include/antares/study-loader/IStudyLoader.h index 9b4c710ed4..7d6f25373b 100644 --- a/src/libs/antares/study-loader/include/antares/study-loader/IStudyLoader.h +++ b/src/libs/antares/study-loader/include/antares/study-loader/IStudyLoader.h @@ -29,6 +29,7 @@ namespace Data { class Study; } + /** * @class IStudyLoader * @brief The IStudyLoader class is an interface for loading studies. diff --git a/src/libs/antares/study/CMakeLists.txt b/src/libs/antares/study/CMakeLists.txt index c0b5b84c56..a3524a4b96 100644 --- a/src/libs/antares/study/CMakeLists.txt +++ b/src/libs/antares/study/CMakeLists.txt @@ -208,7 +208,6 @@ set(SRC_STUDY include/antares/study/load-options.h load-options.cpp include/antares/study/runtime/runtime.h - include/antares/study/runtime/runtime.hxx runtime/runtime.cpp include/antares/study/runtime.h include/antares/study/study.h @@ -250,7 +249,7 @@ set(SRC_STUDY # Sets include/antares/study/sets.h - include/antares/study/sets.hxx + area/sets.cpp # variable selection include/antares/study/variable-print-info.h @@ -283,7 +282,6 @@ add_library(Antares::study ALIAS study) target_link_libraries(study PUBLIC - Boost::boost yuni-static-core Antares::date #parameters Antares::inifile #parameters @@ -295,6 +293,7 @@ target_link_libraries(study Antares::mersenne Antares::result_writer #study.h Antares::series + Antares::array antares-core antares-solver-simulation Antares::hydro diff --git a/src/libs/antares/study/area/area.cpp b/src/libs/antares/study/area/area.cpp index 77f0fe6dd9..3bd4b91222 100644 --- a/src/libs/antares/study/area/area.cpp +++ b/src/libs/antares/study/area/area.cpp @@ -52,8 +52,7 @@ Area::Area(): } Area::Area(const AnyString& name): - reserves(fhrMax, HOURS_PER_YEAR), - miscGen(fhhMax, HOURS_PER_YEAR) + Area() { internalInitialize(); this->name = name; @@ -61,14 +60,11 @@ Area::Area(const AnyString& name): } Area::Area(const AnyString& name, const AnyString& id): - - reserves(fhrMax, HOURS_PER_YEAR), - miscGen(fhhMax, HOURS_PER_YEAR) + Area() { internalInitialize(); this->name = name; this->id = Antares::transformNameIntoID(id); - } Area::~Area() @@ -189,7 +185,7 @@ uint64_t Area::memoryUsage() const ret += wind.memoryUsage(); // Hydro - ret += PreproHydroMemoryUsage(hydro.prepro); + ret += PreproHydroMemoryUsage(hydro.prepro.get()); if (hydro.series) { ret += hydro.series->memoryUsage(); @@ -227,7 +223,7 @@ void Area::createMissingTimeSeries() { if (!hydro.series) { - hydro.series = new DataSeriesHydro(); + hydro.series = std::make_unique(); } } @@ -235,19 +231,19 @@ void Area::createMissingPrepros() { if (!load.prepro) { - load.prepro = new Data::Load::Prepro(); + load.prepro = std::make_unique(); } if (!solar.prepro) { - solar.prepro = new Data::Solar::Prepro(); + solar.prepro = std::make_unique(); } if (!wind.prepro) { - wind.prepro = new Data::Wind::Prepro(); + wind.prepro = std::make_unique(); } if (!hydro.prepro) { - hydro.prepro = new PreproHydro(); + hydro.prepro = std::make_unique(); } thermal.list.ensureDataPrepro(); } diff --git a/src/libs/antares/study/area/links.cpp b/src/libs/antares/study/area/links.cpp index 4d4b6af140..f7b722da49 100644 --- a/src/libs/antares/study/area/links.cpp +++ b/src/libs/antares/study/area/links.cpp @@ -21,10 +21,10 @@ #include "antares/study/area/links.h" +#include +#include #include -#include - #include #include #include "antares/study//study.h" @@ -305,7 +305,20 @@ AreaLink* AreaAddLinkBetweenAreas(Area* area, Area* with, bool warning) namespace // anonymous { -bool handleKey(Data::AreaLink& link, const String& key, const String& value) + +bool isPropertyUsedForLinkTSgeneration(const std::string& key) +{ + std::array listKeys = {"unitcount", + "nominalcapacity", + "law.planned", + "law.forced", + "volatility.planned", + "volatility.forced", + "force-no-generation"}; + return std::find(listKeys.begin(), listKeys.end(), key) != listKeys.end(); +} + +bool AreaLinksInternalLoadFromProperty(AreaLink& link, const String& key, const String& value) { if (key == "hurdles-cost") { @@ -448,13 +461,9 @@ bool handleKey(Data::AreaLink& link, const String& key, const String& value) link.filterYearByYear = stringIntoDatePrecision(value); return true; } - - return false; -} - -bool AreaLinksInternalLoadFromProperty(AreaLink& link, const String& key, const String& value) -{ - return handleKey(link, key, value); + // Properties used by TS generator only. + // We just skip them (otherwise : reading error) + return isPropertyUsedForLinkTSgeneration(key.to()); } [[noreturn]] void logLinkDataCheckError(const AreaLink& link, const String& msg, int hour) @@ -475,7 +484,7 @@ bool AreaLinksInternalLoadFromProperty(AreaLink& link, const String& key, const } } // anonymous namespace -bool AreaLinksLoadFromFolder(Study& study, AreaList* l, Area* area, const fs::path& folder) +bool AreaLinksLoadFromFolder(Study& study, AreaList* areaList, Area* area, const fs::path& folder) { // Assert assert(area); @@ -497,16 +506,16 @@ bool AreaLinksLoadFromFolder(Study& study, AreaList* l, Area* area, const fs::pa for (auto* s = ini.firstSection; s; s = s->next) { // Getting the name of the area - std::string buffer = transformNameIntoID(s->name); + const std::string targetAreaName = transformNameIntoID(s->name); // Trying to find it - Area* linkedWith = AreaListLFind(l, buffer.c_str()); - if (!linkedWith) + Area* targetArea = AreaListLFind(areaList, targetAreaName.c_str()); + if (!targetArea) { logs.error() << '`' << s->name << "`: Impossible to find the area"; continue; } - AreaLink* lnk = AreaAddLinkBetweenAreas(area, linkedWith); + AreaLink* lnk = AreaAddLinkBetweenAreas(area, targetArea); if (!lnk) { logs.error() << "Impossible to create a link between two areas"; diff --git a/src/libs/antares/study/area/list.cpp b/src/libs/antares/study/area/list.cpp index e7bd727287..cee20dc5d5 100644 --- a/src/libs/antares/study/area/list.cpp +++ b/src/libs/antares/study/area/list.cpp @@ -376,7 +376,6 @@ bool saveAreaAdequacyPatchIniFile(const Area& area, const Clob& buffer) } AreaList::AreaList(Study& study): - byIndex(nullptr), pStudy(study) { } @@ -450,43 +449,31 @@ const AreaLink* AreaList::findLink(const AreaName& area, const AreaName& with) c void AreaList::clear() { - delete[] byIndex; - byIndex = nullptr; + byIndex.clear(); - if (!areas.empty()) - { - Area::Map copy; - copy.swap(areas); + Area::Map copy; + copy.swap(areas); - auto end = copy.end(); - for (auto i = copy.begin(); i != end; ++i) - { - delete i->second; - } + auto end = copy.end(); + for (auto i = copy.begin(); i != end; ++i) + { + delete i->second; } } void AreaList::rebuildIndexes() { - delete[] byIndex; + byIndex.clear(); - if (areas.empty()) - { - byIndex = nullptr; - } - else - { - using AreaWeakPtr = Area*; - byIndex = new AreaWeakPtr[areas.size()]; + byIndex.resize(areas.size()); - uint indx = 0; - auto end = areas.end(); - for (auto i = areas.begin(); i != end; ++i, ++indx) - { - Area* area = i->second; - byIndex[indx] = area; - area->index = indx; - } + uint indx = 0; + auto end = areas.end(); + for (auto i = areas.begin(); i != end; ++i, ++indx) + { + Area* area = i->second; + byIndex[indx] = area; + area->index = indx; } } @@ -944,13 +931,13 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, // if changes are required, please update reloadXCastData() buffer.clear() << study.folderInput << SEP << "hydro" << SEP << "prepro"; ret = area.hydro.prepro->loadFromFolder(study, area.id, buffer.c_str()) && ret; + ret = area.hydro.prepro->validate(area.id) && ret; } - auto* hydroSeries = area.hydro.series; if (!options.loadOnlyNeeded || !area.hydro.prepro) // Series { buffer.clear() << study.folderInput << SEP << "hydro" << SEP << "series"; - ret = hydroSeries->loadGenerationTS(area.id, buffer, studyVersion) && ret; + ret = area.hydro.series->loadGenerationTS(area.id, buffer, studyVersion) && ret; } if (studyVersion < StudyVersion(9, 1)) @@ -965,11 +952,12 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, else { buffer.clear() << study.folderInput << SEP << "hydro" << SEP << "series"; - ret = hydroSeries->LoadMaxPower(area.id, buffer) && ret; + ret = area.hydro.series->LoadMaxPower(area.id, buffer) && ret; } - hydroSeries->resizeTSinDeratedMode( - study.parameters.derated, studyVersion, study.usedByTheSolver); + area.hydro.series->resizeTSinDeratedMode(study.parameters.derated, + studyVersion, + study.usedByTheSolver); } // Wind @@ -993,6 +981,7 @@ static bool AreaListLoadFromFolderSingleArea(Study& study, { buffer.clear() << study.folderInput << SEP << "thermal" << SEP << "prepro"; ret = area.thermal.list.loadPreproFromFolder(study, buffer) && ret; + ret = area.thermal.list.validatePrepro(study) && ret; buffer.clear() << study.folderInput << SEP << "thermal" << SEP << "series"; ret = area.thermal.list.loadDataSeriesFromFolder(study, buffer) && ret; ret = area.thermal.list.loadEconomicCosts(study, buffer) && ret; @@ -1160,6 +1149,7 @@ bool AreaList::loadFromFolder(const StudyLoadOptions& options) logs.info() << "Loading global hydro data..."; buffer.clear() << pStudy.folderInput << SEP << "hydro"; ret = PartHydro::LoadFromFolder(pStudy, buffer) && ret; + ret = PartHydro::validate(pStudy) && ret; } // Thermal data, specific to areas @@ -1180,6 +1170,7 @@ bool AreaList::loadFromFolder(const StudyLoadOptions& options) Area& area = *(i->second); buffer.clear() << pStudy.folderInput << thermalPlant << area.id; ret = area.thermal.list.loadFromFolder(pStudy, buffer.c_str(), &area) && ret; + ret = area.thermal.list.validateClusters(pStudy.parameters) && ret; } } @@ -1219,6 +1210,7 @@ bool AreaList::loadFromFolder(const StudyLoadOptions& options) Area& area = *(i->second); buffer.clear() << pStudy.folderInput << renewablePlant << area.id; ret = area.renewable.list.loadFromFolder(buffer.c_str(), &area) && ret; + ret = area.renewable.list.validateClusters() && ret; } } @@ -1273,13 +1265,10 @@ Area* AreaList::findFromPosition(const int x, const int y) const for (auto i = this->areas.rbegin(); i != end; ++i) { auto lastArea = i->second; - if (lastArea->ui) + if (lastArea->ui && std::abs(lastArea->ui->x - x) < nearestDistance + && std::abs(lastArea->ui->y - y) < nearestDistance) { - if (std::abs(lastArea->ui->x - x) < nearestDistance - && std::abs(lastArea->ui->y - y) < nearestDistance) - { - nearestItem = lastArea; - } + nearestItem = lastArea; } } return nearestItem; @@ -1326,11 +1315,11 @@ void AreaListEnsureDataLoadPrepro(AreaList* l) assert(l); l->each( - [&](Data::Area& area) + [](Data::Area& area) { if (!area.load.prepro) { - area.load.prepro = new Antares::Data::Load::Prepro(); + area.load.prepro = std::make_unique(); } }); } @@ -1345,7 +1334,7 @@ void AreaListEnsureDataSolarPrepro(AreaList* l) { if (!area.solar.prepro) { - area.solar.prepro = new Antares::Data::Solar::Prepro(); + area.solar.prepro = std::make_unique(); } }); } @@ -1360,7 +1349,7 @@ void AreaListEnsureDataWindPrepro(AreaList* l) { if (!area.wind.prepro) { - area.wind.prepro = new Antares::Data::Wind::Prepro(); + area.wind.prepro = std::make_unique(); } }); } @@ -1375,7 +1364,7 @@ void AreaListEnsureDataHydroTimeSeries(AreaList* l) { if (!area.hydro.series) { - area.hydro.series = new DataSeriesHydro(); + area.hydro.series = std::make_unique(); } }); } @@ -1390,7 +1379,7 @@ void AreaListEnsureDataHydroPrepro(AreaList* l) { if (!area.hydro.prepro) { - area.hydro.prepro = new PreproHydro(); + area.hydro.prepro = std::make_unique(); } }); } @@ -1698,9 +1687,9 @@ void AreaList::removeWindTimeseries() void AreaList::removeThermalTimeseries() { each( - [](Data::Area& area) + [](const Data::Area& area) { - for (auto& c: area.thermal.list.all()) + for (const auto& c: area.thermal.list.all()) { c->series.reset(); } diff --git a/src/libs/antares/study/area/scratchpad.cpp b/src/libs/antares/study/area/scratchpad.cpp index a08d6b01c3..d0a1637a1d 100644 --- a/src/libs/antares/study/area/scratchpad.cpp +++ b/src/libs/antares/study/area/scratchpad.cpp @@ -66,7 +66,6 @@ AreaScratchpad::AreaScratchpad(const StudyRuntimeInfos& rinfos, Area& area): { // alias to the simulation mode auto mode = rinfos.mode; - uint nbMonthsPerYear = 12; for (uint i = 0; i != 168; ++i) { @@ -168,7 +167,7 @@ AreaScratchpad::AreaScratchpad(const StudyRuntimeInfos& rinfos, Area& area): auto& colPowerOverWater = m[PreproHydro::powerOverWater]; auto& colMaxEnergy = m[PreproHydro::maximumEnergy]; - for (uint month = 0; month < nbMonthsPerYear; ++month) + for (uint month = 0; month < MONTHS_PER_YEAR; ++month) { valueCol += colMaxEnergy[month] * (1. - colPowerOverWater[month]); } diff --git a/src/libs/antares/study/include/antares/study/sets.hxx b/src/libs/antares/study/area/sets.cpp similarity index 55% rename from src/libs/antares/study/include/antares/study/sets.hxx rename to src/libs/antares/study/area/sets.cpp index d2976252cc..f853c21c0c 100644 --- a/src/libs/antares/study/include/antares/study/sets.hxx +++ b/src/libs/antares/study/area/sets.cpp @@ -18,113 +18,72 @@ ** You should have received a copy of the Mozilla Public Licence 2.0 ** along with Antares_Simulator. If not, see . */ -#ifndef __ANTARES_LIBS_STUDY_SETS_HXX__ -#define __ANTARES_LIBS_STUDY_SETS_HXX__ +#include "antares/study/sets.h" -namespace Antares +namespace Antares::Data { -namespace Data -{ -template -inline Sets::Sets(): - pByIndex(NULL), - pNameByIndex(NULL), - pModified(false) -{ -} - -template -inline Sets::Sets(const Sets& rhs): +Sets::Sets(const Sets& rhs): pMap(rhs.pMap), - pOptions(rhs.pOptions), - pByIndex(NULL), - pNameByIndex(NULL), - pModified(false) + pOptions(rhs.pOptions) { - if (rhs.pByIndex) + if (rhs.pByIndex.size()) { rebuildIndexes(); } } -template -inline Sets::~Sets() -{ - delete[] pByIndex; -} - -template -typename Sets::iterator Sets::begin() +Sets::iterator Sets::begin() { return pMap.begin(); } -template -typename Sets::const_iterator Sets::begin() const +Sets::const_iterator Sets::begin() const { return pMap.begin(); } -template -typename Sets::iterator Sets::end() +Sets::iterator Sets::end() { return pMap.end(); } -template -typename Sets::const_iterator Sets::end() const +Sets::const_iterator Sets::end() const { return pMap.end(); } -template -void Sets::clear() +void Sets::clear() { - if (pByIndex) - { - delete[] pByIndex; - pByIndex = NULL; - } - if (pNameByIndex) - { - delete[] pNameByIndex; - pNameByIndex = NULL; - } - + pByIndex.clear(); + pNameByIndex.clear(); pMap.clear(); pOptions.clear(); } -template -inline T& Sets::operator[](uint i) +Sets::SetAreasType& Sets::operator[](uint i) { assert(i < pMap.size() && "Sets: operator[] index out of bounds"); return *(pByIndex[i]); } -template -inline const T& Sets::operator[](uint i) const +const Sets::SetAreasType& Sets::operator[](uint i) const { assert(i < pMap.size() && "Sets: operator[] index out of bounds"); return *(pByIndex[i]); } -template -template -void Sets::dumpToLogs(L& log) const +void Sets::dumpToLogs() const { using namespace Yuni; - const typename MapType::const_iterator end = pMap.end(); - for (typename MapType::const_iterator i = pMap.begin(); i != end; ++i) + for (const auto& [setId, set]: pMap) { - log.info() << " found `" << i->first << "` (" << (uint)i->second->size() << ' ' - << (i->second->size() < 2 ? "item" : "items") - << ((!hasOutput(i->first)) ? ", no output" : "") << ')'; + logs.info() << " found `" << setId << "` (" << set->size() << ' ' + << (set->size() < 2 ? "item" : "items") + << ((!hasOutput(setId)) ? ", no output" : "") << ')'; } } -template -void Sets::defaultForAreas() +void Sets::defaultForAreas() { using namespace Yuni; clear(); @@ -132,23 +91,21 @@ void Sets::defaultForAreas() opts.caption = "All areas"; opts.comments = "Spatial aggregates on all areas"; opts.output = false; - opts.rules.push_back(Rule(ruleFilter, new String("add-all"))); - auto item = std::make_shared(); - add("all areas", item, opts); + opts.rules.emplace_back(ruleFilter, "add-all"); + auto district = std::make_shared(); + add("all areas", district, opts); } -template -YString Sets::toString() +YString Sets::toString() { using namespace Yuni; using namespace Antares; static const char* cmds[ruleMax] = {"none", "+", "-", "apply-filter"}; - const auto end = pOptions.cend(); YString ret = ""; - for (auto i = pOptions.cbegin(); i != end; ++i) + for (const auto& [setId, options]: pOptions) { - const Options& opts = i->second; - ret << '[' << i->first << "]\n"; + const Options& opts = options; + ret << '[' << setId << "]\n"; ret << "caption = " << opts.caption << '\n'; if (not opts.comments.empty()) { @@ -169,15 +126,10 @@ YString Sets::toString() return ret; } -template -template -bool Sets::saveToFile(const StringT& filename) const +bool Sets::saveToFile(const Yuni::String& filename) const { - using namespace Yuni; - using namespace Antares; - - IO::File::Stream file; - if (!file.open(filename, IO::OpenMode::write | IO::OpenMode::truncate)) + Yuni::IO::File::Stream file; + if (!file.open(filename, Yuni::IO::OpenMode::write | Yuni::IO::OpenMode::truncate)) { logs.error() << "I/O Error: " << filename << ": impossible to write the file"; return false; @@ -209,8 +161,7 @@ bool Sets::saveToFile(const StringT& filename) const return true; } -template -bool Sets::loadFromFile(const std::filesystem::path& filename) +bool Sets::loadFromFile(const std::filesystem::path& filename) { using namespace Yuni; using namespace Antares; @@ -240,7 +191,7 @@ bool Sets::loadFromFile(const std::filesystem::path& filename) } // Creating a new section - auto item = std::make_shared(); + auto district = std::make_shared(); Options opts; opts.caption = section->name; @@ -258,17 +209,17 @@ bool Sets::loadFromFile(const std::filesystem::path& filename) if (p->key == "+") { - opts.rules.push_back(Rule(ruleAdd, new String(value))); + opts.rules.emplace_back(ruleAdd, value.to()); continue; } if (p->key == "-") { - opts.rules.push_back(Rule(ruleRemove, new String(value))); + opts.rules.emplace_back(ruleRemove, value.to()); continue; } if (p->key == "apply-filter") { - opts.rules.push_back(Rule(ruleFilter, new String(value))); + opts.rules.emplace_back(ruleFilter, value.to()); continue; } if (p->key == "output") @@ -288,14 +239,14 @@ bool Sets::loadFromFile(const std::filesystem::path& filename) continue; } - logs.warning() << "sets: `" << filename << "`: Invalid property `" - << p->key << '\''; + logs.warning() << "sets: `" << filename << "`: Invalid property `" << p->key + << '\''; } // Add the new group IDType newid = section->name; newid.toLower(); - add(newid, item, opts); + add(newid, district, opts); } // Not modified anymore @@ -307,31 +258,28 @@ bool Sets::loadFromFile(const std::filesystem::path& filename) return false; } -template -template -inline void Sets::rebuildAllFromRules(HandlerT& handler) +void Sets::rebuildAllFromRules(SetHandlerAreas& handler) { - for (uint i = 0; i != pMap.size(); ++i) + for (const auto& setId: pNameByIndex) { - rebuildFromRules(pNameByIndex[i], handler); + rebuildFromRules(setId, handler); } } -template -template -void Sets::rebuildFromRules(const IDType& id, HandlerT& handler) +void Sets::rebuildFromRules(const IDType& id, SetHandlerAreas& handler) { using namespace Yuni; using namespace Antares; - typename MapOptions::iterator i = pOptions.find(id); - if (i == pOptions.end()) + const auto pair = pOptions.find(id); + if (pair == pOptions.end()) { return; } + // Options - Options& opts = i->second; - Type& set = *(pMap[id]); + Options& opts = pair->second; + auto& set = *(pMap[id]); // Clear the result first handler.clear(set); @@ -339,23 +287,20 @@ void Sets::rebuildFromRules(const IDType& id, HandlerT& handler) for (uint i = 0; i != opts.rules.size(); ++i) { const Rule& rule = opts.rules[i]; - const Yuni::String& arg = *(rule.second); + const std::string name = rule.second; switch (rule.first) // type { case ruleAdd: { // Trying to add a single item - if (!handler.add(set, arg)) + if (!handler.add(set, name)) { // Failed. Maybe the argument references another group - const IDType other = arg; - typename MapType::iterator i = pMap.find(other); + const IDType other = name; + MapType::iterator i = pMap.find(other); if (i != pMap.end()) { - if (handler.add(set, *(i->second))) - { - break; - } + handler.add(set, *(i->second)); } } break; @@ -363,24 +308,21 @@ void Sets::rebuildFromRules(const IDType& id, HandlerT& handler) case ruleRemove: { // Trying to remove a single item - if (!handler.remove(set, arg)) + if (!handler.remove(set, name)) { // Failed. Maybe the argument references another group - const IDType other = arg; - typename MapType::iterator i = pMap.find(other); + const IDType other = name; + MapType::iterator i = pMap.find(other); if (i != pMap.end()) { - if (handler.remove(set, *(i->second))) - { - break; - } + handler.remove(set, *(i->second)); } } break; } case ruleFilter: { - handler.applyFilter(set, arg); + handler.applyFilter(set, name); break; } case ruleNone: @@ -398,90 +340,125 @@ void Sets::rebuildFromRules(const IDType& id, HandlerT& handler) << " rules, got " << opts.resultSize << " items"; } -template -void Sets::rebuildIndexes() +void Sets::rebuildIndexes() { - delete[] pByIndex; - delete[] pNameByIndex; + pNameByIndex.clear(); + pNameByIndex.resize(pMap.size()); - if (!pMap.empty()) - { - pByIndex = new TypePtr[pMap.size()]; - pNameByIndex = new IDType[pMap.size()]; - const typename MapType::iterator end = pMap.end(); - uint index = 0; - for (typename MapType::iterator i = pMap.begin(); i != end; ++i) - { - pByIndex[index] = i->second; - pNameByIndex[index] = i->first; - ++index; - } - } - else + pByIndex.clear(); + pByIndex.resize(pMap.size()); + + uint index = 0; + for (const auto& [setId, set]: pMap) { - pByIndex = NULL; - pNameByIndex = NULL; + pByIndex[index] = set; + pNameByIndex[index] = setId; + ++index; } } -template -template -inline bool Sets::hasOutput(const StringT& s) const +bool Sets::hasOutput(const Yuni::ShortString128& s) const { - // Assert, if a C* container can not be found at compile time - static_assert(Yuni::Traits::CString::valid); - - typename MapOptions::const_iterator i = pOptions.find(s); - return (i != pOptions.end()) ? i->second.output : false; + const auto pair = pOptions.find(s); + return (pair != pOptions.end()) ? pair->second.output : false; } -template -inline bool Sets::hasOutput(const uint index) const +bool Sets::hasOutput(const uint index) const { return hasOutput(IDType(pNameByIndex[index])); } -template -template -inline uint Sets::resultSize(const StringT& s) const +uint Sets::resultSize(const Yuni::ShortString128& s) const { - // Assert, if a C* container can not be found at compile time - static_assert(Yuni::Traits::CString::valid); - - typename MapOptions::const_iterator i = pOptions.find(s); - return (i != pOptions.end()) ? i->second.resultSize : 0; + const auto pair = pOptions.find(s); + return (pair != pOptions.end()) ? pair->second.resultSize : 0; } -template -template -inline typename Sets::IDType Sets::caption(const StringT& s) const +Sets::IDType Sets::caption(const Yuni::ShortString128& s) const { - // Assert, if a C* container can not be found at compile time - static_assert(Yuni::Traits::CString::valid); - - typename MapOptions::const_iterator i = pOptions.find(s); - return (i != pOptions.end()) ? i->second.caption : IDType(); + const auto pair = pOptions.find(s); + return (pair != pOptions.end()) ? pair->second.caption : IDType(); } -template -inline typename Sets::IDType Sets::caption(const uint i) const +Sets::IDType Sets::caption(const uint i) const { return caption(IDType(pNameByIndex[i])); } -template -inline uint Sets::resultSize(const uint index) const +uint Sets::resultSize(const uint index) const { return resultSize(IDType(pNameByIndex[index])); } -template -inline uint Sets::size() const +uint Sets::size() const { return (uint)pMap.size(); } -} // namespace Data -} // namespace Antares +SetHandlerAreas::SetHandlerAreas(AreaList& areas): + areas_(areas) +{ +} + +void SetHandlerAreas::clear(Sets::SetAreasType& set) +{ + set.clear(); +} + +uint SetHandlerAreas::size(Sets::SetAreasType& set) +{ + return (uint)set.size(); +} + +bool SetHandlerAreas::add(Sets::SetAreasType& set, const std::string& value) +{ + Area* area = AreaListLFind(&areas_, value.c_str()); + if (area) + { + set.insert(area); + return true; + } + return false; +} + +void SetHandlerAreas::add(Sets::SetAreasType& set, const Sets::SetAreasType& otherSet) +{ + set.insert(otherSet.begin(), otherSet.end()); +} + +bool SetHandlerAreas::remove(Sets::SetAreasType& set, const std::string& value) +{ + Area* area = AreaListLFind(&areas_, value.c_str()); + if (area) + { + set.erase(area); + return true; + } + return false; +} + +void SetHandlerAreas::remove(Sets::SetAreasType& set, const Sets::SetAreasType& otherSet) +{ + std::ranges::for_each(otherSet, [&set](auto* area) { set.erase(area); }); +} + +bool SetHandlerAreas::applyFilter(Sets::SetAreasType& set, const std::string& value) +{ + if (value == "add-all") + { + for (const auto& [areaName, area]: areas_) + { + set.insert(area); + } + return true; + } + + if (value == "remove-all") + { + set.clear(); + return true; + } + return false; +} -#endif // __ANTARES_LIBS_STUDY_SETS_HXX__ +} // namespace Antares::Data diff --git a/src/libs/antares/study/binding_constraint/BindingConstraintGroupRepository.cpp b/src/libs/antares/study/binding_constraint/BindingConstraintGroupRepository.cpp index ce168c7eef..b29ad4fba2 100644 --- a/src/libs/antares/study/binding_constraint/BindingConstraintGroupRepository.cpp +++ b/src/libs/antares/study/binding_constraint/BindingConstraintGroupRepository.cpp @@ -60,9 +60,8 @@ bool BindingConstraintGroupRepository::buildFrom(const BindingConstraintsReposit bool BindingConstraintGroupRepository::timeSeriesWidthConsistentInGroups() const { - bool allConsistent = !std::any_of( - groups_.begin(), - groups_.end(), + bool allConsistent = !std::ranges::any_of( + groups_, [](const auto& group) { const auto& constraints = group->constraints(); @@ -71,9 +70,8 @@ bool BindingConstraintGroupRepository::timeSeriesWidthConsistentInGroups() const return false; } auto width = (*constraints.begin())->RHSTimeSeries().width; - bool isConsistent = std::all_of( - constraints.begin(), - constraints.end(), + bool isConsistent = std::ranges::all_of( + constraints, [&width](const std::shared_ptr& bc) { bool sameWidth = bc->RHSTimeSeries().width == width; @@ -94,17 +92,15 @@ bool BindingConstraintGroupRepository::timeSeriesWidthConsistentInGroups() const void BindingConstraintGroupRepository::resizeAllTimeseriesNumbers(unsigned int nb_years) { - std::for_each(groups_.begin(), - groups_.end(), - [&](auto& group) { group->timeseriesNumbers.reset(nb_years); }); + std::ranges::for_each(groups_, + [&nb_years](auto& group) { group->timeseriesNumbers.reset(nb_years); }); } BindingConstraintGroup* BindingConstraintGroupRepository::operator[](const std::string& name) const { - if (auto group = std::find_if(groups_.begin(), - groups_.end(), - [&name](auto& group_of_constraint) - { return group_of_constraint->name() == name; }); + if (auto group = std::ranges::find_if(groups_, + [&name](auto& group_of_constraint) + { return group_of_constraint->name() == name; }); group != groups_.end()) { return group->get(); diff --git a/src/libs/antares/study/cleaner/cleaner-v20.cpp b/src/libs/antares/study/cleaner/cleaner-v20.cpp index b3dc2ed6f6..f2fa71b17d 100644 --- a/src/libs/antares/study/cleaner/cleaner-v20.cpp +++ b/src/libs/antares/study/cleaner/cleaner-v20.cpp @@ -391,20 +391,19 @@ bool listOfFilesAnDirectoriesToKeep(StudyCleaningInfos* infos) buffer.clear() << infos->folder << "/input/bindingconstraints/bindingconstraints.ini"; if (ini.open(buffer)) { - String v; - ini.each( - [&](const IniFile::Section& section) + [&e](const IniFile::Section& section) { auto* property = section.firstProperty; for (; property; property = property->next) { if (property->key == "id") { - v = property->value; + String v = property->value; v.toLower(); - buffer.clear() << "input/bindingconstraints/" << v << ".txt"; - e.add(buffer); + String tmp; + tmp << "input/bindingconstraints/" << v << ".txt"; + e.add(tmp); // Go to the next binding constraint break; } diff --git a/src/libs/antares/study/filter.cpp b/src/libs/antares/study/filter.cpp index aa8916c26c..cb94bf5d30 100644 --- a/src/libs/antares/study/filter.cpp +++ b/src/libs/antares/study/filter.cpp @@ -82,7 +82,7 @@ uint stringIntoDatePrecision(const AnyString& string) uint flag = 0; string.words(",; \r\n\t", - [&](const AnyString& word) -> bool + [&flag](const AnyString& word) -> bool { ShortString16 s = word; s.toLower(); diff --git a/src/libs/antares/study/fwd.cpp b/src/libs/antares/study/fwd.cpp index 68dae733e6..100a4b127e 100644 --- a/src/libs/antares/study/fwd.cpp +++ b/src/libs/antares/study/fwd.cpp @@ -91,43 +91,6 @@ const char* SeedToID(SeedIndex seed) return ""; } -// ... Initial reservoir levels ... -InitialReservoirLevels StringToInitialReservoirLevels(const AnyString& text) -{ - if (!text) - { - return irlUnknown; - } - - CString<24, false> s = text; - s.trim(); - s.toLower(); - if (s == "cold start") - { - return irlColdStart; - } - if (s == "hot start") - { - return irlHotStart; - } - - return irlUnknown; -} - -const char* InitialReservoirLevelsToCString(InitialReservoirLevels iniLevels) -{ - switch (iniLevels) - { - case irlColdStart: - return "cold start"; - case irlHotStart: - return "hot start"; - case irlUnknown: - return ""; - } - return ""; -} - // ... Hydro heuristic policy ... HydroHeuristicPolicy StringToHydroHeuristicPolicy(const AnyString& text) { diff --git a/src/libs/antares/study/header.cpp b/src/libs/antares/study/header.cpp index 4b751d75c7..ae44e94ad5 100644 --- a/src/libs/antares/study/header.cpp +++ b/src/libs/antares/study/header.cpp @@ -166,18 +166,8 @@ bool StudyHeader::internalLoadFromINIFile(const IniFile& ini, bool warnings) } } - if (version >= StudyVersion(7, 0)) + if (version.isSupported(true)) { - if (version > Data::StudyVersion::latest()) - { - if (warnings) - { - logs.error() << "Header: This version is not supported (version found:" - << version.toString() - << ", expected: <=" << Data::StudyVersion::latest().toString() << ')'; - } - return false; - } return true; } @@ -185,6 +175,7 @@ bool StudyHeader::internalLoadFromINIFile(const IniFile& ini, bool warnings) { logs.error() << "Study header: Invalid format"; } + return false; } diff --git a/src/libs/antares/study/include/antares/study/area/area.h b/src/libs/antares/study/include/antares/study/area/area.h index ede65679a2..7550d9840f 100644 --- a/src/libs/antares/study/include/antares/study/area/area.h +++ b/src/libs/antares/study/include/antares/study/area/area.h @@ -689,7 +689,7 @@ class AreaList final: public Yuni::NonCopyable public: //! All areas by their index - Area** byIndex; + std::vector byIndex; //! All areas in the list Area::Map areas; diff --git a/src/libs/antares/study/include/antares/study/area/scratchpad.h b/src/libs/antares/study/include/antares/study/area/scratchpad.h index 3258b7423d..864d50a155 100644 --- a/src/libs/antares/study/include/antares/study/area/scratchpad.h +++ b/src/libs/antares/study/include/antares/study/area/scratchpad.h @@ -66,11 +66,11 @@ class AreaScratchpad final //! Sum of all 'must-run' clusters // This variable is initialized every MC-year - double mustrunSum[HOURS_PER_YEAR]; + std::array mustrunSum; //! Sum of all original 'must-run' clusters (adequacy only) // This variable is initialized every MC-year - double originalMustrunSum[HOURS_PER_YEAR]; + std::array originalMustrunSum; /*! ** \brief Dispatchable Generation Margin diff --git a/src/libs/antares/study/include/antares/study/fwd.h b/src/libs/antares/study/include/antares/study/fwd.h index 56b6e3982b..6fa2819aca 100644 --- a/src/libs/antares/study/include/antares/study/fwd.h +++ b/src/libs/antares/study/include/antares/study/fwd.h @@ -382,24 +382,6 @@ const char* SeedToCString(SeedIndex seed); */ const char* SeedToID(SeedIndex seed); -// ... Initial reservoir levels ... -enum InitialReservoirLevels -{ - irlColdStart = 0, - irlHotStart, - irlUnknown, -}; - -/*! -** \brief Convert an Initial Reservoir Levels strategy into a text -*/ -const char* InitialReservoirLevelsToCString(InitialReservoirLevels iniLevels); - -/*! -** \brief Convert a text into an Initial Reservoir Levels strategy -*/ -InitialReservoirLevels StringToInitialReservoirLevels(const AnyString& text); - // ... Hydro heuristic policy ... enum HydroHeuristicPolicy { diff --git a/src/libs/antares/study/include/antares/study/header.h b/src/libs/antares/study/include/antares/study/header.h index ec513143ec..aea7e0f35c 100644 --- a/src/libs/antares/study/include/antares/study/header.h +++ b/src/libs/antares/study/include/antares/study/header.h @@ -55,7 +55,6 @@ class StudyHeader final */ static bool readVersionFromFile(const std::filesystem::path& filename, std::string& version); -public: //! \name Constructor & Destructor //@{ /*! @@ -109,7 +108,8 @@ class StudyHeader final */ static StudyVersion tryToFindTheVersion(const std::string& folder); -public: + bool validateVersion(); + //! Caption of the study Yuni::String caption; diff --git a/src/libs/antares/study/include/antares/study/load-options.h b/src/libs/antares/study/include/antares/study/load-options.h index 898b641653..41eee86cbb 100644 --- a/src/libs/antares/study/include/antares/study/load-options.h +++ b/src/libs/antares/study/include/antares/study/load-options.h @@ -52,6 +52,7 @@ class StudyLoadOptions bool loadOnlyNeeded; //! Force the year-by-year flag bool forceYearByYear; + //! Force the derated mode bool forceDerated; diff --git a/src/libs/antares/study/include/antares/study/parameters.h b/src/libs/antares/study/include/antares/study/parameters.h index fcbb8b0080..1b2ce027d9 100644 --- a/src/libs/antares/study/include/antares/study/parameters.h +++ b/src/libs/antares/study/include/antares/study/parameters.h @@ -50,21 +50,6 @@ namespace Antares::Data class Parameters final { public: - //! \name Constructor - //@{ - /*! - ** \brief Default Constructor - ** - ** \warning None of the variables are initialized. You must explicitly use - ** the method `reset()` or the method `loadFromFile()` - ** \see reset() - ** \see loadFromFile() - */ - Parameters(); - //! Destructor - ~Parameters(); - //@} - //! \name Simulation mode //@{ //! Get if the simulation is in economy mode @@ -90,9 +75,7 @@ class Parameters final ** \param version Current study version ** \return True if the settings have been loaded, false if at least one error has occured */ - bool loadFromFile(const AnyString& filename, - StudyVersion& version, - const StudyLoadOptions& options); + bool loadFromFile(const AnyString& filename, const StudyVersion& version); /*! ** \brief Prepare all settings for a simulation @@ -152,6 +135,8 @@ class Parameters final */ void fixBadValues(); + void validateOptions(const StudyLoadOptions&); + /*! ** \brief Try to detect then fix refresh intervals */ @@ -463,12 +448,6 @@ class Parameters final RenewableGeneration renewableGeneration; - struct - { - //! Initial reservoir levels - InitialReservoirLevels iniLevels; - } initialReservoirLevels; - struct { //! Hydro heuristic policy @@ -481,11 +460,6 @@ class Parameters final HydroPricingMode hpMode; } hydroPricing; - // In case of hydro hot start and MC years simultaneous run - // ... Answers the question : do all sets of simultaneous years have the same size ? - // (obvious if the parallel mode is not required : answer is yes). - bool allSetsHaveSameSize; - //! Transmission capacities GlobalTransmissionCapacities transmissionCapacities; //! Simplex optimization range (day/week) @@ -504,7 +478,7 @@ class Parameters final //@{ //! No output // This variable is not stored within the study but only used by the solver - bool noOutput; + bool noOutput = false; //@} bool hydroDebug; @@ -526,9 +500,7 @@ class Parameters final private: //! Load data from an INI file - bool loadFromINI(const IniFile& ini, - const StudyVersion& version, - const StudyLoadOptions& options); + bool loadFromINI(const IniFile& ini, const StudyVersion& version); void resetPlayedYears(uint nbOfYears); diff --git a/src/libs/antares/study/include/antares/study/parameters/adq-patch-params.h b/src/libs/antares/study/include/antares/study/parameters/adq-patch-params.h index 25c8b0f79b..53584a96d5 100644 --- a/src/libs/antares/study/include/antares/study/parameters/adq-patch-params.h +++ b/src/libs/antares/study/include/antares/study/parameters/adq-patch-params.h @@ -78,25 +78,6 @@ enum class AdqPatchPTO }; // enum AdqPatchPTO -struct LocalMatching -{ - bool enabled = true; - //! Transmission capacities from physical areas outside adequacy patch (area type 1) to - //! physical areas inside adequacy patch (area type 2). NTC is set to null (if true) - //! only in the first step of adequacy patch local matching rule. - bool setToZeroOutsideInsideLinks = true; - //! Transmission capacities between physical areas outside adequacy patch (area type 1). - //! NTC is set to null (if true) only in the first step of adequacy patch local matching - //! rule. - bool setToZeroOutsideOutsideLinks = true; - /*! - ** \brief Reset to default values related to local matching - */ - void reset(); - bool updateFromKeyValue(const Yuni::String& key, const Yuni::String& value); - void addProperties(IniFile::Section* section) const; -}; - class CurtailmentSharing { public: @@ -113,8 +94,6 @@ class CurtailmentSharing //! Check CSR cost function prior & after CSR optimization bool checkCsrCostFunction; - bool recomputeDTGMRG = false; - bool updateFromKeyValue(const Yuni::String& key, const Yuni::String& value); void addProperties(IniFile::Section* section) const; @@ -127,7 +106,10 @@ class CurtailmentSharing struct AdqPatchParams { bool enabled; - LocalMatching localMatching; + //! Transmission capacities from physical areas outside adequacy patch (area type 1) to + //! physical areas inside adequacy patch (area type 2). NTC is set to null (if true) + //! only in the first step of adequacy patch local matching rule. + bool setToZeroOutsideInsideLinks = true; CurtailmentSharing curtailmentSharing; void reset(); diff --git a/src/libs/antares/study/include/antares/study/parts/hydro/container.h b/src/libs/antares/study/include/antares/study/parts/hydro/container.h index 5d79c65d30..1da5ab6023 100644 --- a/src/libs/antares/study/include/antares/study/parts/hydro/container.h +++ b/src/libs/antares/study/include/antares/study/parts/hydro/container.h @@ -21,6 +21,8 @@ #ifndef __ANTARES_LIBS_STUDY_PARTS_HYDRO_CONTAINER_H__ #define __ANTARES_LIBS_STUDY_PARTS_HYDRO_CONTAINER_H__ +#include + #include "../../fwd.h" #include "allocation.h" #include "prepro.h" @@ -28,6 +30,60 @@ namespace Antares::Data { + +//! The maximum number of days in a year +constexpr size_t dayYearCount = 366; + +struct DailyDemand +{ + //! Net demand, for each day of the year, for each area + double DLN = 0.; + //! Daily local effective load + double DLE = 0.; +}; + +struct MonthlyGenerationTargetData +{ + //! Monthly local effective demand + double MLE = 0.; + //! Monthly optimal generation + double MOG = 0.; + //! Monthly optimal level + double MOL = 0.; + //! Monthly target generations + double MTG = 0.; +}; + +//! Hydro Management Data for a given area +struct TimeDependantHydroManagementData +{ + std::array daily{0}; + std::array monthly{0}; +}; + +//! Area Hydro Management Data for a given year +struct AreaDependantHydroManagementData +{ + //! inflows + std::array inflows{}; + //! monthly minimal generation + std::array mingens{}; + + //! daily minimal generation + std::array dailyMinGen{}; + + // Data for minGen<->inflows preChecks + //! monthly total mingen + std::array totalMonthMingen{}; + //! monthly total inflows + std::array totalMonthInflows{}; + //! yearly total mingen + double totalYearMingen = 0; + //! yearly total inflows + double totalYearInflows = 0; + +}; // struct AreaDependantHydroManagementData + /*! ** \brief Hydro for a single area */ @@ -52,7 +108,6 @@ class PartHydro pumpMod, }; -public: /*! ** \brief Load data for hydro container from a folder ** @@ -61,6 +116,13 @@ class PartHydro */ static bool LoadFromFolder(Study& study, const AnyString& folder); + /*! + ** \brief Check and validate the loaded datas + ** + ** \return A non-zero value if the operation succeeded, 0 otherwise + */ + static bool validate(Study& study); + /*! ** \brief Save data from several containers to a folder (except data for the prepro and *time-series) @@ -71,13 +133,12 @@ class PartHydro */ static bool SaveToFolder(const AreaList& areas, const AnyString& folder); -public: /*! ** \brief Default Constructor */ PartHydro(); //! Destructor - ~PartHydro(); + ~PartHydro() = default; /*! ** \brief Reset internal data @@ -100,7 +161,6 @@ class PartHydro bool CheckDailyMaxEnergy(const AnyString& areaName); -public: //! Inter-daily breakdown (previously called Smoothing Factor or alpha) double interDailyBreakdown; //! Intra-daily modulation @@ -151,15 +211,22 @@ class PartHydro HydroAllocation allocation; //! Data for the pre-processor - PreproHydro* prepro; + std::unique_ptr prepro; //! Data for time-series - DataSeriesHydro* series; + std::unique_ptr series; // TODO : following time series could be hosted by the series data member above (of type // DataSeriesHydro), // which contains other time. Matrix dailyNbHoursAtGenPmax; Matrix dailyNbHoursAtPumpPmax; + std::unordered_map managementData; + + std::vector> deltaBetweenFinalAndInitialLevels; + +private: + static bool checkReservoirLevels(const Study& study); + static bool checkProperties(Study& study); }; // class PartHydro @@ -167,10 +234,7 @@ class PartHydro // As this function can be called a lot of times, we pass working variables and returned variables // as arguments, so that we don't have to create them locally (as in a classical function) each // time. -void getWaterValue(const double& level, - const Matrix& waterValues, - const uint day, - double& waterValueToReturn); +double getWaterValue(const double& level, const Matrix& waterValues, const uint day); // Interpolates a rate from the credit modulation table according to a level double getWeeklyModulation(const double& level /* format : in % of reservoir capacity */, diff --git a/src/libs/antares/study/include/antares/study/parts/hydro/prepro.h b/src/libs/antares/study/include/antares/study/parts/hydro/prepro.h index dbc015ecce..b35798f862 100644 --- a/src/libs/antares/study/include/antares/study/parts/hydro/prepro.h +++ b/src/libs/antares/study/include/antares/study/parts/hydro/prepro.h @@ -95,8 +95,9 @@ class PreproHydro ** \param folder The source folder (ex: `input/hydro/prepro`) ** \return A non-zero value if the operation succeeded, 0 otherwise */ - bool loadFromFolder(Study& s, const AreaName& areaID, const char folder[]); + bool loadFromFolder(Study& s, const AreaName& areaID, const std::string& folder); + bool validate(const std::string& areaID); /*! ** \brief Save hydro settings for the prepro into a folder ** diff --git a/src/libs/antares/study/include/antares/study/parts/load/container.h b/src/libs/antares/study/include/antares/study/parts/load/container.h index 083dc6df7d..ec7402034a 100644 --- a/src/libs/antares/study/include/antares/study/parts/load/container.h +++ b/src/libs/antares/study/include/antares/study/parts/load/container.h @@ -44,7 +44,7 @@ class Container final: private Yuni::NonCopyable */ Container(); //! Destructor - ~Container(); + ~Container() = default; //@} /*! @@ -67,9 +67,8 @@ class Container final: private Yuni::NonCopyable */ uint64_t memoryUsage() const; -public: //! Data for the pre-processor - Data::Load::Prepro* prepro; + std::unique_ptr prepro; TimeSeriesNumbers tsNumbers; diff --git a/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h index edec4d1468..275d495020 100644 --- a/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/renewable/cluster_list.h @@ -26,9 +26,7 @@ #include "../common/cluster_list.h" #include "cluster.h" -namespace Antares -{ -namespace Data +namespace Antares::Data { /*! ** \brief List of renewable clusters @@ -39,10 +37,12 @@ class RenewableClusterList: public ClusterList public: std::string typeID() const override; uint64_t memoryUsage() const override; + bool loadFromFolder(const AnyString& folder, Area* area); + bool validateClusters() const; + bool saveToFolder(const AnyString& folder) const override; }; // class RenewableClusterList -} // namespace Data -} // namespace Antares +} // namespace Antares::Data #endif /* __ANTARES_LIBS_STUDY_PARTS_RENEWABLE_CLUSTER_LIST_H__ */ diff --git a/src/libs/antares/study/include/antares/study/parts/short-term-storage/cluster.h b/src/libs/antares/study/include/antares/study/parts/short-term-storage/cluster.h index afe2e1976f..cc9af74015 100644 --- a/src/libs/antares/study/include/antares/study/parts/short-term-storage/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/short-term-storage/cluster.h @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #pragma once #include diff --git a/src/libs/antares/study/include/antares/study/parts/short-term-storage/properties.h b/src/libs/antares/study/include/antares/study/parts/short-term-storage/properties.h index 11b4808e0d..ac1d37e791 100644 --- a/src/libs/antares/study/include/antares/study/parts/short-term-storage/properties.h +++ b/src/libs/antares/study/include/antares/study/parts/short-term-storage/properties.h @@ -41,12 +41,17 @@ class Properties std::optional withdrawalNominalCapacity; /// Not optional Reservoir capacity in MWh, >= 0 std::optional reservoirCapacity; + /// Initial level, <= 1 double initialLevel = initiallevelDefault; /// Bool to optimise or not initial level bool initialLevelOptim = false; - /// Efficiency factor between 0 and 1 - double efficiencyFactor = 1; + + /// Efficiency factor for injection between 0 and 1 + double injectionEfficiency = 1; + /// Efficiency factor for withdrawal between 0 and 1 + double withdrawalEfficiency = 1; + // Used to sort outputs std::string groupName = "OTHER1"; /// cluster name diff --git a/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h b/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h index e6302680f8..238a25d425 100644 --- a/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h +++ b/src/libs/antares/study/include/antares/study/parts/short-term-storage/series.h @@ -28,7 +28,7 @@ class Series { public: // check if series values are valid - bool validate() const; + bool validate(const std::string& id = "") const; // load all series files with folder path bool loadFromFolder(const std::string& folder); @@ -42,13 +42,17 @@ class Series std::vector lowerRuleCurve; std::vector upperRuleCurve; + std::vector costInjection; + std::vector costWithdrawal; + std::vector costLevel; + private: - bool validateSizes() const; - bool validateMaxInjection() const; - bool validateMaxWithdrawal() const; - bool validateRuleCurves() const; - bool validateUpperRuleCurve() const; - bool validateLowerRuleCurve() const; + bool validateSizes(const std::string&) const; + bool validateMaxInjection(const std::string&) const; + bool validateMaxWithdrawal(const std::string&) const; + bool validateRuleCurves(const std::string&) const; + bool validateUpperRuleCurve(const std::string&) const; + bool validateLowerRuleCurve(const std::string&) const; }; bool loadFile(const std::string& folder, std::vector& vect); diff --git a/src/libs/antares/study/include/antares/study/parts/solar/container.h b/src/libs/antares/study/include/antares/study/parts/solar/container.h index a4ea96d55b..390b72cd90 100644 --- a/src/libs/antares/study/include/antares/study/parts/solar/container.h +++ b/src/libs/antares/study/include/antares/study/parts/solar/container.h @@ -41,7 +41,7 @@ class Container */ Container(); //! Destructor - ~Container(); + ~Container() = default; //@} /*! @@ -64,9 +64,8 @@ class Container */ uint64_t memoryUsage() const; -public: //! Data for the pre-processor - Data::Solar::Prepro* prepro; + std::unique_ptr prepro; TimeSeriesNumbers tsNumbers; diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h b/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h index 7d1ce30bac..9216ac88aa 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cluster.h @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #ifndef __ANTARES_LIBS_STUDY_PARTS_THERMAL_CLUSTER_H__ #define __ANTARES_LIBS_STUDY_PARTS_THERMAL_CLUSTER_H__ @@ -115,7 +115,7 @@ class ThermalCluster final: public Cluster, public std::enable_shared_from_this< explicit ThermalCluster(Data::Area* parent); ThermalCluster() = delete; - ~ThermalCluster(); + ~ThermalCluster() = default; /*! ** \brief Invalidate all data associated to the thermal cluster @@ -353,7 +353,7 @@ class ThermalCluster final: public Cluster, public std::enable_shared_from_this< std::vector PthetaInf; //! Data for the preprocessor - PreproAvailability* prepro = nullptr; + std::unique_ptr prepro; /*! ** \brief Production Cost, Market Bid Cost and Marginal Cost Matrixes - Per Hour and per Time diff --git a/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h b/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h index ea1518750d..9f091defda 100644 --- a/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h +++ b/src/libs/antares/study/include/antares/study/parts/thermal/cluster_list.h @@ -113,6 +113,9 @@ class ThermalClusterList: public ClusterList ** \return A non-zero value if the operation succeeded, 0 otherwise */ bool loadPreproFromFolder(Study& s, const AnyString& folder); + bool validatePrepro(const Study& study); + + bool validateClusters(const Parameters& param) const; bool loadEconomicCosts(Study& s, const AnyString& folder); diff --git a/src/libs/antares/study/include/antares/study/parts/wind/container.h b/src/libs/antares/study/include/antares/study/parts/wind/container.h index 7e36522597..ba149068f5 100644 --- a/src/libs/antares/study/include/antares/study/parts/wind/container.h +++ b/src/libs/antares/study/include/antares/study/parts/wind/container.h @@ -41,7 +41,7 @@ class Container */ Container(); //! Destructor - ~Container(); + ~Container() = default; //@} /*! @@ -64,9 +64,8 @@ class Container */ uint64_t memoryUsage() const; -public: //! Data for the pre-processor - Data::Wind::Prepro* prepro; + std::unique_ptr prepro; TimeSeriesNumbers tsNumbers; diff --git a/src/libs/antares/study/include/antares/study/progression/progression.h b/src/libs/antares/study/include/antares/study/progression/progression.h index bcdeca82ac..19c2be8c00 100644 --- a/src/libs/antares/study/include/antares/study/progression/progression.h +++ b/src/libs/antares/study/include/antares/study/progression/progression.h @@ -76,11 +76,11 @@ class Progression final public: //! The total number of ticks to achieve - int maxTickCount; + unsigned maxTickCount; //! The current number of ticks - std::atomic tickCount; + std::atomic tickCount; //! The last number of ticks, to reduce the log verbosity - int lastTickCount; + unsigned lastTickCount; // Caption to use when displaying logs // Example: 'year: 10000, task: thermal' Yuni::CString<40, false> caption; @@ -104,7 +104,7 @@ class Progression final return *this; } - Task& operator+=(int value) + Task& operator+=(unsigned value) { pPart.tickCount += value; return *this; @@ -138,7 +138,7 @@ class Progression final ** \internal The number of ticks should remain an `int` because ** we can not use unsigned atomic integer */ - void add(uint year, Section section, int nbTicks); + void add(uint year, Section section, unsigned nbTicks); void add(Section section, int nbTicks); @@ -169,15 +169,7 @@ class Progression final public: Meter(); - virtual ~Meter() - { - if (logsContainer) - { - delete[] logsContainer; - } - } - - void allocateLogsContainer(uint nb); + virtual ~Meter() = default; /*! ** \brief Prepare enough space to allow @n simultaneous tasks @@ -188,16 +180,12 @@ class Progression final virtual bool onInterval(uint) override; public: - // Progression::Part::Map parts; Part::ListRef inUse; std::mutex mutex; uint nbParallelYears; - // Because writing something to the logs might be expensive, we have to - // reduce the time spent in locking the mutex. - // We will use a temp vector of string to delay the writing into the logs - Yuni::CString<256, false>* logsContainer; + std::vector> logsContainer; }; // class Meter diff --git a/src/libs/antares/study/include/antares/study/progression/progression.hxx b/src/libs/antares/study/include/antares/study/progression/progression.hxx index 91430681dc..ad262b4ad5 100644 --- a/src/libs/antares/study/include/antares/study/progression/progression.hxx +++ b/src/libs/antares/study/include/antares/study/progression/progression.hxx @@ -26,16 +26,10 @@ namespace Antares namespace Solver { inline Progression::Meter::Meter(): - nbParallelYears(0), - logsContainer(nullptr) + nbParallelYears(0) { } -inline void Progression::Meter::allocateLogsContainer(uint nb) -{ - logsContainer = new Yuni::CString<256, false>[nb]; -} - inline void Progression::Meter::taskCount(uint n) { (void)n; @@ -49,7 +43,7 @@ inline void Progression::add(Section section, int nbTicks) inline void Progression::setNumberOfParallelYears(uint nb) { pProgressMeter.nbParallelYears = nb; - pProgressMeter.allocateLogsContainer(nb); + pProgressMeter.logsContainer.resize(nb); } inline Progression::Part& Progression::begin(uint year, Progression::Section section) diff --git a/src/libs/antares/study/include/antares/study/runtime/runtime.h b/src/libs/antares/study/include/antares/study/runtime/runtime.h index 0ea07ce3bc..d87761674f 100644 --- a/src/libs/antares/study/include/antares/study/runtime/runtime.h +++ b/src/libs/antares/study/include/antares/study/runtime/runtime.h @@ -25,11 +25,13 @@ #include #include -#include "antares/study/study.h" +#include namespace Antares::Data { +class Study; + enum RangeLimitsIndex { rangeBegin = 0, @@ -139,8 +141,12 @@ class StudyRuntimeInfos void checkThermalTSGeneration(Study& study); }; // struct StudyRuntimeInfos -} // namespace Antares::Data +#ifdef NDEBUG +inline void StudyRangeLimits::checkIntegrity() const +{ +} +#endif -#include "runtime.hxx" +} // namespace Antares::Data #endif // __ANTARES_LIBS_STUDY_RUNTIME_RUNTIME_INFOS_H__ diff --git a/src/libs/antares/study/include/antares/study/scenario-builder/hydroLevelsData.h b/src/libs/antares/study/include/antares/study/scenario-builder/hydroLevelsData.h index 0f01fb9c32..b5cb21073d 100644 --- a/src/libs/antares/study/include/antares/study/scenario-builder/hydroLevelsData.h +++ b/src/libs/antares/study/include/antares/study/scenario-builder/hydroLevelsData.h @@ -21,6 +21,8 @@ #ifndef __LIBS_STUDY_SCENARIO_BUILDER_DATA_HYDRO_LEVELS_H__ #define __LIBS_STUDY_SCENARIO_BUILDER_DATA_HYDRO_LEVELS_H__ +#include + #include "scBuilderDataInterface.h" namespace Antares @@ -39,7 +41,10 @@ class hydroLevelsData final: public dataInterface using MatrixType = Matrix; public: - // We use default constructor and destructor + // Constructor + + hydroLevelsData(const std::string& iniFilePrefix, + std::function applyToTarget); //! \name Data manupulation //@{ @@ -51,7 +56,7 @@ class hydroLevelsData final: public dataInterface /*! ** \brief Export the data into a mere INI file */ - void saveToINIFile(const Study& study, Yuni::IO::File::Stream& file) const; + void saveToINIFile(const Study& study, Yuni::IO::File::Stream& file) const override; /*! ** \brief Assign a single value @@ -71,11 +76,15 @@ class hydroLevelsData final: public dataInterface void set_value(uint x, uint y, double value); - bool apply(Study& study); + bool apply(Study& study) override; private: //! Hydro levels overlay (0 if auto) MatrixType pHydroLevelsRules; + // prefix to be added when calling saveToINIFileHydroLevel + const std::string addToPrefix_; + + std::function applyToTarget_; }; // class hydroLevelsData @@ -105,6 +114,16 @@ inline double hydroLevelsData::get_value(uint x, uint y) const return pHydroLevelsRules.entry[y][x]; } +inline void initLevelApply(Study& study, Matrix& matrix) +{ + study.scenarioInitialHydroLevels.copyFrom(matrix); +} + +inline void finalLevelApply(Study& study, Matrix& matrix) +{ + study.scenarioFinalHydroLevels.copyFrom(matrix); +} + } // namespace ScenarioBuilder } // namespace Data } // namespace Antares diff --git a/src/libs/antares/study/include/antares/study/scenario-builder/rules.h b/src/libs/antares/study/include/antares/study/scenario-builder/rules.h index b79d92be86..ff5261d64a 100644 --- a/src/libs/antares/study/include/antares/study/scenario-builder/rules.h +++ b/src/libs/antares/study/include/antares/study/scenario-builder/rules.h @@ -119,8 +119,10 @@ class Rules final: private Yuni::NonCopyable //! Renewable (array [0..pAreaCount - 1]) std::vector renewable; - //! hydro levels - hydroLevelsData hydroLevels; + //! hydro initial levels + hydroLevelsData hydroInitialLevels = {"hl,", initLevelApply}; + //! hydro final levels + hydroLevelsData hydroFinalLevels = {"hfl,", finalLevelApply}; // Links NTC std::vector linksNTC; @@ -135,7 +137,8 @@ class Rules final: private Yuni::NonCopyable bool readWind(const AreaName::Vector& instrs, String value, bool updaterMode); bool readHydro(const AreaName::Vector& instrs, String value, bool updaterMode); bool readSolar(const AreaName::Vector& instrs, String value, bool updaterMode); - bool readHydroLevels(const AreaName::Vector& instrs, String value, bool updaterMode); + bool readInitialHydroLevels(const AreaName::Vector& instrs, String value, bool updaterMode); + bool readFinalHydroLevels(const AreaName::Vector& instrs, String value, bool updaterMode); bool readLink(const AreaName::Vector& instrs, String value, bool updaterMode); bool readBindingConstraints(const AreaName::Vector& splitKey, String value); diff --git a/src/libs/antares/study/include/antares/study/sets.h b/src/libs/antares/study/include/antares/study/sets.h index 0309916749..3932c99372 100644 --- a/src/libs/antares/study/include/antares/study/sets.h +++ b/src/libs/antares/study/include/antares/study/sets.h @@ -18,8 +18,7 @@ ** You should have received a copy of the Mozilla Public Licence 2.0 ** along with Antares_Simulator. If not, see . */ -#ifndef __ANTARES_LIBS_STUDY_SETS_H__ -#define __ANTARES_LIBS_STUDY_SETS_H__ +#pragma once #include #include @@ -31,29 +30,32 @@ #include #include +#include "antares/study/area/area.h" -namespace Antares +namespace Antares::Data { -namespace Data -{ -template +class SetHandlerAreas; + class Sets final { public: - //! Type - using Type = T; - // - using IDType = Yuni::CString<128, false>; + using IDType = Yuni::ShortString128; + + //! A single set of areas + // CompareAreaName : to control the order of areas in a set of areas. This order can have an + // effect, even if tiny, on the results of aggregations. + using SetAreasType = std::set; + //! Value - using TypePtr = std::shared_ptr; + using TypePtr = std::shared_ptr; //! Map of Item using MapType = std::map; //! Standard iterators from the STL - using iterator = typename MapType::iterator; + using iterator = MapType::iterator; //! Standard iterators from the STL (const) - using const_iterator = typename MapType::const_iterator; + using const_iterator = MapType::const_iterator; enum RuleType { @@ -65,7 +67,7 @@ class Sets final }; //! Definition of a single rule - using Rule = std::pair; + using Rule = std::pair; //! Rule Set using RuleSet = std::vector; @@ -128,13 +130,13 @@ class Sets final /*! ** \brief Default constructor */ - Sets(); + Sets() = default; /*! ** \brief Copy constructor */ Sets(const Sets& rhs); //! Destructor - ~Sets(); + ~Sets() = default; //@} //! \name Iterators @@ -150,37 +152,6 @@ class Sets final */ void clear(); - /*! - ** - */ - TypePtr add(const IDType& name) - { - TypePtr p = new T(); - pMap[name] = p; - pOptions[name].reset(name); - return p; - } - - /*! - ** - */ - TypePtr add(const IDType& name, const TypePtr& data) - { - pMap[name] = data; - pOptions[name].reset(name); - return data; - } - - /*! - ** - */ - TypePtr add(const IDType& name, const TypePtr& data, Options& opts) - { - pMap[name] = data; - pOptions[name] = opts; - return data; - } - bool forceReload(bool /*reload*/) const { pModified = true; @@ -194,13 +165,10 @@ class Sets final uint size() const; - void rebuildIndexes(); - /*! ** \brief Get if the results for a given group should be written to the output */ - template - bool hasOutput(const StringT& s) const; + bool hasOutput(const Yuni::ShortString128& s) const; /*! ** \brief Get if the results for a given group should be written to the output @@ -210,24 +178,21 @@ class Sets final /*! ** \brief Get the size of a result set */ - template - uint resultSize(const StringT& s) const; + uint resultSize(const Yuni::ShortString128& s) const; /*! ** \brief Get the size of a result set */ uint resultSize(const uint index) const; - template - void dumpToLogs(L& log) const; + void dumpToLogs() const; /*! ** \brief Load a rule set from an INI File */ bool loadFromFile(const std::filesystem::path& filename); - template - bool saveToFile(const StringT& filename) const; + bool saveToFile(const Yuni::String& filename) const; /*! ** \brief format the string to match the options */ @@ -238,17 +203,10 @@ class Sets final */ void defaultForAreas(); - /*! - ** \brief Rebuild the lists of a group from the rules - */ - template - void rebuildFromRules(const IDType& id, HandlerT& handler); - /*! ** \brief Rebuild the lists of all group from the rules */ - template - void rebuildAllFromRules(HandlerT& handler); + void rebuildAllFromRules(SetHandlerAreas& handler); const IDType& nameByIndex(const uint i) const { @@ -256,28 +214,65 @@ class Sets final return pNameByIndex[i]; } - template - IDType caption(const StringT& s) const; - + IDType caption(const Yuni::ShortString128& s) const; IDType caption(const uint i) const; - T& operator[](uint i); - const T& operator[](uint i) const; + SetAreasType& operator[](uint i); + const SetAreasType& operator[](uint i) const; private: + TypePtr add(const IDType& name) + { + TypePtr p = std::make_shared(); + pMap[name] = p; + pOptions[name].reset(name); + return p; + } + + TypePtr add(const IDType& name, const TypePtr& data) + { + pMap[name] = data; + pOptions[name].reset(name); + return data; + } + + TypePtr add(const IDType& name, const TypePtr& data, Options& opts) + { + pMap[name] = data; + pOptions[name] = opts; + return data; + } + + /*! + ** \brief Rebuild the lists of a group from the rules + */ + void rebuildFromRules(const IDType& id, SetHandlerAreas& handler); + void rebuildIndexes(); + //! All groups MapType pMap; MapOptions pOptions; //! - TypePtr* pByIndex; - IDType* pNameByIndex; - mutable bool pModified; - + std::vector pByIndex; + std::vector pNameByIndex; + mutable bool pModified = false; }; // class Sets -} // namespace Data -} // namespace Antares +class SetHandlerAreas +{ +public: + explicit SetHandlerAreas(AreaList& areas); + void clear(Sets::SetAreasType& set); + uint size(Sets::SetAreasType& set); -#include "sets.hxx" + bool add(Sets::SetAreasType& set, const std::string& value); + void add(Sets::SetAreasType& set, const Sets::SetAreasType& otherSet); + bool remove(Sets::SetAreasType& set, const std::string& value); + void remove(Sets::SetAreasType& set, const Sets::SetAreasType& otherSet); + bool applyFilter(Sets::SetAreasType& set, const std::string& value); + +private: + AreaList& areas_; +}; // class SetHandlerAreas -#endif // __ANTARES_LIBS_STUDY_SETS_H__ +} // namespace Antares::Data diff --git a/src/libs/antares/study/include/antares/study/study.h b/src/libs/antares/study/include/antares/study/study.h index cbe251805b..0a7dd0eb31 100644 --- a/src/libs/antares/study/include/antares/study/study.h +++ b/src/libs/antares/study/include/antares/study/study.h @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #ifndef __ANTARES_LIBS_STUDY_STUDY_H__ #define __ANTARES_LIBS_STUDY_STUDY_H__ @@ -31,6 +31,7 @@ #include #include +#include #include #include "antares/antares/antares.h" #include "antares/study/binding_constraint/BindingConstraintGroupRepository.h" @@ -65,25 +66,8 @@ class Study: public Yuni::NonCopyable, public LayerData //! List of studies using List = std::list; - //! A single set of areas - // CompareAreaName : to control the order of areas in a set of areas. This order can have an - // effect, even if tiny, on the results of aggregations. - using SingleSetOfAreas = std::set; - //! Multiple sets of areas - using SetsOfAreas = Antares::Data::Sets; - - //! A single set of links - using SingleSetOfLinks = std::set; - //! Multiple sets of links - using SetsOfLinks = Antares::Data::Sets; - - //! List of disabled areas - using DisabledAreaList = std::set; - //! List of disabled links - using DisabledAreaLinkList = std::set; - //! List of disabled thermal clusters - using DisabledThermalClusterList = std::set; + using SetsOfAreas = Antares::Data::Sets; //! Extension filename using FileExtension = std::string; @@ -362,8 +346,6 @@ class Study: public Yuni::NonCopyable, public LayerData void destroyAllWindTSGeneratorData(); //! Destroy all data of the hydro TS generator void destroyAllHydroTSGeneratorData(); - //! Destroy all data of the thermal TS generator - void destroyAllThermalTSGeneratorData(); /*! ** \brief Import all time-series into the input folder @@ -390,10 +372,6 @@ class Study: public Yuni::NonCopyable, public LayerData ** \brief Re-Initialize/Re-Load the scenario builder data */ void scenarioRulesCreate(); - /*! - ** \brief Re-Initialize/Re-Load the scenario builder data but consider a single ruleset only - */ - void scenarioRulesCreate(const RulesScenarioName& thisoneonly); /*! ** \brief Release the scenario builder @@ -411,7 +389,7 @@ class Study: public Yuni::NonCopyable, public LayerData *"max"). ** */ - std::map getRawNumberCoresPerLevel(); + unsigned getNumberOfCoresPerMode(unsigned nbLogicalCores, int ncMode); /*! ** \brief Computes number of cores @@ -421,22 +399,6 @@ class Study: public Yuni::NonCopyable, public LayerData */ void getNumberOfCores(const bool forceParallel, const uint nbYearsParallelForced); - /*! - ** \brief In case hydro hot start is enabled, checking all conditions are met. - ** - ** If hydro hot start is enabled, check that : - ** - For all areas for which reservoir management is enabled : - ** + Their starting level is initialized on the same day - ** + This day is the first day of the simulation calendar - ** - The simulation lasts exactly one year - ** - All batches (or sets) of simultaneous years have the same size (obvious if a parallel run - *is not required : answer is yes). - ** - ** If these conditions are not met, some error message is raised, when attempting to run the - *study. - */ - bool checkHydroHotStart(); - /*! ** \brief Remove timeseries if ts-generator is enabled */ @@ -594,24 +556,23 @@ class Study: public Yuni::NonCopyable, public LayerData //@{ //! Sets of areas SetsOfAreas setsOfAreas; - //! Sets of links - SetsOfLinks setsOfLinks; //@} //! \name Scenario Builder //@{ //! Rules for building scenarios (can be null) - ScenarioBuilder::Sets* scenarioRules = nullptr; + std::unique_ptr scenarioRules; //@} - TimeSeries::TS scenarioHydroLevels; - + TimeSeries::TS scenarioInitialHydroLevels; + // Hydro Final Levels + TimeSeries::TS scenarioFinalHydroLevels; /*! ** \brief Runtime informations ** ** These informations are only needed when a study is processed. */ - StudyRuntimeInfos* runtime = nullptr; + StudyRuntimeInfos runtime; // Antares::Solver::Variable::State* state; @@ -705,7 +666,6 @@ YString StudyCreateOutputPath(SimulationMode mode, int64_t startTime); } // namespace Antares::Data -#include "runtime.h" #include "study.hxx" #endif /* __ANTARES_LIBS_STUDY_STUDY_H__ */ diff --git a/src/libs/antares/study/include/antares/study/study.hxx b/src/libs/antares/study/include/antares/study/study.hxx index 9f0053d0a4..5c1ad58282 100644 --- a/src/libs/antares/study/include/antares/study/study.hxx +++ b/src/libs/antares/study/include/antares/study/study.hxx @@ -53,9 +53,6 @@ inline void Study::destroyTSGeneratorData() case TimeSeriesType::timeSeriesHydro: destroyAllHydroTSGeneratorData(); break; - case TimeSeriesType::timeSeriesThermal: - destroyAllThermalTSGeneratorData(); - break; default: break; } diff --git a/src/libs/antares/study/include/antares/study/xcast/xcast.h b/src/libs/antares/study/include/antares/study/xcast/xcast.h index e331287881..cc7e281763 100644 --- a/src/libs/antares/study/include/antares/study/xcast/xcast.h +++ b/src/libs/antares/study/include/antares/study/xcast/xcast.h @@ -27,6 +27,7 @@ #include #include +#include namespace Antares::Data { diff --git a/src/libs/antares/study/load.cpp b/src/libs/antares/study/load.cpp index eefe3b2606..626cb3564d 100644 --- a/src/libs/antares/study/load.cpp +++ b/src/libs/antares/study/load.cpp @@ -83,7 +83,13 @@ bool Study::internalLoadIni(const String& path, const StudyLoadOptions& options) } // Load the general data buffer.clear() << folderSettings << SEP << "generaldata.ini"; - if (!parameters.loadFromFile(buffer, header.version, options)) + bool errorWhileLoading = !parameters.loadFromFile(buffer, header.version); + + parameters.validateOptions(options); + + parameters.fixBadValues(); + + if (errorWhileLoading) { if (options.loadOnlyNeeded) { @@ -120,11 +126,11 @@ void Study::parameterFiller(const StudyLoadOptions& options) if (usedByTheSolver) { // We have time-series to import - if (parameters.exportTimeSeriesInInput && header.version == StudyVersion::latest()) + if (parameters.exportTimeSeriesInInput && header.version != StudyVersion::latest()) { logs.info() << "Stochastic TS stored in input parametrized." - " Disabling Store in input because study is not at latest version" - "Prevents writing data in unsupported format at the study version"; + " Disabling Store in input because study is not at latest version." + " This prevents writing data in unsupported format at the study version"; parameters.exportTimeSeriesInInput = 0; } } @@ -166,13 +172,6 @@ void Study::parameterFiller(const StudyLoadOptions& options) parameters.firstMonthInYear, parameters.leapYear}); - // In case hydro hot start is enabled, check all conditions are met. - // (has to be called after areas load and calendar building) - if (usedByTheSolver && !checkHydroHotStart()) - { - logs.error() << "hydro hot start is enabled, conditions are not met. Aborting"; - } - // Reducing memory footprint reduceMemoryUsage(); } @@ -290,97 +289,6 @@ bool Study::internalLoadBindingConstraints(const StudyLoadOptions& options) return (!r && options.loadOnlyNeeded) ? false : r; } -class SetHandlerAreas -{ -public: - SetHandlerAreas(Study& study): - pStudy(study) - { - } - - void clear(Study::SingleSetOfAreas& set) - { - set.clear(); - } - - uint size(Study::SingleSetOfAreas& set) - { - return (uint)set.size(); - } - - bool add(Study::SingleSetOfAreas& set, const String& value) - { - Area* area = AreaListLFind(&pStudy.areas, value.c_str()); - if (area) - { - set.insert(area); - return true; - } - return false; - } - - bool add(Study::SingleSetOfAreas& set, const Study::SingleSetOfAreas& otherSet) - { - if (!otherSet.empty()) - { - auto end = otherSet.end(); - for (auto i = otherSet.begin(); i != end; ++i) - { - set.insert(*i); - } - } - return true; - } - - bool remove(Study::SingleSetOfAreas& set, const String& value) - { - Area* area = AreaListLFind(&pStudy.areas, value.c_str()); - if (area) - { - set.erase(area); - return true; - } - return false; - } - - bool remove(Study::SingleSetOfAreas& set, const Study::SingleSetOfAreas& otherSet) - { - if (!otherSet.empty()) - { - auto end = otherSet.end(); - for (auto i = otherSet.begin(); i != end; ++i) - { - set.erase(*i); - } - } - return true; - } - - bool applyFilter(Study::SingleSetOfAreas& set, const String& value) - { - if (value == "add-all") - { - auto end = pStudy.areas.end(); - for (auto i = pStudy.areas.begin(); i != end; ++i) - { - set.insert(i->second); - } - return true; - } - - if (value == "remove-all") - { - set.clear(); - return true; - } - return false; - } - -private: - Study& pStudy; - -}; // class SetHandlerAreas - bool Study::internalLoadSets() { const fs::path path = fs::path(folderInput.c_str()) / "areas" / "sets.ini"; @@ -395,10 +303,10 @@ bool Study::internalLoadSets() if (setsOfAreas.loadFromFile(path)) { // Apply the rules - SetHandlerAreas handler(*this); + SetHandlerAreas handler(areas); setsOfAreas.rebuildAllFromRules(handler); // Write the results into the logs - setsOfAreas.dumpToLogs(logs); + setsOfAreas.dumpToLogs(); return true; } @@ -418,7 +326,7 @@ bool Study::reloadXCastData() // if changes are required, please update AreaListLoadFromFolderSingleArea() bool ret = true; areas.each( - [&](Data::Area& area) + [this, &ret](Area& area) { assert(area.load.prepro); assert(area.solar.prepro); diff --git a/src/libs/antares/study/parameters.cpp b/src/libs/antares/study/parameters.cpp index 3ac64a284e..628237bbef 100644 --- a/src/libs/antares/study/parameters.cpp +++ b/src/libs/antares/study/parameters.cpp @@ -54,7 +54,7 @@ static bool ConvertCStrToListTimeSeries(const String& value, uint& v) } value.words(" ,;\t\r\n", - [&](const AnyString& element) -> bool + [&v](const AnyString& element) { ShortString16 word(element); word.toLower(); @@ -208,13 +208,6 @@ const char* SimulationModeToCString(SimulationMode mode) } } -Parameters::Parameters(): - noOutput(false) -{ -} - -Parameters::~Parameters() = default; - bool Parameters::economy() const { return mode == SimulationMode::Economy; @@ -231,8 +224,8 @@ void Parameters::resetSeeds() // For retro-compatibility, the wind ts-generator should produce the // same results than before 3.8. // It must have the same seed than before - auto increment = (unsigned)antaresSeedIncrement; - auto s = (unsigned)antaresSeedDefaultValue; + auto increment = antaresSeedIncrement; + auto s = antaresSeedDefaultValue; seed[seedTsGenWind] = s; // The same way for all others @@ -311,15 +304,11 @@ void Parameters::reset() readonly = false; synthesis = true; - // Initial reservoir levels - initialReservoirLevels.iniLevels = irlColdStart; - // Hydro heuristic policy hydroHeuristicPolicy.hhPolicy = hhpAccommodateRuleCurves; // Hydro pricing hydroPricing.hpMode = hpHeuristic; - allSetsHaveSameSize = true; // Shedding strategies power.fluctuations = lssFreeModulations; @@ -539,6 +528,12 @@ static bool SGDIntLoadFamily_General(Parameters& d, { return value.to(d.nbTimeSeriesSolar); } + if (key == "nbtimeserieslinks") + { + // This data is among solver data, but is useless while running a simulation + // Only by TS generator. We skip it here (otherwise, we get a reading error). + return true; + } // Interval values if (key == "refreshintervalload") { @@ -573,43 +568,11 @@ static bool SGDIntLoadFamily_General(Parameters& d, if (key == "simulation.start") { - uint day; - if (not value.to(day)) - { - return false; - } - if (day == 0) - { - day = 1; - } - else - { - if (day > 365) - { - day = 365; - } - --day; - } - d.simulationDays.first = day; - return true; + return value.to(d.simulationDays.first); } if (key == "simulation.end") { - uint day; - if (not value.to(day)) - { - return false; - } - if (day == 0) - { - day = 1; - } - else if (day > 365) - { - day = 365; - } - d.simulationDays.end = day; // not included - return true; + return value.to(d.simulationDays.end); } if (key == "thematic-trimming") @@ -810,19 +773,6 @@ static bool SGDIntLoadFamily_OtherPreferences(Parameters& d, d.hydroPricing.hpMode = hpHeuristic; return false; } - if (key == "initial-reservoir-levels") - { - auto iniLevels = StringToInitialReservoirLevels(value); - if (iniLevels != irlUnknown) - { - d.initialReservoirLevels.iniLevels = iniLevels; - return true; - } - logs.warning() << "parameters: invalid initital reservoir levels mode. Got '" << value - << "'. reset to cold start mode."; - d.initialReservoirLevels.iniLevels = irlColdStart; - return false; - } if (key == "number-of-cores-mode") { @@ -1094,6 +1044,10 @@ static bool SGDIntLoadFamily_SeedsMersenneTwister(Parameters& d, return value.to(d.seed[sd]); } } + if (key == "seed-tsgen-links") + { + return true; // Useless for solver, belongs to TS generator + } } } return false; @@ -1155,6 +1109,21 @@ static bool SGDIntLoadFamily_Legacy(Parameters& d, return true; } + if (key == "initial-reservoir-levels") // ignored since 9.2 + { + if (version >= StudyVersion(9, 2)) + { + logs.warning() + << "Option initial-reservoir-levels is deprecated, please remove it from the study"; + } + else if (value == "hot start") + { + logs.warning() + << "Hydro hot start not supported with this solver, please use a version < 9.2"; + } + return true; + } + return false; } @@ -1164,9 +1133,7 @@ bool firstKeyLetterIsValid(const String& name) return (firstLetter >= 'a' && firstLetter <= 'z'); } -bool Parameters::loadFromINI(const IniFile& ini, - const StudyVersion& version, - const StudyLoadOptions& options) +bool Parameters::loadFromINI(const IniFile& ini, const StudyVersion& version) { // Reset inner data reset(); @@ -1236,62 +1203,10 @@ bool Parameters::loadFromINI(const IniFile& ini, } } - // forcing value - if (options.nbYears != 0) - { - if (options.nbYears > nbYears) - { - // The variable `yearsFilter` must be enlarged - yearsFilter.resize(options.nbYears, false); - } - nbYears = options.nbYears; - - // Resize years weight (add or remove item) - if (yearsWeight.size() != nbYears) - { - yearsWeight.resize(nbYears, 1.f); - } - } - - // Simulation mode - // ... Enforcing simulation mode - if (options.forceMode != SimulationMode::Unknown) - { - mode = options.forceMode; - logs.info() << " forcing the simulation mode " << SimulationModeToCString(mode); - } - else - { - logs.info() << " simulation mode: " << SimulationModeToCString(mode); - } - - if (options.forceDerated) - { - derated = true; - } - - namedProblems = options.namedProblems; - - handleOptimizationOptions(options); - - // Attempt to fix bad values if any - fixBadValues(); - fixRefreshIntervals(); fixGenRefreshForNTC(); - // Specific action before launching a simulation - if (options.usedByTheSolver) - { - prepareForSimulation(options); - } - - if (options.mpsToExport || options.namedProblems) - { - this->include.exportMPS = mpsExportStatus::EXPORT_BOTH_OPTIMS; - } - // We currently always returns true to not block any loading process // Anyway we already have reported all problems return true; @@ -1382,6 +1297,68 @@ void Parameters::fixBadValues() { nbTimeSeriesSolar = 1; } + + if (simulationDays.first == 0) + { + simulationDays.first = 1; + } + else + { + simulationDays.first = std::clamp(simulationDays.first, 1u, 365u); + --simulationDays.first; // value between 0 and 364 for edge cases + } + + simulationDays.end = std::clamp(simulationDays.end, 1u, 365u); +} + +void Parameters::validateOptions(const StudyLoadOptions& options) +{ + if (options.forceDerated) + { + derated = true; + } + // forcing value + if (options.nbYears != 0) + { + if (options.nbYears > nbYears) + { + // The variable `yearsFilter` must be enlarged + yearsFilter.resize(options.nbYears, false); + } + nbYears = options.nbYears; + + // Resize years weight (add or remove item) + if (yearsWeight.size() != nbYears) + { + yearsWeight.resize(nbYears, 1.f); + } + } + + // Simulation mode + // ... Enforcing simulation mode + if (options.forceMode != SimulationMode::Unknown) + { + mode = options.forceMode; + logs.info() << " forcing the simulation mode " << SimulationModeToCString(mode); + } + else + { + logs.info() << " simulation mode: " << SimulationModeToCString(mode); + } + // Specific action before launching a simulation + if (options.usedByTheSolver) + { + prepareForSimulation(options); + } + + if (options.mpsToExport || options.namedProblems) + { + this->include.exportMPS = mpsExportStatus::EXPORT_BOTH_OPTIMS; + } + + namedProblems = options.namedProblems; + + handleOptimizationOptions(options); } uint64_t Parameters::memoryUsage() const @@ -1874,8 +1851,6 @@ void Parameters::saveToINI(IniFile& ini) const // Other preferences { auto* section = ini.addSection("other preferences"); - section->add("initial-reservoir-levels", - InitialReservoirLevelsToCString(initialReservoirLevels.iniLevels)); section->add("hydro-heuristic-policy", HydroHeuristicPolicyToCString(hydroHeuristicPolicy.hhPolicy)); section->add("hydro-pricing-mode", HydroPricingModeToCString(hydroPricing.hpMode)); @@ -1990,15 +1965,13 @@ void Parameters::saveToINI(IniFile& ini) const } } -bool Parameters::loadFromFile(const AnyString& filename, - StudyVersion& version, - const StudyLoadOptions& options) +bool Parameters::loadFromFile(const AnyString& filename, const StudyVersion& version) { // Loading the INI file IniFile ini; if (ini.open(filename)) { - return loadFromINI(ini, version, options); + return loadFromINI(ini, version); } // Error otherwise diff --git a/src/libs/antares/study/parameters/adq-patch-params.cpp b/src/libs/antares/study/parameters/adq-patch-params.cpp index cbce2e51b0..f0158b85e5 100644 --- a/src/libs/antares/study/parameters/adq-patch-params.cpp +++ b/src/libs/antares/study/parameters/adq-patch-params.cpp @@ -31,38 +31,23 @@ namespace Antares::Data::AdequacyPatch // Local matching // ------------------- -void LocalMatching::reset() +static bool legacyLocalMatchingKeys(const Yuni::String& key) { - setToZeroOutsideInsideLinks = true; - setToZeroOutsideOutsideLinks = true; -} - -bool LocalMatching::updateFromKeyValue(const Yuni::String& key, const Yuni::String& value) -{ - if (key == "set-to-null-ntc-from-physical-out-to-physical-in-for-first-step") - { - return value.to(setToZeroOutsideInsideLinks); - } if (key == "set-to-null-ntc-between-physical-out-for-first-step") { - return value.to(setToZeroOutsideOutsideLinks); + logs.warning() << "Parameter set-to-null-ntc-between-physical-out-for-first-step not " + "supported with this solver version, use a version < 9.2"; + return true; } if (key == "enable-first-step") { - return value.to(enabled); + logs.warning() << "Parameter enable-first-step not supported with this solver version, use " + "a version < 9.2"; + return true; } return false; } -void LocalMatching::addProperties(IniFile::Section* section) const -{ - section->add("set-to-null-ntc-from-physical-out-to-physical-in-for-first-step", - setToZeroOutsideInsideLinks); - section->add("set-to-null-ntc-between-physical-out-for-first-step", - setToZeroOutsideOutsideLinks); - section->add("enable-first-step", enabled); -} - // ----------------------- // Curtailment sharing // ----------------------- @@ -135,7 +120,7 @@ bool CurtailmentSharing::updateFromKeyValue(const Yuni::String& key, const Yuni: return value.to(thresholdVarBoundsRelaxation); } - return false; + return legacyLocalMatchingKeys(key); } const char* PriceTakingOrderToString(AdequacyPatch::AdqPatchPTO pto) @@ -168,10 +153,8 @@ void CurtailmentSharing::addProperties(IniFile::Section* section) const // ------------------------ void AdqPatchParams::reset() { - enabled = false; - - localMatching.reset(); curtailmentSharing.reset(); + setToZeroOutsideInsideLinks = true; } void AdqPatchParams::addExcludedVariables(std::vector& out) const @@ -180,15 +163,9 @@ void AdqPatchParams::addExcludedVariables(std::vector& out) const { out.emplace_back("DENS"); out.emplace_back("LMR VIOL."); - out.emplace_back("SPIL. ENRG. CSR"); + out.emplace_back("UNSP. ENRG CSR"); out.emplace_back("DTG MRG CSR"); } - - // If the adequacy patch is enabled, but the LMR is disabled, the DENS variable shouldn't exist - if (enabled && !localMatching.enabled) - { - out.emplace_back("DENS"); - } } bool AdqPatchParams::updateFromKeyValue(const Yuni::String& key, const Yuni::String& value) @@ -197,17 +174,20 @@ bool AdqPatchParams::updateFromKeyValue(const Yuni::String& key, const Yuni::Str { return value.to(enabled); } - - return curtailmentSharing.updateFromKeyValue(key, value) - != localMatching.updateFromKeyValue(key, value); // XOR + if (key == "set-to-null-ntc-from-physical-out-to-physical-in-for-first-step") + { + return value.to(setToZeroOutsideInsideLinks); + } + return curtailmentSharing.updateFromKeyValue(key, value); } void AdqPatchParams::saveToINI(IniFile& ini) const { auto* section = ini.addSection("adequacy patch"); section->add("include-adq-patch", enabled); + section->add("set-to-null-ntc-from-physical-out-to-physical-in-for-first-step", + setToZeroOutsideInsideLinks); - localMatching.addProperties(section); curtailmentSharing.addProperties(section); } diff --git a/src/libs/antares/study/parts/common/cluster_list.cpp b/src/libs/antares/study/parts/common/cluster_list.cpp index e00934dfe7..9c39ca7c8b 100644 --- a/src/libs/antares/study/parts/common/cluster_list.cpp +++ b/src/libs/antares/study/parts/common/cluster_list.cpp @@ -264,7 +264,8 @@ template bool ClusterList::loadDataSeriesFromFolder(Study& s, const AnyString& folder) { return std::ranges::all_of(allClusters_, - [&](auto c) { return c->loadDataSeriesFromFolder(s, folder); }); + [&s, &folder](auto c) + { return c->loadDataSeriesFromFolder(s, folder); }); } template diff --git a/src/libs/antares/study/parts/hydro/allocation.cpp b/src/libs/antares/study/parts/hydro/allocation.cpp index 93ee0ef5d0..052bc3411d 100644 --- a/src/libs/antares/study/parts/hydro/allocation.cpp +++ b/src/libs/antares/study/parts/hydro/allocation.cpp @@ -164,37 +164,36 @@ void HydroAllocation::clear() #endif } -bool HydroAllocation::loadFromFile(const AreaName& referencearea, - const fs::path& filename) +bool HydroAllocation::loadFromFile(const AreaName& referencearea, const fs::path& filename) { clear(); IniFile ini; - if (fs::exists(filename) && ini.open(filename)) + if (!fs::exists(filename) || !ini.open(filename)) { - if (!ini.empty()) - { - AreaName areaname; - ini.each( - [&](const IniFile::Section& section) - { - for (auto* p = section.firstProperty; p; p = p->next) - { - double coeff = p->value.to(); - if (!Utils::isZero(coeff)) - { - areaname = p->key; - areaname.toLower(); - pValues[areaname] = coeff; - } - } - }); - } + pValues[referencearea] = 1.0; + return true; } - else + + if (ini.empty()) { - pValues[referencearea] = 1.0; + return true; } + + ini.each( + [this](const IniFile::Section& section) + { + for (auto* p = section.firstProperty; p; p = p->next) + { + double coeff = p->value.to(); + if (!Utils::isZero(coeff)) + { + AreaName areaname = p->key; + areaname.toLower(); + pValues[areaname] = coeff; + } + } + }); return true; } diff --git a/src/libs/antares/study/parts/hydro/container.cpp b/src/libs/antares/study/parts/hydro/container.cpp index e86b32a568..336595b95b 100644 --- a/src/libs/antares/study/parts/hydro/container.cpp +++ b/src/libs/antares/study/parts/hydro/container.cpp @@ -48,17 +48,10 @@ PartHydro::PartHydro(): leewayLowerBound(1.), leewayUpperBound(1.), pumpingEfficiency(1.), - prepro(nullptr), series(nullptr) { } -PartHydro::~PartHydro() -{ - delete prepro; - delete series; -} - void PartHydro::reset() { intraDailyModulation = 24; @@ -106,6 +99,39 @@ void PartHydro::reset() } } +template +static bool loadProperties(Study& study, + IniFile::Property* property, + const std::string& filename, + T PartHydro::*ptr) +{ + if (!property) + { + return false; + } + + bool ret = true; + + // Browse all properties + for (; property; property = property->next) + { + AreaName id = property->key; + id.toLower(); + + Area* area = study.areas.find(id); + if (area) + { + ret = property->value.to(area->hydro.*ptr) && ret; + } + else + { + logs.warning() << filename << ": `" << id << "`: Unknown area"; + return false; + } + } + return ret; +} + bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) { auto& buffer = study.bufferLoadingTS; @@ -113,7 +139,7 @@ bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) // Initialize all alpha values to 0 study.areas.each( - [&](Data::Area& area) + [&ret, &buffer, &study, &folder](Data::Area& area) { area.hydro.interDailyBreakdown = 1.; area.hydro.intraDailyModulation = 24.; @@ -130,6 +156,7 @@ bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) area.hydro.initializeReservoirLevelDate = 0; area.hydro.reservoirCapacity = 0.; area.hydro.pumpingEfficiency = 1.; + area.hydro.deltaBetweenFinalAndInitialLevels.resize(study.parameters.nbYears); if (study.header.version >= StudyVersion(9, 1)) { @@ -200,46 +227,6 @@ bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) Matrix<>::optFixedSize, &study.dataBuffer) && ret; - - if (study.usedByTheSolver) - { - auto& col = area.hydro.inflowPattern[0]; - bool errorInflow = false; - for (unsigned int day = 0; day < DAYS_PER_YEAR; day++) - { - if (col[day] < 0 && !errorInflow) - { - logs.error() << area.name << ": invalid inflow value"; - errorInflow = true; - ret = false; - } - } - bool errorLevels = false; - auto& colMin = area.hydro.reservoirLevel[minimum]; - auto& colAvg = area.hydro.reservoirLevel[average]; - auto& colMax = area.hydro.reservoirLevel[maximum]; - for (unsigned int day = 0; day < DAYS_PER_YEAR; day++) - { - if (!errorLevels - && (colMin[day] < 0 || colAvg[day] < 0 || colMin[day] > colMax[day] - || colAvg[day] > 100 || colMax[day] > 100)) - { - logs.error() << area.name << ": invalid reservoir level value"; - errorLevels = true; - ret = false; - } - } - - for (int i = 0; i < 101; i++) - { - if ((area.hydro.creditModulation[i][0] < 0) - || (area.hydro.creditModulation[i][1] < 0)) - { - logs.error() << area.name << ": invalid credit modulation value"; - ret = false; - } - } - } }); IniFile ini; @@ -248,432 +235,242 @@ bool PartHydro::LoadFromFolder(Study& study, const AnyString& folder) return false; } - const char* const sectionName = "inter-daily-breakdown"; + if (IniFile::Section* section = ini.find("inter-daily-breakdown")) + { + ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::interDailyBreakdown) + && ret; + } - IniFile::Section* section; - IniFile::Property* property; + if (IniFile::Section* section = ini.find("intra-daily-modulation")) + { + ret = loadProperties(study, + section->firstProperty, + buffer, + &PartHydro::intraDailyModulation) + && ret; + } - if ((section = ini.find(sectionName))) + if (IniFile::Section* section = ini.find("reservoir")) { - if ((property = section->firstProperty)) - { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - Area* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.interDailyBreakdown) && ret; - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } + ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::reservoirManagement) + && ret; } - if ((section = ini.find("intra-daily-modulation"))) + if (IniFile::Section* section = ini.find("reservoir capacity")) { - if ((property = section->firstProperty)) - { - AreaName id; + ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::reservoirCapacity) + && ret; + } - // Browse all properties - for (; property; property = property->next) - { - id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.intraDailyModulation) && ret; - if (area->hydro.intraDailyModulation < 1.) - { - logs.error() - << area->id << ": Invalid intra-daily modulation. It must be >= 1.0, Got " - << area->hydro.intraDailyModulation << " (truncated to 1)"; - area->hydro.intraDailyModulation = 1.; - } - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } + if (IniFile::Section* section = ini.find("follow load")) + { + ret = loadProperties(study, + section->firstProperty, + buffer, + &PartHydro::followLoadModulations) + && ret; } - if ((section = ini.find("reservoir"))) + if (IniFile::Section* section = ini.find("use water")) { - if ((property = section->firstProperty)) - { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.reservoirManagement) && ret; - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } + ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::useWaterValue) + && ret; } - if ((section = ini.find("reservoir capacity"))) + if (IniFile::Section* section = ini.find("hard bounds")) { - if ((property = section->firstProperty)) - { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.reservoirCapacity) && ret; - if (area->hydro.reservoirCapacity < 1e-6) - { - logs.error() << area->id << ": Invalid reservoir capacity."; - area->hydro.reservoirCapacity = 0.; - } - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } + ret = loadProperties(study, + section->firstProperty, + buffer, + &PartHydro::hardBoundsOnRuleCurves) + && ret; } - // Check on reservoir capacity (has to be done after reservoir management and capacity reading, - // not before). Some areas reservoir capacities may not be printed in hydro ini file when saving - // the study, because they are too small (< 1e-6). We cannot have reservoir management = yes and - // capacity = 0 because of further division by capacity. reservoir management = no and capacity - // = 0 is possible (no use of capacity further) - study.areas.each( - [&](Data::Area& area) - { - if (area.hydro.reservoirCapacity < 1e-3 && area.hydro.reservoirManagement) - { - logs.error() << area.name - << ": reservoir capacity not defined. Impossible to manage."; - ret = false && ret; - } - }); + if (IniFile::Section* section = ini.find("use heuristic")) + { + ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::useHeuristicTarget) + && ret; + } - if ((section = ini.find("inter-monthly-breakdown"))) + if (IniFile::Section* section = ini.find("power to level")) { - if ((property = section->firstProperty)) - { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.intermonthlyBreakdown) && ret; - if (area->hydro.intermonthlyBreakdown < 0) - { - logs.error() << area->id << ": Invalid intermonthly breakdown"; - area->hydro.intermonthlyBreakdown = 0.; - } - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } + ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::powerToLevel) + && ret; } - if ((section = ini.find("follow load"))) + + if (IniFile::Section* section = ini.find("initialize reservoir date")) { - if ((property = section->firstProperty)) - { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.followLoadModulations) && ret; - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } + ret = loadProperties(study, + section->firstProperty, + buffer, + &PartHydro::initializeReservoirLevelDate) + && ret; } - if ((section = ini.find("use water"))) + + if (IniFile::Section* section = ini.find("use leeway")) { - if ((property = section->firstProperty)) - { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.useWaterValue) && ret; - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } + ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::useLeeway) && ret; } - if ((section = ini.find("hard bounds"))) + + if (IniFile::Section* section = ini.find("leeway low")) { - if ((property = section->firstProperty)) - { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.hardBoundsOnRuleCurves) && ret; - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } + ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::leewayLowerBound) + && ret; } - if ((section = ini.find("use heuristic"))) + + if (IniFile::Section* section = ini.find("leeway up")) { - if ((property = section->firstProperty)) - { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.useHeuristicTarget) && ret; - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } + ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::leewayUpperBound) + && ret; } - if ((section = ini.find("power to level"))) + + if (IniFile::Section* section = ini.find("pumping efficiency")) { - if ((property = section->firstProperty)) - { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.powerToLevel) && ret; - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } + ret = loadProperties(study, section->firstProperty, buffer, &PartHydro::pumpingEfficiency) + && ret; } - if ((section = ini.find("initialize reservoir date"))) + + return ret; +} + +bool PartHydro::checkReservoirLevels(const Study& study) +{ + bool ret = true; + + for (const auto& [areaName, area]: study.areas) { - if ((property = section->firstProperty)) + if (!study.usedByTheSolver) { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.initializeReservoirLevelDate) && ret; - if (area->hydro.initializeReservoirLevelDate < 0) - { - logs.error() << area->id << ": Invalid initialize reservoir date"; - area->hydro.initializeReservoirLevelDate = 0; - } - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } + return true; } - } - // Leeways : use leeway bounds (upper and lower) - if ((section = ini.find("use leeway"))) - { - if ((property = section->firstProperty)) + + auto& col = area->hydro.inflowPattern[0]; + bool errorInflow = false; + for (unsigned int day = 0; day < DAYS_PER_YEAR; day++) { - // Browse all properties - for (; property; property = property->next) + if (col[day] < 0 && !errorInflow) { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.useLeeway) && ret; - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } + logs.error() << areaName << ": invalid inflow value"; + errorInflow = true; + ret = false; } } - } - if ((section = ini.find("leeway low"))) - { - if ((property = section->firstProperty)) + bool errorLevels = false; + auto& colMin = area->hydro.reservoirLevel[minimum]; + auto& colAvg = area->hydro.reservoirLevel[average]; + auto& colMax = area->hydro.reservoirLevel[maximum]; + for (unsigned int day = 0; day < DAYS_PER_YEAR; day++) { - // Browse all properties - for (; property; property = property->next) + if (!errorLevels + && (colMin[day] < 0 || colAvg[day] < 0 || colMin[day] > colMax[day] + || colAvg[day] > 100 || colMax[day] > 100)) { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.leewayLowerBound) && ret; - if (area->hydro.leewayLowerBound < 0.) - { - logs.error() - << area->id << ": Invalid leeway lower bound. It must be >= 0.0, Got " - << area->hydro.leewayLowerBound; - area->hydro.leewayLowerBound = 0.; - } - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } + logs.error() << areaName << ": invalid reservoir level value"; + errorLevels = true; + ret = false; } } - } - if ((section = ini.find("leeway up"))) - { - if ((property = section->firstProperty)) + + for (int i = 0; i < 101; i++) { - // Browse all properties - for (; property; property = property->next) + if ((area->hydro.creditModulation[i][0] < 0) + || (area->hydro.creditModulation[i][1] < 0)) { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.leewayUpperBound) && ret; - if (area->hydro.leewayUpperBound < 0.) - { - logs.error() - << area->id << ": Invalid leeway upper bound. It must be >= 0.0, Got " - << area->hydro.leewayUpperBound; - area->hydro.leewayUpperBound = 0.; - } - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } + logs.error() << areaName << ": invalid credit modulation value"; + ret = false; } } } - // they are too small (< 1e-6). We cannot allow these areas to have reservoir management = - // true. + return ret; +} + +bool PartHydro::checkProperties(Study& study) +{ + bool ret = true; + + // Check on reservoir capacity (has to be done after reservoir management and capacity reading, + // not before). Some areas reservoir capacities may not be printed in hydro ini file when saving + // the study, because they are too small (< 1e-6). We cannot have reservoir management = yes and + // capacity = 0 because of further division by capacity. reservoir management = no and capacity + // = 0 is possible (no use of capacity further) study.areas.each( - [&](Data::Area& area) + [&ret](Data::Area& area) { - if (area.hydro.leewayLowerBound > area.hydro.leewayUpperBound) + if (area.hydro.reservoirCapacity < 1e-3 && area.hydro.reservoirManagement) { - logs.error() << area.id << ": Leeway lower bound greater than leeway upper bound."; + logs.error() << area.name + << ": reservoir capacity not defined. Impossible to manage."; + ret = false; } - }); - - if ((section = ini.find("pumping efficiency"))) - { - if ((property = section->firstProperty)) - { - // Browse all properties - for (; property; property = property->next) - { - AreaName id = property->key; - id.toLower(); - - auto* area = study.areas.find(id); - if (area) - { - ret = property->value.to(area->hydro.pumpingEfficiency) && ret; - if (area->hydro.pumpingEfficiency < 0) - { - logs.error() << area->id << ": Invalid pumping efficiency"; - area->hydro.pumpingEfficiency = 0.; - } - } - else - { - logs.warning() << buffer << ": `" << id << "`: Unknown area"; - } - } - } - } - study.areas.each( - [&](Data::Area& area) - { - if (not area.hydro.useHeuristicTarget && not area.hydro.useWaterValue) + if (!area.hydro.useHeuristicTarget && !area.hydro.useWaterValue) { logs.error() << area.name << " : use water value = no conflicts with use heuristic target = no"; - ret = false && ret; + ret = false; + } + + if (area.hydro.intraDailyModulation < 1.) + { + logs.error() << area.id << ": Invalid intra-daily modulation. It must be >= 1.0, Got " + << area.hydro.intraDailyModulation << " (truncated to 1)"; + area.hydro.intraDailyModulation = 1.; + } + + if (area.hydro.reservoirCapacity < 0) + { + logs.error() << area.id << ": Invalid reservoir capacity."; + area.hydro.reservoirCapacity = 0.; + } + + if (area.hydro.intermonthlyBreakdown < 0) + { + logs.error() << area.id << ": Invalid intermonthly breakdown"; + area.hydro.intermonthlyBreakdown = 0.; + } + + if (area.hydro.initializeReservoirLevelDate < 0) + { + logs.error() << area.id << ": Invalid initialize reservoir date"; + area.hydro.initializeReservoirLevelDate = 0; + } + + if (area.hydro.leewayLowerBound < 0.) + { + logs.error() << area.id << ": Invalid leeway lower bound. It must be >= 0.0, Got " + << area.hydro.leewayLowerBound; + area.hydro.leewayLowerBound = 0.; + } + + if (area.hydro.leewayUpperBound < 0.) + { + logs.error() << area.id << ": Invalid leeway upper bound. It must be >= 0.0, Got " + << area.hydro.leewayUpperBound; + area.hydro.leewayUpperBound = 0.; + } + + if (area.hydro.leewayLowerBound > area.hydro.leewayUpperBound) + { + logs.error() << area.id << ": Leeway lower bound greater than leeway upper bound."; + } + + if (area.hydro.pumpingEfficiency < 0) + { + logs.error() << area.id << ": Invalid pumping efficiency"; + area.hydro.pumpingEfficiency = 0.; } }); return ret; } +bool PartHydro::validate(Study& study) +{ + bool ret = checkReservoirLevels(study); + return checkProperties(study) && ret; +} + bool PartHydro::SaveToFolder(const AreaList& areas, const AnyString& folder) { if (!folder) @@ -686,69 +483,94 @@ bool PartHydro::SaveToFolder(const AreaList& areas, const AnyString& folder) String buffer; buffer.clear() << folder << SEP << "common" << SEP << "capacity"; + struct AllSections + { + IniFile::Section* s; + IniFile::Section* smod; + IniFile::Section* sIMB; + IniFile::Section* sreservoir; + IniFile::Section* sreservoirCapacity; + IniFile::Section* sFollowLoad; + IniFile::Section* sUseWater; + IniFile::Section* sHardBounds; + IniFile::Section* sInitializeReservoirDate; + IniFile::Section* sUseHeuristic; + IniFile::Section* sUseLeeway; + IniFile::Section* sPowerToLevel; + IniFile::Section* sLeewayLow; + IniFile::Section* sLeewayUp; + IniFile::Section* spumpingEfficiency; + + AllSections(IniFile& ini): + s(ini.addSection("inter-daily-breakdown")), + smod(ini.addSection("intra-daily-modulation")), + sIMB(ini.addSection("inter-monthly-breakdown")), + sreservoir(ini.addSection("reservoir")), + sreservoirCapacity(ini.addSection("reservoir capacity")), + sFollowLoad(ini.addSection("follow load")), + sUseWater(ini.addSection("use water")), + sHardBounds(ini.addSection("hard bounds")), + sInitializeReservoirDate(ini.addSection("initialize reservoir date")), + sUseHeuristic(ini.addSection("use heuristic")), + sUseLeeway(ini.addSection("use leeway")), + sPowerToLevel(ini.addSection("power to level")), + sLeewayLow(ini.addSection("leeway low")), + sLeewayUp(ini.addSection("leeway up")), + spumpingEfficiency(ini.addSection("pumping efficiency")) + { + } + }; + // Init IniFile ini; - auto* s = ini.addSection("inter-daily-breakdown"); - auto* smod = ini.addSection("intra-daily-modulation"); - auto* sIMB = ini.addSection("inter-monthly-breakdown"); - auto* sreservoir = ini.addSection("reservoir"); - auto* sreservoirCapacity = ini.addSection("reservoir capacity"); - auto* sFollowLoad = ini.addSection("follow load"); - auto* sUseWater = ini.addSection("use water"); - auto* sHardBounds = ini.addSection("hard bounds"); - auto* sInitializeReservoirDate = ini.addSection("initialize reservoir date"); - auto* sUseHeuristic = ini.addSection("use heuristic"); - auto* sUseLeeway = ini.addSection("use leeway"); - auto* sPowerToLevel = ini.addSection("power to level"); - auto* sLeewayLow = ini.addSection("leeway low"); - auto* sLeewayUp = ini.addSection("leeway up"); - auto* spumpingEfficiency = ini.addSection("pumping efficiency"); + AllSections allSections(ini); // return status bool ret = true; // Add all alpha values for each area areas.each( - [&](const Data::Area& area) + [&allSections, &buffer, &folder, &ret](const Data::Area& area) { - s->add(area.id, area.hydro.interDailyBreakdown); - smod->add(area.id, area.hydro.intraDailyModulation); - sIMB->add(area.id, area.hydro.intermonthlyBreakdown); - sInitializeReservoirDate->add(area.id, area.hydro.initializeReservoirLevelDate); - sLeewayLow->add(area.id, area.hydro.leewayLowerBound); - sLeewayUp->add(area.id, area.hydro.leewayUpperBound); - spumpingEfficiency->add(area.id, area.hydro.pumpingEfficiency); + allSections.s->add(area.id, area.hydro.interDailyBreakdown); + allSections.smod->add(area.id, area.hydro.intraDailyModulation); + allSections.sIMB->add(area.id, area.hydro.intermonthlyBreakdown); + allSections.sInitializeReservoirDate->add(area.id, + area.hydro.initializeReservoirLevelDate); + allSections.sLeewayLow->add(area.id, area.hydro.leewayLowerBound); + allSections.sLeewayUp->add(area.id, area.hydro.leewayUpperBound); + allSections.spumpingEfficiency->add(area.id, area.hydro.pumpingEfficiency); if (area.hydro.reservoirCapacity > 1e-6) { - sreservoirCapacity->add(area.id, area.hydro.reservoirCapacity); + allSections.sreservoirCapacity->add(area.id, area.hydro.reservoirCapacity); } if (area.hydro.reservoirManagement) { - sreservoir->add(area.id, true); + allSections.sreservoir->add(area.id, true); } if (!area.hydro.followLoadModulations) { - sFollowLoad->add(area.id, false); + allSections.sFollowLoad->add(area.id, false); } if (area.hydro.useWaterValue) { - sUseWater->add(area.id, true); + allSections.sUseWater->add(area.id, true); } if (area.hydro.hardBoundsOnRuleCurves) { - sHardBounds->add(area.id, true); + allSections.sHardBounds->add(area.id, true); } if (!area.hydro.useHeuristicTarget) { - sUseHeuristic->add(area.id, false); + allSections.sUseHeuristic->add(area.id, false); } if (area.hydro.useLeeway) { - sUseLeeway->add(area.id, true); + allSections.sUseLeeway->add(area.id, true); } if (area.hydro.powerToLevel) { - sPowerToLevel->add(area.id, true); + allSections.sPowerToLevel->add(area.id, true); } // max hours gen @@ -938,10 +760,9 @@ bool PartHydro::CheckDailyMaxEnergy(const AnyString& areaName) return ret; } -void getWaterValue(const double& level /* format : in % of reservoir capacity */, - const Matrix& waterValues, - const uint day, - double& waterValueToReturn) +double getWaterValue(const double& level /* format : in % of reservoir capacity */, + const Matrix& waterValues, + const uint day) { assert((level >= 0. && level <= 100.) && "getWaterValue function : invalid level"); double levelUp = ceil(level); @@ -949,13 +770,10 @@ void getWaterValue(const double& level /* format : in % of reservoir capacity */ if ((int)(levelUp) == (int)(levelDown)) { - waterValueToReturn = waterValues[(int)(levelUp)][day]; - } - else - { - waterValueToReturn = waterValues[(int)(levelUp)][day] * (level - levelDown) - + waterValues[(int)(levelDown)][day] * (levelUp - level); + return waterValues[(int)(levelUp)][day]; } + return waterValues[(int)(levelUp)][day] * (level - levelDown) + + waterValues[(int)(levelDown)][day] * (levelUp - level); } double getWeeklyModulation(const double& level /* format : in % of reservoir capacity */, diff --git a/src/libs/antares/study/parts/hydro/hydromaxtimeseriesreader.cpp b/src/libs/antares/study/parts/hydro/hydromaxtimeseriesreader.cpp index b7864e5b31..fa2827fc88 100644 --- a/src/libs/antares/study/parts/hydro/hydromaxtimeseriesreader.cpp +++ b/src/libs/antares/study/parts/hydro/hydromaxtimeseriesreader.cpp @@ -47,6 +47,24 @@ HydroMaxTimeSeriesReader::HydroMaxTimeSeriesReader(PartHydro& hydro, dailyMaxPumpAndGen.reset(4U, DAYS_PER_YEAR, true); } +static bool checkPower(const Matrix<>& dailyMaxPumpAndGen, const std::string& areaName) +{ + for (uint i = 0; i < 4U; ++i) + { + auto& col = dailyMaxPumpAndGen[i]; + for (uint day = 0; day < DAYS_PER_YEAR; ++day) + { + if (col[day] < 0. || (i % 2U /*column hours*/ && col[day] > 24.)) + { + logs.error() << areaName << ": invalid power or energy value"; + return false; + } + } + } + + return true; +} + bool HydroMaxTimeSeriesReader::loadDailyMaxPowersAndEnergies(const AnyString& folder, bool usedBySolver) { @@ -90,21 +108,6 @@ bool HydroMaxTimeSeriesReader::loadDailyMaxPowersAndEnergies(const AnyString& fo Matrix<>::optFixedSize, &fileContent) && ret; - - bool errorPowers = false; - for (uint i = 0; i < 4U; ++i) - { - auto& col = dailyMaxPumpAndGen[i]; - for (uint day = 0; day < DAYS_PER_YEAR; ++day) - { - if (!errorPowers && (col[day] < 0. || (i % 2U /*column hours*/ && col[day] > 24.))) - { - logs.error() << areaName_ << ": invalid power or energy value"; - errorPowers = true; - ret = false; - } - } - } } return ret; } @@ -138,6 +141,7 @@ void HydroMaxTimeSeriesReader::copyDailyMaxPumpingEnergy() const bool HydroMaxTimeSeriesReader::read(const AnyString& folder, bool usedBySolver) { bool ret = loadDailyMaxPowersAndEnergies(folder, usedBySolver); + ret = checkPower(dailyMaxPumpAndGen, areaName_) && ret; copyDailyMaxEnergy(); hydro_.series->buildHourlyMaxPowerFromDailyTS(dailyMaxPumpAndGen[genMaxP], dailyMaxPumpAndGen[pumpMaxP]); diff --git a/src/libs/antares/study/parts/hydro/prepro.cpp b/src/libs/antares/study/parts/hydro/prepro.cpp index d8ddb72352..13711759f4 100644 --- a/src/libs/antares/study/parts/hydro/prepro.cpp +++ b/src/libs/antares/study/parts/hydro/prepro.cpp @@ -145,22 +145,32 @@ bool PreproHydro::saveToFolder(const AreaName& areaID, const char* folder) return false; } -bool PreproHydro::loadFromFolder(Study& s, const AreaName& areaID, const char* folder) +bool PreproHydro::loadFromFolder(Study& s, const AreaName& areaID, const std::string& folder) { - /* Asserts */ - assert(folder); - assert('\0' != *folder); - enum { mtrxOption = Matrix<>::optFixedSize | Matrix<>::optImmediate, }; + constexpr int maxNbOfLineToLoad = 12; + data.resize(hydroPreproMax, 12, true); String& buffer = s.bufferLoadingTS; buffer.clear() << folder << SEP << areaID << SEP << "prepro.ini"; bool ret = PreproHydroLoadSettings(this, buffer); + + buffer.clear() << folder << SEP << areaID << SEP << "energy.txt"; + ret = data.loadFromCSVFile(buffer, hydroPreproMax, maxNbOfLineToLoad, mtrxOption, &s.dataBuffer) + && ret; + + return ret; +} + +bool PreproHydro::validate(const std::string& areaID) +{ + bool ret = true; + if (intermonthlyCorrelation < 0. || intermonthlyCorrelation > 1.) { logs.error() << "Hydro: Prepro: `" << areaID @@ -175,77 +185,58 @@ bool PreproHydro::loadFromFolder(Study& s, const AreaName& areaID, const char* f } } - buffer.clear() << folder << SEP << areaID << SEP << "energy.txt"; - ret = data.loadFromCSVFile(buffer, hydroPreproMax, 12, mtrxOption, &s.dataBuffer) && ret; - - if (JIT::enabled) - { - return ret; - } - - // Checks + const auto& col = data[powerOverWater]; + for (unsigned i = 0; i != data.height; ++i) { - auto& col = data[powerOverWater]; - for (uint i = 0; i != data.height; ++i) + const double d = col[i]; + if (d < 0. || d > 1.) { - const double d = col[i]; - if (d < 0. || d > 1.) - { - logs.error() << "Hydro: Prepro: " << areaID - << ": invalid value for ROR (line: " << (i + 1) << ")"; - } + logs.error() << "Hydro: Prepro: " << areaID + << ": invalid value for ROR (line: " << (i + 1) << ")"; } } - { - auto& colMin = data[minimumEnergy]; - auto& colMax = data[maximumEnergy]; + const auto& colMin = data[minimumEnergy]; + const auto& colMax = data[maximumEnergy]; - for (uint i = 0; i != data.height; ++i) + for (unsigned i = 0; i != data.height; ++i) + { + if (colMin[i] < 0.) { - if (colMin[i] < 0.) - { - ret = false; - logs.error() << "Hydro: Prepro: `" << areaID - << "`: minimum energy: At least one value is negative (line: " - << (i + 1) << ')'; - continue; - } - if (colMin[i] > colMax[i]) - { - ret = false; - logs.error() << "Hydro: Prepro: `" << areaID - << "`: the minimum energy must be less than the maximum energy (line: " - << (i + 1) << ')'; - } + ret = false; + logs.error() << "Hydro: Prepro: `" << areaID + << "`: minimum energy: At least one value is negative (line: " << (i + 1) + << ')'; + continue; + } + if (colMin[i] > colMax[i]) + { + ret = false; + logs.error() << "Hydro: Prepro: `" << areaID + << "`: the minimum energy must be less than the maximum energy (line: " + << (i + 1) << ')'; } } + const auto& colExp = data[expectation]; + for (unsigned i = 0; i != data.height; i++) { - auto& colExp = data[expectation]; - - for (uint i = 0; i != data.height; i++) + if (colExp[i] < 0.) { - if (colExp[i] < 0.) - { - ret = false; - logs.error() << "Hydro: Prepro: `" << areaID - << "`: invalid value for expectation (line: " << (i + 1) << ")"; - } + ret = false; + logs.error() << "Hydro: Prepro: `" << areaID + << "`: invalid value for expectation (line: " << (i + 1) << ")"; } } + const auto& colStdDev = data[stdDeviation]; + for (unsigned i = 0; i != data.height; i++) { - auto& colStdDev = data[stdDeviation]; - - for (uint i = 0; i != data.height; i++) + if (colStdDev[i] < 0.) { - if (colStdDev[i] < 0.) - { - ret = false; - logs.error() << "Hydro: Prepro: `" << areaID - << "`: invalid value for standard deviation (line: " << (i + 1) << ")"; - } + ret = false; + logs.error() << "Hydro: Prepro: `" << areaID + << "`: invalid value for standard deviation (line: " << (i + 1) << ")"; } } diff --git a/src/libs/antares/study/parts/hydro/series.cpp b/src/libs/antares/study/parts/hydro/series.cpp index 3eda6d5fc3..8c73772565 100644 --- a/src/libs/antares/study/parts/hydro/series.cpp +++ b/src/libs/antares/study/parts/hydro/series.cpp @@ -54,7 +54,7 @@ static void ConvertDailyTSintoHourlyTS(const Matrix::ColumnType& dailyCo { uint hour = 0; uint day = 0; - + while (hour < HOURS_PER_YEAR && day < DAYS_PER_YEAR) { for (uint i = 0; i < HOURS_PER_DAY; ++i) diff --git a/src/libs/antares/study/parts/load/container.cpp b/src/libs/antares/study/parts/load/container.cpp index b377eb0bf3..364b761985 100644 --- a/src/libs/antares/study/parts/load/container.cpp +++ b/src/libs/antares/study/parts/load/container.cpp @@ -31,17 +31,10 @@ using namespace Yuni; namespace Antares::Data::Load { Container::Container(): - prepro(nullptr), series(tsNumbers) { } -Container::~Container() -{ - delete prepro; - prepro = nullptr; -} - bool Container::forceReload(bool reload) const { bool ret = true; diff --git a/src/libs/antares/study/parts/renewable/cluster_list.cpp b/src/libs/antares/study/parts/renewable/cluster_list.cpp index d42e9c8d89..aa1c915a75 100644 --- a/src/libs/antares/study/parts/renewable/cluster_list.cpp +++ b/src/libs/antares/study/parts/renewable/cluster_list.cpp @@ -28,9 +28,7 @@ using namespace Yuni; -namespace Antares -{ -namespace Data +namespace Antares::Data { #define SEP IO::Separator @@ -211,7 +209,6 @@ bool RenewableClusterList::loadFromFolder(const AnyString& folder, Area* area) continue; } - cluster->integrityCheck(); addToCompleteList(cluster); } } @@ -223,7 +220,17 @@ bool RenewableClusterList::loadFromFolder(const AnyString& folder, Area* area) return false; } +bool RenewableClusterList::validateClusters() const +{ + bool ret = true; + for (const auto& cluster: allClusters_) + { + ret = cluster->integrityCheck() && ret; + } + + return ret; +} + #undef SEP -} // namespace Data -} // namespace Antares +} // namespace Antares::Data diff --git a/src/libs/antares/study/parts/short-term-storage/cluster.cpp b/src/libs/antares/study/parts/short-term-storage/cluster.cpp index fe06ace18e..fc2ee8c263 100644 --- a/src/libs/antares/study/parts/short-term-storage/cluster.cpp +++ b/src/libs/antares/study/parts/short-term-storage/cluster.cpp @@ -73,7 +73,7 @@ bool STStorageCluster::validate() const } logs.debug() << "Validating properties and series for st storage: " << id; - return properties.validate() && series->validate(); + return properties.validate() && series->validate(id); } bool STStorageCluster::loadSeries(const std::string& folder) const diff --git a/src/libs/antares/study/parts/short-term-storage/container.cpp b/src/libs/antares/study/parts/short-term-storage/container.cpp index 1c9ca78bf7..9a27233064 100644 --- a/src/libs/antares/study/parts/short-term-storage/container.cpp +++ b/src/libs/antares/study/parts/short-term-storage/container.cpp @@ -37,9 +37,7 @@ namespace Antares::Data::ShortTermStorage { bool STStorageInput::validate() const { - return std::all_of(storagesByIndex.cbegin(), - storagesByIndex.cend(), - [](auto& cluster) { return cluster.validate(); }); + return std::ranges::all_of(storagesByIndex, [](auto& cluster) { return cluster.validate(); }); } bool STStorageInput::createSTStorageClustersFromIniFile(const fs::path& path) @@ -69,9 +67,9 @@ bool STStorageInput::createSTStorageClustersFromIniFile(const fs::path& path) storagesByIndex.push_back(cluster); } - std::sort(storagesByIndex.begin(), - storagesByIndex.end(), - [&](const auto& a, const auto& b) { return a.properties.name < b.properties.name; }); + std::ranges::sort(storagesByIndex, + [](const auto& a, const auto& b) + { return a.properties.name < b.properties.name; }); return true; } @@ -102,9 +100,8 @@ bool STStorageInput::saveToFolder(const std::string& folder) const IniFile ini; logs.debug() << "saving file " << pathIni; - std::for_each(storagesByIndex.cbegin(), - storagesByIndex.cend(), - [&ini](auto& storage) { return storage.saveProperties(ini); }); + std::ranges::for_each(storagesByIndex, + [&ini](auto& storage) { return storage.saveProperties(ini); }); return ini.save(pathIni); } @@ -112,29 +109,20 @@ bool STStorageInput::saveToFolder(const std::string& folder) const bool STStorageInput::saveDataSeriesToFolder(const std::string& folder) const { Yuni::IO::Directory::Create(folder); - return std::all_of(storagesByIndex.cbegin(), - storagesByIndex.cend(), - [&folder](auto& storage) - { return storage.saveSeries(folder + SEP + storage.id); }); + return std::ranges::all_of(storagesByIndex, + [&folder](auto& storage) + { return storage.saveSeries(folder + SEP + storage.id); }); } std::size_t STStorageInput::count() const { - return std::count_if(storagesByIndex.begin(), - storagesByIndex.end(), - [](const STStorageCluster& st) { return st.properties.enabled; }); + return std::ranges::count_if(storagesByIndex, + [](const STStorageCluster& st) { return st.properties.enabled; }); } uint STStorageInput::removeDisabledClusters() { - const auto& it = std::remove_if(storagesByIndex.begin(), - storagesByIndex.end(), - [](const auto& c) { return !c.enabled(); }); - - uint disabledCount = std::distance(it, storagesByIndex.end()); - storagesByIndex.erase(it, storagesByIndex.end()); - - return disabledCount; + return std::erase_if(storagesByIndex, [](const auto& c) { return !c.enabled(); }); } } // namespace Antares::Data::ShortTermStorage diff --git a/src/libs/antares/study/parts/short-term-storage/properties.cpp b/src/libs/antares/study/parts/short-term-storage/properties.cpp index 546717588e..b4592105fe 100644 --- a/src/libs/antares/study/parts/short-term-storage/properties.cpp +++ b/src/libs/antares/study/parts/short-term-storage/properties.cpp @@ -61,7 +61,12 @@ bool Properties::loadKey(const IniFile::Property* p) if (p->key == "efficiency") { - return p->value.to(this->efficiencyFactor); + return p->value.to(this->injectionEfficiency); + } + + if (p->key == "efficiencywithdrawal") + { + return p->value.to(this->withdrawalEfficiency); } if (p->key == "name") @@ -105,7 +110,8 @@ void Properties::save(IniFile& ini) const s->add("injectionnominalcapacity", this->injectionNominalCapacity); s->add("withdrawalnominalcapacity", this->withdrawalNominalCapacity); - s->add("efficiency", this->efficiencyFactor); + s->add("efficiency", this->injectionEfficiency); + s->add("efficiencyWithdrawal", this->withdrawalEfficiency); s->add("initialleveloptim", this->initialLevelOptim); s->add("enabled", this->enabled); } @@ -157,16 +163,30 @@ bool Properties::validate() return false; } - if (efficiencyFactor < 0) + if (injectionEfficiency < 0) { logs.warning() << "Property efficiency must be >= 0 " << "for short term storage " << name; - efficiencyFactor = 0; + injectionEfficiency = 0; } - if (efficiencyFactor > 1) + if (injectionEfficiency > 1) { logs.warning() << "Property efficiency must be <= 1 " << "for short term storage " << name; - efficiencyFactor = 1; + injectionEfficiency = 1; + } + + if (withdrawalEfficiency < 0) + { + logs.warning() << "Property efficiencyWithdrawal must be >= 0 " << "for short term storage " + << name; + withdrawalEfficiency = 0; + } + + if (withdrawalEfficiency > 1) + { + logs.warning() << "Property efficiencyWithdrawal must be <= 1 " << "for short term storage " + << name; + withdrawalEfficiency = 1; } if (initialLevel < 0) diff --git a/src/libs/antares/study/parts/short-term-storage/series.cpp b/src/libs/antares/study/parts/short-term-storage/series.cpp index bda3bc0ed2..43354fff88 100644 --- a/src/libs/antares/study/parts/short-term-storage/series.cpp +++ b/src/libs/antares/study/parts/short-term-storage/series.cpp @@ -43,6 +43,10 @@ bool Series::loadFromFolder(const std::string& folder) ret = loadFile(folder + SEP + "lower-rule-curve.txt", lowerRuleCurve) && ret; ret = loadFile(folder + SEP + "upper-rule-curve.txt", upperRuleCurve) && ret; + ret = loadFile(folder + SEP + "cost-injection.txt", costInjection) && ret; + ret = loadFile(folder + SEP + "cost-withdrawal.txt", costWithdrawal) && ret; + ret = loadFile(folder + SEP + "cost-level.txt", costLevel) && ret; + return ret; } @@ -55,7 +59,7 @@ bool loadFile(const std::string& path, std::vector& vect) std::ifstream file; file.open(path); - if (!file) + if (!file.is_open()) { logs.debug() << "File not found: " << path; return true; @@ -112,6 +116,10 @@ void Series::fillDefaultSeriesIfEmpty() fillIfEmpty(inflows, 0.0); fillIfEmpty(lowerRuleCurve, 0.0); fillIfEmpty(upperRuleCurve, 1.0); + + fillIfEmpty(costInjection, 0.0); + fillIfEmpty(costWithdrawal, 0.0); + fillIfEmpty(costLevel, 0.0); } bool Series::saveToFolder(const std::string& folder) const @@ -134,6 +142,10 @@ bool Series::saveToFolder(const std::string& folder) const checkWrite("lower-rule-curve.txt", lowerRuleCurve); checkWrite("upper-rule-curve.txt", upperRuleCurve); + checkWrite("cost-injection.txt", costInjection); + checkWrite("cost-withdrawal.txt", costWithdrawal); + checkWrite("cost-level.txt", costLevel); + return ret; } @@ -158,47 +170,65 @@ bool writeVectorToFile(const std::string& path, const std::vector& vect) return true; } -bool Series::validate() const +bool Series::validate(const std::string& id) const { - return validateSizes() && validateMaxInjection() && validateMaxWithdrawal() - && validateRuleCurves(); + return validateSizes(id) && validateMaxInjection(id) && validateMaxWithdrawal(id) + && validateRuleCurves(id); } -static bool checkVectBetweenZeroOne(const std::vector& v, const std::string& name) +static bool checkVectBetweenZeroOne(const std::string& name, + const std::string& id, + const std::vector& v) { if (!std::all_of(v.begin(), v.end(), [](double d) { return (d >= 0.0 && d <= 1.0); })) { - logs.warning() << "Values for " << name << " series should be between 0 and 1"; + logs.warning() << "Short-term storage " << id << " Values for " << name + << " values should be between 0 and 1"; return false; } return true; } -bool Series::validateSizes() const +static bool checkSize(const std::string& seriesFilename, + const std::string& id, + const std::vector& v) { - if (maxInjectionModulation.size() != HOURS_PER_YEAR - || maxWithdrawalModulation.size() != HOURS_PER_YEAR || inflows.size() != HOURS_PER_YEAR - || lowerRuleCurve.size() != HOURS_PER_YEAR || upperRuleCurve.size() != HOURS_PER_YEAR) + if (v.size() != HOURS_PER_YEAR) { - logs.warning() << "Size of series for short term storage is wrong"; + logs.warning() << "Short-term storage " << id + << " Invalid size for file: " << seriesFilename << ". Got " << v.size() + << " lines, expected " << HOURS_PER_YEAR; return false; } + return true; } -bool Series::validateMaxInjection() const +bool Series::validateSizes(const std::string& id) const +{ + return checkSize("PMAX-injection.txt", id, maxInjectionModulation) + && checkSize("PMAX-withdrawal.txt", id, maxWithdrawalModulation) + && checkSize("inflows.txt", id, inflows) + && checkSize("lower-rule-curve.txt", id, lowerRuleCurve) + && checkSize("upper-rule-curve.txt", id, upperRuleCurve) + && checkSize("cost-injection.txt", id, costInjection) + && checkSize("cost-withdrawal.txt", id, costWithdrawal) + && checkSize("cost-level.txt", id, costLevel); +} + +bool Series::validateMaxInjection(const std::string& id) const { - return checkVectBetweenZeroOne(maxInjectionModulation, "PMAX injection"); + return checkVectBetweenZeroOne("PMAX injection", id, maxInjectionModulation); } -bool Series::validateMaxWithdrawal() const +bool Series::validateMaxWithdrawal(const std::string& id) const { - return checkVectBetweenZeroOne(maxWithdrawalModulation, "PMAX withdrawal"); + return checkVectBetweenZeroOne("PMAX withdrawal", id, maxWithdrawalModulation); } -bool Series::validateRuleCurves() const +bool Series::validateRuleCurves(const std::string& id) const { - if (!validateUpperRuleCurve() || !validateLowerRuleCurve()) + if (!validateUpperRuleCurve(id) || !validateLowerRuleCurve(id)) { return false; } @@ -207,21 +237,22 @@ bool Series::validateRuleCurves() const { if (lowerRuleCurve[i] > upperRuleCurve[i]) { - logs.warning() << "Lower rule curve greater than upper at line: " << i + 1; + logs.warning() << "Short-term storage " << id + << " Lower rule curve greater than upper at line: " << i + 1; return false; } } return true; } -bool Series::validateUpperRuleCurve() const +bool Series::validateUpperRuleCurve(const std::string& id) const { - return checkVectBetweenZeroOne(upperRuleCurve, "upper rule curve"); + return checkVectBetweenZeroOne("upper rule curve", id, upperRuleCurve); } -bool Series::validateLowerRuleCurve() const +bool Series::validateLowerRuleCurve(const std::string& id) const { - return checkVectBetweenZeroOne(maxInjectionModulation, "lower rule curve"); + return checkVectBetweenZeroOne("lower rule curve", id, maxInjectionModulation); } } // namespace Antares::Data::ShortTermStorage diff --git a/src/libs/antares/study/parts/solar/container.cpp b/src/libs/antares/study/parts/solar/container.cpp index 27e96d823c..08c85a0cc0 100644 --- a/src/libs/antares/study/parts/solar/container.cpp +++ b/src/libs/antares/study/parts/solar/container.cpp @@ -31,16 +31,10 @@ using namespace Yuni; namespace Antares::Data::Solar { Container::Container(): - prepro(nullptr), series(tsNumbers) { } -Container::~Container() -{ - delete prepro; -} - bool Container::forceReload(bool reload) const { bool ret = true; diff --git a/src/libs/antares/study/parts/thermal/cluster.cpp b/src/libs/antares/study/parts/thermal/cluster.cpp index 6a008f8929..9198bc1ec6 100644 --- a/src/libs/antares/study/parts/thermal/cluster.cpp +++ b/src/libs/antares/study/parts/thermal/cluster.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/study/parts/thermal/cluster.h" @@ -129,11 +129,6 @@ Data::ThermalCluster::ThermalCluster(Area* parent): assert(parent && "A parent for a thermal dispatchable cluster can not be null"); } -Data::ThermalCluster::~ThermalCluster() -{ - delete prepro; -} - uint ThermalCluster::groupId() const { return groupID; @@ -202,7 +197,7 @@ void Data::ThermalCluster::copyFrom(const ThermalCluster& cluster) // prepro if (!prepro) { - prepro = new PreproAvailability(id(), unitCount); + prepro = std::make_unique(id(), unitCount); } prepro->copyFrom(*cluster.prepro); @@ -477,7 +472,7 @@ void Data::ThermalCluster::reset() // we must simply reset their content. if (!prepro) { - prepro = new PreproAvailability(id(), unitCount); + prepro = std::make_unique(id(), unitCount); } prepro->reset(); @@ -512,20 +507,6 @@ bool Data::ThermalCluster::integrityCheck() bool ret = true; - if (minUpTime > 168 or 0 == minUpTime) - { - logs.error() << "Thermal cluster " << parentArea->name << "/" << pName - << ": The min. up time must be between 1 and 168"; - minUpTime = 1; - ret = false; - } - if (minDownTime > 168 or 0 == minDownTime) - { - logs.error() << "Thermal cluster " << parentArea->name << "/" << pName - << ": The min. down time must be between 1 and 168"; - minDownTime = 1; - ret = false; - } if (nominalCapacity < 0.) { logs.error() << "Thermal cluster " << parentArea->name << "/" << pName diff --git a/src/libs/antares/study/parts/thermal/cluster_list.cpp b/src/libs/antares/study/parts/thermal/cluster_list.cpp index 2059cf9238..1b46282504 100644 --- a/src/libs/antares/study/parts/thermal/cluster_list.cpp +++ b/src/libs/antares/study/parts/thermal/cluster_list.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/study/parts/thermal/cluster_list.h" @@ -159,46 +159,13 @@ bool ThermalClusterList::loadFromFolder(Study& study, const AnyString& folder, A options = Matrix<>::optFixedSize, }; - bool r = cluster->modulation.loadFromCSVFile(modulationFile, - thermalModulationMax, - HOURS_PER_YEAR, - options); - if (!r && study.usedByTheSolver) - { - cluster->modulation.reset(thermalModulationMax, HOURS_PER_YEAR); - cluster->modulation.fill(1.); - cluster->modulation.fillColumn(thermalMinGenModulation, 0.); - } - ret = ret && r; - - // Special operations when not ran from the interface (aka solver) - if (study.usedByTheSolver) - { - if (!study.parameters.include.thermal.minStablePower) - { - cluster->minStablePower = 0.; - } - if (!study.parameters.include.thermal.minUPTime) - { - cluster->minUpDownTime = 1; - cluster->minUpTime = 1; - cluster->minDownTime = 1; - } - else - { - cluster->minUpDownTime = std::max(cluster->minUpTime, cluster->minDownTime); - } - - if (!study.parameters.include.reserve.spinning) - { - cluster->spinning = 0; - } - - cluster->nominalCapacityWithSpinning = cluster->nominalCapacity; - } + ret = cluster->modulation.loadFromCSVFile(modulationFile, + thermalModulationMax, + HOURS_PER_YEAR, + options) + && ret; // Check the data integrity of the cluster - cluster->integrityCheck(); addToCompleteList(cluster); } @@ -208,6 +175,42 @@ bool ThermalClusterList::loadFromFolder(Study& study, const AnyString& folder, A return ret; } +bool ThermalClusterList::validateClusters(const Parameters& parameters) const +{ + bool ret = true; + + for (const auto& cluster: allClusters_) + { + cluster->minUpTime = std::clamp(cluster->minUpTime, 1u, 168u); + cluster->minDownTime = std::clamp(cluster->minDownTime, 1u, 168u); + + // update the minUpDownTime + cluster->minUpDownTime = std::max(cluster->minUpTime, cluster->minDownTime); + + if (!parameters.include.thermal.minStablePower) + { + cluster->minStablePower = 0.; + } + if (!parameters.include.thermal.minUPTime) + { + cluster->minUpDownTime = 1; + cluster->minUpTime = 1; + cluster->minDownTime = 1; + } + + if (!parameters.include.reserve.spinning) + { + cluster->spinning = 0; + } + + cluster->nominalCapacityWithSpinning = cluster->nominalCapacity; + + ret = cluster->integrityCheck() && ret; + } + + return ret; +} + static bool ThermalClusterLoadFromProperty(ThermalCluster& cluster, const IniFile::Property* p) { if (p->key.empty()) @@ -268,35 +271,11 @@ static bool ThermalClusterLoadFromProperty(ThermalCluster& cluster, const IniFil if (p->key == "min-up-time") { - if (p->value.to(cluster.minUpTime)) - { - if (cluster.minUpTime < 1) - { - cluster.minUpTime = 1; - } - if (cluster.minUpTime > 168) - { - cluster.minUpTime = 168; - } - return true; - } - return false; + return p->value.to(cluster.minUpTime); } if (p->key == "min-down-time") { - if (p->value.to(cluster.minDownTime)) - { - if (cluster.minDownTime < 1) - { - cluster.minDownTime = 1; - } - if (cluster.minDownTime > 168) - { - cluster.minDownTime = 168; - } - return true; - } - return false; + return p->value.to(cluster.minDownTime); } if (p->key == "name") { @@ -375,8 +354,6 @@ bool ThermalClusterLoadFromSection(const AnyString& filename, << property->key << "`: The property is unknown and ignored"; } } - // update the minUpDownTime - cluster.minUpDownTime = std::max(cluster.minUpTime, cluster.minDownTime); } return true; } @@ -399,7 +376,7 @@ void ThermalClusterList::reverseCalculationOfSpinning() void ThermalClusterList::enableMustrunForEveryone() { - for (auto& c: allClusters_) + for (const auto& c: allClusters_) { c->mustrun = true; } @@ -411,7 +388,7 @@ void ThermalClusterList::ensureDataPrepro() { if (!c->prepro) { - c->prepro = new PreproAvailability(c->id(), c->unitCount); + c->prepro = std::make_unique(c->id(), c->unitCount); } } } @@ -563,7 +540,6 @@ bool ThermalClusterList::saveToFolder(const AnyString& folder) const { ret = false; } - } // Write the ini file @@ -606,32 +582,46 @@ bool ThermalClusterList::saveEconomicCosts(const AnyString& folder) const bool ThermalClusterList::loadPreproFromFolder(Study& study, const AnyString& folder) { - const bool globalThermalTSgeneration = study.parameters.timeSeriesToGenerate - & timeSeriesThermal; - Clob buffer; auto hasPrepro = [](auto c) { return (bool)c->prepro; }; - auto loadAndCheckPrepro = [&buffer, &folder, &study, &globalThermalTSgeneration](auto c) + auto loadPrepro = [&buffer, &folder, &study](auto& c) { assert(c->parentArea && "cluster: invalid parent area"); buffer.clear() << folder << SEP << c->parentArea->id << SEP << c->id(); - bool result = c->prepro->loadFromFolder(study, buffer); + return c->prepro->loadFromFolder(study, buffer); + }; - if (study.usedByTheSolver && globalThermalTSgeneration) - { - result = c->prepro->validate() && result; - } + return std::ranges::all_of(allClusters_ | std::views::filter(hasPrepro), loadPrepro); +} - if (result && study.usedByTheSolver && c->doWeGenerateTS(globalThermalTSgeneration)) - { - result = c->prepro->normalizeAndCheckNPO(); - } - return result; - }; +bool ThermalClusterList::validatePrepro(const Study& study) +{ + auto hasPrepro = [](auto c) { return (bool)c->prepro; }; - return std::ranges::all_of(allClusters_ | std::views::filter(hasPrepro), loadAndCheckPrepro); + const bool globalThermalTSgeneration = study.parameters.timeSeriesToGenerate + & timeSeriesThermal; + + if (!study.usedByTheSolver) + { + return true; + } + + return std::ranges::all_of(allClusters_ | std::views::filter(hasPrepro), + [&globalThermalTSgeneration](auto& c) + { + if (globalThermalTSgeneration && !c->prepro->validate()) + { + return false; + } + + if (c->doWeGenerateTS(globalThermalTSgeneration)) + { + return c->prepro->normalizeAndCheckNPO(); + } + return true; + }); } bool ThermalClusterList::loadEconomicCosts(Study& study, const AnyString& folder) diff --git a/src/libs/antares/study/parts/wind/container.cpp b/src/libs/antares/study/parts/wind/container.cpp index eff23dff6f..64575b73ab 100644 --- a/src/libs/antares/study/parts/wind/container.cpp +++ b/src/libs/antares/study/parts/wind/container.cpp @@ -30,16 +30,10 @@ using namespace Yuni; namespace Antares::Data::Wind { Container::Container(): - prepro(nullptr), series(tsNumbers) { } -Container::~Container() -{ - delete prepro; -} - bool Container::forceReload(bool reload) const { bool ret = true; diff --git a/src/libs/antares/study/progression/progression.cpp b/src/libs/antares/study/progression/progression.cpp index a78c86959f..28c1d3288e 100644 --- a/src/libs/antares/study/progression/progression.cpp +++ b/src/libs/antares/study/progression/progression.cpp @@ -42,7 +42,7 @@ Progression::Task::Task(const Antares::Data::Study& study, uint year, Section se assert(&pProgression); } -void Progression::add(uint year, Section section, int nbTicks) +void Progression::add(uint year, Section section, unsigned nbTicks) { // This section is not thread-safe because always called before really launching // the simulation diff --git a/src/libs/antares/study/runtime/runtime.cpp b/src/libs/antares/study/runtime/runtime.cpp index f10da99345..61be13d6cf 100644 --- a/src/libs/antares/study/runtime/runtime.cpp +++ b/src/libs/antares/study/runtime/runtime.cpp @@ -21,6 +21,7 @@ #include "antares/study/runtime/runtime.h" +#include #include #include "antares/antares/fatal-error.h" #include "antares/study/area/scratchpad.h" @@ -103,7 +104,7 @@ static void StudyRuntimeInfosInitializeAreaLinks(Study& study, StudyRuntimeInfos uint indx = 0; study.areas.each( - [&](Data::Area& area) + [&indx, &r](Data::Area& area) { area.buildLinksIndexes(); @@ -175,6 +176,7 @@ void StudyRuntimeInfos::initializeRangeLimits(const Study& study, StudyRangeLimi limits.month[rangeCount] = limits.month[rangeEnd] - limits.month[rangeBegin] + 1; // year limits.year[rangeBegin] = 0; + /// reminder to get rangeLimits.year[Data::rangeEnd] limits.year[rangeEnd] = study.parameters.nbYears - 1; limits.year[rangeCount] = study.parameters.effectiveNbYears; @@ -213,9 +215,8 @@ void StudyRuntimeInfos::initializeRangeLimits(const Study& study, StudyRangeLimi } else { - simulationDaysPerMonth[(uint)ca.month] = study.calendar.months[(uint)ca.month].days - - ca.dayMonth; - simulationDaysPerMonth[(uint)cb.month] = cb.dayMonth + 1; + simulationDaysPerMonth[ca.month] = study.calendar.months[ca.month].days - ca.dayMonth; + simulationDaysPerMonth[cb.month] = cb.dayMonth + 1; for (uint i = ca.month + 1; i < cb.month; ++i) { simulationDaysPerMonth[i] = study.calendar.months[i].days; @@ -270,9 +271,9 @@ void StudyRuntimeInfos::checkThermalTSGeneration(Study& study) thermalTSRefresh = globalThermalTSgeneration; study.areas.each( - [this, globalThermalTSgeneration](Data::Area& area) + [this, globalThermalTSgeneration](const Data::Area& area) { - for (auto& c: area.thermal.list.each_enabled_and_not_mustrun()) + for (const auto& c: area.thermal.list.each_enabled_and_not_mustrun()) { thermalTSRefresh = thermalTSRefresh || c->doWeGenerateTS(globalThermalTSgeneration); } @@ -442,7 +443,7 @@ void StudyRangeLimits::checkIntegrity() const void StudyRuntimeInfos::disableAllFilters(Study& study) { study.areas.each( - [&](Data::Area& area) + [](Data::Area& area) { area.filterSynthesis = filterAll; area.filterYearByYear = filterAll; diff --git a/src/libs/antares/study/scenario-builder/BindingConstraintsTSNumbersData.cpp b/src/libs/antares/study/scenario-builder/BindingConstraintsTSNumbersData.cpp index 24b5b8cb6b..5ffef13e98 100644 --- a/src/libs/antares/study/scenario-builder/BindingConstraintsTSNumbersData.cpp +++ b/src/libs/antares/study/scenario-builder/BindingConstraintsTSNumbersData.cpp @@ -80,13 +80,12 @@ bool BindingConstraintsTSNumberData::apply(Study& study) bool BindingConstraintsTSNumberData::reset(const Study& study) { const uint nbYears = study.parameters.nbYears; - std::for_each(study.bindingConstraintsGroups.begin(), - study.bindingConstraintsGroups.end(), - [&](const auto& group) - { - auto& ts_numbers = rules_[group->name()]; - ts_numbers.reset(1, nbYears); - }); + std::ranges::for_each(study.bindingConstraintsGroups, + [this, &nbYears](const auto& group) + { + auto& ts_numbers = rules_[group->name()]; + ts_numbers.reset(1, nbYears); + }); return true; } diff --git a/src/libs/antares/study/scenario-builder/hydroLevelsData.cpp b/src/libs/antares/study/scenario-builder/hydroLevelsData.cpp index 8abb019366..8d0575b96a 100644 --- a/src/libs/antares/study/scenario-builder/hydroLevelsData.cpp +++ b/src/libs/antares/study/scenario-builder/hydroLevelsData.cpp @@ -28,6 +28,13 @@ namespace Antares::Data::ScenarioBuilder { +hydroLevelsData::hydroLevelsData(const std::string& iniFilePrefix, + std::function applyToTarget): + addToPrefix_(iniFilePrefix), + applyToTarget_(applyToTarget) +{ +} + bool hydroLevelsData::reset(const Study& study) { const uint nbYears = study.parameters.nbYears; @@ -40,10 +47,6 @@ bool hydroLevelsData::reset(const Study& study) void hydroLevelsData::saveToINIFile(const Study& study, Yuni::IO::File::Stream& file) const { - // Prefix - CString<512, false> prefix; - prefix += "hl,"; - // Turning values into strings (precision 4) std::ostringstream value_into_string; value_into_string << std::setprecision(4); @@ -65,7 +68,7 @@ void hydroLevelsData::saveToINIFile(const Study& study, Yuni::IO::File::Stream& } assert(index < study.areas.size()); value_into_string << value; - file << prefix << study.areas.byIndex[index]->id << ',' << y << " = " + file << addToPrefix_ << study.areas.byIndex[index]->id << ',' << y << " = " << value_into_string.str() << '\n'; value_into_string.str(std::string()); // Clearing converter } @@ -79,7 +82,7 @@ void hydroLevelsData::set_value(uint x, uint y, double value) bool hydroLevelsData::apply(Study& study) { - study.scenarioHydroLevels.copyFrom(pHydroLevelsRules); + applyToTarget_(study, pHydroLevelsRules); return true; } diff --git a/src/libs/antares/study/scenario-builder/rules.cpp b/src/libs/antares/study/scenario-builder/rules.cpp index fb39a275fd..2037eede6b 100644 --- a/src/libs/antares/study/scenario-builder/rules.cpp +++ b/src/libs/antares/study/scenario-builder/rules.cpp @@ -59,7 +59,8 @@ void Rules::saveToINIFile(Yuni::IO::File::Stream& file) const linksNTC[i].saveToINIFile(study_, file); } // hydro levels - hydroLevels.saveToINIFile(study_, file); + hydroInitialLevels.saveToINIFile(study_, file); + hydroFinalLevels.saveToINIFile(study_, file); } binding_constraints.saveToINIFile(study_, file); file << '\n'; @@ -95,7 +96,8 @@ bool Rules::reset() renewable[i].reset(study_); } - hydroLevels.reset(study_); + hydroInitialLevels.reset(study_); + hydroFinalLevels.reset(study_); // links NTC linksNTC.clear(); @@ -263,7 +265,7 @@ bool Rules::readSolar(const AreaName::Vector& splitKey, String value, bool updat return true; } -bool Rules::readHydroLevels(const AreaName::Vector& splitKey, String value, bool updaterMode) +bool Rules::readInitialHydroLevels(const AreaName::Vector& splitKey, String value, bool updaterMode) { const uint year = splitKey[2].to(); const AreaName& areaname = splitKey[1]; @@ -275,7 +277,23 @@ bool Rules::readHydroLevels(const AreaName::Vector& splitKey, String value, bool } double val = fromStringToHydroLevel(value, 1.); - hydroLevels.setTSnumber(area->index, year, val); + hydroInitialLevels.setTSnumber(area->index, year, val); + return true; +} + +bool Rules::readFinalHydroLevels(const AreaName::Vector& splitKey, String value, bool updaterMode) +{ + const uint year = splitKey[2].to(); + const AreaName& areaname = splitKey[1]; + + const Data::Area* area = getArea(areaname, updaterMode); + if (!area) + { + return false; + } + + double finalLevel = fromStringToHydroLevel(value, 1.); + hydroFinalLevels.setTSnumber(area->index, year, finalLevel); return true; } @@ -389,7 +407,11 @@ bool Rules::readLine(const AreaName::Vector& splitKey, String value, bool update } else if (kind_of_scenario == "hl") { - return readHydroLevels(splitKey, value, updaterMode); + return readInitialHydroLevels(splitKey, value, updaterMode); + } + else if (kind_of_scenario == "hfl") + { + return readFinalHydroLevels(splitKey, value, updaterMode); } else if (kind_of_scenario == "ntc") { @@ -402,63 +424,63 @@ bool Rules::readLine(const AreaName::Vector& splitKey, String value, bool update return false; } - bool Rules::apply() +bool Rules::apply() +{ + bool returned_status = true; + if (pAreaCount) { - bool returned_status = true; - if (pAreaCount) + returned_status = load.apply(study_) && returned_status; + returned_status = solar.apply(study_) && returned_status; + returned_status = hydro.apply(study_) && returned_status; + returned_status = wind.apply(study_) && returned_status; + for (uint i = 0; i != pAreaCount; ++i) { - returned_status = load.apply(study_) && returned_status; - returned_status = solar.apply(study_) && returned_status; - returned_status = hydro.apply(study_) && returned_status; - returned_status = wind.apply(study_) && returned_status; - for (uint i = 0; i != pAreaCount; ++i) - { - returned_status = thermal[i].apply(study_) && returned_status; - returned_status = renewable[i].apply(study_) && returned_status; - returned_status = linksNTC[i].apply(study_) && returned_status; - } - returned_status = hydroLevels.apply(study_) && returned_status; - returned_status = binding_constraints.apply(study_) && returned_status; + returned_status = thermal[i].apply(study_) && returned_status; + returned_status = renewable[i].apply(study_) && returned_status; + returned_status = linksNTC[i].apply(study_) && returned_status; } - else + returned_status = hydroInitialLevels.apply(study_) && returned_status; + returned_status = hydroFinalLevels.apply(study_) && returned_status; + returned_status = binding_constraints.apply(study_) && returned_status; + } + else + { + returned_status = false; + } + return returned_status; +} + +void Rules::sendWarningsForDisabledClusters() +{ + for (auto it = disabledClustersOnRuleActive.begin(); it != disabledClustersOnRuleActive.end(); + it++) + { + std::vector& scenariiForCurrentCluster = it->second; + int nbScenariiForCluster = (int)scenariiForCurrentCluster.size(); + std::vector::iterator itv = scenariiForCurrentCluster.begin(); + + // Listing the 10 first years for which the current cluster was given a specific TS + // number in the scenario builder. Note that this list of years size could be less then + // 10, but are at least 1. + std::string listYears = std::to_string(*itv); + itv++; + for (int year_count = 1; itv != scenariiForCurrentCluster.end() && year_count < 10; + itv++, year_count++) { - returned_status = false; + listYears += ", " + std::to_string(*itv); } - return returned_status; - } - void Rules::sendWarningsForDisabledClusters() - { - for (auto it = disabledClustersOnRuleActive.begin(); - it != disabledClustersOnRuleActive.end(); - it++) + // Adding last scenario to the list + if (nbScenariiForCluster > 10) { - std::vector& scenariiForCurrentCluster = it->second; - int nbScenariiForCluster = (int)scenariiForCurrentCluster.size(); - std::vector::iterator itv = scenariiForCurrentCluster.begin(); - - // Listing the 10 first years for which the current cluster was given a specific TS - // number in the scenario builder. Note that this list of years size could be less then - // 10, but are at least 1. - std::string listYears = std::to_string(*itv); - itv++; - for (int year_count = 1; itv != scenariiForCurrentCluster.end() && year_count < 10; - itv++, year_count++) - { - listYears += ", " + std::to_string(*itv); - } - - // Adding last scenario to the list - if (nbScenariiForCluster > 10) - { - listYears += ", ..., " + std::to_string(scenariiForCurrentCluster.back()); - } - - logs.warning() << "Cluster " << it->first - << " not found: it may be disabled, though given TS numbers in sc " - "builder for year(s) :"; - logs.warning() << listYears; + listYears += ", ..., " + std::to_string(scenariiForCurrentCluster.back()); } + + logs.warning() << "Cluster " << it->first + << " not found: it may be disabled, though given TS numbers in sc " + "builder for year(s) :"; + logs.warning() << listYears; } +} } // namespace Antares::Data::ScenarioBuilder diff --git a/src/libs/antares/study/scenario-builder/sets.cpp b/src/libs/antares/study/scenario-builder/sets.cpp index 962f7c122d..76dbcb9166 100644 --- a/src/libs/antares/study/scenario-builder/sets.cpp +++ b/src/libs/antares/study/scenario-builder/sets.cpp @@ -195,7 +195,7 @@ bool Sets::internalLoadFromINIFile(const AnyString& filename) } ini.each( - [&](const IniFile::Section& section) + [this](const IniFile::Section& section) { if (section.name.empty()) { diff --git a/src/libs/antares/study/study.cpp b/src/libs/antares/study/study.cpp index 8337795ca1..29f22e9bf5 100644 --- a/src/libs/antares/study/study.cpp +++ b/src/libs/antares/study/study.cpp @@ -26,6 +26,7 @@ #include // For use of floor(...) and ceil(...) #include #include // std::ostringstream +#include #include #include @@ -104,14 +105,11 @@ Study::~Study() void Study::clear() { - // Releasing runtime infos - FreeAndNil(runtime); - FreeAndNil(scenarioRules); + scenarioRules.reset(); FreeAndNil(uiinfo); // areas setsOfAreas.clear(); - setsOfLinks.clear(); preproLoadCorrelation.clear(); preproSolarCorrelation.clear(); @@ -151,9 +149,7 @@ void Study::createAsNew() // Sets setsOfAreas.defaultForAreas(); - setsOfLinks.clear(); setsOfAreas.markAsModified(); - setsOfLinks.markAsModified(); // Binding constraints bindingConstraints.clear(); @@ -211,112 +207,32 @@ uint64_t Study::memoryUsage() const + (uiinfo ? uiinfo->memoryUsage() : 0); } -std::map Study::getRawNumberCoresPerLevel() +unsigned Study::getNumberOfCoresPerMode(unsigned nbLogicalCores, int ncMode) { - std::map table; - - uint nbLogicalCores = Yuni::System::CPU::Count(); if (!nbLogicalCores) { logs.fatal() << "Number of logical cores available is 0."; + return 0; } - switch (nbLogicalCores) + switch (ncMode) { - case 1: - table["min"] = 1; - table["low"] = 1; - table["med"] = 1; - table["high"] = 1; - table["max"] = 1; - break; - case 2: - table["min"] = 1; - table["low"] = 1; - table["med"] = 1; - table["high"] = 2; - table["max"] = 2; - break; - case 3: - table["min"] = 1; - table["low"] = 2; - table["med"] = 2; - table["high"] = 2; - table["max"] = 3; - break; - case 4: - table["min"] = 1; - table["low"] = 2; - table["med"] = 2; - table["high"] = 3; - table["max"] = 4; - break; - case 5: - table["min"] = 1; - table["low"] = 2; - table["med"] = 3; - table["high"] = 4; - table["max"] = 5; - break; - case 6: - table["min"] = 1; - table["low"] = 2; - table["med"] = 3; - table["high"] = 4; - table["max"] = 6; - break; - case 7: - table["min"] = 1; - table["low"] = 2; - table["med"] = 3; - table["high"] = 5; - table["max"] = 7; - break; - case 8: - table["min"] = 1; - table["low"] = 2; - table["med"] = 4; - table["high"] = 6; - table["max"] = 8; - break; - case 9: - table["min"] = 1; - table["low"] = 3; - table["med"] = 5; - table["high"] = 7; - table["max"] = 8; - break; - case 10: - table["min"] = 1; - table["low"] = 3; - table["med"] = 5; - table["high"] = 8; - table["max"] = 9; - break; - case 11: - table["min"] = 1; - table["low"] = 3; - table["med"] = 6; - table["high"] = 8; - table["max"] = 10; - break; - case 12: - table["min"] = 1; - table["low"] = 3; - table["med"] = 6; - table["high"] = 9; - table["max"] = 11; - break; + case ncMin: + return 1; + case ncLow: + return std::ceil(nbLogicalCores / 4.); + case ncAvg: + return std::ceil(nbLogicalCores / 2.); + case ncHigh: + return std::ceil(3 * nbLogicalCores / 4.); + case ncMax: + return nbLogicalCores; default: - table["min"] = 1; - table["low"] = (uint)std::ceil(nbLogicalCores / 4.); - table["med"] = (uint)std::ceil(nbLogicalCores / 2.); - table["high"] = (uint)std::ceil(3 * nbLogicalCores / 4.); - table["max"] = nbLogicalCores - 1; + logs.fatal() << "Simulation cores level not correct : " << ncMode; break; } - return table; + return 0; } void Study::getNumberOfCores(const bool forceParallel, const uint nbYearsParallelForced) @@ -327,33 +243,8 @@ void Study::getNumberOfCores(const bool forceParallel, const uint nbYearsParalle This number is limited by the smallest refresh span (if at least one type of time series is generated) */ - - std::map table = getRawNumberCoresPerLevel(); - - // Getting the number of parallel years based on the number of cores level. - switch (parameters.nbCores.ncMode) - { - case ncMin: - nbYearsParallelRaw = table["min"]; - break; - case ncLow: - nbYearsParallelRaw = table["low"]; - break; - case ncAvg: - nbYearsParallelRaw = table["med"]; - break; - case ncHigh: - nbYearsParallelRaw = table["high"]; - break; - case ncMax: - nbYearsParallelRaw = table["max"]; - break; - default: - logs.fatal() << "Simulation cores level not correct : " << (int)parameters.nbCores.ncMode; - break; - } - - maxNbYearsInParallel = nbYearsParallelRaw; + unsigned nbLogicalCores = std::thread::hardware_concurrency(); + maxNbYearsInParallel = getNumberOfCoresPerMode(nbLogicalCores, parameters.nbCores.ncMode); // In case solver option '--force-parallel n' is used, previous computation is overridden. if (forceParallel) @@ -500,104 +391,11 @@ void Study::getNumberOfCores(const bool forceParallel, const uint nbYearsParalle // enabled. // Useful for RAM estimation. maxNbYearsInParallel_save = maxNbYearsInParallel; - - // Here we answer the question (useful only if hydro hot start is asked) : do all sets of - // parallel years have the same size ? - if (parameters.initialReservoirLevels.iniLevels == Antares::Data::irlHotStart - && setsOfParallelYears.size() && maxNbYearsInParallel > 1) - { - uint currentSetSize = (uint)setsOfParallelYears[0].size(); - if (setsOfParallelYears.size() > 1) - { - for (uint s = 1; s < setsOfParallelYears.size(); s++) - { - if (setsOfParallelYears[s].size() != currentSetSize) - { - parameters.allSetsHaveSameSize = false; - break; - } - } - } - } // End if hot start -} - -bool Study::checkHydroHotStart() -{ - bool hydroHotStart = (parameters.initialReservoirLevels.iniLevels == irlHotStart); - - // No need to check further if hydro hot start is not required - if (!hydroHotStart) - { - return true; - } - - // Here we answer the question (useful only if hydro hot start is asked) : In case of parallel - // run, do all sets of parallel years have the same size ? - if (maxNbYearsInParallel != 1 && !parameters.allSetsHaveSameSize) - { - logs.error() << "Hot Start Hydro option : conflict with parallelization parameters."; - logs.error() - << "Please update relevant simulation parameters or use Cold Start option. "; - return false; - } - - // Checking calendar conditions - // ... The simulation lasts one year exactly - uint nbDaysInSimulation = parameters.simulationDays.end - parameters.simulationDays.first + 1; - if (nbDaysInSimulation < 364) - { - logs.error() - << "Hot Start Hydro option : simulation calendar must cover one complete year. "; - logs.error() << "Please update data or use Cold Start option."; - return false; - } - - // ... For all areas for which reservoir management is enabled : - // - Their starting level is initialized on the same day - // - This day is the first day of the simulation calendar - const Area::Map::iterator end = areas.end(); - for (Area::Map::iterator i = areas.begin(); i != end; ++i) - { - // Reference to the area - Area* area = i->second; - - // No need to make a check on level initialization when reservoir management - // is not activated for the current area - if (!area->hydro.reservoirManagement) - { - continue; - } - - // Month the reservoir level is initialized according to. - // This month number is given in the civil calendar, from january to december (0 is - // january). - int initLevelOnMonth = area->hydro.initializeReservoirLevelDate; - - // Conversion of the previous month into simulation calendar - uint initLevelOnSimMonth = calendar.mapping.months[initLevelOnMonth]; - - // Previous month's first day in the year - uint initLevelOnSimDay = calendar.months[initLevelOnSimMonth].daysYear.first; - - // Check the day of level initialization is the first day of simulation - if (initLevelOnSimDay != parameters.simulationDays.first) - { - logs.error() - << "Hot Start Hydro option : area '" << area->name - << "' - hydro level must be initialized on the first simulation month. "; - logs.error() << "Please update data or use Cold Start option."; - return false; - } - } // End loop over areas - - return true; } bool Study::initializeRuntimeInfos() { - delete runtime; - runtime = new StudyRuntimeInfos(); - return runtime->loadFromStudy(*this); + return runtime.loadFromStudy(*this); } void Study::performTransformationsBeforeLaunchingSimulation() @@ -611,7 +409,7 @@ void Study::performTransformationsBeforeLaunchingSimulation() // ForEach area areas.each( - [&](Data::Area& area) + [this](Data::Area& area) { if (not parameters.geographicTrimming) { @@ -789,7 +587,7 @@ void Study::saveAboutTheStudy(Solver::IResultWriter& resultWriter) buffer << "@ " << i->first << "\r\n"; } } - areas.each([&](const Data::Area& area) { buffer << area.name << "\r\n"; }); + areas.each([&buffer](const Data::Area& area) { buffer << area.name << "\r\n"; }); resultWriter.addEntryFromBuffer(path.c_str(), buffer); } @@ -880,7 +678,7 @@ bool Study::areaDelete(Area* area) // and the scenario builder data *before* reloading uiinfo. { // Updating all hydro allocation - areas.each([&](Data::Area& areait) { areait.hydro.allocation.remove(area->id); }); + areas.each([&area](Data::Area& areait) { areait.hydro.allocation.remove(area->id); }); // We __must__ update the scenario builder data // We may delete an area and re-create a new one with the same @@ -947,7 +745,8 @@ void Study::areaDelete(Area::Vector& arealist) << area.name; // Updating all hydro allocation - areas.each([&](Data::Area& areait) { areait.hydro.allocation.remove(area.id); }); + areas.each([&area](Data::Area& areait) + { areait.hydro.allocation.remove(area.id); }); // Remove all binding constraints attached to the area bindingConstraints.remove(*i); @@ -1046,7 +845,8 @@ bool Study::areaRename(Area* area, AreaName newName) logs.info() << "renaming area " << area->name << " into " << newName; // Updating all hydro allocation - areas.each([&](Data::Area& areait) { areait.hydro.allocation.rename(oldid, newid); }); + areas.each([&oldid, &newid](Data::Area& areait) + { areait.hydro.allocation.rename(oldid, newid); }); ScenarioBuilderUpdater updaterSB(*this); bool ret = true; @@ -1179,34 +979,22 @@ bool Study::clusterRename(Cluster* cluster, ClusterName newName) void Study::destroyAllLoadTSGeneratorData() { - areas.each([&](Data::Area& area) { FreeAndNil(area.load.prepro); }); + areas.each([](Data::Area& area) { area.load.prepro.reset(); }); } void Study::destroyAllSolarTSGeneratorData() { - areas.each([&](Data::Area& area) { FreeAndNil(area.solar.prepro); }); + areas.each([](Data::Area& area) { area.solar.prepro.reset(); }); } void Study::destroyAllHydroTSGeneratorData() { - areas.each([&](Data::Area& area) { FreeAndNil(area.hydro.prepro); }); + areas.each([](Data::Area& area) { area.hydro.prepro.reset(); }); } void Study::destroyAllWindTSGeneratorData() { - areas.each([&](Data::Area& area) { FreeAndNil(area.wind.prepro); }); -} - -void Study::destroyAllThermalTSGeneratorData() -{ - areas.each( - [&](Data::Area& area) - { - for (const auto& cluster: area.thermal.list.each_enabled_and_not_mustrun()) - { - FreeAndNil(cluster->prepro); - } - }); + areas.each([](Data::Area& area) { area.wind.prepro.reset(); }); } void Study::ensureDataAreLoadedForAllBindingConstraints() @@ -1253,25 +1041,24 @@ struct TS final void Study::initializeProgressMeter(bool tsGeneratorOnly) { - uint years = tsGeneratorOnly ? 1 : (runtime->rangeLimits.year[rangeEnd] + 1); - assert(runtime); + uint years = tsGeneratorOnly ? 1 : (runtime.rangeLimits.year[rangeEnd] + 1); - int ticksPerYear = 0; - int ticksPerOutput = 0; + unsigned ticksPerYear = 0; + unsigned ticksPerOutput = 0; if (not tsGeneratorOnly) { // One tick at the begining and 2 at the end of the year // Output - Areas - ticksPerOutput += (int)areas.size(); + ticksPerOutput += areas.size(); // Output - Links - ticksPerOutput += (int)runtime->interconnectionsCount(); + ticksPerOutput += runtime.interconnectionsCount(); // Output - digest ticksPerOutput += 1; ticksPerYear = 1; } - int n; + unsigned n; for (uint y = 0; y != years; ++y) { @@ -1280,7 +1067,7 @@ void Study::initializeProgressMeter(bool tsGeneratorOnly) n = parameters.nbTimeSeriesLoad * areas.size() * 365; if (0 != (timeSeriesLoad & parameters.timeSeriesToArchive)) { - n += (int)areas.size(); + n += areas.size(); } progression.add(y, Solver::Progression::sectTSGLoad, n); } @@ -1289,7 +1076,7 @@ void Study::initializeProgressMeter(bool tsGeneratorOnly) n = parameters.nbTimeSeriesSolar * areas.size() * 365; if (0 != (timeSeriesSolar & parameters.timeSeriesToArchive)) { - n += (int)areas.size(); + n += areas.size(); } progression.add(y, Solver::Progression::sectTSGSolar, n); } @@ -1298,7 +1085,7 @@ void Study::initializeProgressMeter(bool tsGeneratorOnly) n = parameters.nbTimeSeriesWind * areas.size() * 365; if (0 != (timeSeriesWind & parameters.timeSeriesToArchive)) { - n += (int)areas.size(); + n += areas.size(); } progression.add(y, Solver::Progression::sectTSGWind, n); } @@ -1308,17 +1095,17 @@ void Study::initializeProgressMeter(bool tsGeneratorOnly) n = parameters.nbTimeSeriesHydro; if (0 != (timeSeriesHydro & parameters.timeSeriesToArchive)) { - n += (int)areas.size(); + n += areas.size(); } progression.add(y, Solver::Progression::sectTSGHydro, n); } if (TS::IsNeeded(*this, y)) { - n = runtime->thermalPlantTotalCount; + n = runtime.thermalPlantTotalCount; if (0 != (timeSeriesThermal & parameters.timeSeriesToArchive)) { - n += (int)runtime->thermalPlantTotalCount; - n += (int)runtime->thermalPlantTotalCountMustRun; + n += runtime.thermalPlantTotalCount; + n += runtime.thermalPlantTotalCountMustRun; } progression.add(y, Solver::Progression::sectTSGThermal, n); } @@ -1338,23 +1125,23 @@ void Study::initializeProgressMeter(bool tsGeneratorOnly) n = 0; if (0 != (timeSeriesLoad & parameters.exportTimeSeriesInInput)) { - n += (int)areas.size(); + n += areas.size(); } if (0 != (timeSeriesSolar & parameters.exportTimeSeriesInInput)) { - n += (int)areas.size(); + n += areas.size(); } if (0 != (timeSeriesWind & parameters.exportTimeSeriesInInput)) { - n += (int)areas.size(); + n += areas.size(); } if (0 != (timeSeriesHydro & parameters.exportTimeSeriesInInput)) { - n += (int)areas.size(); + n += areas.size(); } if (0 != (timeSeriesThermal & parameters.exportTimeSeriesInInput)) { - n += (int)areas.size(); + n += areas.size(); } if (n) { @@ -1381,7 +1168,6 @@ bool Study::forceReload(bool reload) const ret = preproHydroCorrelation.forceReload(reload) and ret; ret = setsOfAreas.forceReload(reload) and ret; - ret = setsOfLinks.forceReload(reload) and ret; return ret; } @@ -1397,7 +1183,6 @@ void Study::markAsModified() const bindingConstraints.markAsModified(); setsOfAreas.markAsModified(); - setsOfLinks.markAsModified(); } void Study::relocate(const std::string& newFolder) @@ -1415,6 +1200,7 @@ void Study::resizeAllTimeseriesNumbers(uint n) bindingConstraintsGroups.resizeAllTimeseriesNumbers(n); } +// TODO VP: Could be removed with the GUI bool Study::checkForFilenameLimits(bool output, const String& chfolder) const { enum @@ -1447,7 +1233,7 @@ bool Study::checkForFilenameLimits(bool output, const String& chfolder) const String areaname; areas.each( - [&](const Area& area) + [&output, &linkname, &areaname](const Area& area) { if (areaname.size() < area.id.size()) { @@ -1459,19 +1245,12 @@ bool Study::checkForFilenameLimits(bool output, const String& chfolder) const { auto& link = *(i->second); uint len = link.from->id.size() + link.with->id.size(); - len += output ? 3 : 1; + len += 3; if (len > linkname.size()) { linkname.clear(); linkname << i->second->from->id; - if (output) - { - linkname << " - "; // 3 - } - else - { - linkname << SEP; - } + linkname << " - "; // 3 linkname << i->second->with->id; } } @@ -1527,7 +1306,7 @@ bool Study::checkForFilenameLimits(bool output, const String& chfolder) const // or even constraints areas.each( - [&](const Area& area) + [&areaname, &clustername](const Area& area) { if (areaname.size() < area.id.size()) { diff --git a/src/libs/antares/study/study.extra.cpp b/src/libs/antares/study/study.extra.cpp index 1ec628c321..fdfb6eb2d3 100644 --- a/src/libs/antares/study/study.extra.cpp +++ b/src/libs/antares/study/study.extra.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/study/study.h" @@ -35,32 +35,16 @@ String StudyIconFile; void Study::scenarioRulesCreate() { // releasing the previous instance of the scenario builder - delete scenarioRules; + scenarioRules.reset(); // When ran from the solver, the scenario builder must be present - scenarioRules = new ScenarioBuilder::Sets(); - scenarioRules->loadFromStudy(*this); -} - -void Study::scenarioRulesCreate(const RulesScenarioName& /*thisoneonly*/) -{ - // releasing the previous instance of the scenario builder - delete scenarioRules; - // When ran from the solver, the scenario builder must be present - scenarioRules = new ScenarioBuilder::Sets(); + scenarioRules = std::make_unique(); scenarioRules->loadFromStudy(*this); } void Study::scenarioRulesDestroy() { - if (scenarioRules) - { - // releasing the previous instance of the scenario builder - // safety dereferencing for the interface if running - ScenarioBuilder::Sets* sb = scenarioRules; - scenarioRules = nullptr; - delete sb; - } + scenarioRules.reset(); } void Study::scenarioRulesLoadIfNotAvailable() @@ -68,7 +52,7 @@ void Study::scenarioRulesLoadIfNotAvailable() if (!scenarioRules) { // When ran from the solver, the scenario builder must be present - scenarioRules = new ScenarioBuilder::Sets(); + scenarioRules = std::make_unique(); scenarioRules->loadFromStudy(*this); } } diff --git a/src/libs/antares/study/study.importprepro.cpp b/src/libs/antares/study/study.importprepro.cpp index 837f37a485..69a0fe058b 100644 --- a/src/libs/antares/study/study.importprepro.cpp +++ b/src/libs/antares/study/study.importprepro.cpp @@ -33,7 +33,7 @@ bool Study::importTimeseriesIntoInput() { // Special case: some thermal clusters may force TS generation const bool importThermal = parameters.haveToImport(timeSeriesThermal) - && runtime->thermalTSRefresh; + && runtime.thermalTSRefresh; // Something to import ? if ((parameters.exportTimeSeriesInInput && parameters.timeSeriesToGenerate) || importThermal) { @@ -50,56 +50,52 @@ bool Study::importTimeseriesIntoInput() if (parameters.haveToImport(timeSeriesLoad)) { logs.info() << "Importing load timeseries..."; - areas.each( - [&](const Data::Area& area) - { - logs.info() << "Importing load timeseries : " << area.name; - buffer.clear() << folderInput << SEP << "load" << SEP << "series"; - ret = area.load.series.saveToFolder(area.id, buffer.c_str(), "load_") && ret; - ++progression; - }); + for (const auto& [areaName, area]: areas) + { + logs.info() << "Importing load timeseries : " << areaName; + buffer.clear() << folderInput << SEP << "load" << SEP << "series"; + ret = area->load.series.saveToFolder(area->id, buffer.c_str(), "load_") && ret; + ++progression; + } } // Solar if (parameters.haveToImport(timeSeriesSolar)) { logs.info() << "Importing solar timeseries..."; - areas.each( - [&](const Data::Area& area) - { - logs.info() << "Importing solar timeseries : " << area.name; - buffer.clear() << folderInput << SEP << "solar" << SEP << "series"; - ret = area.solar.series.saveToFolder(area.id, buffer.c_str(), "solar_") && ret; - ++progression; - }); + for (const auto& [areaName, area]: areas) + { + logs.info() << "Importing solar timeseries : " << areaName; + buffer.clear() << folderInput << SEP << "solar" << SEP << "series"; + ret = area->solar.series.saveToFolder(area->id, buffer.c_str(), "solar_") && ret; + ++progression; + } } // Hydro if (parameters.haveToImport(timeSeriesHydro)) { logs.info() << "Importing hydro timeseries..."; - areas.each( - [&](const Data::Area& area) - { - logs.info() << "Importing hydro timeseries : " << area.name; - buffer.clear() << folderInput << SEP << "hydro" << SEP << "series"; - ret = area.hydro.series->saveToFolder(area.id, buffer) && ret; - ++progression; - }); + for (const auto& [areaName, area]: areas) + { + logs.info() << "Importing hydro timeseries : " << areaName; + buffer.clear() << folderInput << SEP << "hydro" << SEP << "series"; + ret = area->hydro.series->saveToFolder(area->id, buffer) && ret; + ++progression; + } } // Wind if (parameters.haveToImport(timeSeriesWind)) { logs.info() << "Importing wind timeseries..."; - areas.each( - [&](const Data::Area& area) - { - logs.info() << "Importing wind timeseries : " << area.name; - buffer.clear() << folderInput << SEP << "wind" << SEP << "series"; - area.wind.series.saveToFolder(area.id, buffer.c_str(), "wind_") && ret; - ++progression; - }); + for (const auto& [areaName, area]: areas) + { + logs.info() << "Importing wind timeseries : " << areaName; + buffer.clear() << folderInput << SEP << "wind" << SEP << "series"; + area->wind.series.saveToFolder(area->id, buffer.c_str(), "wind_") && ret; + ++progression; + } } // Thermal @@ -108,18 +104,17 @@ bool Study::importTimeseriesIntoInput() logs.info() << "Importing thermal timeseries..."; String msg; - areas.each( - [&](Data::Area& area) - { - msg.clear() << "Importing thermal timeseries : " << area.name; + for (const auto& [areaName, area]: areas) + { + msg.clear() << "Importing thermal timeseries : " << areaName; - // Spinning - area.thermal.list.reverseCalculationOfSpinning(); + // Spinning + area->thermal.list.reverseCalculationOfSpinning(); - buffer.clear() << folderInput << SEP << "thermal" << SEP << "series"; - ret = area.thermal.list.saveDataSeriesToFolder(buffer.c_str()) && ret; - ++progression; - }); + buffer.clear() << folderInput << SEP << "thermal" << SEP << "series"; + ret = area->thermal.list.saveDataSeriesToFolder(buffer.c_str()) && ret; + ++progression; + } } return ret; diff --git a/src/libs/antares/study/version.cpp b/src/libs/antares/study/version.cpp index 5459ed5d63..8fad2748fd 100644 --- a/src/libs/antares/study/version.cpp +++ b/src/libs/antares/study/version.cpp @@ -43,7 +43,8 @@ constexpr auto supportedVersions = std::to_array({ StudyVersion(8, 7), StudyVersion(8, 8), StudyVersion(9, 0), - StudyVersion(9, 1) + StudyVersion(9, 1), + StudyVersion(9, 2) // Add new versions here }); diff --git a/src/libs/antares/study/xcast/xcast.cpp b/src/libs/antares/study/xcast/xcast.cpp index 4233784088..0f2e05956b 100644 --- a/src/libs/antares/study/xcast/xcast.cpp +++ b/src/libs/antares/study/xcast/xcast.cpp @@ -201,19 +201,16 @@ bool XCast::loadFromFolder(const AnyString& folder) IniFile ini; if (ini.open(buffer)) { - // For each section - const IniFile::Property* p; - CString<30, false> key; - ini.each( - [&](const IniFile::Section& section) + [this, &buffer](const IniFile::Section& section) { // For each property if (section.name == "general") { - for (p = section.firstProperty; p != nullptr; p = p->next) + for (const IniFile::Property* p = section.firstProperty; p != nullptr; + p = p->next) { - key = p->key; + CString<30, false> key = p->key; key.toLower(); if (key == "distribution") { diff --git a/src/libs/antares/sys/policy.cpp b/src/libs/antares/sys/policy.cpp index b9a60ea4af..0427c7441c 100644 --- a/src/libs/antares/sys/policy.cpp +++ b/src/libs/antares/sys/policy.cpp @@ -65,22 +65,20 @@ static void OpenFromINIFileWL(const String& filename, const StringT& hostname) return; } - PolicyKey key; - ShortString128 hostnameVersion; - ShortString128 hostnameAll; - hostnameVersion << hostname << ':' << ANTARES_VERSION; - hostnameAll << hostname << ":*"; + std::string hostnameVersion = hostname + ':' + ANTARES_VERSION; + std::string hostnameAll = hostname + ":*"; ini.each( - [&](const IniFile::Section& section) + [&hostnameVersion, &hostnameAll](const IniFile::Section& section) { // This section is dedicated to another host if (section.name == "*:*" or section.name == "*:" ANTARES_VERSION or section.name.equals(hostnameAll) or section.name.equals(hostnameVersion)) { section.each( - [&](const IniFile::Property& property) + [](const IniFile::Property& property) { + PolicyKey key; key = property.key; key.trim(" \t"); (*entries)[key] = property.value; diff --git a/src/libs/antares/utils/include/antares/utils/utils.h b/src/libs/antares/utils/include/antares/utils/utils.h index 1043e7ca4e..a2f50a2e54 100644 --- a/src/libs/antares/utils/include/antares/utils/utils.h +++ b/src/libs/antares/utils/include/antares/utils/utils.h @@ -36,9 +36,10 @@ namespace Antares */ template void TransformNameIntoID(const AnyString& name, StringT& out); - std::string transformNameIntoID(const std::string& name); +std::string FormattedTime(const std::string& format); + /*! ** \brief Beautify a name, for renaming an area for example */ @@ -51,11 +52,8 @@ std::vector> splitStringIntoPairs(const std: namespace Utils { - bool isZero(double d); - double round(double d, unsigned precision); - } // namespace Utils } // namespace Antares diff --git a/src/libs/antares/utils/utils.cpp b/src/libs/antares/utils/utils.cpp index 047881b0e6..92be168726 100644 --- a/src/libs/antares/utils/utils.cpp +++ b/src/libs/antares/utils/utils.cpp @@ -96,6 +96,18 @@ void BeautifyName(std::string& out, const std::string& oldname) out = yuniOut.c_str(); } +std::string FormattedTime(const std::string& format) +{ + using namespace std::chrono; + auto time = system_clock::to_time_t(system_clock::now()); + std::tm local_time = *std::localtime(&time); + + char time_buffer[256]; + std::strftime(time_buffer, sizeof(time_buffer), format.c_str(), &local_time); + + return std::string(time_buffer); +} + std::vector> splitStringIntoPairs(const std::string& s, char delimiter1, char delimiter2) @@ -116,6 +128,8 @@ std::vector> splitStringIntoPairs(const std: else { logs.warning() << "Error while parsing: " << token; + logs.warning() << "Correct format is: \"object1" << delimiter2 << "object2" + << delimiter1 << "object3" << delimiter2 << "object4\""; } } @@ -133,7 +147,7 @@ bool isZero(double d) double round(double d, unsigned precision) { - unsigned factor = std::pow(10, precision); + auto factor = std::pow(10, precision); return std::round(d * factor) / factor; } diff --git a/src/libs/antares/writer/CMakeLists.txt b/src/libs/antares/writer/CMakeLists.txt index 21ddd81ba4..9795f6ace4 100644 --- a/src/libs/antares/writer/CMakeLists.txt +++ b/src/libs/antares/writer/CMakeLists.txt @@ -1,5 +1,4 @@ project(result-writer) -find_package(minizip) add_library(result_writer # Helper class diff --git a/src/libs/antares/writer/in_memory_writer.cpp b/src/libs/antares/writer/in_memory_writer.cpp index e3e643a74f..182fee1927 100644 --- a/src/libs/antares/writer/in_memory_writer.cpp +++ b/src/libs/antares/writer/in_memory_writer.cpp @@ -24,9 +24,9 @@ #include #include +#include #include #include -#include namespace fs = std::filesystem; diff --git a/src/libs/antares/writer/zip_writer.cpp b/src/libs/antares/writer/zip_writer.cpp index 362d0e730e..ddfee2918e 100644 --- a/src/libs/antares/writer/zip_writer.cpp +++ b/src/libs/antares/writer/zip_writer.cpp @@ -51,7 +51,6 @@ static void logErrorAndThrow [[noreturn]] (const std::string& errorMessage) throw std::runtime_error(errorMessage); } - // Class ZipWriteJob template ZipWriteJob::ZipWriteJob(ZipWriter& writer, @@ -100,7 +99,9 @@ void ZipWriteJob::writeEntry() { logErrorAndThrow("Error opening entry " + pEntryPath + " (" + std::to_string(ret) + ")"); } - int32_t bw = mz_zip_writer_entry_write(pZipHandle, pContent.data(), pContent.size()); + int32_t bw = mz_zip_writer_entry_write(pZipHandle, + pContent.data(), + static_cast(pContent.size())); if (static_cast(bw) != pContent.size()) { logErrorAndThrow("Error writing entry " + pEntryPath + "(written = " + std::to_string(bw) diff --git a/src/libs/fswalker/fswalker.cpp b/src/libs/fswalker/fswalker.cpp index 25a188798e..403572bb3e 100644 --- a/src/libs/fswalker/fswalker.cpp +++ b/src/libs/fswalker/fswalker.cpp @@ -267,7 +267,7 @@ bool WalkerThread::triggerFileEvent(const String& filename, int64_t modified, uint64_t size) { - assert(pFileJob != NULL); + assert(pFileJob); // Statistics ++statistics.fileCount; @@ -320,7 +320,7 @@ void WalkerThread::walk(const String& path) do { - assert(pContext.top() != NULL); + assert(pContext.top()); auto& context = *(pContext.top()); if (pShouldStop) diff --git a/src/packaging/CMakeLists.txt b/src/packaging/CMakeLists.txt index 6d68ec5e38..868cd7a8ec 100644 --- a/src/packaging/CMakeLists.txt +++ b/src/packaging/CMakeLists.txt @@ -10,6 +10,8 @@ set(TARGET_LIBS #No alias #not dependency is present since once a dependency is in the export set #it is available for everything + solver_api #What we want to export + #solver_api study study-loader @@ -33,6 +35,7 @@ set(TARGET_LIBS #No alias exception benchmarking antares-solver-variable + lps #study-loader #nothing diff --git a/src/packaging/Config.cmake.in b/src/packaging/Config.cmake.in index be7a1a62fa..c9bcb039e1 100644 --- a/src/packaging/Config.cmake.in +++ b/src/packaging/Config.cmake.in @@ -1,8 +1,18 @@ @PACKAGE_INIT@ include(CMakeFindDependencyMacro) -find_dependency(ortools) -find_dependency(minizip) +find_dependency(Boost REQUIRED) +find_package(minizip-ng QUIET) #Optional, don't use find_dependency it forces return in case of dep not found +if (minizip-ng_FOUND) + add_library(MINIZIP::minizip ALIAS MINIZIP::minizip-ng) +else () + find_dependency(minizip) + if (NOT minizip_FOUND) + message (FATAL_ERROR "Minizip dependency (minizip or minizip-ng) not found.") + endif () +endif () +find_dependency(ortools REQUIRED) +find_dependency(sirius_solver REQUIRED) include("${CMAKE_CURRENT_LIST_DIR}/AntaresTargets.cmake") diff --git a/src/ports/sirius-solver/portfile.cmake b/src/ports/sirius-solver/portfile.cmake new file mode 100644 index 0000000000..287994c152 --- /dev/null +++ b/src/ports/sirius-solver/portfile.cmake @@ -0,0 +1,21 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO "rte-france/sirius-solver" + REF "antares-integration-v1.5" + SHA512 19c6c156861bdeb58c2f17f703124d52020c79f9b81734057bf1bc5dff3dbc464179f99aeab6c8c44a84de1f84ed8f4929f9a919d2bf8bd49ac737f656088e19 + HEAD_REF main +) + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}/src" +) + +vcpkg_cmake_install() + +vcpkg_cmake_config_fixup(PACKAGE_NAME sirius_solver CONFIG_PATH cmake) + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") + +vcpkg_copy_pdbs() + +file(INSTALL "${SOURCE_PATH}/LICENSE.TXT" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) diff --git a/src/ports/sirius-solver/vcpkg.json b/src/ports/sirius-solver/vcpkg.json new file mode 100644 index 0000000000..ded804499d --- /dev/null +++ b/src/ports/sirius-solver/vcpkg.json @@ -0,0 +1,16 @@ +{ + "name": "sirius-solver", + "version": "1.5", + "port-version": 0, + "description": "Sirius solver", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ] +} diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index aeb17fb3a0..37d0f4c003 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory(application) add_subdirectory(constraints-builder) add_subdirectory(hydro) add_subdirectory(infeasible-problem-analysis) +add_subdirectory(lps) add_subdirectory(misc) add_subdirectory(optimisation) add_subdirectory(signal-handling) @@ -18,6 +19,8 @@ add_subdirectory(simulation) add_subdirectory(ts-generator) add_subdirectory(utils) add_subdirectory(variable) +add_subdirectory(modeler) +add_subdirectory(expressions) # # Resource file for Windows @@ -112,4 +115,4 @@ INSTALL(EXPORT antares-solver ) -######### \ No newline at end of file +######### diff --git a/src/solver/application/CMakeLists.txt b/src/solver/application/CMakeLists.txt index 413e99543b..9f554a4b9f 100644 --- a/src/solver/application/CMakeLists.txt +++ b/src/solver/application/CMakeLists.txt @@ -1,10 +1,12 @@ set(HEADERS include/antares/application/application.h + include/antares/application/ScenarioBuilderOwner.h ) set(SRC_APPLICATION ${HEADERS} application.cpp process-priority.cpp + ScenarioBuilderOwner.cpp ) source_group("application" FILES ${SRC_APPLICATION}) @@ -29,10 +31,10 @@ target_link_libraries(application ) target_include_directories(application - PUBLIC + PUBLIC $ ) -install(DIRECTORY include/antares +install(DIRECTORY include/antares DESTINATION "include" ) \ No newline at end of file diff --git a/src/solver/application/ScenarioBuilderOwner.cpp b/src/solver/application/ScenarioBuilderOwner.cpp new file mode 100644 index 0000000000..f2f0c90c7e --- /dev/null +++ b/src/solver/application/ScenarioBuilderOwner.cpp @@ -0,0 +1,57 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ + +#include +#include +#include "antares/solver/simulation/apply-scenario.h" +#include "antares/solver/simulation/timeseries-numbers.h" +#include "antares/solver/ts-generator/generator.h" +#include "antares/study/study.h" + +Antares::Solver::ScenarioBuilderOwner::ScenarioBuilderOwner(Data::Study& study): + study_(study) +{ +} + +void Antares::Solver::ScenarioBuilderOwner::callScenarioBuilder() +{ + TSGenerator::ResizeGeneratedTimeSeries(study_.areas, study_.parameters); + + // Sampled time-series Numbers + // We will resize all matrix related to the time-series numbers + // This operation can be done once since the number of years is constant + // for a single simulation + study_.resizeAllTimeseriesNumbers(1 + study_.runtime.rangeLimits.year[Data::rangeEnd]); + if (not TimeSeriesNumbers::CheckNumberOfColumns(study_.areas)) + { + throw FatalError( + "Inconsistent number of time-series detected. Please check your input data."); + } + + if (not TimeSeriesNumbers::Generate(study_)) + { + throw FatalError("An unrecoverable error has occurred. Can not continue."); + } + if (study_.parameters.useCustomScenario) + { + ApplyCustomScenario(study_); + } +} diff --git a/src/solver/application/application.cpp b/src/solver/application/application.cpp index 374982928e..837971f279 100644 --- a/src/solver/application/application.cpp +++ b/src/solver/application/application.cpp @@ -20,29 +20,25 @@ */ #include "antares/application/application.h" -#include - #include +#include #include #include #include #include #include #include -#include #include #include #include "antares/antares/version.h" #include "antares/config/config.h" -#include "antares/file-tree-study-loader/FileTreeStudyLoader.h" #include "antares/signal-handling/public.h" #include "antares/solver/misc/system-memory.h" #include "antares/solver/misc/write-command-line.h" -#include "antares/solver/simulation/adequacy_mode.h" -#include "antares/solver/simulation/economy_mode.h" +#include "antares/solver/simulation/simulation-run.h" #include "antares/solver/simulation/simulation.h" +#include "antares/solver/simulation/solver.h" #include "antares/solver/utils/ortools_utils.h" -#include "antares/study/simulation.h" using namespace Antares::Check; @@ -63,7 +59,7 @@ Application::Application() resetProcessPriority(); } -void Application::parseCommandLine(Data::StudyLoadOptions& options) +bool Application::parseCommandLine(Data::StudyLoadOptions& options) { auto parser = CreateParser(pSettings, options); auto ret = parser->operator()(pArgc, pArgv); @@ -73,27 +69,28 @@ void Application::parseCommandLine(Data::StudyLoadOptions& options) throw Error::CommandLineArguments(parser->errors()); case Yuni::GetOpt::ReturnCode::help: pStudy = nullptr; - return; + return false; default: - break; + return true; } } -void Application::handleOptions(const Data::StudyLoadOptions& options) +bool Application::handleOptions(const Data::StudyLoadOptions& options) { if (options.displayVersion) { PrintVersionToStdCout(); pStudy = nullptr; - return; + return false; } if (options.listSolvers) { printSolvers(); pStudy = nullptr; - return; + return false; } + return true; } void Application::readDataForTheStudy(Data::StudyLoadOptions& options) @@ -117,7 +114,7 @@ void Application::readDataForTheStudy(Data::StudyLoadOptions& options) std::exception_ptr loadingException; try { - pDurationCollector("study_loading") << [&] + pDurationCollector("study_loading") << [this, &study, &options] { if (study.loadFromFolder(pSettings.studyFolder, options)) { @@ -223,7 +220,6 @@ void Application::readDataForTheStudy(Data::StudyLoadOptions& options) writeComment(study); } - // Runtime data dedicated for the solver if (!study.initializeRuntimeInfos()) { throw Error::RuntimeInfoInitialization(); @@ -232,6 +228,8 @@ void Application::readDataForTheStudy(Data::StudyLoadOptions& options) // Apply transformations needed by the solver only (and not the interface for example) study.performTransformationsBeforeLaunchingSimulation(); + ScenarioBuilderOwner(study).callScenarioBuilder(); + // alloc global vectors SIM_AllocationTableaux(study); } @@ -256,7 +254,6 @@ void Application::startSimulation(Data::StudyLoadOptions& options) pStudy = std::make_unique(true /* for the solver */); pParameters = &(pStudy->parameters); - readDataForTheStudy(options); postParametersChecks(); @@ -312,7 +309,7 @@ void Application::postParametersChecks() const checkCO2CostColumnNumber(pStudy->areas); } -void Application::prepare(int argc, char* argv[]) +void Application::prepare(int argc, const char* argv[]) { pArgc = argc; pArgv = argv; @@ -335,9 +332,15 @@ void Application::prepare(int argc, char* argv[]) // The parser contains references to members of pSettings and options, // don't de-allocate these. - parseCommandLine(options); + if (!parseCommandLine(options)) // --help + { + return; + } - handleOptions(options); + if (!handleOptions(options)) // --version, --list-solvers + { + return; + } // Perform some checks checkAndCorrectSettingsAndOptions(pSettings, options); @@ -380,23 +383,12 @@ void Application::execute() memoryReport.interval(1000 * 60 * 5); // 5 minutes memoryReport.start(); - pStudy->computePThetaInfForThermalClusters(); - - // Run the simulation - switch (pStudy->runtime->mode) - { - case Data::SimulationMode::Economy: - case Data::SimulationMode::Expansion: - runSimulationInEconomicMode(); - break; - case Data::SimulationMode::Adequacy: - runSimulationInAdequacyMode(); - break; - default: - break; - } - // TODO : make an interface class for ISimulation, check writer & queue before - // runSimulationInMode() + Simulation::NullSimulationObserver observer; + pOptimizationInfo = simulationRun(*pStudy, + pSettings, + pDurationCollector, + *resultWriter, + observer); // Importing Time-Series if asked pStudy->importTimeseriesIntoInput(); @@ -405,38 +397,6 @@ void Application::execute() pStudy->progression.stop(); } -void Application::runSimulationInEconomicMode() -{ - Solver::runSimulationInEconomicMode(*pStudy, - pSettings, - pDurationCollector, - *resultWriter, - pOptimizationInfo); -} - -void Application::runSimulationInAdequacyMode() -{ - Solver::runSimulationInAdequacyMode(*pStudy, - pSettings, - pDurationCollector, - *resultWriter, - pOptimizationInfo); -} - -static std::string timeToString() -{ - using namespace std::chrono; - auto time = system_clock::to_time_t(system_clock::now()); - std::tm local_time = *std::localtime(&time); - - char time_buffer[256]; - std::strftime(time_buffer, sizeof(time_buffer), "%Y%m%d-%H%M%S", &local_time); - - std::string currentTime = time_buffer; - - return currentTime; -} - void Application::resetLogFilename() const { fs::path logfile = fs::path(pSettings.studyFolder.c_str()) / "logs"; @@ -447,8 +407,9 @@ void Application::resetLogFilename() const + ". Aborting now."); } - logfile /= "solver-"; // append the filename - logfile += timeToString() + ".log"; // complete filename with timestamp and extension + logfile /= "solver-"; // append the filename + logfile += FormattedTime("%Y%m%d-%H%M%S") + + ".log"; // complete filename with timestamp and extension // Assigning the log filename logs.logfile(logfile.string()); diff --git a/src/solver/simulation/sim_spread_generator.cpp b/src/solver/application/include/antares/application/ScenarioBuilderOwner.h similarity index 75% rename from src/solver/simulation/sim_spread_generator.cpp rename to src/solver/application/include/antares/application/ScenarioBuilderOwner.h index 734cb92da6..f536737be0 100644 --- a/src/solver/simulation/sim_spread_generator.cpp +++ b/src/solver/application/include/antares/application/ScenarioBuilderOwner.h @@ -18,23 +18,27 @@ ** You should have received a copy of the Mozilla Public Licence 2.0 ** along with Antares_Simulator. If not, see . */ +#pragma once -#include "antares/solver/simulation/sim_spread_generator.h" - -namespace SIM +namespace Antares { -SpreadGenerator::SpreadGenerator(double range): - range_(range) +namespace Data { +class Study; } -void SpreadGenerator::reset(unsigned int seed) +namespace Solver { - mt_.reset(seed); -} -double SpreadGenerator::generate() +class ScenarioBuilderOwner { - return mt_.next() * range_; -} -} // namespace SIM +public: + explicit ScenarioBuilderOwner(Antares::Data::Study& study); + + void callScenarioBuilder(); + +private: + Antares::Data::Study& study_; +}; +} // namespace Solver +} // namespace Antares diff --git a/src/solver/application/include/antares/application/application.h b/src/solver/application/include/antares/application/application.h index 7f6dab80d6..9ce49039a1 100644 --- a/src/solver/application/include/antares/application/application.h +++ b/src/solver/application/include/antares/application/application.h @@ -29,6 +29,7 @@ #include #include "antares/infoCollection/StudyInfoCollector.h" #include "antares/solver/misc/options.h" +#include "antares/solver/simulation/ISimulationObserver.h" namespace Antares::Solver { @@ -56,7 +57,7 @@ class Application final: public Yuni::IEventObserver. -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/solver/constraints-builder/cbuilder.h" @@ -54,15 +54,6 @@ CBuilder::CBuilder(Antares::Data::Study& study): { } -CBuilder::~CBuilder() -{ - // delete all the elements of pLink - for (auto i = pLink.begin(); i != pLink.end(); i++) - { - delete *i; - } -} - bool Antares::CBuilder::isCycleDriver(linkInfo* lnkI) { std::string s1(lnkI->ptr->from->name.to()); @@ -180,7 +171,7 @@ bool CBuilder::updateLinks() } // check validity of loopflow against NTC - if (includeLoopFlow && !checkValidityOfNodalLoopFlow(linkInfo, hour)) + if (includeLoopFlow && !checkValidityOfNodalLoopFlow(linkInfo.get(), hour)) { return false; } @@ -190,8 +181,8 @@ bool CBuilder::updateLinks() continue; } - updateLinkPhaseShift(linkInfo, hour); - if (!checkLinkPhaseShift(linkInfo, hour)) + updateLinkPhaseShift(linkInfo.get(), hour); + if (!checkLinkPhaseShift(linkInfo.get(), hour)) { return false; } @@ -239,7 +230,7 @@ bool CBuilder::update() && ((*linkInfoIt)->type == Antares::Data::atAC /*|| (*linkInfoIt)->type == linkInfo::tyACPST*/)) { - enabledACLines.push_back(*linkInfoIt); + enabledACLines.push_back((*linkInfoIt).get()); } } @@ -364,8 +355,7 @@ bool CBuilder::saveCBuilderToFile(const String& filename) const if (filename == "") { - fs::path path = fs::path(pStudy.folder.c_str()) / "settings" - / "constraintbuilder.ini"; + fs::path path = fs::path(pStudy.folder.c_str()) / "settings" / "constraintbuilder.ini"; return ini.save(path.string()); } @@ -399,12 +389,12 @@ bool CBuilder::completeCBuilderFromFile(const std::string& filename) CString<50, false> key; CString<50, false> value; - for (section = ini.firstSection; section != NULL; section = section->next) + for (section = ini.firstSection; section; section = section->next) { if (section->name == ".general") { IniFile::Property* p = section->firstProperty; - for (; p != NULL; p = p->next) + for (; p; p = p->next) { key = p->key; key.toLower(); diff --git a/src/solver/constraints-builder/include/antares/solver/constraints-builder/cbuilder.h b/src/solver/constraints-builder/include/antares/solver/constraints-builder/cbuilder.h index 833f9e82e6..29ddd2b4c5 100644 --- a/src/solver/constraints-builder/include/antares/solver/constraints-builder/cbuilder.h +++ b/src/solver/constraints-builder/include/antares/solver/constraints-builder/cbuilder.h @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #ifndef __ANTARES_CONSTRAINTSBUILDER_BUILDER_CBUILDER_H__ #define __ANTARES_CONSTRAINTSBUILDER_BUILDER_CBUILDER_H__ @@ -231,7 +231,7 @@ class CBuilder final */ CBuilder(Antares::Data::Study&); //! Destructor - ~CBuilder(); + ~CBuilder() = default; //@} /*! @@ -262,7 +262,7 @@ class CBuilder final { auto linkIT = std::find_if(pLink.begin(), pLink.end(), - [&u, &v](const linkInfo* edgeP) -> bool + [&u, &v](std::shared_ptr edgeP) -> bool { if (edgeP->ptr->from->id == u && edgeP->ptr->with->id == v) { @@ -279,7 +279,7 @@ class CBuilder final }); if (linkIT != pLink.end()) { - return *linkIT; + return linkIT->get(); } return nullptr; @@ -294,11 +294,11 @@ class CBuilder final auto a = area.second; std::for_each(pLink.begin(), pLink.end(), - [&a, this](linkInfo* edgeP) + [&a, this](std::shared_ptr edgeP) { if (edgeP->ptr->from == a || edgeP->ptr->with == a) { - this->areaToLinks[a].insert(edgeP); + this->areaToLinks[a].insert(edgeP.get()); } }); } @@ -308,7 +308,7 @@ class CBuilder final { if (i < pLink.size()) { - return pLink[i]; + return pLink[i].get(); } return nullptr; } @@ -418,7 +418,7 @@ class CBuilder final const double& secondMember); public: - Vector pLink; + std::vector> pLink; private: std::string pPrefix; diff --git a/src/solver/constraints-builder/include/antares/solver/constraints-builder/grid.h b/src/solver/constraints-builder/include/antares/solver/constraints-builder/grid.h index 3f69322359..a29f27eee8 100644 --- a/src/solver/constraints-builder/include/antares/solver/constraints-builder/grid.h +++ b/src/solver/constraints-builder/include/antares/solver/constraints-builder/grid.h @@ -28,10 +28,6 @@ #include -// #include -// #include -// #include - namespace Antares { namespace Graph diff --git a/src/solver/constraints-builder/load.cpp b/src/solver/constraints-builder/load.cpp index 22d8632cda..73beec49c1 100644 --- a/src/solver/constraints-builder/load.cpp +++ b/src/solver/constraints-builder/load.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include #include @@ -43,18 +43,18 @@ bool CBuilder::completeFromStudy() { // for all links of the study // check if it has been enabled in the INI File - linkInfo* k = findLinkInfoFromNodeNames(j->second->from->id, j->second->with->id); + auto k = findLinkInfoFromNodeNames(j->second->from->id, j->second->with->id); if (!k) { - k = new linkInfo(); + auto infos = std::make_shared(); logs.info() << "Read data (link " << nCount++ << ")"; // if Yes, complete the linkInfo // load the pointer - k->ptr = j->second; - k->type = k->ptr->assetType; + infos->ptr = j->second; + infos->type = infos->ptr->assetType; - pLink.push_back(k); + pLink.push_back(infos); } } } diff --git a/src/solver/expressions/CMakeLists.txt b/src/solver/expressions/CMakeLists.txt new file mode 100644 index 0000000000..6ef342a633 --- /dev/null +++ b/src/solver/expressions/CMakeLists.txt @@ -0,0 +1,83 @@ +project(Expressions) + + +set(SRC_Expressions + nodes/PortFieldNode.cpp + nodes/ComponentNode.cpp + nodes/BinaryNode.cpp + nodes/UnaryNode.cpp + + visitors/CloneVisitor.cpp + visitors/CompareVisitor.cpp + visitors/EvalVisitor.cpp + visitors/EvaluationContext.cpp + visitors/LinearityVisitor.cpp + visitors/TimeIndexVisitor.cpp + visitors/PrintVisitor.cpp + visitors/SubstitutionVisitor.cpp + visitors/InvalidNode.cpp + + include/antares/solver/expressions/nodes/AddNode.h + include/antares/solver/expressions/nodes/BinaryNode.h + include/antares/solver/expressions/nodes/ComparisonNode.h + include/antares/solver/expressions/nodes/ComponentNode.h + include/antares/solver/expressions/nodes/DivisionNode.h + include/antares/solver/expressions/nodes/EqualNode.h + include/antares/solver/expressions/nodes/ExpressionsNodes.h + include/antares/solver/expressions/nodes/GreaterThanOrEqualNode.h + include/antares/solver/expressions/nodes/Leaf.h + include/antares/solver/expressions/nodes/LessThanOrEqualNode.h + include/antares/solver/expressions/nodes/LiteralNode.h + include/antares/solver/expressions/nodes/MultiplicationNode.h + include/antares/solver/expressions/nodes/NegationNode.h + include/antares/solver/expressions/nodes/Node.h + include/antares/solver/expressions/nodes/NodesForwardDeclaration.h + include/antares/solver/expressions/nodes/ParameterNode.h + include/antares/solver/expressions/nodes/PortFieldNode.h + include/antares/solver/expressions/nodes/SubtractionNode.h + include/antares/solver/expressions/nodes/UnaryNode.h + include/antares/solver/expressions/nodes/VariableNode.h + + include/antares/solver/expressions/visitors/CloneVisitor.h + include/antares/solver/expressions/visitors/CompareVisitor.h + include/antares/solver/expressions/visitors/EvalVisitor.h + include/antares/solver/expressions/visitors/EvaluationContext.h + include/antares/solver/expressions/visitors/LinearStatus.h + include/antares/solver/expressions/visitors/LinearityVisitor.h + include/antares/solver/expressions/visitors/NodeVisitor.h + include/antares/solver/expressions/visitors/PrintVisitor.h + include/antares/solver/expressions/visitors/TimeIndexVisitor.h + include/antares/solver/expressions/visitors/TimeIndex.h + include/antares/solver/expressions/visitors/SubstitutionVisitor.h + include/antares/solver/expressions/visitors/InvalidNode.h + + include/antares/solver/expressions/Registry.hxx + include/antares/solver/expressions/IName.h +) + +source_group("expressions" FILES ${SRC_Expressions}) +add_library(antares-solver-expressions + ${SRC_Expressions}) + +target_include_directories(antares-solver-expressions + PUBLIC + $ +) +target_link_libraries(antares-solver-expressions + PUBLIC + Antares::logs + ) + + + +add_library(antares-solver-expressions-iterators + iterators/pre-order.cpp + include/antares/solver/expressions/iterators/pre-order.h +) + +target_link_libraries(antares-solver-expressions-iterators PRIVATE antares-solver-expressions) + +install(DIRECTORY include/antares + DESTINATION "include" +) + diff --git a/src/solver/main/economy.cpp b/src/solver/expressions/include/antares/solver/expressions/IName.h similarity index 54% rename from src/solver/main/economy.cpp rename to src/solver/expressions/include/antares/solver/expressions/IName.h index f4fc8ba907..237fe6d567 100644 --- a/src/solver/main/economy.cpp +++ b/src/solver/expressions/include/antares/solver/expressions/IName.h @@ -18,30 +18,16 @@ ** You should have received a copy of the Mozilla Public Licence 2.0 ** along with Antares_Simulator. If not, see . */ - -#include "antares/solver/simulation/economy.h" - -#include -#include -#include "antares/application/application.h" -#include "antares/solver/simulation/solver.h" +#pragma once +#include namespace Antares::Solver { -void Application::runSimulationInEconomicMode() +class IName { - // Type of the simulation - typedef Solver::Simulation::ISimulation SimulationType; - SimulationType simulation(*pStudy, pSettings, pDurationCollector, *resultWriter); - simulation.checkWriter(); - simulation.run(); - - if (!(pSettings.noOutput || pSettings.tsGeneratorsOnly)) - { - pDurationCollector("synthesis_export") - << [&simulation] { simulation.writeResults(/*synthesis:*/ true); }; - - this->pOptimizationInfo = simulation.getOptimizationInfo(); - } -} +public: + virtual ~IName() = default; + virtual std::string name() const = 0; + bool operator==(const IName& other) const = default; +}; } // namespace Antares::Solver diff --git a/src/solver/expressions/include/antares/solver/expressions/Registry.hxx b/src/solver/expressions/include/antares/solver/expressions/Registry.hxx new file mode 100644 index 0000000000..2ccc9ff8fd --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/Registry.hxx @@ -0,0 +1,53 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include +#include +#include +#include + +namespace Antares::Solver +{ +// Template class to manage the memory allocation and registry for a base class +template +class Registry +{ +public: + // Method to create a new derived class object and add it to the registry + template + requires std::derived_from + Derived* create(Args&&... args) + { + auto created = std::make_unique(std::forward(args)...); + + std::lock_guard lock(mutex_); + registry_.push_back(std::move(created)); + return dynamic_cast( + registry_.back().get()); // Return the pointer to the newly created object + } + +private: + std::vector> + registry_; // Registry to manage dynamically allocated objects + std::mutex mutex_; +}; +} // namespace Antares::Solver diff --git a/src/solver/expressions/include/antares/solver/expressions/iterators/pre-order.h b/src/solver/expressions/include/antares/solver/expressions/iterators/pre-order.h new file mode 100644 index 0000000000..a3beb9efcc --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/iterators/pre-order.h @@ -0,0 +1,58 @@ +#pragma once + +#include +#include + +namespace Antares::Solver::Nodes +{ +// Forward-declaration is enough + +class Node; + +// PreOrder Iterator for AST +class ASTPreOrderIterator +{ + std::stack nodeStack; + +public: + // Iterator type aliases + using iterator_category = std::forward_iterator_tag; + using value_type = Node; + using difference_type = std::ptrdiff_t; + using pointer = Node*; + using reference = Node&; + + // Constructor + explicit ASTPreOrderIterator(Node* root = nullptr); + + // Dereference operator + reference operator*() const; + + // Pointer access operator + pointer operator->() const; + + // Increment operator (pre-order traversal) + ASTPreOrderIterator& operator++(); + + // Equality comparison + bool operator==(const ASTPreOrderIterator& other) const; + + // Inequality comparison + bool operator!=(const ASTPreOrderIterator& other) const; +}; + +// AST container class to expose begin/end iterators +class AST +{ + Node* root; + +public: + explicit AST(Node* rootNode); + + // Begin iterator + ASTPreOrderIterator begin(); + + // End iterator (indicating traversal is complete) + ASTPreOrderIterator end(); +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/AddNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/AddNode.h new file mode 100644 index 0000000000..ea0e251607 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/AddNode.h @@ -0,0 +1,37 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +class AddNode: public BinaryNode +{ +public: + using BinaryNode::BinaryNode; + + std::string name() const override + { + return "AddNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/BinaryNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/BinaryNode.h new file mode 100644 index 0000000000..1ce7e05bd1 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/BinaryNode.h @@ -0,0 +1,64 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +class BinaryNode: public Node +{ +public: + /** + * @brief Constructs a binary node with the specified left and right operands. + * + * @param left The left operand. + * @param right The right operand. + * @note BinaryNode(n1, n2) and BinaryNode(n2, n1) are not equivalent. + */ + explicit BinaryNode(Node* left, Node* right); + + /** + * @brief Retrieves a pointer to the left operand. + * + * @return A pointer to the left operand. + */ + Node* left() const; + + /** + * @brief Retrieves a pointer to the right operand. + * + * @return A pointer to the right operand. + */ + Node* right() const; + +private: + /** + * @brief A pointer to the left operand. + */ + Node* leftOperand_ = nullptr; + + /** + * @brief A pointer to the right operand. + */ + Node* rightOperand_ = nullptr; +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/ComparisonNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/ComparisonNode.h new file mode 100644 index 0000000000..7fd6ac9cb2 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/ComparisonNode.h @@ -0,0 +1,35 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a comparison node in a syntax tree. + */ +class ComparisonNode: public BinaryNode +{ +public: + using BinaryNode::BinaryNode; +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/ComponentNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/ComponentNode.h new file mode 100644 index 0000000000..50e25439a8 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/ComponentNode.h @@ -0,0 +1,89 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once +#include + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a component node in a syntax tree. + */ +class ComponentNode: public Node +{ +public: + /** + * @brief Constructs a component node with the specified ID and name. + * + * @param component_id The component ID. + * @param component_name The component name. + */ + explicit ComponentNode(const std::string& component_id, const std::string& component_name); + /** + * @brief Retrieves the component ID. + * + * @return The component ID. + */ + const std::string& getComponentId() const; + + /** + * @brief Retrieves the component name. + * + * @return The component name. + */ + const std::string& getComponentName() const; + + bool operator==(const ComponentNode& other) const = default; + +private: + std::string component_id_; + std::string component_name_; +}; + +/** + * @brief Represents a component variable node in a syntax tree. + */ +class ComponentVariableNode: public ComponentNode +{ +public: + using ComponentNode::ComponentNode; + + std::string name() const override + { + return "ComponentVariableNode"; + } +}; + +/** + * @brief Represents a component parameter node in a syntax tree. + */ +class ComponentParameterNode: public ComponentNode +{ +public: + using ComponentNode::ComponentNode; + + std::string name() const override + { + return "ComponentParameterNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/DivisionNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/DivisionNode.h new file mode 100644 index 0000000000..989324756e --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/DivisionNode.h @@ -0,0 +1,40 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a division node in a syntax tree. + */ +class DivisionNode: public BinaryNode +{ +public: + using BinaryNode::BinaryNode; + + std::string name() const override + { + return "DivisionNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/EqualNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/EqualNode.h new file mode 100644 index 0000000000..75eb2e43a5 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/EqualNode.h @@ -0,0 +1,40 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents an equality comparison node in a syntax tree. + */ +class EqualNode: public ComparisonNode +{ +public: + using ComparisonNode::ComparisonNode; + + std::string name() const override + { + return "EqualNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h b/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h new file mode 100644 index 0000000000..2ecf1fe001 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/ExpressionsNodes.h @@ -0,0 +1,35 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/GreaterThanOrEqualNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/GreaterThanOrEqualNode.h new file mode 100644 index 0000000000..bee2c16413 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/GreaterThanOrEqualNode.h @@ -0,0 +1,40 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a greater than or equal comparison node in a syntax tree. + */ +class GreaterThanOrEqualNode: public ComparisonNode +{ +public: + using ComparisonNode::ComparisonNode; + + std::string name() const override + { + return "GreaterThanOrEqualNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/Leaf.h b/src/solver/expressions/include/antares/solver/expressions/nodes/Leaf.h new file mode 100644 index 0000000000..c971be8fb4 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/Leaf.h @@ -0,0 +1,63 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a leaf node in a syntax tree. + * + * @tparam T The type of the value stored in the leaf node. + */ +template +class Leaf: public Node +{ +public: + /** + * @brief Constructs a leaf node with the specified value. + * + * @param value The value to store in the leaf node. + */ + explicit Leaf(const T& value): + value_(value) + { + } + + /** + * @brief Retrieves the value stored in the leaf node. + * + * @return The value stored in the leaf node. + */ + T value() const + { + return value_; + } + +private: + /** + * @brief The value stored in the leaf node. + */ + T value_; +}; + +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/LessThanOrEqualNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/LessThanOrEqualNode.h new file mode 100644 index 0000000000..25cc479529 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/LessThanOrEqualNode.h @@ -0,0 +1,40 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a less than or equal comparison node in a syntax tree. + */ +class LessThanOrEqualNode: public ComparisonNode +{ +public: + using ComparisonNode::ComparisonNode; + + std::string name() const override + { + return "LessThanOrEqualNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/LiteralNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/LiteralNode.h new file mode 100644 index 0000000000..f875b754b9 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/LiteralNode.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a literal node in a syntax tree, storing a double value. + */ +class LiteralNode: public Leaf +{ +public: + using Leaf::Leaf; + + std::string name() const override + { + return "LiteralNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/MultiplicationNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/MultiplicationNode.h new file mode 100644 index 0000000000..4b6e877dd0 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/MultiplicationNode.h @@ -0,0 +1,40 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a multiplication node in a syntax tree. + */ +class MultiplicationNode: public BinaryNode +{ +public: + using BinaryNode::BinaryNode; + + std::string name() const override + { + return "MultiplicationNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/NegationNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/NegationNode.h new file mode 100644 index 0000000000..d8eec04a24 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/NegationNode.h @@ -0,0 +1,40 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a negation node in a syntax tree. + */ +class NegationNode final: public UnaryNode +{ +public: + using UnaryNode::UnaryNode; + + std::string name() const override + { + return "NegationNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/Node.h b/src/solver/expressions/include/antares/solver/expressions/nodes/Node.h new file mode 100644 index 0000000000..410a1cd7e6 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/Node.h @@ -0,0 +1,34 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Base class for nodes in a syntax tree. + */ +class Node: public IName +{ +public: + virtual ~Node() = default; +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h b/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h new file mode 100644 index 0000000000..bc1b44b2a1 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/NodesForwardDeclaration.h @@ -0,0 +1,41 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +namespace Antares::Solver::Nodes +{ +class Node; +class AddNode; +class SubtractionNode; +class MultiplicationNode; +class DivisionNode; +class EqualNode; +class LessThanOrEqualNode; +class GreaterThanOrEqualNode; +class NegationNode; +class LiteralNode; +class ComponentNode; +class ComponentVariableNode; +class ComponentParameterNode; +class ParameterNode; +class VariableNode; +class PortFieldNode; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/ParameterNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/ParameterNode.h new file mode 100644 index 0000000000..45f97bccf8 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/ParameterNode.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a parameter node in a syntax tree, storing a string value. + */ +class ParameterNode final: public Leaf +{ +public: + using Leaf::Leaf; + + std::string name() const override + { + return "ParameterNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldNode.h new file mode 100644 index 0000000000..32895d3be5 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/PortFieldNode.h @@ -0,0 +1,67 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once +#include + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a port field node in a syntax tree. + */ +class PortFieldNode: public Node +{ +public: + /** + * @brief Constructs a port field node with the specified port and field names. + * + * @param port_name The port name. + * @param field_name The field name. + */ + explicit PortFieldNode(const std::string& port_name, const std::string& field_name); + + /** + * @brief Retrieves the port name. + * + * @return The port name. + */ + const std::string& getPortName() const; + + /** + * @brief Retrieves the field name. + * + * @return The field name. + */ + const std::string& getFieldName() const; + + bool operator==(const PortFieldNode& other) const = default; + + std::string name() const override + { + return "PortFieldNode"; + } + +private: + std::string port_name_; + std::string field_name_; +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/SubtractionNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/SubtractionNode.h new file mode 100644 index 0000000000..822bf2620c --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/SubtractionNode.h @@ -0,0 +1,40 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a subtraction node in a syntax tree. + */ +class SubtractionNode: public BinaryNode +{ +public: + using BinaryNode::BinaryNode; + + std::string name() const override + { + return "SubtractionNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/UnaryNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/UnaryNode.h new file mode 100644 index 0000000000..c02969554e --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/UnaryNode.h @@ -0,0 +1,52 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +namespace Antares::Solver::Nodes +{ +/** + * @brief Represents a unary node in a syntax tree. + */ +class UnaryNode: public Node +{ +public: + /** + * @brief Constructs a unary node with the specified child. + * + * @param child The child node. + */ + explicit UnaryNode(Node* child); + /** + * @brief Retrieves a pointer to the child node. + * + * @return A pointer to the child node. + */ + Node* child() const; + +private: + /** + * @brief A pointer to the child node. + */ + Node* child_ = nullptr; +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/nodes/VariableNode.h b/src/solver/expressions/include/antares/solver/expressions/nodes/VariableNode.h new file mode 100644 index 0000000000..cc29ad9016 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/nodes/VariableNode.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include + +namespace Antares::Solver::Nodes +{ + +/** + * @brief Represents a variable node in a syntax tree, storing a string value. + */ +class VariableNode final: public Leaf +{ +public: + using Leaf::Leaf; + + std::string name() const override + { + return "VariableNode"; + } +}; +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h new file mode 100644 index 0000000000..caafab8df0 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/CloneVisitor.h @@ -0,0 +1,60 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include +#include "antares/solver/expressions/visitors/NodeVisitor.h" + +namespace Antares::Solver::Visitors +{ +/** + * @brief Represents a visitor for cloning nodes in a syntax tree. + */ +class CloneVisitor: public NodeVisitor +{ +public: + /** + * @brief Constructs a clone visitor with the specified registry for creating new nodes. + * + * @param registry The registry used for creating new nodes. + */ + explicit CloneVisitor(Registry& registry); + std::string name() const override; + + Nodes::Node* visit(const Nodes::AddNode* node) override; + Nodes::Node* visit(const Nodes::SubtractionNode* node) override; + Nodes::Node* visit(const Nodes::MultiplicationNode* node) override; + Nodes::Node* visit(const Nodes::DivisionNode* node) override; + Nodes::Node* visit(const Nodes::EqualNode* node) override; + Nodes::Node* visit(const Nodes::LessThanOrEqualNode* node) override; + Nodes::Node* visit(const Nodes::GreaterThanOrEqualNode* node) override; + Nodes::Node* visit(const Nodes::NegationNode* node) override; + Nodes::Node* visit(const Nodes::VariableNode* node) override; + Nodes::Node* visit(const Nodes::ParameterNode* node) override; + Nodes::Node* visit(const Nodes::LiteralNode* node) override; + Nodes::Node* visit(const Nodes::PortFieldNode* node) override; + Nodes::Node* visit(const Nodes::ComponentVariableNode* node) override; + Nodes::Node* visit(const Nodes::ComponentParameterNode* node) override; + +private: + Registry& registry_; +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h new file mode 100644 index 0000000000..579eb8c2ed --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/CompareVisitor.h @@ -0,0 +1,54 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include +#include "antares/solver/expressions/visitors/NodeVisitor.h" + +namespace Antares::Solver::Visitors +{ +/** + * @brief Represents a visitor for comparing nodes in a syntax tree. + */ +class CompareVisitor: public NodeVisitor +{ +public: + CompareVisitor() = default; + std::string name() const override; + + bool visit(const Nodes::AddNode* add, const Nodes::Node* other) override; + bool visit(const Nodes::SubtractionNode* add, const Nodes::Node* other) override; + bool visit(const Nodes::MultiplicationNode* add, const Nodes::Node* other) override; + bool visit(const Nodes::DivisionNode* add, const Nodes::Node* other) override; + bool visit(const Nodes::EqualNode* add, const Nodes::Node* other) override; + bool visit(const Nodes::LessThanOrEqualNode* add, const Nodes::Node* other) override; + bool visit(const Nodes::GreaterThanOrEqualNode* add, const Nodes::Node* other) override; + bool visit(const Nodes::NegationNode* neg, const Nodes::Node* other) override; + bool visit(const Nodes::VariableNode* param, const Nodes::Node* other) override; + bool visit(const Nodes::ParameterNode* param, const Nodes::Node* other) override; + bool visit(const Nodes::LiteralNode* param, const Nodes::Node* other) override; + bool visit(const Nodes::PortFieldNode* port_field_node, const Nodes::Node* other) override; + bool visit(const Nodes::ComponentVariableNode* component_node, + const Nodes::Node* other) override; + bool visit(const Nodes::ComponentParameterNode* component_node, + const Nodes::Node* other) override; +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h new file mode 100644 index 0000000000..0ec4ae6612 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/EvalVisitor.h @@ -0,0 +1,77 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include +#include "antares/solver/expressions/visitors/NodeVisitor.h" + +namespace Antares::Solver::Visitors +{ + +class EvalVisitorDivisionException: public std::runtime_error +{ +public: + EvalVisitorDivisionException(double left, double right, const std::string& message); +}; + +class EvalVisitorNotImplemented: public std::invalid_argument +{ +public: + EvalVisitorNotImplemented(const std::string& visitor, const std::string& node); +}; + +/** + * @brief Represents a visitor for evaluating expressions within a given context. + */ +class EvalVisitor: public NodeVisitor +{ +public: + /** + * @brief Default constructor, creates an evaluation visitor with no context. + */ + EvalVisitor() = default; // No context (variables / parameters) + + /** + * @brief Constructs an evaluation visitor with the specified context. + * + * @param context The evaluation context. + */ + explicit EvalVisitor(EvaluationContext context); + std::string name() const override; + +private: + const EvaluationContext context_; + double visit(const Nodes::AddNode* node) override; + double visit(const Nodes::SubtractionNode* node) override; + double visit(const Nodes::MultiplicationNode* node) override; + double visit(const Nodes::DivisionNode* node) override; + double visit(const Nodes::EqualNode* node) override; + double visit(const Nodes::LessThanOrEqualNode* node) override; + double visit(const Nodes::GreaterThanOrEqualNode* node) override; + double visit(const Nodes::NegationNode* node) override; + double visit(const Nodes::VariableNode* node) override; + double visit(const Nodes::ParameterNode* node) override; + double visit(const Nodes::LiteralNode* node) override; + double visit(const Nodes::PortFieldNode* node) override; + double visit(const Nodes::ComponentVariableNode* node) override; + double visit(const Nodes::ComponentParameterNode* node) override; +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/EvaluationContext.h b/src/solver/expressions/include/antares/solver/expressions/visitors/EvaluationContext.h new file mode 100644 index 0000000000..7e985eb248 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/EvaluationContext.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +namespace Antares::Solver::Visitors +{ +/** + * @brief Represents the context for evaluating expressions. + * + * Stores and provides access to parameter and variable values. + */ +class EvaluationContext +{ +public: + /** + * @brief Default constructor, creates an evaluation context without parameter and variable + * values. + */ + EvaluationContext() = default; + /** + * @brief Constructs an evaluation context with the specified parameter and variable + * values. + * + * @param parameters parameter values. + * @param variables variable values. + */ + explicit EvaluationContext(std::map parameters, + std::map variables); + + /** + * @brief Retrieves the value of a variable. + * + * @param name The name of the variable. + * @return The value of the variable. + * @throws std::out_of_range If the variable is not found. + */ + double getVariableValue(const std::string& key) const; + + /** + * @brief Retrieves the value of a parameter. + * + * @param name The name of the parameter. + * @return The value of the parameter. + * @throws std::out_of_range If the parameter is not found. + */ + double getParameterValue(const std::string& key) const; + +private: + /** + * @brief A map storing parameter values. + */ + std::map parameters_; + + /** + * @brief A map storing variable values. + */ + std::map variables_; +}; + +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/InvalidNode.h b/src/solver/expressions/include/antares/solver/expressions/visitors/InvalidNode.h new file mode 100644 index 0000000000..9edbca3203 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/InvalidNode.h @@ -0,0 +1,32 @@ + +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once +#include + +namespace Antares::Solver::Visitors +{ +class InvalidNode: public std::invalid_argument +{ +public: + explicit InvalidNode(const std::string& node_name = ""); +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/LinearStatus.h b/src/solver/expressions/include/antares/solver/expressions/visitors/LinearStatus.h new file mode 100644 index 0000000000..590bedbcf9 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/LinearStatus.h @@ -0,0 +1,178 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +namespace Antares::Solver::Visitors +{ +/** + * @brief Represents the linearity of a node. + */ +enum class LinearStatus : char +{ + CONSTANT = 0, + LINEAR = 1, + NON_LINEAR = 2 +}; + +/** + * @brief Combines two LinearStatus values into a single character. + * + * @param a The first LinearStatus value. + * @param b The second LinearStatus value. + * + * @return The combined LinearStatus value as a character. + */ +constexpr char pair(LinearStatus a, LinearStatus b) +{ + return static_cast(a) << 4 | static_cast(b); +} + +/** + * @brief Multiplies two LinearStatus values. + * + * @param a The first LinearStatus value. + * @param b The second LinearStatus value. + * + * @return The resulting LinearStatus value based on the multiplication of a and b. + */ +constexpr LinearStatus operator*(LinearStatus a, LinearStatus b) +{ + switch (pair(a, b)) + { + case pair(LinearStatus::CONSTANT, LinearStatus::CONSTANT): + return LinearStatus::CONSTANT; + case pair(LinearStatus::CONSTANT, LinearStatus::LINEAR): + return LinearStatus::LINEAR; + case pair(LinearStatus::CONSTANT, LinearStatus::NON_LINEAR): + return LinearStatus::NON_LINEAR; + + case pair(LinearStatus::LINEAR, LinearStatus::CONSTANT): + return LinearStatus::LINEAR; + case pair(LinearStatus::LINEAR, LinearStatus::LINEAR): + case pair(LinearStatus::LINEAR, LinearStatus::NON_LINEAR): + return LinearStatus::NON_LINEAR; + + case pair(LinearStatus::NON_LINEAR, LinearStatus::CONSTANT): + case pair(LinearStatus::NON_LINEAR, LinearStatus::LINEAR): + case pair(LinearStatus::NON_LINEAR, LinearStatus::NON_LINEAR): + return LinearStatus::NON_LINEAR; + + default: + return LinearStatus::NON_LINEAR; + } +} + +/** + * @brief Divides two LinearStatus values. + * + * @param a The first LinearStatus value. + * @param b The second LinearStatus value. + * + * @return The resulting LinearStatus value based on the division of a and b. + */ +constexpr LinearStatus operator/(LinearStatus a, LinearStatus b) +{ + switch (pair(a, b)) + { + case pair(LinearStatus::CONSTANT, LinearStatus::CONSTANT): + return LinearStatus::CONSTANT; + case pair(LinearStatus::CONSTANT, LinearStatus::LINEAR): + return LinearStatus::NON_LINEAR; + case pair(LinearStatus::CONSTANT, LinearStatus::NON_LINEAR): + return LinearStatus::NON_LINEAR; + + case pair(LinearStatus::LINEAR, LinearStatus::CONSTANT): + return LinearStatus::LINEAR; + case pair(LinearStatus::LINEAR, LinearStatus::LINEAR): + case pair(LinearStatus::LINEAR, LinearStatus::NON_LINEAR): + return LinearStatus::NON_LINEAR; + + case pair(LinearStatus::NON_LINEAR, LinearStatus::CONSTANT): + case pair(LinearStatus::NON_LINEAR, LinearStatus::LINEAR): + case pair(LinearStatus::NON_LINEAR, LinearStatus::NON_LINEAR): + return LinearStatus::NON_LINEAR; + + default: + return LinearStatus::NON_LINEAR; + } +} + +/** + * @brief Add two LinearStatus values. + * + * @param a The first LinearStatus value. + * @param b The second LinearStatus value. + * + * @return The resulting LinearStatus value based on the addition of a and b. + */ +constexpr LinearStatus operator+(LinearStatus a, LinearStatus b) +{ + switch (pair(a, b)) + { + case pair(LinearStatus::CONSTANT, LinearStatus::CONSTANT): + return LinearStatus::CONSTANT; + case pair(LinearStatus::CONSTANT, LinearStatus::LINEAR): + return LinearStatus::LINEAR; + case pair(LinearStatus::CONSTANT, LinearStatus::NON_LINEAR): + return LinearStatus::NON_LINEAR; + + case pair(LinearStatus::LINEAR, LinearStatus::CONSTANT): + return LinearStatus::LINEAR; + case pair(LinearStatus::LINEAR, LinearStatus::LINEAR): + return LinearStatus::LINEAR; + case pair(LinearStatus::LINEAR, LinearStatus::NON_LINEAR): + return LinearStatus::NON_LINEAR; + + case pair(LinearStatus::NON_LINEAR, LinearStatus::CONSTANT): + case pair(LinearStatus::NON_LINEAR, LinearStatus::LINEAR): + case pair(LinearStatus::NON_LINEAR, LinearStatus::NON_LINEAR): + return LinearStatus::NON_LINEAR; + + default: + return LinearStatus::NON_LINEAR; + } +} + +/** + * @brief Subtracts two LinearStatus values. + * + * @param a The first LinearStatus value. + * @param b The second LinearStatus value. + * + * @return The resulting LinearStatus value based on the subtraction of a and b. + */ +constexpr LinearStatus operator-(LinearStatus a, LinearStatus b) +{ + return operator+(a, b); +} + +/** + * @brief Negates a LinearStatus value (no effect). + * + * @param a The LinearStatus value to negate. + * + * @return The unchanged LinearStatus value. + */ +constexpr LinearStatus operator-(LinearStatus a) +{ + return a; +} +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h new file mode 100644 index 0000000000..2db78786a9 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/LinearityVisitor.h @@ -0,0 +1,52 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include "antares/solver/expressions/visitors/LinearStatus.h" +#include "antares/solver/expressions/visitors/NodeVisitor.h" + +namespace Antares::Solver::Visitors +{ +/** + * @brief Represents a visitor for determining the linearity of nodes (expression). + */ +class LinearityVisitor: public NodeVisitor +{ +public: + std::string name() const override; + +private: + LinearStatus visit(const Nodes::AddNode* add) override; + LinearStatus visit(const Nodes::SubtractionNode* add) override; + LinearStatus visit(const Nodes::MultiplicationNode* add) override; + LinearStatus visit(const Nodes::DivisionNode* add) override; + LinearStatus visit(const Nodes::EqualNode* add) override; + LinearStatus visit(const Nodes::LessThanOrEqualNode* add) override; + LinearStatus visit(const Nodes::GreaterThanOrEqualNode* add) override; + LinearStatus visit(const Nodes::NegationNode* neg) override; + LinearStatus visit(const Nodes::VariableNode* param) override; + LinearStatus visit(const Nodes::ParameterNode* param) override; + LinearStatus visit(const Nodes::LiteralNode* lit) override; + LinearStatus visit(const Nodes::PortFieldNode* port_field_node) override; + LinearStatus visit(const Nodes::ComponentVariableNode* component_variable_node) override; + LinearStatus visit(const Nodes::ComponentParameterNode* component_parameter_node) override; +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h new file mode 100644 index 0000000000..218987fa76 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/NodeVisitor.h @@ -0,0 +1,262 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace Antares::Solver::Visitors +{ + +template +RetT tryVisit(const Nodes::Node* node, VisitorT& visitor, Args... args) +{ + auto* x = dynamic_cast(node); + return visitor.visit(x, args...); +} + +template +class NodeVisitor; + +template +struct NodeVisitsProvider +{ + using FunctionT = R (*)(const Nodes::Node*, NodeVisitor&, Args... args); + + /** + * Creates a map associating node types with corresponding visitor functions. + * + * @tparam NodeTypes A variadic pack of node types to be included in the map. + * @return An `std::unordered_map` containing the associations between node types and their + * corresponding visitor functions. + */ + template + static auto NodesVisitList() + { + std::unordered_map nodeDispatchFunctions; + ( + [&nodeDispatchFunctions] { + nodeDispatchFunctions[typeid(NodeTypes)] = &tryVisit, + NodeTypes>; + }(), + ...); + return nodeDispatchFunctions; + } +}; + +template +class NodeVisitor: public IName +{ +public: + virtual ~NodeVisitor() = default; + + /** + * Dispatches a node to an appropriate visitor function based on its type. + * + * This method uses a map that associates node types + * with their corresponding visitor functions. It attempts to find the visitor function + * for the provided `node`. If a match is found, the corresponding + * visitor function is called with the node, and any + * additional arguments (`args...`). + * + * @param node A pointer to the Node object to be visited. + * @param args Variadic template arguments to be passed to the visitor functions. + * @return The return value of the visitor function. + * + */ + R dispatch(const Nodes::Node* node, Args... args) + { + if (!node) + { + throw InvalidNode(); + } + + const static auto nodeVisitList = NodeVisitsProvider::template NodesVisitList< + Nodes::AddNode, + Nodes::SubtractionNode, + Nodes::MultiplicationNode, + Nodes::DivisionNode, + Nodes::EqualNode, + Nodes::LessThanOrEqualNode, + Nodes::GreaterThanOrEqualNode, + Nodes::NegationNode, + Nodes::ParameterNode, + Nodes::VariableNode, + Nodes::LiteralNode, + Nodes::PortFieldNode, + Nodes::ComponentVariableNode, + Nodes::ComponentParameterNode>(); + + try + { + return nodeVisitList.at(typeid(*node))(node, *this, args...); + } + catch (std::exception&) + { + logs.error() << "Antares::Solver::Visitor: could not visit the node!"; + throw; + } + } + + /** + * @brief Visits an AddNode and processes its children. + * + * @param node A pointer to the AddNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the AddNode. + */ + virtual R visit(const Nodes::AddNode*, Args... args) = 0; + /** + * @brief Visits a SubtractionNode and processes its children. + * + * @param node A pointer to the SubtractionNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the SubtractionNode. + */ + virtual R visit(const Nodes::SubtractionNode*, Args... args) = 0; + /** + * @brief Visits a MultiplicationNode and processes its children. + * + * @param node A pointer to the MultiplicationNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the MultiplicationNode. + */ + virtual R visit(const Nodes::MultiplicationNode*, Args... args) = 0; + /** + * @brief Visits a DivisionNode and processes its children. + * + * @param node A pointer to the DivisionNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the DivisionNode. + */ + virtual R visit(const Nodes::DivisionNode*, Args... args) = 0; + /** + * @brief Visits an EqualNode and processes its children. + * + * @param node A pointer to the EqualNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the EqualNode. + */ + virtual R visit(const Nodes::EqualNode*, Args... args) = 0; + + /** + * @brief Visits a LessThanOrEqualNode and processes its children. + * + * @param node A pointer to the LessThanOrEqualNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the LessThanOrEqualNode. + */ + virtual R visit(const Nodes::LessThanOrEqualNode*, Args... args) = 0; + + /** + * @brief Visits a GreaterThanOrEqualNode and processes its children. + * + * @param node A pointer to the GreaterThanOrEqualNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the GreaterThanOrEqualNode. + */ + virtual R visit(const Nodes::GreaterThanOrEqualNode*, Args... args) = 0; + + /** + * @brief Visits a NegationNode and processes its child. + * + * @param node A pointer to the NegationNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the NegationNode. + */ + virtual R visit(const Nodes::NegationNode*, Args... args) = 0; + + /** + * @brief Visits a LiteralNode. + * + * @param node A pointer to the LiteralNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the LiteralNode. + */ + virtual R visit(const Nodes::LiteralNode*, Args... args) = 0; + + /** + * @brief Visits a VariableNode. + * + * @param node A pointer to the VariableNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the VariableNode. + */ + virtual R visit(const Nodes::VariableNode*, Args... args) = 0; + + /** + * @brief Visits a ParameterNode. + * + * @param node A pointer to the ParameterNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the ParameterNode. + */ + virtual R visit(const Nodes::ParameterNode*, Args... args) = 0; + + /** + * @brief Visits a PortFieldNode. + * + * @param node A pointer to the PortFieldNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the PortFieldNode. + */ + virtual R visit(const Nodes::PortFieldNode*, Args... args) = 0; + + /** + * @brief Visits a ComponentVariableNode. + * + * @param node A pointer to the ComponentVariableNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the ComponentVariableNode. + */ + virtual R visit(const Nodes::ComponentVariableNode*, Args... args) = 0; + + /** + * @brief Visits a ComponentParameterNode. + * + * @param node A pointer to the ComponentParameterNode to be visited. + * @param args Additional arguments to be passed to the visitor's methods. + * + * @return The result of processing the ComponentParameterNode. + */ + virtual R visit(const Nodes::ComponentParameterNode*, Args... args) = 0; +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h new file mode 100644 index 0000000000..abe19f8122 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/PrintVisitor.h @@ -0,0 +1,51 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include "antares/solver/expressions/visitors/NodeVisitor.h" + +namespace Antares::Solver::Visitors +{ +/** + * @brief Represents a visitor for printing nodes in a syntax tree as strings. + */ +class PrintVisitor: public NodeVisitor +{ +public: + std::string name() const override; + +private: + std::string visit(const Nodes::AddNode* node) override; + std::string visit(const Nodes::SubtractionNode* node) override; + std::string visit(const Nodes::MultiplicationNode* node) override; + std::string visit(const Nodes::DivisionNode* node) override; + std::string visit(const Nodes::EqualNode* node) override; + std::string visit(const Nodes::LessThanOrEqualNode* node) override; + std::string visit(const Nodes::GreaterThanOrEqualNode* node) override; + std::string visit(const Nodes::NegationNode* node) override; + std::string visit(const Nodes::VariableNode* node) override; + std::string visit(const Nodes::ParameterNode* node) override; + std::string visit(const Nodes::LiteralNode* node) override; + std::string visit(const Nodes::PortFieldNode* node) override; + std::string visit(const Nodes::ComponentVariableNode* node) override; + std::string visit(const Nodes::ComponentParameterNode* node) override; +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/SubstitutionVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/SubstitutionVisitor.h new file mode 100644 index 0000000000..14ea70de3c --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/SubstitutionVisitor.h @@ -0,0 +1,58 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include + +#include +#include +#include + +namespace Antares::Solver::Visitors +{ +/** + * @brief Represents the context for performing substitutions in a syntax tree. + */ +struct SubstitutionContext +{ + std::unordered_set variables; +}; + +/** + * @brief Represents a visitor for substituting component variables in a syntax tree. + * + * @param registry The registry used for creating new nodes. + * @param ctx The substitution context. + */ +class SubstitutionVisitor: public CloneVisitor +{ +public: + SubstitutionVisitor(Registry& registry, SubstitutionContext& ctx); + + SubstitutionContext& ctx_; + Registry& registry_; + std::string name() const override; + +private: + // Only override visit method for ComponentVariableNode, clone the rest + Nodes::Node* visit(const Nodes::ComponentVariableNode* node) override; +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndex.h b/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndex.h new file mode 100644 index 0000000000..06b561fc6c --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndex.h @@ -0,0 +1,57 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +namespace Antares::Solver::Visitors +{ +/** + * @brief Represents the time and scenario variation of a value. + */ +enum class TimeIndex : unsigned int +{ + CONSTANT_IN_TIME_AND_SCENARIO = 0, + VARYING_IN_TIME_ONLY = 1, + VARYING_IN_SCENARIO_ONLY = 2, + VARYING_IN_TIME_AND_SCENARIO = 3 +}; + +/** + * @brief Combines two TimeIndex values. + * + * @param left The left operand. + * @param right The right operand. + * + * @return The combined TimeIndex value. + */ +constexpr TimeIndex operator|(const TimeIndex& left, const TimeIndex& right) +{ + /* + 0 | x = x + 3 | x = 3 + 1 | 1 = 1 + 1 | 2 = 3 + 2 | 2 = 2 + */ + return static_cast(static_cast(left) + | static_cast(right)); +} + +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h b/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h new file mode 100644 index 0000000000..1b9c8ddd37 --- /dev/null +++ b/src/solver/expressions/include/antares/solver/expressions/visitors/TimeIndexVisitor.h @@ -0,0 +1,61 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include "antares/solver/expressions/visitors/NodeVisitor.h" +#include "antares/solver/expressions/visitors/TimeIndex.h" + +namespace Antares::Solver::Visitors +{ +/** + * @brief Represents a visitor for determining the time and scenario dependency of nodes in a syntax + * tree. + */ +class TimeIndexVisitor: public NodeVisitor +{ +public: + /** + * @brief Constructs a time index visitor with the specified context. + * + * @param context The context containing the time index for each node. + */ + explicit TimeIndexVisitor(std::unordered_map context); + + std::string name() const override; + +private: + std::unordered_map context_; + TimeIndex visit(const Nodes::AddNode* add) override; + TimeIndex visit(const Nodes::SubtractionNode* add) override; + TimeIndex visit(const Nodes::MultiplicationNode* add) override; + TimeIndex visit(const Nodes::DivisionNode* add) override; + TimeIndex visit(const Nodes::EqualNode* add) override; + TimeIndex visit(const Nodes::LessThanOrEqualNode* add) override; + TimeIndex visit(const Nodes::GreaterThanOrEqualNode* add) override; + TimeIndex visit(const Nodes::NegationNode* neg) override; + TimeIndex visit(const Nodes::VariableNode* param) override; + TimeIndex visit(const Nodes::ParameterNode* param) override; + TimeIndex visit(const Nodes::LiteralNode* lit) override; + TimeIndex visit(const Nodes::PortFieldNode* port_field_node) override; + TimeIndex visit(const Nodes::ComponentVariableNode* component_variable_node) override; + TimeIndex visit(const Nodes::ComponentParameterNode* component_parameter_node) override; +}; +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/iterators/pre-order.cpp b/src/solver/expressions/iterators/pre-order.cpp new file mode 100644 index 0000000000..5e8a968b31 --- /dev/null +++ b/src/solver/expressions/iterators/pre-order.cpp @@ -0,0 +1,103 @@ +#include + +#include +#include + +namespace Antares::Solver::Nodes +{ +namespace +{ +// Children, left to right +std::vector childrenLeftToRight(Node* node) +{ + if (auto* bin = dynamic_cast(node)) + { + return {bin->left(), bin->right()}; + } + else if (auto* unary = dynamic_cast(node)) + { + return {unary->child()}; + } + return {}; +} +} // namespace + +// Constructor +ASTPreOrderIterator::ASTPreOrderIterator(Node* root) +{ + if (root) + { + nodeStack.push(root); + } +} + +// Dereference operator +ASTPreOrderIterator::reference ASTPreOrderIterator::operator*() const +{ + return *nodeStack.top(); +} + +// Pointer access operator +ASTPreOrderIterator::pointer ASTPreOrderIterator::operator->() const +{ + return nodeStack.top(); +} + +// Increment operator (pre-order traversal) +ASTPreOrderIterator& ASTPreOrderIterator::operator++() +{ + if (nodeStack.empty()) + { + return *this; + } + + Node* current = nodeStack.top(); + nodeStack.pop(); + + const auto children = childrenLeftToRight(current); + // Push children in reverse order to process them in left-to-right order + for (auto* it: children | std::views::reverse) + { + nodeStack.push(it); + } + + return *this; +} + +// Equality comparison +bool ASTPreOrderIterator::operator==(const ASTPreOrderIterator& other) const +{ + if (nodeStack.empty() && other.nodeStack.empty()) + { + return true; + } + if (nodeStack.empty() || other.nodeStack.empty()) + { + return false; + } + return nodeStack.top() == other.nodeStack.top(); +} + +// Inequality comparison +bool ASTPreOrderIterator::operator!=(const ASTPreOrderIterator& other) const +{ + return !(*this == other); +} + +AST::AST(Node* rootNode): + root(rootNode) +{ +} + +// Begin iterator +ASTPreOrderIterator AST::begin() +{ + return ASTPreOrderIterator(root); +} + +// End iterator (indicating traversal is complete) +ASTPreOrderIterator AST::end() +{ + return ASTPreOrderIterator(nullptr); +} +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/nodes/BinaryNode.cpp b/src/solver/expressions/nodes/BinaryNode.cpp new file mode 100644 index 0000000000..31f22a7fc0 --- /dev/null +++ b/src/solver/expressions/nodes/BinaryNode.cpp @@ -0,0 +1,41 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#include + +namespace Antares::Solver::Nodes +{ +BinaryNode::BinaryNode(Node* left, Node* right): + leftOperand_(left), + rightOperand_(right) +{ +} + +Node* BinaryNode::right() const +{ + return rightOperand_; +} + +Node* BinaryNode::left() const +{ + return leftOperand_; +} + +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/nodes/ComponentNode.cpp b/src/solver/expressions/nodes/ComponentNode.cpp new file mode 100644 index 0000000000..4f72ffe940 --- /dev/null +++ b/src/solver/expressions/nodes/ComponentNode.cpp @@ -0,0 +1,40 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#include + +namespace Antares::Solver::Nodes +{ +ComponentNode::ComponentNode(const std::string& component_id, const std::string& component_name): + component_id_(component_id), + component_name_(component_name) +{ +} + +const std::string& ComponentNode::getComponentId() const +{ + return component_id_; +} + +const std::string& ComponentNode::getComponentName() const +{ + return component_name_; +} +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/nodes/PortFieldNode.cpp b/src/solver/expressions/nodes/PortFieldNode.cpp new file mode 100644 index 0000000000..2490977c6e --- /dev/null +++ b/src/solver/expressions/nodes/PortFieldNode.cpp @@ -0,0 +1,40 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#include + +namespace Antares::Solver::Nodes +{ +PortFieldNode::PortFieldNode(const std::string& port_name, const std::string& field_name): + port_name_(port_name), + field_name_(field_name) +{ +} + +const std::string& PortFieldNode::getPortName() const +{ + return port_name_; +} + +const std::string& PortFieldNode::getFieldName() const +{ + return field_name_; +} +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/nodes/UnaryNode.cpp b/src/solver/expressions/nodes/UnaryNode.cpp new file mode 100644 index 0000000000..c52b2d973b --- /dev/null +++ b/src/solver/expressions/nodes/UnaryNode.cpp @@ -0,0 +1,34 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#include + +namespace Antares::Solver::Nodes +{ +UnaryNode::UnaryNode(Node* n): + child_(n) +{ +} + +Node* UnaryNode::child() const +{ + return child_; +} +} // namespace Antares::Solver::Nodes diff --git a/src/solver/expressions/visitors/CloneVisitor.cpp b/src/solver/expressions/visitors/CloneVisitor.cpp new file mode 100644 index 0000000000..36c53084e4 --- /dev/null +++ b/src/solver/expressions/visitors/CloneVisitor.cpp @@ -0,0 +1,115 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#include +#include + +namespace Antares::Solver::Visitors +{ +CloneVisitor::CloneVisitor(Registry& registry): + registry_(registry) +{ +} + +Nodes::Node* CloneVisitor::visit(const Nodes::AddNode* node) +{ + return registry_.create(dispatch(node->left()), dispatch(node->right())); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::SubtractionNode* node) +{ + return registry_.create(dispatch(node->left()), + dispatch(node->right())); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::MultiplicationNode* node) +{ + return registry_.create(dispatch(node->left()), + dispatch(node->right())); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::DivisionNode* node) +{ + return registry_.create(dispatch(node->left()), dispatch(node->right())); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::EqualNode* node) +{ + return registry_.create(dispatch(node->left()), dispatch(node->right())); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::LessThanOrEqualNode* node) +{ + return registry_.create(dispatch(node->left()), + dispatch(node->right())); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::GreaterThanOrEqualNode* node) +{ + return registry_.create(dispatch(node->left()), + dispatch(node->right())); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::NegationNode* negationNode) +{ + return registry_.create(dispatch(negationNode->child())); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::VariableNode* variableNode) +{ + return registry_.create(variableNode->value()); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::ParameterNode* parameterNode) +{ + return registry_.create(parameterNode->value()); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::LiteralNode* literalNode) +{ + return registry_.create(literalNode->value()); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::PortFieldNode* port_field_node) +{ + return registry_.create(port_field_node->getPortName(), + port_field_node->getFieldName()); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::ComponentVariableNode* component_variable_node) +{ + return registry_.create( + component_variable_node->getComponentId(), + component_variable_node->getComponentName()); +} + +Nodes::Node* CloneVisitor::visit(const Nodes::ComponentParameterNode* component_parameter_node) +{ + return registry_.create( + component_parameter_node->getComponentId(), + component_parameter_node->getComponentName()); +} + +std::string CloneVisitor::name() const +{ + return "CloneVisitor"; +} + +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/CompareVisitor.cpp b/src/solver/expressions/visitors/CompareVisitor.cpp new file mode 100644 index 0000000000..c7fc5c71dc --- /dev/null +++ b/src/solver/expressions/visitors/CompareVisitor.cpp @@ -0,0 +1,137 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ +#include +#include + +template +static bool compareBinaryNode(V& visitor, const T* node, const Antares::Solver::Nodes::Node* other) +{ + if (const T* other_node = dynamic_cast(other)) + { + bool left = visitor.dispatch(node->left(), other_node->left()); + bool right = visitor.dispatch(node->right(), other_node->right()); + return left && right; + } + return false; +} + +template +static bool compareGetValue(const T* node, const Antares::Solver::Nodes::Node* other) +{ + if (const T* other_node = dynamic_cast(other)) + { + return node->value() == other_node->value(); + } + return false; +} + +template +static bool compareEqualOperator(const T* node, const Antares::Solver::Nodes::Node* other) +{ + if (const T* other_node = dynamic_cast(other)) + { + return *node == *other_node; + } + return false; +} + +namespace Antares::Solver::Visitors +{ +bool CompareVisitor::visit(const Nodes::AddNode* node, const Nodes::Node* other) +{ + return compareBinaryNode(*this, node, other); +} + +bool CompareVisitor::visit(const Nodes::SubtractionNode* node, const Nodes::Node* other) +{ + return compareBinaryNode(*this, node, other); +} + +bool CompareVisitor::visit(const Nodes::MultiplicationNode* node, const Nodes::Node* other) +{ + return compareBinaryNode(*this, node, other); +} + +bool CompareVisitor::visit(const Nodes::DivisionNode* node, const Nodes::Node* other) +{ + return compareBinaryNode(*this, node, other); +} + +bool CompareVisitor::visit(const Nodes::EqualNode* node, const Nodes::Node* other) +{ + return compareBinaryNode(*this, node, other); +} + +bool CompareVisitor::visit(const Nodes::LessThanOrEqualNode* node, const Nodes::Node* other) +{ + return compareBinaryNode(*this, node, other); +} + +bool CompareVisitor::visit(const Nodes::GreaterThanOrEqualNode* node, const Nodes::Node* other) +{ + return compareBinaryNode(*this, node, other); +} + +bool CompareVisitor::visit(const Nodes::NegationNode* node, const Nodes::Node* other) +{ + if (auto* other_node = dynamic_cast(other)) + { + return dispatch(node->child(), other_node->child()); + } + return false; +} + +bool CompareVisitor::visit(const Nodes::ParameterNode* node, const Nodes::Node* other) +{ + return compareGetValue(node, other); +} + +bool CompareVisitor::visit(const Nodes::LiteralNode* node, const Nodes::Node* other) +{ + return compareGetValue(node, other); +} + +bool CompareVisitor::visit(const Nodes::VariableNode* node, const Nodes::Node* other) +{ + return compareGetValue(node, other); +} + +bool CompareVisitor::visit(const Nodes::PortFieldNode* node, const Nodes::Node* other) +{ + return compareEqualOperator(node, other); +} + +bool CompareVisitor::visit(const Nodes::ComponentVariableNode* node, const Nodes::Node* other) +{ + return compareEqualOperator(node, other); +} + +bool CompareVisitor::visit(const Nodes::ComponentParameterNode* node, const Nodes::Node* other) +{ + return compareEqualOperator(node, other); +} + +std::string CompareVisitor::name() const +{ + return "CompareVisitor"; +} + +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/EvalVisitor.cpp b/src/solver/expressions/visitors/EvalVisitor.cpp new file mode 100644 index 0000000000..336376fd4e --- /dev/null +++ b/src/solver/expressions/visitors/EvalVisitor.cpp @@ -0,0 +1,136 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ + +#include "antares/solver/expressions/visitors/EvalVisitor.h" + +#include + +namespace Antares::Solver::Visitors +{ +EvalVisitor::EvalVisitor(EvaluationContext context): + context_(std::move(context)) +{ +} + +double EvalVisitor::visit(const Nodes::AddNode* node) +{ + return dispatch(node->left()) + dispatch(node->right()); +} + +double EvalVisitor::visit(const Nodes::SubtractionNode* node) +{ + return dispatch(node->left()) - dispatch(node->right()); +} + +double EvalVisitor::visit(const Nodes::MultiplicationNode* node) +{ + return dispatch(node->left()) * dispatch(node->right()); +} + +double EvalVisitor::visit(const Nodes::DivisionNode* node) +{ + double left = dispatch(node->left()); + double right = dispatch(node->right()); + double result = 0.; + try + { + result = left / right; + if (!std::isfinite(result)) + { + throw EvalVisitorDivisionException(left, right, "is not a finite number"); + } + } + catch (const std::exception& ex) + { + throw EvalVisitorDivisionException(left, right, ex.what()); + } + return result; +} + +double EvalVisitor::visit(const Nodes::EqualNode* node) +{ + throw EvalVisitorNotImplemented(name(), node->name()); +} + +double EvalVisitor::visit(const Nodes::LessThanOrEqualNode* node) +{ + throw EvalVisitorNotImplemented(name(), node->name()); +} + +double EvalVisitor::visit(const Nodes::GreaterThanOrEqualNode* node) +{ + throw EvalVisitorNotImplemented(name(), node->name()); +} + +double EvalVisitor::visit(const Nodes::VariableNode* node) +{ + return context_.getVariableValue(node->value()); +} + +double EvalVisitor::visit(const Nodes::ParameterNode* node) +{ + return context_.getParameterValue(node->value()); +} + +double EvalVisitor::visit(const Nodes::LiteralNode* node) +{ + return node->value(); +} + +double EvalVisitor::visit(const Nodes::NegationNode* node) +{ + return -dispatch(node->child()); +} + +double EvalVisitor::visit(const Nodes::PortFieldNode* node) +{ + throw EvalVisitorNotImplemented(name(), node->name()); +} + +double EvalVisitor::visit(const Nodes::ComponentVariableNode* node) +{ + throw EvalVisitorNotImplemented(name(), node->name()); +} + +double EvalVisitor::visit(const Nodes::ComponentParameterNode* node) +{ + throw EvalVisitorNotImplemented(name(), node->name()); +} + +std::string EvalVisitor::name() const +{ + return "EvalVisitor"; +} + +EvalVisitorDivisionException::EvalVisitorDivisionException(double left, + double right, + const std::string& message): + std::runtime_error("DivisionNode: Error while evaluating : " + std::to_string(left) + "/" + + std::to_string(right) + " " + message) +{ +} + +EvalVisitorNotImplemented::EvalVisitorNotImplemented(const std::string& visitor, + const std::string& node): + std::invalid_argument("Visitor" + visitor + " not implemented for node type " + node) +{ +} +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/EvaluationContext.cpp b/src/solver/expressions/visitors/EvaluationContext.cpp new file mode 100644 index 0000000000..d25f9ec603 --- /dev/null +++ b/src/solver/expressions/visitors/EvaluationContext.cpp @@ -0,0 +1,21 @@ +#include + +namespace Antares::Solver::Visitors +{ +EvaluationContext::EvaluationContext(std::map parameters, + std::map variables): + parameters_(std::move(parameters)), + variables_(std::move(variables)) +{ +} + +double EvaluationContext::getVariableValue(const std::string& key) const +{ + return variables_.at(key); +} + +double EvaluationContext::getParameterValue(const std::string& key) const +{ + return parameters_.at(key); +} +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/InvalidNode.cpp b/src/solver/expressions/visitors/InvalidNode.cpp new file mode 100644 index 0000000000..5245a5ebc9 --- /dev/null +++ b/src/solver/expressions/visitors/InvalidNode.cpp @@ -0,0 +1,10 @@ +#include + +namespace Antares::Solver::Visitors +{ + +InvalidNode::InvalidNode(const std::string& node_name): + std::invalid_argument("Antares::Solver::Nodes Visitor: invalid node type " + node_name) +{ +} +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/LinearityVisitor.cpp b/src/solver/expressions/visitors/LinearityVisitor.cpp new file mode 100644 index 0000000000..902ae530fd --- /dev/null +++ b/src/solver/expressions/visitors/LinearityVisitor.cpp @@ -0,0 +1,104 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ + +#include "antares/solver/expressions/visitors/LinearityVisitor.h" + +#include +#include + +namespace Antares::Solver::Visitors +{ + +LinearStatus LinearityVisitor::visit(const Nodes::AddNode* node) +{ + return dispatch(node->left()) + dispatch(node->right()); +} + +LinearStatus LinearityVisitor::visit(const Nodes::SubtractionNode* node) +{ + return dispatch(node->left()) - dispatch(node->right()); +} + +LinearStatus LinearityVisitor::visit(const Nodes::MultiplicationNode* node) +{ + return dispatch(node->left()) * dispatch(node->right()); +} + +LinearStatus LinearityVisitor::visit(const Nodes::DivisionNode* node) +{ + return dispatch(node->left()) / dispatch(node->right()); +} + +LinearStatus LinearityVisitor::visit(const Nodes::EqualNode* node) +{ + return dispatch(node->left()) + dispatch(node->right()); +} + +LinearStatus LinearityVisitor::visit(const Nodes::LessThanOrEqualNode* node) +{ + return dispatch(node->left()) + dispatch(node->right()); +} + +LinearStatus LinearityVisitor::visit(const Nodes::GreaterThanOrEqualNode* node) +{ + return dispatch(node->left()) + dispatch(node->right()); +} + +LinearStatus LinearityVisitor::visit([[maybe_unused]] const Nodes::VariableNode*) +{ + return LinearStatus::LINEAR; +} + +LinearStatus LinearityVisitor::visit([[maybe_unused]] const Nodes::ParameterNode*) +{ + return LinearStatus::CONSTANT; +} + +LinearStatus LinearityVisitor::visit([[maybe_unused]] const Nodes::LiteralNode*) +{ + return LinearStatus::CONSTANT; +} + +LinearStatus LinearityVisitor::visit(const Nodes::NegationNode* node) +{ + return -dispatch(node->child()); +} + +LinearStatus LinearityVisitor::visit(const Nodes::PortFieldNode*) +{ + return LinearStatus::CONSTANT; +} + +LinearStatus LinearityVisitor::visit([[maybe_unused]] const Nodes::ComponentVariableNode*) +{ + return LinearStatus::LINEAR; +} + +LinearStatus LinearityVisitor::visit([[maybe_unused]] const Nodes::ComponentParameterNode*) +{ + return LinearStatus::CONSTANT; +} + +std::string LinearityVisitor::name() const +{ + return "LinearityVisitor"; +} +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/PrintVisitor.cpp b/src/solver/expressions/visitors/PrintVisitor.cpp new file mode 100644 index 0000000000..dda167028c --- /dev/null +++ b/src/solver/expressions/visitors/PrintVisitor.cpp @@ -0,0 +1,104 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#include + +#include +#include + +namespace Antares::Solver::Visitors +{ +std::string PrintVisitor::visit(const Nodes::AddNode* node) +{ + // Ici le compilateur (g++) a besoin de savoir qu'on veut le visit du type de base + // sinon erreur de compil 'fonction non trouvée' + return "(" + dispatch(node->left()) + "+" + dispatch(node->right()) + ")"; +} + +std::string PrintVisitor::visit(const Nodes::SubtractionNode* node) +{ + return "(" + dispatch(node->left()) + "-" + dispatch(node->right()) + ")"; +} + +std::string PrintVisitor::visit(const Nodes::MultiplicationNode* node) +{ + return "(" + dispatch(node->left()) + "*" + dispatch(node->right()) + ")"; +} + +std::string PrintVisitor::visit(const Nodes::DivisionNode* node) +{ + return "(" + dispatch(node->left()) + "/" + dispatch(node->right()) + ")"; +} + +std::string PrintVisitor::visit(const Nodes::EqualNode* node) +{ + return dispatch(node->left()) + "==" + dispatch(node->right()); +} + +std::string PrintVisitor::visit(const Nodes::LessThanOrEqualNode* node) +{ + return dispatch(node->left()) + "<=" + dispatch(node->right()); +} + +std::string PrintVisitor::visit(const Nodes::GreaterThanOrEqualNode* node) +{ + return dispatch(node->left()) + ">=" + dispatch(node->right()); +} + +std::string PrintVisitor::visit(const Nodes::NegationNode* node) +{ + return "-(" + dispatch(node->child()) + ")"; +} + +std::string PrintVisitor::visit(const Nodes::ParameterNode* node) +{ + return node->value(); +} + +std::string PrintVisitor::visit(const Nodes::VariableNode* node) +{ + return node->value(); +} + +std::string PrintVisitor::visit(const Nodes::LiteralNode* node) +{ + return std::to_string(node->value()); +} + +std::string PrintVisitor::visit(const Nodes::PortFieldNode* node) +{ + return node->getPortName() + "." + node->getFieldName(); +} + +std::string PrintVisitor::visit(const Nodes::ComponentVariableNode* node) +{ + return node->getComponentId() + "." + node->getComponentName(); +} + +std::string PrintVisitor::visit(const Nodes::ComponentParameterNode* node) +{ + return node->getComponentId() + "." + node->getComponentName(); +} + +std::string PrintVisitor::name() const +{ + return "PrintVisitor"; +} +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/SubstitutionVisitor.cpp b/src/solver/expressions/visitors/SubstitutionVisitor.cpp new file mode 100644 index 0000000000..417f77a417 --- /dev/null +++ b/src/solver/expressions/visitors/SubstitutionVisitor.cpp @@ -0,0 +1,59 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ + +#include + +#include +#include + +namespace Antares::Solver::Visitors +{ +SubstitutionVisitor::SubstitutionVisitor(Registry& registry, SubstitutionContext& ctx): + CloneVisitor(registry), + ctx_(ctx), + registry_(registry) +{ +} + +Nodes::Node* SubstitutionVisitor::visit(const Nodes::ComponentVariableNode* node) +{ + // This search has linear complexity + // To get a search of log complexity, we need to use std::unordered_set::find + // But std::unordered_set::find_if does not exist + auto it = std::find_if(ctx_.variables.begin(), + ctx_.variables.end(), + [&node](auto* x) { return *x == *node; }); + if (it != ctx_.variables.end()) + { + return *it; + } + + else + { + return CloneVisitor::visit(node); + } +} + +std::string SubstitutionVisitor::name() const +{ + return "SubstitutionVisitor"; +} +} // namespace Antares::Solver::Visitors diff --git a/src/solver/expressions/visitors/TimeIndexVisitor.cpp b/src/solver/expressions/visitors/TimeIndexVisitor.cpp new file mode 100644 index 0000000000..5e23c68856 --- /dev/null +++ b/src/solver/expressions/visitors/TimeIndexVisitor.cpp @@ -0,0 +1,108 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ + +#include +#include + +namespace Antares::Solver::Visitors +{ + +TimeIndex TimeIndexVisitor::visit(const Nodes::AddNode* add) +{ + return dispatch(add->left()) | dispatch(add->right()); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::SubtractionNode* sub) +{ + return dispatch(sub->left()) | dispatch(sub->right()); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::MultiplicationNode* mult) +{ + return dispatch(mult->left()) | dispatch(mult->right()); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::DivisionNode* div) +{ + return dispatch(div->left()) | dispatch(div->right()); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::EqualNode* equ) +{ + return dispatch(equ->left()) | dispatch(equ->right()); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::LessThanOrEqualNode* lt) +{ + return dispatch(lt->left()) | dispatch(lt->right()); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::GreaterThanOrEqualNode* gt) +{ + return dispatch(gt->left()) | dispatch(gt->right()); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::VariableNode* var) +{ + return context_.at(var); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::ParameterNode* param) +{ + return context_.at(param); +} + +TimeIndex TimeIndexVisitor::visit([[maybe_unused]] const Nodes::LiteralNode* lit) +{ + return TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO; +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::NegationNode* neg) +{ + return dispatch(neg->child()); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::PortFieldNode* port_field_node) +{ + return context_.at(port_field_node); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::ComponentVariableNode* component_variable_node) +{ + return context_.at(component_variable_node); +} + +TimeIndex TimeIndexVisitor::visit(const Nodes::ComponentParameterNode* component_parameter_node) +{ + return context_.at(component_parameter_node); +} + +TimeIndexVisitor::TimeIndexVisitor(std::unordered_map context): + context_(std::move(context)) +{ +} + +std::string TimeIndexVisitor::name() const +{ + return "TimeIndexVisitor"; +} + +} // namespace Antares::Solver::Visitors diff --git a/src/solver/hydro/CMakeLists.txt b/src/solver/hydro/CMakeLists.txt index d497ec1591..3ba25e80d4 100644 --- a/src/solver/hydro/CMakeLists.txt +++ b/src/solver/hydro/CMakeLists.txt @@ -50,8 +50,18 @@ set(SRC_EXT_SOLVER_H2O2_DAILY set(SRC_MANAGEMENT include/antares/solver/hydro/management/management.h management/management.cpp + include/antares/solver/hydro/management/PrepareInflows.h + management/PrepareInflows.cpp management/monthly.cpp management/daily.cpp + include/antares/solver/hydro/management/MinGenerationScaling.h + management/MinGenerationScaling.cpp + include/antares/solver/hydro/management/HydroInputsChecker.h + management/HydroInputsChecker.cpp + include/antares/solver/hydro/management/HydroErrorsCollector.h + management/HydroErrorsCollector.cpp + include/antares/solver/hydro/management/finalLevelValidator.h + management/finalLevelValidator.cpp ) @@ -73,6 +83,7 @@ target_link_libraries(antares-solver-hydro sirius_solver Antares::date Antares::result_writer + ) target_include_directories(antares-solver-hydro diff --git a/src/solver/hydro/daily/h2o_j_construire_les_variables.cpp b/src/solver/hydro/daily/h2o_j_construire_les_variables.cpp index 117d8ace5a..98ab62116c 100644 --- a/src/solver/hydro/daily/h2o_j_construire_les_variables.cpp +++ b/src/solver/hydro/daily/h2o_j_construire_les_variables.cpp @@ -57,14 +57,14 @@ void H2O_j_ConstruireLesVariables( Xmin[Var] = 0.0; Xmax[Var] = LINFINI; TypeDeVariable[Var] = VARIABLE_BORNEE_INFERIEUREMENT; - AdresseOuPlacerLaValeurDesVariablesOptimisees[Var] = NULL; + AdresseOuPlacerLaValeurDesVariablesOptimisees[Var] = nullptr; Var++; CorrespondanceDesVariables.NumeroDeLaVariableXi = Var; Xmin[Var] = 0.0; Xmax[Var] = LINFINI; TypeDeVariable[Var] = VARIABLE_BORNEE_INFERIEUREMENT; - AdresseOuPlacerLaValeurDesVariablesOptimisees[Var] = NULL; + AdresseOuPlacerLaValeurDesVariablesOptimisees[Var] = nullptr; Var++; return; diff --git a/src/solver/hydro/daily/h2o_j_resoudre_le_probleme_lineaire.cpp b/src/solver/hydro/daily/h2o_j_resoudre_le_probleme_lineaire.cpp index f4e727adc9..1786428cef 100644 --- a/src/solver/hydro/daily/h2o_j_resoudre_le_probleme_lineaire.cpp +++ b/src/solver/hydro/daily/h2o_j_resoudre_le_probleme_lineaire.cpp @@ -135,7 +135,7 @@ void H2O_J_ResoudreLeProblemeLineaire(DONNEES_MENSUELLES* DonneesMensuelles, int { SPX_LibererProbleme(ProbSpx); - ProbSpx = NULL; + ProbSpx = nullptr; PremierPassage = false; goto RESOLUTION; } diff --git a/src/solver/hydro/daily2/h2o2_j_resoudre_le_probleme_lineaire.cpp b/src/solver/hydro/daily2/h2o2_j_resoudre_le_probleme_lineaire.cpp index e5b4f7411f..a0366dce53 100644 --- a/src/solver/hydro/daily2/h2o2_j_resoudre_le_probleme_lineaire.cpp +++ b/src/solver/hydro/daily2/h2o2_j_resoudre_le_probleme_lineaire.cpp @@ -135,7 +135,7 @@ void H2O2_J_ResoudreLeProblemeLineaire(DONNEES_MENSUELLES_ETENDUES& DonneesMensu { SPX_LibererProbleme(ProbSpx); - ProbSpx = NULL; + ProbSpx = nullptr; premierPassage = false; goto RESOLUTION; } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_local_matching/adequacy_patch_weekly_optimization.h b/src/solver/hydro/include/antares/solver/hydro/management/HydroErrorsCollector.h similarity index 50% rename from src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_local_matching/adequacy_patch_weekly_optimization.h rename to src/solver/hydro/include/antares/solver/hydro/management/HydroErrorsCollector.h index 2585fc8053..d6054f12b6 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_local_matching/adequacy_patch_weekly_optimization.h +++ b/src/solver/hydro/include/antares/solver/hydro/management/HydroErrorsCollector.h @@ -20,31 +20,44 @@ */ #pragma once +#include +#include +#include +#include -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/sim_structure_probleme_economique.h" -#include "antares/study/area/area.h" - -#include "../base_weekly_optimization.h" - -using Antares::Data::AreaList; - -namespace Antares::Solver::Optimization +namespace Antares { -class AdequacyPatchOptimization: public WeeklyOptimization + +class HydroErrorsCollector { public: - explicit AdequacyPatchOptimization(const Antares::Data::Study& study, - const OptimizationOptions& options, - PROBLEME_HEBDO* problemeHebdo, - Antares::Data::AdequacyPatch::AdqPatchParams&, - uint numSpace, - IResultWriter& writer); + class AreaReference + { + public: + AreaReference(HydroErrorsCollector* collector, const std::string& name); + template + AreaReference& operator<<(const T& msg); - ~AdequacyPatchOptimization() override = default; - void solve() override; + private: + std::string& areaSingleErrorMessage_; + }; + + AreaReference operator()(const std::string& name); + HydroErrorsCollector() = default; + void CheckForErrors() const; private: - const Antares::Data::Study& study_; + std::map> areasErrorMap_; + std::string& CurrentMessage(const std::string& name); }; -} // namespace Antares::Solver::Optimization + +template +HydroErrorsCollector::AreaReference& HydroErrorsCollector::AreaReference::operator<<(const T& msg) +{ + std::ostringstream strfy; + strfy << msg; + areaSingleErrorMessage_ += strfy.str(); + return *this; +} + +} // namespace Antares diff --git a/src/solver/hydro/include/antares/solver/hydro/management/HydroInputsChecker.h b/src/solver/hydro/include/antares/solver/hydro/management/HydroInputsChecker.h new file mode 100644 index 0000000000..af9049a97e --- /dev/null +++ b/src/solver/hydro/include/antares/solver/hydro/management/HydroInputsChecker.h @@ -0,0 +1,64 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once +#include +#include "antares/date/date.h" +#include "antares/solver/hydro/management/HydroErrorsCollector.h" +#include "antares/solver/hydro/management/MinGenerationScaling.h" +#include "antares/solver/hydro/management/PrepareInflows.h" +#include "antares/study/study.h" + +namespace Antares +{ + +class HydroInputsChecker +{ +public: + explicit HydroInputsChecker(Antares::Data::Study& study); + void Execute(uint year); + void CheckForErrors() const; + void CheckFinalReservoirLevelsConfiguration(uint year); + +private: + Data::AreaList& areas_; + const Data::Parameters& parameters_; + const Date::Calendar& calendar_; + PrepareInflows prepareInflows_; + MinGenerationScaling minGenerationScaling_; + const Data::TimeSeries::TS& scenarioInitialHydroLevels_; + const Data::TimeSeries::TS& scenarioFinalHydroLevels_; + HydroErrorsCollector errorCollector_; + + //! return false if checkGenerationPowerConsistency or checkMinGeneration returns false + bool checkMonthlyMinGeneration(uint year, const Data::Area& area); + //! check Yearly minimum generation is lower than available inflows + bool checkYearlyMinGeneration(uint year, const Data::Area& area); + //! check Weekly minimum generation is lower than available inflows + bool checkWeeklyMinGeneration(uint year, const Data::Area& area); + //! check Hourly minimum generation is lower than available inflows + bool checkGenerationPowerConsistency(uint year); + //! return false if checkGenerationPowerConsistency or checkMinGeneration returns false + bool checksOnGenerationPowerBounds(uint year); + //! check minimum generation is lower than available inflows + bool checkMinGeneration(uint year); +}; + +} // namespace Antares diff --git a/src/solver/hydro/include/antares/solver/hydro/management/MinGenerationScaling.h b/src/solver/hydro/include/antares/solver/hydro/management/MinGenerationScaling.h new file mode 100644 index 0000000000..31feb6fa53 --- /dev/null +++ b/src/solver/hydro/include/antares/solver/hydro/management/MinGenerationScaling.h @@ -0,0 +1,41 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once + +#include +#include "antares/date/date.h" + +namespace Antares +{ + +//! Prepare minimum generation scaling for each area +class MinGenerationScaling +{ +public: + MinGenerationScaling(Data::AreaList& areas, const Date::Calendar& calendar); + void Run(uint year); + +private: + Data::AreaList& areas_; + const Date::Calendar& calendar_; +}; + +} // namespace Antares diff --git a/src/solver/hydro/include/antares/solver/hydro/management/PrepareInflows.h b/src/solver/hydro/include/antares/solver/hydro/management/PrepareInflows.h new file mode 100644 index 0000000000..79b7eae0a5 --- /dev/null +++ b/src/solver/hydro/include/antares/solver/hydro/management/PrepareInflows.h @@ -0,0 +1,43 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#pragma once +#include +#include "antares/date/date.h" + +namespace Antares +{ + +//! Prepare inflows scaling for each area +class PrepareInflows +{ +public: + PrepareInflows(Data::AreaList& areas, const Date::Calendar& calendar); + void Run(uint year); + +private: + void LoadInflows(uint year); + //! prepare data for Final reservoir level + void ChangeInflowsToAccommodateFinalLevels(uint year); + Data::AreaList& areas_; + const Date::Calendar& calendar_; +}; + +} // namespace Antares diff --git a/src/solver/hydro/include/antares/solver/hydro/management/finalLevelValidator.h b/src/solver/hydro/include/antares/solver/hydro/management/finalLevelValidator.h new file mode 100644 index 0000000000..ecbcd8ed31 --- /dev/null +++ b/src/solver/hydro/include/antares/solver/hydro/management/finalLevelValidator.h @@ -0,0 +1,84 @@ +/* +** 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 "antares/solver/hydro/management/HydroErrorsCollector.h" +#include "antares/study/parts/hydro/container.h" + +namespace Antares +{ +namespace Data +{ +class PartHydro; +} + +namespace Solver +{ +class FinalLevelValidator +{ +public: + FinalLevelValidator(Antares::Data::PartHydro& hydro, + unsigned int areaIndex, + const Antares::Data::AreaName areaName, + double initialLevel, + double finalLevel, + const unsigned int year, + const unsigned int lastSimulationDay, + const unsigned int firstMonthOfSimulation, + HydroErrorsCollector& errorCollector); + bool check(); + bool finalLevelFineForUse(); + +private: + bool wasSetInScenarioBuilder(); + bool compatibleWithReservoirProperties(); + bool skippingFinalLevelUse(); + bool checkForInfeasibility(); + bool hydroAllocationStartMatchesSimulation() const; + bool isFinalLevelReachable() const; + double calculateTotalInflows() const; + bool isBetweenRuleCurves() const; + + // Data from simulation + unsigned int year_ = 0; + unsigned int lastSimulationDay_ = 0; + unsigned int firstMonthOfSimulation_ = 0; + + // Data from area + Antares::Data::PartHydro& hydro_; + unsigned int areaIndex_; + const Antares::Data::AreaName areaName_; + double initialLevel_; + double finalLevel_; + + bool finalLevelFineForUse_ = false; + + // area input errors + HydroErrorsCollector& errorCollector_; +}; +} // namespace Solver +} // namespace Antares diff --git a/src/solver/hydro/include/antares/solver/hydro/management/management.h b/src/solver/hydro/include/antares/solver/hydro/management/management.h index 29f64fbd93..8f4cf12d01 100644 --- a/src/solver/hydro/include/antares/solver/hydro/management/management.h +++ b/src/solver/hydro/include/antares/solver/hydro/management/management.h @@ -47,49 +47,6 @@ double GammaVariable(double a, MersenneTwister& random); } // namespace Solver -enum -{ - //! The maximum number of days in a year - dayYearCount = 366 -}; - -//! Temporary data -struct TmpDataByArea -{ - //! Monthly local effective demand - double MLE[12]; - //! Monthly optimal generation - double MOG[12]; - //! Monthly optimal level - double MOL[12]; - //! Monthly target generations - double MTG[12]; - //! inflows - double inflows[12]; - //! monthly minimal generation - std::array mingens; - - //! Net demand, for each day of the year, for each area - double DLN[dayYearCount]; - //! Daily local effective load - double DLE[dayYearCount]; - //! Daily optimized Generation - double DOG[dayYearCount]; - //! daily minimal generation - std::array dailyMinGen; - - // Data for minGen<->inflows preChecks - //! monthly total mingen - std::array totalMonthMingen; - //! monthly total inflows - std::array totalMonthInflows; - //! yearly total mingen - double totalYearMingen; - //! yearly total inflows - double totalYearInflows; - -}; // struct TmpDataByArea - typedef struct { std::vector HydrauliqueModulableQuotidien; /* indice par jour */ @@ -100,6 +57,8 @@ typedef struct } VENTILATION_HYDRO_RESULTS_BY_AREA; using HYDRO_VENTILATION_RESULTS = std::vector; +using HydroSpecificMap = std::unordered_map; class HydroManagement final { @@ -107,12 +66,10 @@ class HydroManagement final HydroManagement(const Data::AreaList& areas, const Data::Parameters& params, const Date::Calendar& calendar, - unsigned int maxNbYearsInParallel, Solver::IResultWriter& resultWriter); //! Perform the hydro ventilation void makeVentilation(double* randomReservoirLevel, - Solver::Variable::State& state, uint y, Antares::Data::Area::ScratchMap& scratchmap); @@ -122,47 +79,37 @@ class HydroManagement final } private: - //! Prepare inflows scaling for each area - void prepareInflowsScaling(uint year); - //! Prepare minimum generation scaling for each area - void minGenerationScaling(uint year); - //! check Monthly minimum generation is lower than available inflows - bool checkMonthlyMinGeneration(uint year, const Data::Area& area) const; - //! check Yearly minimum generation is lower than available inflows - bool checkYearlyMinGeneration(uint year, const Data::Area& area) const; - //! check Weekly minimum generation is lower than available inflows - bool checkWeeklyMinGeneration(uint year, const Data::Area& area) const; - //! check Hourly minimum generation is lower than available inflows - bool checkGenerationPowerConsistency(uint year) const; - //! return false if checkGenerationPowerConsistency or checkMinGeneration returns false - bool checksOnGenerationPowerBounds(uint year) const; - //! check minimum generation is lower than available inflows - bool checkMinGeneration(uint year) const; //! Prepare the net demand for each area void prepareNetDemand(uint year, Data::SimulationMode mode, - const Antares::Data::Area::ScratchMap& scratchmap); + const Antares::Data::Area::ScratchMap& scratchmap, + HydroSpecificMap& hydro_specific_map); //! Prepare the effective demand for each area - void prepareEffectiveDemand(); + void prepareEffectiveDemand(uint year, HydroSpecificMap& hydro_specific_map) const; //! Monthly Optimal generations - void prepareMonthlyOptimalGenerations(double* random_reservoir_level, uint y); + void prepareMonthlyOptimalGenerations(const double* random_reservoir_level, + uint y, + HydroSpecificMap& hydro_specific_map); //! Monthly target generations // note: inflows may have two different types, if in swap mode or not // \return The total inflow for the whole year - double prepareMonthlyTargetGenerations(Data::Area& area, TmpDataByArea& data); + double prepareMonthlyTargetGenerations( + Data::Area& area, + Antares::Data::AreaDependantHydroManagementData& data, + Antares::Data::TimeDependantHydroManagementData& hydro_specific); - void prepareDailyOptimalGenerations(Solver::Variable::State& state, - uint y, - Antares::Data::Area::ScratchMap& scratchmap); + void prepareDailyOptimalGenerations(uint y, + Antares::Data::Area::ScratchMap& scratchmap, + HydroSpecificMap& hydro_specific_map); - void prepareDailyOptimalGenerations(Solver::Variable::State& state, - Data::Area& area, - uint y, - Antares::Data::Area::ScratchMap& scratchmap); + void prepareDailyOptimalGenerations( + Data::Area& area, + uint y, + Antares::Data::Area::ScratchMap& scratchmap, + Antares::Data::TimeDependantHydroManagementData& hydro_specific); private: - std::unordered_map tmpDataByArea_; const Data::AreaList& areas_; const Date::Calendar& calendar_; const Data::Parameters& parameters_; diff --git a/src/solver/hydro/management/HydroErrorsCollector.cpp b/src/solver/hydro/management/HydroErrorsCollector.cpp new file mode 100644 index 0000000000..729726e14e --- /dev/null +++ b/src/solver/hydro/management/HydroErrorsCollector.cpp @@ -0,0 +1,45 @@ +#include "antares/solver/hydro/management/HydroErrorsCollector.h" + +#include +#include + +#include + +#include "antares/antares/fatal-error.h" + +namespace Antares +{ + +void HydroErrorsCollector::CheckForErrors() const +{ + if (!areasErrorMap_.empty()) + { + for (const auto& [key, values]: areasErrorMap_) + { + for (const auto& value: values | std::views::take(10)) + { + logs.error() << "In Area " << key << ": " << value << " "; + } + } + + throw FatalError("Hydro validation has failed !"); + } +} + +HydroErrorsCollector::AreaReference::AreaReference(HydroErrorsCollector* collector, + const std::string& name): + areaSingleErrorMessage_(collector->CurrentMessage(name)) +{ +} + +HydroErrorsCollector::AreaReference HydroErrorsCollector::operator()(const std::string& name) +{ + return AreaReference(this, name); +} + +std::string& HydroErrorsCollector::CurrentMessage(const std::string& name) +{ + auto& msgs = areasErrorMap_[name]; + return *msgs.insert(msgs.end(), ""); +} +} // namespace Antares diff --git a/src/solver/hydro/management/HydroInputsChecker.cpp b/src/solver/hydro/management/HydroInputsChecker.cpp new file mode 100644 index 0000000000..d9956e94a2 --- /dev/null +++ b/src/solver/hydro/management/HydroInputsChecker.cpp @@ -0,0 +1,244 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#include "antares/solver/hydro/management/HydroInputsChecker.h" + +#include + +#include +#include "antares/solver/hydro/management/finalLevelValidator.h" +#include "antares/solver/hydro/monthly/h2o_m_donnees_annuelles.h" +#include "antares/solver/hydro/monthly/h2o_m_fonctions.h" +#include "antares/solver/simulation/common-eco-adq.h" + +namespace Antares +{ + +HydroInputsChecker::HydroInputsChecker(Antares::Data::Study& study): + areas_(study.areas), + parameters_(study.parameters), + calendar_(study.calendar), + prepareInflows_(study.areas, study.calendar), + minGenerationScaling_(study.areas, study.calendar), + scenarioInitialHydroLevels_(study.scenarioInitialHydroLevels), + scenarioFinalHydroLevels_(study.scenarioFinalHydroLevels) +{ +} + +void HydroInputsChecker::Execute(uint year) +{ + prepareInflows_.Run(year); + minGenerationScaling_.Run(year); + if (!checksOnGenerationPowerBounds(year)) + { + logs.error() << "hydro inputs checks: invalid minimum generation in year " << year; + } + if (parameters_.useCustomScenario) + { + CheckFinalReservoirLevelsConfiguration(year); + } +} + +bool HydroInputsChecker::checksOnGenerationPowerBounds(uint year) +{ + return checkMinGeneration(year) && checkGenerationPowerConsistency(year); +} + +bool HydroInputsChecker::checkMinGeneration(uint year) +{ + bool ret = true; + areas_.each( + [this, &ret, &year](const Data::Area& area) + { + bool useHeuristicTarget = area.hydro.useHeuristicTarget; + bool followLoadModulations = area.hydro.followLoadModulations; + bool reservoirManagement = area.hydro.reservoirManagement; + + if (!useHeuristicTarget) + { + return; + } + + if (!followLoadModulations) + { + ret = checkWeeklyMinGeneration(year, area) && ret; + return; + } + + if (reservoirManagement) + { + ret = checkYearlyMinGeneration(year, area) && ret; + } + else + { + ret = checkMonthlyMinGeneration(year, area) && ret; + } + }); + return ret; +} + +bool HydroInputsChecker::checkWeeklyMinGeneration(uint year, const Data::Area& area) +{ + const auto& srcinflows = area.hydro.series->storage.getColumn(year); + const auto& srcmingen = area.hydro.series->mingen.getColumn(year); + // Weekly minimum generation <= Weekly inflows for each week + bool ret = true; + for (uint week = 0; week < calendar_.maxWeeksInYear - 1; ++week) + { + double totalWeekMingen = 0.0; + double totalWeekInflows = 0.0; + for (uint hour = calendar_.weeks[week].hours.first; + hour < calendar_.weeks[week].hours.end && hour < HOURS_PER_YEAR; + ++hour) + { + totalWeekMingen += srcmingen[hour]; + } + + for (uint day = calendar_.weeks[week].daysYear.first; + day < calendar_.weeks[week].daysYear.end; + ++day) + { + totalWeekInflows += srcinflows[day]; + } + if (totalWeekMingen > totalWeekInflows) + { + errorCollector_(area.name) + << " the minimum generation of " << totalWeekMingen << " MW in week " << week + 1 + << " of TS-" << area.hydro.series->mingen.getSeriesIndex(year) + 1 + << " is incompatible with the inflows of " << totalWeekInflows << " MW."; + ret = false; + } + } + return ret; +} + +bool HydroInputsChecker::checkYearlyMinGeneration(uint year, const Data::Area& area) +{ + const auto& data = area.hydro.managementData.at(year); + bool ret = true; + if (data.totalYearMingen > data.totalYearInflows) + { + // Yearly minimum generation <= Yearly inflows + errorCollector_(area.name) + << " the minimum generation of " << data.totalYearMingen << " MW of TS-" + << area.hydro.series->mingen.getSeriesIndex(year) + 1 + << " is incompatible with the inflows of " << data.totalYearInflows << " MW."; + ret = false; + } + return ret; +} + +bool HydroInputsChecker::checkMonthlyMinGeneration(uint year, const Data::Area& area) +{ + const auto& data = area.hydro.managementData.at(year); + bool ret = true; + for (uint month = 0; month != 12; ++month) + { + uint realmonth = calendar_.months[month].realmonth; + // Monthly minimum generation <= Monthly inflows for each month + if (data.totalMonthMingen[realmonth] > data.totalMonthInflows[realmonth]) + { + errorCollector_(area.name) + << " the minimum generation of " << data.totalMonthMingen[realmonth] + << " MW in month " << month + 1 << " of TS-" + << area.hydro.series->mingen.getSeriesIndex(year) + 1 + << " is incompatible with the inflows of " << data.totalMonthInflows[realmonth] + << " MW."; + ret = false; + } + } + return ret; +} + +bool HydroInputsChecker::checkGenerationPowerConsistency(uint year) +{ + bool ret = true; + + areas_.each( + [this, &ret, &year](const Data::Area& area) + { + const auto& srcmingen = area.hydro.series->mingen.getColumn(year); + const auto& srcmaxgen = area.hydro.series->maxHourlyGenPower.getColumn(year); + + const uint tsIndexMin = area.hydro.series->mingen.getSeriesIndex(year); + const uint tsIndexMax = area.hydro.series->maxHourlyGenPower.getSeriesIndex(year); + + for (uint h = 0; h < HOURS_PER_YEAR; ++h) + { + const auto& min = srcmingen[h]; + const auto& max = srcmaxgen[h]; + + if (max < min) + { + errorCollector_(area.name) + << "In area: " << area.name << " [hourly] minimum generation of " << min + << " MW in timestep " << h + 1 << " of TS-" << tsIndexMin + 1 + << " is incompatible with the maximum generation of " << max + << " MW in timestep " << h + 1 << " of TS-" << tsIndexMax + 1 << " MW."; + ret = false; + return; + } + } + }); + + return ret; +} + +void HydroInputsChecker::CheckFinalReservoirLevelsConfiguration(uint year) +{ + if (!parameters_.yearsFilter.at(year)) + { + return; + } + + areas_.each( + [this, year](Data::Area& area) + { + double initialLevel = scenarioInitialHydroLevels_.entry[area.index][year]; + double finalLevel = scenarioFinalHydroLevels_.entry[area.index][year]; + + Antares::Solver::FinalLevelValidator validator(area.hydro, + area.index, + area.name, + initialLevel, + finalLevel, + year, + parameters_.simulationDays.end, + parameters_.firstMonthInYear, + errorCollector_); + if (!validator.check()) + { + errorCollector_(area.name) + << "hydro final level : infeasibility for area " << area.name + << " please check the corresponding final level data (scenario-builder)"; + } + if (validator.finalLevelFineForUse()) + { + area.hydro.deltaBetweenFinalAndInitialLevels[year] = finalLevel - initialLevel; + } + }); +} // End function CheckFinalReservoirLevelsConfiguration + +void HydroInputsChecker::CheckForErrors() const +{ + errorCollector_.CheckForErrors(); +} + +} // namespace Antares diff --git a/src/solver/hydro/management/MinGenerationScaling.cpp b/src/solver/hydro/management/MinGenerationScaling.cpp new file mode 100644 index 0000000000..08c9bf87d1 --- /dev/null +++ b/src/solver/hydro/management/MinGenerationScaling.cpp @@ -0,0 +1,92 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ + +#include "antares/solver/hydro/management/MinGenerationScaling.h" + +#include + +namespace Antares +{ +MinGenerationScaling::MinGenerationScaling(Data::AreaList& areas, const Date::Calendar& calendar): + areas_(areas), + calendar_(calendar) +{ +} + +void MinGenerationScaling::Run(uint year) +{ + areas_.each( + // un-const because now data is a member of area [&](const Data::Area& area) + [this, &year](Data::Area& area) + { + const auto& srcmingen = area.hydro.series->mingen.getColumn(year); + + auto& data = area.hydro.managementData[year]; + double totalYearMingen = 0.0; + + for (uint month = 0; month != 12; ++month) + { + uint realmonth = calendar_.months[month].realmonth; + uint firstDayOfMonth = calendar_.months[month].daysYear.first; + uint firstDayOfNextMonth = calendar_.months[month].daysYear.end; + + double totalMonthMingen = std::accumulate(srcmingen + firstDayOfMonth * 24, + srcmingen + firstDayOfNextMonth * 24, + 0.); + + data.totalMonthMingen[realmonth] = totalMonthMingen; + totalYearMingen += totalMonthMingen; + + if (!(area.hydro.reservoirCapacity < 1e-4)) + { + if (area.hydro.reservoirManagement) + { + // Set monthly mingen, used later for h2o_m + data.mingens[realmonth] = totalMonthMingen / (area.hydro.reservoirCapacity); + assert(!std::isnan(data.mingens[month]) && "nan value detect in mingen"); + } + else + { + data.mingens[realmonth] = totalMonthMingen; + } + } + else + { + data.mingens[realmonth] = totalMonthMingen; + } + + // Set daily mingen, used later for h2o_d + uint simulationMonth = calendar_.mapping.months[realmonth]; + auto daysPerMonth = calendar_.months[simulationMonth].days; + uint firstDay = calendar_.months[simulationMonth].daysYear.first; + uint endDay = firstDay + daysPerMonth; + + for (uint day = firstDay; day != endDay; ++day) + { + data.dailyMinGen[day] = std::accumulate(srcmingen + day * 24, + srcmingen + day * 24 + 24, + 0.); + } + } + data.totalYearMingen = totalYearMingen; + }); +} +} // namespace Antares diff --git a/src/solver/hydro/management/PrepareInflows.cpp b/src/solver/hydro/management/PrepareInflows.cpp new file mode 100644 index 0000000000..01eb38efaf --- /dev/null +++ b/src/solver/hydro/management/PrepareInflows.cpp @@ -0,0 +1,93 @@ + +#include "antares/solver/hydro/management/PrepareInflows.h" + +namespace Antares +{ + +PrepareInflows::PrepareInflows(Data::AreaList& areas, const Date::Calendar& calendar): + areas_(areas), + calendar_(calendar) +{ +} + +void PrepareInflows::Run(uint year) +{ + LoadInflows(year); + ChangeInflowsToAccommodateFinalLevels(year); +} + +void PrepareInflows::LoadInflows(uint year) +{ + areas_.each( + [this, year](Data::Area& area) + { + const auto& srcinflows = area.hydro.series->storage.getColumn(year); + + auto& data = area.hydro.managementData[year]; + double totalYearInflows = 0.0; + + for (uint month = 0; month != 12; ++month) + { + uint realmonth = calendar_.months[month].realmonth; + + double totalMonthInflows = 0.0; + + uint firstDayOfMonth = calendar_.months[month].daysYear.first; + + uint firstDayOfNextMonth = calendar_.months[month].daysYear.end; + + for (uint d = firstDayOfMonth; d != firstDayOfNextMonth; ++d) + { + totalMonthInflows += srcinflows[d]; + } + + data.totalMonthInflows[realmonth] = totalMonthInflows; + totalYearInflows += totalMonthInflows; + + if (not(area.hydro.reservoirCapacity < 1e-4)) + { + if (area.hydro.reservoirManagement) + { + data.inflows[realmonth] = totalMonthInflows / (area.hydro.reservoirCapacity); + assert(!std::isnan(data.inflows[month]) && "nan value detect in inflows"); + } + else + { + data.inflows[realmonth] = totalMonthInflows; + } + } + else + { + data.inflows[realmonth] = totalMonthInflows; + } + } + data.totalYearInflows = totalYearInflows; + }); +} + +void PrepareInflows::ChangeInflowsToAccommodateFinalLevels(uint year) +{ + areas_.each( + [&year](Data::Area& area) + { + auto& data = area.hydro.managementData[year]; + + if (!area.hydro.deltaBetweenFinalAndInitialLevels[year].has_value()) + { + return; + } + + // Must be done before prepareMonthlyTargetGenerations + double delta = area.hydro.deltaBetweenFinalAndInitialLevels[year].value(); + if (delta < 0) + { + data.inflows[0] -= delta; + } + else if (delta > 0) + { + data.inflows[11] -= delta; + } + }); +} + +} // namespace Antares diff --git a/src/solver/hydro/management/daily.cpp b/src/solver/hydro/management/daily.cpp index 649de96f5d..d7a2aab668 100644 --- a/src/solver/hydro/management/daily.cpp +++ b/src/solver/hydro/management/daily.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -40,7 +39,6 @@ #include "antares/solver/hydro/daily2/h2o2_j_fonctions.h" #include "antares/solver/hydro/management/management.h" #include "antares/solver/simulation/sim_extern_variables_globales.h" -#include "antares/solver/variable/state.h" using namespace Yuni; @@ -87,14 +85,14 @@ struct DebugData std::array OVF{0}; std::array DEV{0}; std::array VIO{0}; - std::array deviationMax{0}; - std::array violationMax{0}; - std::array WASTE{0}; - std::array CoutTotal{0}; - std::array previousMonthWaste{0}; + std::array deviationMax{0}; + std::array violationMax{0}; + std::array WASTE{0}; + std::array CoutTotal{0}; + std::array previousMonthWaste{0}; Solver::IResultWriter& pWriter; - const TmpDataByArea& data; + const Antares::Data::AreaDependantHydroManagementData& data; const VENTILATION_HYDRO_RESULTS_BY_AREA& ventilationResults; const double* srcinflows; const MaxPowerType& maxP; @@ -103,15 +101,18 @@ struct DebugData const ReservoirLevelType& lowLevel; const double reservoirCapacity; + const Antares::Data::TimeDependantHydroManagementData& hydro_specific; + DebugData(Solver::IResultWriter& writer, - const TmpDataByArea& data, + const Antares::Data::AreaDependantHydroManagementData& data, const VENTILATION_HYDRO_RESULTS_BY_AREA& ventilationResults, const double* srcinflows, const MaxPowerType& maxP, const MaxPowerType& maxE, const double* dailyTargetGen, const ReservoirLevelType& lowLevel, - double reservoirCapacity): + double reservoirCapacity, + const Antares::Data::TimeDependantHydroManagementData& hydro_specific): pWriter(writer), data(data), ventilationResults(ventilationResults), @@ -120,7 +121,8 @@ struct DebugData maxE(maxE), dailyTargetGen(dailyTargetGen), lowLevel(lowLevel), - reservoirCapacity(reservoirCapacity) + reservoirCapacity(reservoirCapacity), + hydro_specific(hydro_specific) { OVF.fill(0); DEV.fill(0); @@ -142,7 +144,8 @@ struct DebugData { double value = ventilationResults.HydrauliqueModulableQuotidien[day]; buffer << day << '\t' << value << '\t' << OPP[day] << '\t' << DailyTargetGen[day] - << '\t' << data.DLE[day] << '\t' << data.DLN[day]; + << '\t' << hydro_specific.daily[day].DLE << '\t' + << hydro_specific.daily[day].DLN; buffer << '\n'; } auto buffer_str = buffer.str(); @@ -158,10 +161,10 @@ struct DebugData path << "debug" << SEP << "solver" << SEP << (1 + y) << SEP << "daily." << areaName.c_str() << ".txt"; - buffer << "\tNiveau init : " << data.MOL[initReservoirLvlMonth] << "\n"; - for (uint month = 0; month != 12; ++month) + buffer << "\tNiveau init : " << hydro_specific.monthly[initReservoirLvlMonth].MOL << "\n"; + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { - uint realmonth = (initReservoirLvlMonth + month) % 12; + uint realmonth = (initReservoirLvlMonth + month) % MONTHS_PER_YEAR; uint simulationMonth = calendar.mapping.months[realmonth]; auto daysPerMonth = calendar.months[simulationMonth].days; @@ -203,9 +206,9 @@ struct DebugData buffer << '\t' << deviationMax[realmonth] * 100 << '\t' << '\t' << violationMax[realmonth] * 100 << '\t' << '\t' << WASTE[realmonth] * 100 << '\t' << CoutTotal[realmonth] << '\t' - << (data.MOG[realmonth] / reservoirCapacity) * 100 << '\t' << '\t' - << '\t' << '\t' << '\t' - << (data.MOG[realmonth] / reservoirCapacity + << (hydro_specific.monthly[realmonth].MOG / reservoirCapacity) * 100 + << '\t' << '\t' << '\t' << '\t' << '\t' + << (hydro_specific.monthly[realmonth].MOG / reservoirCapacity + previousMonthWaste[realmonth]) * 100; } @@ -220,14 +223,14 @@ struct DebugData }; inline void HydroManagement::prepareDailyOptimalGenerations( - Solver::Variable::State& state, Data::Area& area, uint y, - Antares::Data::Area::ScratchMap& scratchmap) + Antares::Data::Area::ScratchMap& scratchmap, + Antares::Data::TimeDependantHydroManagementData& hydro_specific) { const auto srcinflows = area.hydro.series->storage.getColumn(y); - auto& data = tmpDataByArea_[&area]; + auto& data = area.hydro.managementData[y]; auto& scratchpad = scratchmap.at(&area); @@ -264,10 +267,11 @@ inline void HydroManagement::prepareDailyOptimalGenerations( maxE, dailyTargetGen, lowLevel, - reservoirCapacity); + reservoirCapacity, + hydro_specific); } - for (uint month = 0; month != 12; ++month) + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { auto daysPerMonth = calendar_.months[month].days; assert(daysPerMonth <= maxOPP); @@ -293,7 +297,7 @@ inline void HydroManagement::prepareDailyOptimalGenerations( || (area.hydro.useHeuristicTarget && !area.hydro.followLoadModulations)) { dayYear = 0; - for (uint month = 0; month != 12; ++month) + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { auto daysPerMonth = calendar_.months[month].days; for (uint day = 0; day != daysPerMonth; ++day) @@ -308,7 +312,7 @@ inline void HydroManagement::prepareDailyOptimalGenerations( else { dayYear = 0; - for (uint month = 0; month != 12; ++month) + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { uint realmonth = calendar_.months[month].realmonth; auto daysPerMonth = calendar_.months[month].days; @@ -319,9 +323,9 @@ inline void HydroManagement::prepareDailyOptimalGenerations( for (uint day = 0; day != daysPerMonth; ++day) { auto dYear = day + dayYear; - if (data.DLE[dYear] > demandMax) + if (hydro_specific.daily[dYear].DLE > demandMax) { - demandMax = data.DLE[dYear]; + demandMax = hydro_specific.daily[dYear].DLE; } } @@ -333,23 +337,24 @@ inline void HydroManagement::prepareDailyOptimalGenerations( for (uint day = 0; day != daysPerMonth; ++day) { auto dYear = day + dayYear; - coeff += std::pow(data.DLE[dYear] / demandMax, + coeff += std::pow(hydro_specific.daily[dYear].DLE / demandMax, area.hydro.interDailyBreakdown); } - coeff = data.MOG[realmonth] / coeff; + coeff = hydro_specific.monthly[realmonth].MOG / coeff; for (uint day = 0; day != daysPerMonth; ++day) { auto dYear = day + dayYear; dailyTargetGen[dYear] = coeff - * std::pow(data.DLE[dYear] / demandMax, + * std::pow(hydro_specific.daily[dYear].DLE + / demandMax, area.hydro.interDailyBreakdown); } } else { assert(daysPerMonth > 0); - double coeff = data.MOG[realmonth] / daysPerMonth; + double coeff = hydro_specific.monthly[realmonth].MOG / daysPerMonth; for (uint day = 0; day != daysPerMonth; ++day) { @@ -364,7 +369,8 @@ inline void HydroManagement::prepareDailyOptimalGenerations( if (debugData) { - for (uint month = 0; month != 12; ++month) + dayYear = 0; + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { auto daysPerMonth = calendar_.months[month].days; @@ -373,14 +379,15 @@ inline void HydroManagement::prepareDailyOptimalGenerations( auto dYear = day + dayYear; debugData->DailyTargetGen[dYear] = dailyTargetGen[dYear]; } + dayYear += daysPerMonth; } } if (not area.hydro.reservoirManagement) { - for (uint month = 0; month != 12; ++month) + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { - uint realmonth = (initReservoirLvlMonth + month) % 12; + uint realmonth = (initReservoirLvlMonth + month) % MONTHS_PER_YEAR; uint simulationMonth = calendar_.mapping.months[realmonth]; auto daysPerMonth = calendar_.months[simulationMonth].days; @@ -391,7 +398,7 @@ inline void HydroManagement::prepareDailyOptimalGenerations( DONNEES_MENSUELLES* problem = H2O_J_Instanciation(); H2O_J_AjouterBruitAuCout(*problem); problem->NombreDeJoursDuMois = (int)daysPerMonth; - problem->TurbineDuMois = data.MOG[realmonth]; + problem->TurbineDuMois = hydro_specific.monthly[realmonth].MOG; uint dayMonth = 0; for (uint day = firstDay; day != endDay; ++day) @@ -416,10 +423,8 @@ inline void HydroManagement::prepareDailyOptimalGenerations( break; case NON: throw solutionNotFound(area.name.c_str(), y); - break; case EMERGENCY_SHUT_DOWN: throw fatalError(area.name.c_str(), y); - break; } H2O_J_Free(problem); @@ -442,14 +447,14 @@ inline void HydroManagement::prepareDailyOptimalGenerations( else { - double monthInitialLevel = data.MOL[initReservoirLvlMonth]; + double monthInitialLevel = hydro_specific.monthly[initReservoirLvlMonth].MOL; double wasteFromPreviousMonth = 0.; Hydro_problem_costs h2o2_optim_costs(parameters_); - for (uint month = 0; month != 12; ++month) + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { - uint realmonth = (initReservoirLvlMonth + month) % 12; + uint realmonth = (initReservoirLvlMonth + month) % MONTHS_PER_YEAR; uint simulationMonth = calendar_.mapping.months[realmonth]; auto daysPerMonth = calendar_.months[simulationMonth].days; @@ -468,7 +473,7 @@ inline void HydroManagement::prepareDailyOptimalGenerations( problem.NombreDeJoursDuMois = (int)daysPerMonth; - problem.TurbineDuMois = (data.MOG[realmonth] + wasteFromPreviousMonth) + problem.TurbineDuMois = (hydro_specific.monthly[realmonth].MOG + wasteFromPreviousMonth) / reservoirCapacity; problem.NiveauInitialDuMois = monthInitialLevel; problem.reservoirCapacity = reservoirCapacity; @@ -537,19 +542,13 @@ inline void HydroManagement::prepareDailyOptimalGenerations( break; case NON: throw solutionNotFound(area.name.c_str(), y); - break; case EMERGENCY_SHUT_DOWN: throw fatalError(area.name.c_str(), y); - break; } H2O2_J_Free(problem); } - uint firstDaySimu = parameters_.simulationDays.first; - state.problemeHebdo->previousSimulationFinalLevel[area.index] - = ventilationResults.NiveauxReservoirsDebutJours[firstDaySimu] * reservoirCapacity; - if (debugData) { debugData->writeDailyDebugData(calendar_, initReservoirLvlMonth, y, area.name); @@ -557,11 +556,12 @@ inline void HydroManagement::prepareDailyOptimalGenerations( } } -void HydroManagement::prepareDailyOptimalGenerations(Solver::Variable::State& state, - uint y, - Antares::Data::Area::ScratchMap& scratchmap) +void HydroManagement::prepareDailyOptimalGenerations(uint y, + Antares::Data::Area::ScratchMap& scratchmap, + HydroSpecificMap& hydro_specific_map) { - areas_.each([&](Data::Area& area) - { prepareDailyOptimalGenerations(state, area, y, scratchmap); }); + areas_.each( + [this, &scratchmap, &y, &hydro_specific_map](Data::Area& area) + { prepareDailyOptimalGenerations(area, y, scratchmap, hydro_specific_map[&area]); }); } } // namespace Antares diff --git a/src/solver/hydro/management/finalLevelValidator.cpp b/src/solver/hydro/management/finalLevelValidator.cpp new file mode 100644 index 0000000000..343a086416 --- /dev/null +++ b/src/solver/hydro/management/finalLevelValidator.cpp @@ -0,0 +1,175 @@ +/* +** 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 "antares/solver/hydro/management/finalLevelValidator.h" + +namespace Antares::Solver +{ + +FinalLevelValidator::FinalLevelValidator( + Antares::Data::PartHydro& hydro, + unsigned int areaIndex, + const Antares::Data::AreaName areaName, // gp : to std::string + double initialLevel, + double finalLevel, + const unsigned int year, + const unsigned int lastSimulationDay, + const unsigned int firstMonthOfSimulation, + HydroErrorsCollector& errorCollector): + year_(year), + lastSimulationDay_(lastSimulationDay), + firstMonthOfSimulation_(firstMonthOfSimulation), + hydro_(hydro), + areaIndex_(areaIndex), + areaName_(areaName), + initialLevel_(initialLevel), + finalLevel_(finalLevel), + errorCollector_(errorCollector) +{ +} + +bool FinalLevelValidator::check() +{ + if (skippingFinalLevelUse()) + { + return true; + } + if (!checkForInfeasibility()) + { + return false; + } + finalLevelFineForUse_ = true; + return true; +} + +bool FinalLevelValidator::skippingFinalLevelUse() +{ + if (!wasSetInScenarioBuilder()) + { + return true; + } + if (!compatibleWithReservoirProperties()) + { + return true; + } + return false; +} + +bool FinalLevelValidator::wasSetInScenarioBuilder() +{ + return !isnan(finalLevel_); +} + +bool FinalLevelValidator::compatibleWithReservoirProperties() +{ + if (hydro_.reservoirManagement && !hydro_.useWaterValue) + { + return true; + } + + logs.warning() + << "Final reservoir level not applicable! Year:" << year_ + 1 << ", Area:" << areaName_ + << ". Check: Reservoir management = Yes, Use water values = No and proper initial " + "reservoir level is provided "; + return false; +} + +bool FinalLevelValidator::checkForInfeasibility() +{ + bool checksOk = hydroAllocationStartMatchesSimulation(); + checksOk = isFinalLevelReachable() && checksOk; + checksOk = isBetweenRuleCurves() && checksOk; + + return checksOk; +} + +bool FinalLevelValidator::hydroAllocationStartMatchesSimulation() const +{ + unsigned initReservoirLvlMonth = hydro_.initializeReservoirLevelDate; // month [0-11] + if (lastSimulationDay_ == DAYS_PER_YEAR && initReservoirLvlMonth == firstMonthOfSimulation_) + { + return true; + } + + errorCollector_(areaName_) << "Year " << year_ + 1 << ": " + << "Hydro allocation must start on the 1st simulation month and " + << "simulation last a whole year"; + + return false; +} + +bool FinalLevelValidator::isFinalLevelReachable() const +{ + double reservoirCapacity = hydro_.reservoirCapacity; + double totalYearInflows = calculateTotalInflows(); + + if ((finalLevel_ - initialLevel_) * reservoirCapacity > totalYearInflows) + { + errorCollector_(areaName_) + << "Year: " << year_ + 1 << " Incompatible total inflows: " << totalYearInflows + << " with initial: " << initialLevel_ << " and final: " << finalLevel_ + << " reservoir levels."; + return false; + } + return true; +} + +double FinalLevelValidator::calculateTotalInflows() const +{ + // calculate yearly inflows + const auto& srcinflows = hydro_.series->storage.getColumn(year_); + + double totalYearInflows = 0.0; + for (unsigned int day = 0; day < DAYS_PER_YEAR; ++day) + { + totalYearInflows += srcinflows[day]; + } + return totalYearInflows; +} + +bool FinalLevelValidator::isBetweenRuleCurves() const +{ + double lowLevelLastDay = hydro_.reservoirLevel[Data::PartHydro::minimum][DAYS_PER_YEAR - 1]; + double highLevelLastDay = hydro_.reservoirLevel[Data::PartHydro::maximum][DAYS_PER_YEAR - 1]; + + if (finalLevel_ < lowLevelLastDay || finalLevel_ > highLevelLastDay) + { + errorCollector_(areaName_) + << "Year: " << year_ + 1 << " Specifed final reservoir level: " << finalLevel_ + << " is incompatible with reservoir level rule curve [" << lowLevelLastDay << " , " + << highLevelLastDay << "]"; + return false; + } + return true; +} + +bool FinalLevelValidator::finalLevelFineForUse() +{ + return finalLevelFineForUse_; +} + +} // namespace Antares::Solver diff --git a/src/solver/hydro/management/management.cpp b/src/solver/hydro/management/management.cpp index 5d8fb79d47..a43dd3161f 100644 --- a/src/solver/hydro/management/management.cpp +++ b/src/solver/hydro/management/management.cpp @@ -23,9 +23,6 @@ #include #include -#include - -#include #include #include @@ -117,12 +114,10 @@ double BetaVariable(double a, double b, MersenneTwister& random) HydroManagement::HydroManagement(const Data::AreaList& areas, const Data::Parameters& params, const Date::Calendar& calendar, - unsigned int maxNbYearsInParallel, Solver::IResultWriter& resultWriter): areas_(areas), calendar_(calendar), parameters_(params), - maxNbYearsInParallel_(maxNbYearsInParallel), resultWriter_(resultWriter) { // Ventilation results memory allocation @@ -142,262 +137,21 @@ HydroManagement::HydroManagement(const Data::AreaList& areas, } } -void HydroManagement::prepareInflowsScaling(uint year) -{ - areas_.each( - [&](const Data::Area& area) - { - const auto& srcinflows = area.hydro.series->storage.getColumn(year); - - auto& data = tmpDataByArea_[&area]; - double totalYearInflows = 0.0; - - for (uint month = 0; month != 12; ++month) - { - uint realmonth = calendar_.months[month].realmonth; - - double totalMonthInflows = 0.0; - - uint firstDayOfMonth = calendar_.months[month].daysYear.first; - - uint firstDayOfNextMonth = calendar_.months[month].daysYear.end; - - for (uint d = firstDayOfMonth; d != firstDayOfNextMonth; ++d) - { - totalMonthInflows += srcinflows[d]; - } - - data.totalMonthInflows[realmonth] = totalMonthInflows; - totalYearInflows += totalMonthInflows; - - if (not(area.hydro.reservoirCapacity < 1e-4)) - { - if (area.hydro.reservoirManagement) - { - data.inflows[realmonth] = totalMonthInflows / (area.hydro.reservoirCapacity); - assert(!std::isnan(data.inflows[month]) && "nan value detect in inflows"); - } - else - { - data.inflows[realmonth] = totalMonthInflows; - } - } - else - { - data.inflows[realmonth] = totalMonthInflows; - } - } - data.totalYearInflows = totalYearInflows; - }); -} - -void HydroManagement::minGenerationScaling(uint year) -{ - areas_.each( - [this, &year](const Data::Area& area) - { - const auto& srcmingen = area.hydro.series->mingen.getColumn(year); - - auto& data = tmpDataByArea_[&area]; - double totalYearMingen = 0.0; - - for (uint month = 0; month != 12; ++month) - { - uint realmonth = calendar_.months[month].realmonth; - uint firstDayOfMonth = calendar_.months[month].daysYear.first; - uint firstDayOfNextMonth = calendar_.months[month].daysYear.end; - - double totalMonthMingen = std::accumulate(srcmingen + firstDayOfMonth * 24, - srcmingen + firstDayOfNextMonth * 24, - 0.); - - data.totalMonthMingen[realmonth] = totalMonthMingen; - totalYearMingen += totalMonthMingen; - - if (!(area.hydro.reservoirCapacity < 1e-4)) - { - if (area.hydro.reservoirManagement) - { - // Set monthly mingen, used later for h2o_m - data.mingens[realmonth] = totalMonthMingen / (area.hydro.reservoirCapacity); - assert(!std::isnan(data.mingens[month]) && "nan value detect in mingen"); - } - else - { - data.mingens[realmonth] = totalMonthMingen; - } - } - else - { - data.mingens[realmonth] = totalMonthMingen; - } - - // Set daily mingen, used later for h2o_d - uint simulationMonth = calendar_.mapping.months[realmonth]; - auto daysPerMonth = calendar_.months[simulationMonth].days; - uint firstDay = calendar_.months[simulationMonth].daysYear.first; - uint endDay = firstDay + daysPerMonth; - - for (uint day = firstDay; day != endDay; ++day) - { - data.dailyMinGen[day] = std::accumulate(srcmingen + day * 24, - srcmingen + day * 24 + 24, - 0.); - } - } - data.totalYearMingen = totalYearMingen; - }); -} - -bool HydroManagement::checkMonthlyMinGeneration(uint year, const Data::Area& area) const -{ - const auto& data = tmpDataByArea_.at(&area); - for (uint month = 0; month != 12; ++month) - { - uint realmonth = calendar_.months[month].realmonth; - // Monthly minimum generation <= Monthly inflows for each month - if (data.totalMonthMingen[realmonth] > data.totalMonthInflows[realmonth]) - { - logs.error() << "In Area " << area.name << " the minimum generation of " - << data.totalMonthMingen[realmonth] << " MW in month " << month + 1 - << " of TS-" << area.hydro.series->mingen.getSeriesIndex(year) + 1 - << " is incompatible with the inflows of " - << data.totalMonthInflows[realmonth] << " MW."; - return false; - } - } - return true; -} - -bool HydroManagement::checkYearlyMinGeneration(uint year, const Data::Area& area) const -{ - const auto& data = tmpDataByArea_.at(&area); - 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-" - << area.hydro.series->mingen.getSeriesIndex(year) + 1 - << " is incompatible with the inflows of " << data.totalYearInflows << " MW."; - return false; - } - return true; -} - -bool HydroManagement::checkWeeklyMinGeneration(uint year, const Data::Area& area) const -{ - const auto& srcinflows = area.hydro.series->storage.getColumn(year); - const auto& srcmingen = area.hydro.series->mingen.getColumn(year); - // Weekly minimum generation <= Weekly inflows for each week - for (uint week = 0; week < calendar_.maxWeeksInYear - 1; ++week) - { - double totalWeekMingen = 0.0; - double totalWeekInflows = 0.0; - for (uint hour = calendar_.weeks[week].hours.first; - hour < calendar_.weeks[week].hours.end && hour < HOURS_PER_YEAR; - ++hour) - { - totalWeekMingen += srcmingen[hour]; - } - - for (uint day = calendar_.weeks[week].daysYear.first; - day < calendar_.weeks[week].daysYear.end; - ++day) - { - totalWeekInflows += srcinflows[day]; - } - if (totalWeekMingen > totalWeekInflows) - { - logs.error() << "In Area " << area.name << " the minimum generation of " - << totalWeekMingen << " MW in week " << week + 1 << " of TS-" - << area.hydro.series->mingen.getSeriesIndex(year) + 1 - << " is incompatible with the inflows of " << totalWeekInflows << " MW."; - return false; - } - } - return true; -} - -bool HydroManagement::checkGenerationPowerConsistency(uint year) const -{ - bool ret = true; - - areas_.each( - [&ret, &year](const Data::Area& area) - { - const auto& srcmingen = area.hydro.series->mingen.getColumn(year); - const auto& srcmaxgen = area.hydro.series->maxHourlyGenPower.getColumn(year); - - const uint tsIndexMin = area.hydro.series->mingen.getSeriesIndex(year); - const uint tsIndexMax = area.hydro.series->maxHourlyGenPower.getSeriesIndex(year); - - for (uint h = 0; h < HOURS_PER_YEAR; ++h) - { - const auto& min = srcmingen[h]; - const auto& max = srcmaxgen[h]; - - if (max < min) - { - logs.error() << "In area: " << area.name << " [hourly] minimum generation of " - << min << " MW in timestep " << h + 1 << " of TS-" << tsIndexMin + 1 - << " is incompatible with the maximum generation of " << max - << " MW in timestep " << h + 1 << " of TS-" << tsIndexMax + 1 - << " MW."; - ret = false; - return; - } - } - }); - - return ret; -} - -bool HydroManagement::checkMinGeneration(uint year) const -{ - bool ret = true; - areas_.each( - [this, &ret, &year](const Data::Area& area) - { - bool useHeuristicTarget = area.hydro.useHeuristicTarget; - bool followLoadModulations = area.hydro.followLoadModulations; - bool reservoirManagement = area.hydro.reservoirManagement; - - if (!useHeuristicTarget) - { - return; - } - - if (!followLoadModulations) - { - ret = checkWeeklyMinGeneration(year, area) && ret; - return; - } - - if (reservoirManagement) - { - ret = checkYearlyMinGeneration(year, area) && ret; - } - else - { - ret = checkMonthlyMinGeneration(year, area) && ret; - } - }); - return ret; -} - void HydroManagement::prepareNetDemand(uint year, Data::SimulationMode mode, - const Antares::Data::Area::ScratchMap& scratchmap) + const Antares::Data::Area::ScratchMap& scratchmap, + HydroSpecificMap& hydro_specific_map) { areas_.each( - [this, &year, &scratchmap, &mode](const Data::Area& area) + [this, &year, &scratchmap, &mode, &hydro_specific_map](Data::Area& area) { const auto& scratchpad = scratchmap.at(&area); const auto& rormatrix = area.hydro.series->ror; const auto* ror = rormatrix.getColumn(year); - auto& data = tmpDataByArea_[&area]; + auto& data = area.hydro.managementData[year]; + auto& hydro_specific = hydro_specific_map[&area]; const double* loadSeries = area.load.series.getColumn(year); const double* windSeries = area.wind.series.getColumn(year); const double* solarSeries = area.solar.series.getColumn(year); @@ -434,17 +188,18 @@ void HydroManagement::prepareNetDemand(uint year, assert(!std::isnan(netdemand) && "hydro management: NaN detected when calculating the net demande"); - data.DLN[dayYear] += netdemand; + hydro_specific.daily[dayYear].DLN += netdemand; } }); } -void HydroManagement::prepareEffectiveDemand() +void HydroManagement::prepareEffectiveDemand(uint year, HydroSpecificMap& hydro_specific_map) const { areas_.each( - [&](Data::Area& area) + [this, &year, &hydro_specific_map](Data::Area& area) { - auto& data = tmpDataByArea_[&area]; + auto& data = area.hydro.managementData[year]; + auto& hydro_specific = hydro_specific_map[&area]; for (uint day = 0; day != 365; ++day) { @@ -455,18 +210,20 @@ void HydroManagement::prepareEffectiveDemand() double effectiveDemand = 0; // area.hydro.allocation is indexed by area index area.hydro.allocation.eachNonNull( - [&](unsigned areaIndex, double value) + [this, &effectiveDemand, &day, &hydro_specific_map](unsigned areaIndex, + double value) { const auto* area = areas_.byIndex[areaIndex]; - effectiveDemand += tmpDataByArea_[area].DLN[day] * value; + effectiveDemand += hydro_specific_map[area].daily[day].DLN * value; }); assert(!std::isnan(effectiveDemand) && "nan value detected for effectiveDemand"); - data.DLE[day] += effectiveDemand; - data.MLE[realmonth] += effectiveDemand; + hydro_specific.daily[day].DLE += effectiveDemand; + hydro_specific.monthly[realmonth].MLE += effectiveDemand; - assert(not std::isnan(data.DLE[day]) && "nan value detected for DLE"); - assert(not std::isnan(data.MLE[realmonth]) && "nan value detected for DLE"); + assert(not std::isnan(hydro_specific.daily[day].DLE) && "nan value detected for DLE"); + assert(not std::isnan(hydro_specific.monthly[realmonth].MLE) + && "nan value detected for DLE"); } auto minimumYear = std::numeric_limits::infinity(); @@ -481,9 +238,9 @@ void HydroManagement::prepareEffectiveDemand() for (uint d = 0; d != daysPerMonth; ++d) { auto dYear = d + dayYear; - if (data.DLE[dYear] < minimumMonth) + if (hydro_specific.daily[dYear].DLE < minimumMonth) { - minimumMonth = data.DLE[dYear]; + minimumMonth = hydro_specific.daily[dYear].DLE; } } @@ -491,13 +248,13 @@ void HydroManagement::prepareEffectiveDemand() { for (uint d = 0; d != daysPerMonth; ++d) { - data.DLE[dayYear + d] -= minimumMonth - 1e-4; + hydro_specific.daily[dayYear + d].DLE -= minimumMonth - 1e-4; } } - if (data.MLE[realmonth] < minimumYear) + if (hydro_specific.monthly[realmonth].MLE < minimumYear) { - minimumYear = data.MLE[realmonth]; + minimumYear = hydro_specific.monthly[realmonth].MLE; } dayYear += daysPerMonth; @@ -507,34 +264,22 @@ void HydroManagement::prepareEffectiveDemand() { for (uint realmonth = 0; realmonth != 12; ++realmonth) { - data.MLE[realmonth] -= minimumYear - 1e-4; + hydro_specific.monthly[realmonth].MLE -= minimumYear - 1e-4; } } }); } -bool HydroManagement::checksOnGenerationPowerBounds(uint year) const -{ - return (checkMinGeneration(year) && checkGenerationPowerConsistency(year)) ? true : false; -} - void HydroManagement::makeVentilation(double* randomReservoirLevel, - Solver::Variable::State& state, uint y, Antares::Data::Area::ScratchMap& scratchmap) { - prepareInflowsScaling(y); - minGenerationScaling(y); - if (!checksOnGenerationPowerBounds(y)) - { - throw FatalError("hydro management: invalid minimum generation"); - } - - prepareNetDemand(y, parameters_.mode, scratchmap); - prepareEffectiveDemand(); + HydroSpecificMap hydro_specific_map; + prepareNetDemand(y, parameters_.mode, scratchmap, hydro_specific_map); + prepareEffectiveDemand(y, hydro_specific_map); - prepareMonthlyOptimalGenerations(randomReservoirLevel, y); - prepareDailyOptimalGenerations(state, y, scratchmap); + prepareMonthlyOptimalGenerations(randomReservoirLevel, y, hydro_specific_map); + prepareDailyOptimalGenerations(y, scratchmap, hydro_specific_map); } } // namespace Antares diff --git a/src/solver/hydro/management/monthly.cpp b/src/solver/hydro/management/monthly.cpp index 2cb868da72..8afcd0e26f 100644 --- a/src/solver/hydro/management/monthly.cpp +++ b/src/solver/hydro/management/monthly.cpp @@ -59,9 +59,9 @@ static void CheckHydroAllocationProblem(Data::Area& area, { logs.warning() << area.id << ": lvi = " << lvi; logs.warning() << area.id << ": cost = " << problem.CoutDepassementVolume; - for (uint month = 0; month != 12; ++month) + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { - uint realmonth = (initLevelMonth + month) % 12; + uint realmonth = (initLevelMonth + month) % MONTHS_PER_YEAR; logs.warning() << "month: " << ((realmonth < 10) ? "0" : "") << realmonth << ", turb.max: " << problem.TurbineMax[realmonth] << ", turb.cible: " << problem.TurbineCible[realmonth] @@ -72,9 +72,9 @@ static void CheckHydroAllocationProblem(Data::Area& area, logs.info(); problem.Volume[initLevelMonth] = lvi; - for (uint month = 0; month != 12; ++month) + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { - uint realmonth = (initLevelMonth + month) % 12; + uint realmonth = (initLevelMonth + month) % MONTHS_PER_YEAR; logs.warning() << "month: " << ((realmonth < 10) ? "0" : "") << realmonth << ", turbine: " << problem.Turbine[realmonth] << ", volume: " << problem.Volume[realmonth]; @@ -82,20 +82,23 @@ static void CheckHydroAllocationProblem(Data::Area& area, } } -double HydroManagement::prepareMonthlyTargetGenerations(Data::Area& area, TmpDataByArea& data) +double HydroManagement::prepareMonthlyTargetGenerations( + Data::Area& area, + Antares::Data::AreaDependantHydroManagementData& data, + Antares::Data::TimeDependantHydroManagementData& hydro_specific) { double total = 0; - for (uint realmonth = 0; realmonth != 12; ++realmonth) + for (uint realmonth = 0; realmonth != MONTHS_PER_YEAR; ++realmonth) { total += data.inflows[realmonth]; } if (not area.hydro.followLoadModulations) { - for (uint realmonth = 0; realmonth != 12; ++realmonth) + for (uint realmonth = 0; realmonth != MONTHS_PER_YEAR; ++realmonth) { - data.MTG[realmonth] = data.inflows[realmonth]; + hydro_specific.monthly[realmonth].MTG = data.inflows[realmonth]; } return total; @@ -103,21 +106,21 @@ double HydroManagement::prepareMonthlyTargetGenerations(Data::Area& area, TmpDat double monthlyMaxDemand = -std::numeric_limits::infinity(); - for (uint realmonth = 0; realmonth != 12; ++realmonth) + for (uint realmonth = 0; realmonth != MONTHS_PER_YEAR; ++realmonth) { - if (data.MLE[realmonth] > monthlyMaxDemand) + if (hydro_specific.monthly[realmonth].MLE > monthlyMaxDemand) { - monthlyMaxDemand = data.MLE[realmonth]; + monthlyMaxDemand = hydro_specific.monthly[realmonth].MLE; } } if (!Utils::isZero(monthlyMaxDemand)) { double coeff = 0.; - for (uint realmonth = 0; realmonth != 12; ++realmonth) + for (uint realmonth = 0; realmonth != MONTHS_PER_YEAR; ++realmonth) { - assert(data.MLE[realmonth] / monthlyMaxDemand >= 0.); - coeff += std::pow(data.MLE[realmonth] / monthlyMaxDemand, + assert(hydro_specific.monthly[realmonth].MLE / monthlyMaxDemand >= 0.); + coeff += std::pow(hydro_specific.monthly[realmonth].MLE / monthlyMaxDemand, area.hydro.intermonthlyBreakdown); } @@ -126,34 +129,38 @@ double HydroManagement::prepareMonthlyTargetGenerations(Data::Area& area, TmpDat coeff = total / coeff; } - for (uint realmonth = 0; realmonth != 12; ++realmonth) + for (uint realmonth = 0; realmonth != MONTHS_PER_YEAR; ++realmonth) { - assert(data.MLE[realmonth] / monthlyMaxDemand >= 0.); - data.MTG[realmonth] = coeff - * std::pow(data.MLE[realmonth] / monthlyMaxDemand, - area.hydro.intermonthlyBreakdown); + assert(hydro_specific.monthly[realmonth].MLE / monthlyMaxDemand >= 0.); + hydro_specific.monthly[realmonth].MTG = coeff + * std::pow(hydro_specific.monthly[realmonth].MLE + / monthlyMaxDemand, + area.hydro.intermonthlyBreakdown); } } else { double coeff = total / 12.; - for (uint realmonth = 0; realmonth != 12; ++realmonth) + for (uint realmonth = 0; realmonth != MONTHS_PER_YEAR; ++realmonth) { - data.MTG[realmonth] = coeff; + hydro_specific.monthly[realmonth].MTG = coeff; } } return total; } -void HydroManagement::prepareMonthlyOptimalGenerations(double* random_reservoir_level, uint y) +void HydroManagement::prepareMonthlyOptimalGenerations(const double* random_reservoir_level, + uint y, + HydroSpecificMap& hydro_specific_map) { uint indexArea = 0; areas_.each( - [&](Data::Area& area) + [this, &random_reservoir_level, &y, &indexArea, &hydro_specific_map](Data::Area& area) { - auto& data = tmpDataByArea_[&area]; + auto& data = area.hydro.managementData[y]; + auto& hydro_specific = hydro_specific_map[&area]; auto& minLvl = area.hydro.reservoirLevel[Data::PartHydro::minimum]; auto& maxLvl = area.hydro.reservoirLevel[Data::PartHydro::maximum]; @@ -166,8 +173,6 @@ void HydroManagement::prepareMonthlyOptimalGenerations(double* random_reservoir_ lvi = random_reservoir_level[indexArea]; } - indexArea++; - double solutionCost = 0.; double solutionCostNoised = 0.; @@ -175,23 +180,23 @@ void HydroManagement::prepareMonthlyOptimalGenerations(double* random_reservoir_ { auto problem = H2O_M_Instanciation(1); - double totalInflowsYear = prepareMonthlyTargetGenerations(area, data); + double totalInflowsYear = prepareMonthlyTargetGenerations(area, data, hydro_specific); assert(totalInflowsYear >= 0.); problem.CoutDepassementVolume = 1e2; problem.CoutViolMaxDuVolumeMin = 1e5; problem.VolumeInitial = lvi; - for (unsigned month = 0; month != 12; ++month) + for (unsigned month = 0; month != MONTHS_PER_YEAR; ++month) { - uint realmonth = (initReservoirLvlMonth + month) % 12; + uint realmonth = (initReservoirLvlMonth + month) % MONTHS_PER_YEAR; uint simulationMonth = calendar_.mapping.months[realmonth]; uint firstDay = calendar_.months[simulationMonth].daysYear.first; problem.TurbineMax[month] = totalInflowsYear; problem.TurbineMin[month] = data.mingens[realmonth]; - problem.TurbineCible[month] = data.MTG[realmonth]; + problem.TurbineCible[month] = hydro_specific.monthly[realmonth].MTG; problem.Apport[month] = data.inflows[realmonth]; problem.VolumeMin[month] = minLvl[firstDay]; problem.VolumeMax[month] = maxLvl[firstDay]; @@ -207,14 +212,15 @@ void HydroManagement::prepareMonthlyOptimalGenerations(double* random_reservoir_ CheckHydroAllocationProblem(area, problem, initReservoirLvlMonth, lvi); } - for (uint month = 0; month != 12; ++month) + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { - uint realmonth = (initReservoirLvlMonth + month) % 12; + uint realmonth = (initReservoirLvlMonth + month) % MONTHS_PER_YEAR; - data.MOG[realmonth] = problem.Turbine[month] * area.hydro.reservoirCapacity; - data.MOL[realmonth] = problem.Volume[month]; + hydro_specific.monthly[realmonth].MOG = problem.Turbine[month] + * area.hydro.reservoirCapacity; + hydro_specific.monthly[realmonth].MOL = problem.Volume[month]; } - data.MOL[initReservoirLvlMonth] = lvi; + hydro_specific.monthly[initReservoirLvlMonth].MOL = lvi; solutionCost = problem.ProblemeHydraulique.CoutDeLaSolution; solutionCostNoised = problem.ProblemeHydraulique.CoutDeLaSolutionBruite; @@ -242,20 +248,24 @@ void HydroManagement::prepareMonthlyOptimalGenerations(double* random_reservoir_ { auto& reservoirLevel = area.hydro.reservoirLevel[Data::PartHydro::average]; - for (uint realmonth = 0; realmonth != 12; ++realmonth) + for (uint realmonth = 0; realmonth != MONTHS_PER_YEAR; ++realmonth) { - data.MOG[realmonth] = data.inflows[realmonth]; - data.MOL[realmonth] = reservoirLevel[realmonth]; + hydro_specific.monthly[realmonth].MOG = data.inflows[realmonth]; + hydro_specific.monthly[realmonth].MOL = reservoirLevel[realmonth]; } } #ifndef NDEBUG - for (uint realmonth = 0; realmonth != 12; ++realmonth) + for (uint realmonth = 0; realmonth != MONTHS_PER_YEAR; ++realmonth) { - assert(!std::isnan(data.MOG[realmonth]) && "nan value detected for MOG"); - assert(!std::isnan(data.MOL[realmonth]) && "nan value detected for MOL"); - assert(!std::isinf(data.MOG[realmonth]) && "infinite value detected for MOG"); - assert(!std::isinf(data.MOL[realmonth]) && "infinite value detected for MOL"); + assert(!std::isnan(hydro_specific.monthly[realmonth].MOG) + && "nan value detected for MOG"); + assert(!std::isnan(hydro_specific.monthly[realmonth].MOL) + && "nan value detected for MOL"); + assert(!std::isinf(hydro_specific.monthly[realmonth].MOG) + && "infinite value detected for MOG"); + assert(!std::isinf(hydro_specific.monthly[realmonth].MOL) + && "infinite value detected for MOL"); } #endif if (parameters_.hydroDebug) @@ -282,9 +292,9 @@ void HydroManagement::prepareMonthlyOptimalGenerations(double* random_reservoir_ buffer << '\t' << "\tInflows" << '\t' << "\tTarget Gen." << "\tTurbined" << "\tLevels" << '\t' << "\tLvl min" << '\t' << "\tLvl max\n"; - for (uint month = 0; month != 12; ++month) + for (uint month = 0; month != MONTHS_PER_YEAR; ++month) { - uint realmonth = (initReservoirLvlMonth + month) % 12; + uint realmonth = (initReservoirLvlMonth + month) % MONTHS_PER_YEAR; uint simulationMonth = calendar_.mapping.months[realmonth]; @@ -295,9 +305,10 @@ void HydroManagement::prepareMonthlyOptimalGenerations(double* random_reservoir_ buffer << monthName[0] << monthName[1] << monthName[2] << '\t'; buffer << '\t'; buffer << data.inflows[realmonth] << '\t'; - buffer << data.MTG[realmonth] << '\t'; - buffer << data.MOG[realmonth] / area.hydro.reservoirCapacity << '\t'; - buffer << data.MOL[realmonth] << '\t'; + buffer << hydro_specific.monthly[realmonth].MTG << '\t'; + buffer << hydro_specific.monthly[realmonth].MOG / area.hydro.reservoirCapacity + << '\t'; + buffer << hydro_specific.monthly[realmonth].MOL << '\t'; buffer << minLvl[firstDay] << '\t'; buffer << maxLvl[firstDay] << '\t'; buffer << '\n'; @@ -305,6 +316,7 @@ void HydroManagement::prepareMonthlyOptimalGenerations(double* random_reservoir_ auto content = buffer.str(); resultWriter_.addEntryFromBuffer(path.str(), content); } + indexArea++; }); } diff --git a/src/solver/hydro/monthly/h2o_m_resoudre_le_probleme_lineaire.cpp b/src/solver/hydro/monthly/h2o_m_resoudre_le_probleme_lineaire.cpp index 75f8178c79..f65ec03e6e 100644 --- a/src/solver/hydro/monthly/h2o_m_resoudre_le_probleme_lineaire.cpp +++ b/src/solver/hydro/monthly/h2o_m_resoudre_le_probleme_lineaire.cpp @@ -132,7 +132,7 @@ void H2O_M_ResoudreLeProblemeLineaire(DONNEES_ANNUELLES& DonneesAnnuelles, int N { SPX_LibererProbleme(ProbSpx); - ProbSpx = NULL; + ProbSpx = nullptr; PremierPassage = false; goto RESOLUTION; } diff --git a/src/solver/infeasible-problem-analysis/CMakeLists.txt b/src/solver/infeasible-problem-analysis/CMakeLists.txt index 720842fd6a..72b93ad153 100644 --- a/src/solver/infeasible-problem-analysis/CMakeLists.txt +++ b/src/solver/infeasible-problem-analysis/CMakeLists.txt @@ -10,14 +10,15 @@ set(SRC_INFEASIBLE_PROBLEM_ANALYSIS include/antares/solver/infeasible-problem-analysis/unfeasible-pb-analyzer.h include/antares/solver/infeasible-problem-analysis/report.h report.cpp - include/antares/solver/infeasible-problem-analysis/constraint.h - constraint.cpp + include/antares/solver/infeasible-problem-analysis/watched-constraints.h + watched-constraints.cpp ) add_library(infeasible_problem_analysis ${SRC_INFEASIBLE_PROBLEM_ANALYSIS}) target_link_libraries(infeasible_problem_analysis PRIVATE ortools::ortools + Boost::headers Antares::logs ) target_include_directories(infeasible_problem_analysis diff --git a/src/solver/infeasible-problem-analysis/constraint-slack-analysis.cpp b/src/solver/infeasible-problem-analysis/constraint-slack-analysis.cpp index 785d4670f8..68c11ff003 100644 --- a/src/solver/infeasible-problem-analysis/constraint-slack-analysis.cpp +++ b/src/solver/infeasible-problem-analysis/constraint-slack-analysis.cpp @@ -31,15 +31,26 @@ using namespace operations_research; +namespace +{ +bool greaterSlackSolutions(const MPVariable* a, const MPVariable* b) +{ + return a->solution_value() > b->solution_value(); +} + +constexpr unsigned int nbMaxSlackVarsToKeep = 10; +} // namespace + namespace Antares::Optimization { void ConstraintSlackAnalysis::run(MPSolver* problem) { - addSlackVariables(problem); + selectConstraintsToWatch(problem); + addSlackVariablesToConstraints(problem); if (slackVariables_.empty()) { - logs.error() << title() << " : no constraints have been selected"; + logs.warning() << title() << " : no constraints have been selected"; return; } @@ -52,10 +63,24 @@ void ConstraintSlackAnalysis::run(MPSolver* problem) return; } - hasDetectedInfeasibilityCause_ = true; + sortSlackVariablesByValue(); + trimSlackVariables(); + if (hasDetectedInfeasibilityCause_ = anySlackVariableNonZero(); !hasDetectedInfeasibilityCause_) + { + logs.warning() << title() << " : no violation detected for selected constraints."; + } } -void ConstraintSlackAnalysis::addSlackVariables(MPSolver* problem) +void ConstraintSlackAnalysis::selectConstraintsToWatch(MPSolver* problem) +{ + ConstraintsFactory factory; + std::regex rgx = factory.constraintsFilter(); + std::ranges::copy_if(problem->constraints(), + std::back_inserter(constraintsToWatch_), + [&rgx](auto* c) { return std::regex_search(c->name(), rgx); }); +} + +void ConstraintSlackAnalysis::addSlackVariablesToConstraints(MPSolver* problem) { /* Optimization: We assess that less than 1 every 3 constraint will match @@ -64,29 +89,21 @@ void ConstraintSlackAnalysis::addSlackVariables(MPSolver* problem) */ const unsigned int selectedConstraintsInverseRatio = 3; slackVariables_.reserve(problem->NumConstraints() / selectedConstraintsInverseRatio); - std::regex rgx(constraint_name_pattern); const double infinity = MPSolver::infinity(); - for (MPConstraint* constraint: problem->constraints()) + for (MPConstraint* c: constraintsToWatch_) { - if (std::regex_search(constraint->name(), rgx)) + if (c->lb() > -infinity) + { + const MPVariable* slack = problem->MakeNumVar(0, infinity, c->name() + "::low"); + c->SetCoefficient(slack, 1.); + slackVariables_.push_back(slack); + } + + if (c->ub() < infinity) { - if (constraint->lb() != -infinity) - { - const MPVariable* slack = problem->MakeNumVar(0, - infinity, - constraint->name() + "::low"); - constraint->SetCoefficient(slack, 1.); - slackVariables_.push_back(slack); - } - - if (constraint->ub() != infinity) - { - const MPVariable* slack = problem->MakeNumVar(0, - infinity, - constraint->name() + "::up"); - constraint->SetCoefficient(slack, -1.); - slackVariables_.push_back(slack); - } + const MPVariable* slack = problem->MakeNumVar(0, infinity, c->name() + "::up"); + c->SetCoefficient(slack, -1.); + slackVariables_.push_back(slack); } } } @@ -104,10 +121,35 @@ void ConstraintSlackAnalysis::buildObjective(MPSolver* problem) const objective->SetMinimization(); } +void ConstraintSlackAnalysis::sortSlackVariablesByValue() +{ + std::sort(std::begin(slackVariables_), std::end(slackVariables_), ::greaterSlackSolutions); +} + +void ConstraintSlackAnalysis::trimSlackVariables() +{ + unsigned int nbSlackVars = slackVariables_.size(); + slackVariables_.resize(std::min(nbMaxSlackVarsToKeep, nbSlackVars)); +} + +bool ConstraintSlackAnalysis::anySlackVariableNonZero() +{ + return std::ranges::any_of(slackVariables_, + [&](auto& v) { return v->solution_value() > thresholdNonZero; }); +} + +const std::vector& +ConstraintSlackAnalysis::largestSlackVariables() +{ + return slackVariables_; +} + void ConstraintSlackAnalysis::printReport() const { InfeasibleProblemReport report(slackVariables_); - report.prettyPrint(); + report.storeSuspiciousConstraints(); + report.storeInfeasibilityCauses(); + std::ranges::for_each(report.getLogs(), [](auto& line) { logs.notice() << line; }); } } // namespace Antares::Optimization diff --git a/src/solver/infeasible-problem-analysis/constraint.cpp b/src/solver/infeasible-problem-analysis/constraint.cpp deleted file mode 100644 index 0e95848ad9..0000000000 --- a/src/solver/infeasible-problem-analysis/constraint.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2007-2024, RTE (https://www.rte-france.com) - * See AUTHORS.txt - * SPDX-License-Identifier: MPL-2.0 - * This file is part of Antares-Simulator, - * Adequacy and Performance assessment for interconnected energy networks. - * - * Antares_Simulator is free software: you can redistribute it and/or modify - * it under the terms of the Mozilla Public Licence 2.0 as published by - * the Mozilla Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Antares_Simulator is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Mozilla Public Licence 2.0 for more details. - * - * You should have received a copy of the Mozilla Public Licence 2.0 - * along with Antares_Simulator. If not, see . - */ -#include "antares/solver/infeasible-problem-analysis/constraint.h" - -#include -#include -#include -#include - -namespace -{ -const std::string kUnknown = ""; -} - -namespace Antares::Optimization -{ -Constraint::Constraint(const std::string& input, const double slackValue): - mInput(input), - mSlackValue(slackValue) -{ -} - -std::size_t Constraint::extractItems() -{ - const auto beg = mInput.begin(); - const auto end = mInput.end(); - std::size_t newPos = 0; - const std::size_t sepSize = 2; - const std::size_t inputSize = mInput.size(); - for (std::size_t pos = 0; pos < inputSize; pos = newPos + sepSize) - { - newPos = mInput.find("::", pos); - if (newPos == std::string::npos) - { - mItems.emplace_back(beg + pos, end); - break; - } - if (newPos > pos) - { - mItems.emplace_back(beg + pos, beg + newPos); - } - } - return mItems.size(); -} - -double Constraint::getSlackValue() const -{ - return mSlackValue; -} - -class StringIsNotWellFormated: public std::runtime_error -{ -public: - StringIsNotWellFormated(const std::string& error_message): - std::runtime_error(error_message) - { - } -}; - -std::string StringBetweenAngleBrackets(const std::string& str) -{ - const auto& begin = str.begin(); - const auto& end = str.end(); - - auto left = std::find(begin, end, '<'); - - if (left == end) - { - std::ostringstream stream; - stream << std::string("Error the string: ") << std::quoted(str) - << " does not contains the left angle bracket " << std::quoted("<"); - throw StringIsNotWellFormated(stream.str()); - } - - auto right = std::find(begin, end, '>'); - if (right == end) - { - std::ostringstream stream; - stream << std::string("Error the string: ") << std::quoted(str) - << " does not contains the right angle bracket " << std::quoted(">"); - throw StringIsNotWellFormated(stream.str()); - } - - if (std::distance(left, right) <= 1) - { - std::ostringstream stream; - stream << std::string("Error the string: ") << std::quoted(str) << " must be of format " - << std::quoted("**"); - throw StringIsNotWellFormated(stream.str()); - } - return std::string(left + 1, right); -} - -std::string Constraint::getAreaName() const -{ - if ((getType() == ConstraintType::binding_constraint_hourly) - || (getType() == ConstraintType::binding_constraint_daily) - || (getType() == ConstraintType::binding_constraint_weekly)) - { - return ""; - } - return StringBetweenAngleBrackets(mItems.at(1)); -} - -std::string Constraint::getTimeStepInYear() const -{ - switch (getType()) - { - case ConstraintType::binding_constraint_hourly: - case ConstraintType::binding_constraint_daily: - case ConstraintType::fictitious_load: - case ConstraintType::hydro_reservoir_level: - case ConstraintType::short_term_storage_level: - return StringBetweenAngleBrackets(mItems.at(mItems.size() - 2)); - default: - return kUnknown; - } -} - -ConstraintType Constraint::getType() const -{ - assert(mItems.size() > 1); - if (mItems.at(1) == "hourly") - { - return ConstraintType::binding_constraint_hourly; - } - if (mItems.at(1) == "daily") - { - return ConstraintType::binding_constraint_daily; - } - if (mItems.at(1) == "weekly") - { - return ConstraintType::binding_constraint_weekly; - } - if (mItems.at(0) == "FictiveLoads") - { - return ConstraintType::fictitious_load; - } - if (mItems.at(0) == "AreaHydroLevel") - { - return ConstraintType::hydro_reservoir_level; - } - if (mItems.at(0) == "Level") - { - return ConstraintType::short_term_storage_level; - } - return ConstraintType::none; -} - -std::string Constraint::getBindingConstraintName() const -{ - switch (getType()) - { - case ConstraintType::binding_constraint_hourly: - case ConstraintType::binding_constraint_daily: - case ConstraintType::binding_constraint_weekly: - return mItems.at(0); - default: - return kUnknown; - } -} - -std::string Constraint::getSTSName() const -{ - if (getType() == ConstraintType::short_term_storage_level) - { - return StringBetweenAngleBrackets(mItems.at(2)); - } - else - { - return kUnknown; - } -} - -std::string Constraint::prettyPrint() const -{ - switch (getType()) - { - case ConstraintType::binding_constraint_hourly: - return "Hourly binding constraint '" + getBindingConstraintName() + "' at hour " - + getTimeStepInYear(); - case ConstraintType::binding_constraint_daily: - return "Daily binding constraint '" + getBindingConstraintName() + "' at day " - + getTimeStepInYear(); - case ConstraintType::binding_constraint_weekly: - return "Weekly binding constraint '" + getBindingConstraintName(); - - case ConstraintType::fictitious_load: - return "Last resort shedding status at area '" + getAreaName() + "' at hour " - + getTimeStepInYear(); - case ConstraintType::hydro_reservoir_level: - return "Hydro reservoir constraint at area '" + getAreaName() + "' at hour " - + getTimeStepInYear(); - case ConstraintType::short_term_storage_level: - return "Short-term-storage reservoir constraint at area '" + getAreaName() + "' in STS '" - + getSTSName() + "' at hour " + getTimeStepInYear(); - - default: - return kUnknown; - } -} -} // namespace Antares::Optimization diff --git a/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/constraint-slack-analysis.h b/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/constraint-slack-analysis.h index a298b6b026..352176a41e 100644 --- a/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/constraint-slack-analysis.h +++ b/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/constraint-slack-analysis.h @@ -23,9 +23,11 @@ #include #include "unfeasibility-analysis.h" +#include "watched-constraints.h" namespace operations_research { +class MPConstraint; class MPVariable; class MPSolver; } // namespace operations_research @@ -40,7 +42,6 @@ namespace Antares::Optimization class ConstraintSlackAnalysis: public UnfeasibilityAnalysis { public: - ConstraintSlackAnalysis() = default; ~ConstraintSlackAnalysis() override = default; void run(operations_research::MPSolver* problem) override; @@ -51,13 +52,19 @@ class ConstraintSlackAnalysis: public UnfeasibilityAnalysis return "Slack variables analysis"; } + const std::vector& largestSlackVariables(); + private: + void selectConstraintsToWatch(operations_research::MPSolver* problem); + void addSlackVariablesToConstraints(operations_research::MPSolver* problem); void buildObjective(operations_research::MPSolver* problem) const; - void addSlackVariables(operations_research::MPSolver* problem); + void sortSlackVariablesByValue(); + void trimSlackVariables(); + bool anySlackVariableNonZero(); + std::vector constraintsToWatch_; std::vector slackVariables_; - const std::string constraint_name_pattern = "^AreaHydroLevel::|::hourly::|::daily::|::weekly::|" - "^FictiveLoads::|^Level::"; + const double thresholdNonZero = 1e-06; }; } // namespace Antares::Optimization diff --git a/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/report.h b/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/report.h index 6ebb919fb1..1d498eb653 100644 --- a/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/report.h +++ b/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/report.h @@ -21,10 +21,12 @@ #pragma once #include +#include #include #include -#include "constraint.h" +#include "ortools/linear_solver/linear_solver.h" +#include "watched-constraints.h" namespace operations_research { @@ -37,20 +39,16 @@ class InfeasibleProblemReport { public: InfeasibleProblemReport() = delete; - explicit InfeasibleProblemReport( - const std::vector& slackVariables); - void prettyPrint(); + explicit InfeasibleProblemReport(const std::vector&); + void storeSuspiciousConstraints(); + void storeInfeasibilityCauses(); + std::vector getLogs(); private: - void turnSlackVarsIntoConstraints( - const std::vector& slackVariables); - void sortConstraints(); - void trimConstraints(); - void extractItems(); - void logSuspiciousConstraints(); + void buildConstraintsFromSlackVars(const std::vector&); + void filterConstraintsToOneByType(); - std::vector mConstraints; - std::map mTypes; - const unsigned int nbVariables = 10; + std::vector> constraints_; + std::vector report_; }; } // namespace Antares::Optimization diff --git a/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/watched-constraints.h b/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/watched-constraints.h new file mode 100644 index 0000000000..1c1c533d71 --- /dev/null +++ b/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/watched-constraints.h @@ -0,0 +1,113 @@ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Antares::Optimization +{ +class WatchedConstraint +{ +public: + explicit WatchedConstraint(const std::string& name, const double slackValue); + virtual ~WatchedConstraint() = default; + virtual std::string infeasibility() = 0; + virtual std::string infeasibilityCause() = 0; + double slackValue() const; + +protected: + const std::vector& splitName() const; + +private: + std::vector splitName_; + double slack_value_; +}; + +class HourlyBC: public WatchedConstraint +{ + using WatchedConstraint::WatchedConstraint; + +public: + ~HourlyBC() override = default; + std::string infeasibility() override; + std::string infeasibilityCause() override; +}; + +class DailyBC: public WatchedConstraint +{ + using WatchedConstraint::WatchedConstraint; + +public: + ~DailyBC() override = default; + std::string infeasibility() override; + std::string infeasibilityCause() override; +}; + +class WeeklyBC: public WatchedConstraint +{ + using WatchedConstraint::WatchedConstraint; + +public: + ~WeeklyBC() override = default; + std::string infeasibility() override; + std::string infeasibilityCause() override; +}; + +class FictitiousLoad: public WatchedConstraint +{ + using WatchedConstraint::WatchedConstraint; + +public: + ~FictitiousLoad() override = default; + std::string infeasibility() override; + std::string infeasibilityCause() override; +}; + +class HydroLevel: public WatchedConstraint +{ + using WatchedConstraint::WatchedConstraint; + +public: + ~HydroLevel() override = default; + std::string infeasibility() override; + std::string infeasibilityCause() override; +}; + +class STS: public WatchedConstraint +{ + using WatchedConstraint::WatchedConstraint; + +public: + ~STS() override = default; + std::string infeasibility() override; + std::string infeasibilityCause() override; +}; + +class HydroProduction: public WatchedConstraint +{ + using WatchedConstraint::WatchedConstraint; + +public: + ~HydroProduction() override = default; + std::string infeasibility() override; + std::string infeasibilityCause() override; +}; + +class ConstraintsFactory +{ +public: + explicit ConstraintsFactory(); + std::unique_ptr create(const std::string&, const double) const; + std::regex constraintsFilter(); + +private: + std::map(const std::string&, const double)>> + regex_to_ctypes_; +}; + +} // namespace Antares::Optimization diff --git a/src/solver/infeasible-problem-analysis/report.cpp b/src/solver/infeasible-problem-analysis/report.cpp index 28e72109bf..a323b30be2 100644 --- a/src/solver/infeasible-problem-analysis/report.cpp +++ b/src/solver/infeasible-problem-analysis/report.cpp @@ -21,105 +21,87 @@ #include "antares/solver/infeasible-problem-analysis/report.h" #include - -#include -#include "antares/solver/infeasible-problem-analysis/constraint.h" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include "ortools/linear_solver/linear_solver.h" -#pragma GCC diagnostic pop - -using namespace operations_research; - -static bool compareSlackSolutions(const Antares::Optimization::Constraint& a, - const Antares::Optimization::Constraint& b) -{ - return a.getSlackValue() > b.getSlackValue(); -} +#include +#include namespace Antares::Optimization { InfeasibleProblemReport::InfeasibleProblemReport( - const std::vector& slackVariables) + const std::vector& slackVariables) { - turnSlackVarsIntoConstraints(slackVariables); - sortConstraints(); - trimConstraints(); + buildConstraintsFromSlackVars(slackVariables); } -void InfeasibleProblemReport::turnSlackVarsIntoConstraints( - const std::vector& slackVariables) +void InfeasibleProblemReport::buildConstraintsFromSlackVars( + const std::vector& slackVariables) { - for (const MPVariable* slack: slackVariables) + const ConstraintsFactory constraintsFactory; + for (const auto* slackVar: slackVariables) { - mConstraints.emplace_back(slack->name(), slack->solution_value()); + auto constraint = constraintsFactory.create(slackVar->name(), slackVar->solution_value()); + if (constraint) + { + constraints_.push_back(std::move(constraint)); + } } } -void InfeasibleProblemReport::sortConstraints() +bool lessTypeName(const std::shared_ptr a, + const std::shared_ptr b) { - std::sort(std::begin(mConstraints), std::end(mConstraints), ::compareSlackSolutions); + const WatchedConstraint* a_raw = a.get(); + const WatchedConstraint* b_raw = b.get(); + // TODO Compiler-dependent behavior + return std::type_index(typeid(*a_raw)) < std::type_index(typeid(*b_raw)); } -void InfeasibleProblemReport::trimConstraints() +bool sameType(const std::shared_ptr a, + const std::shared_ptr b) { - if (nbVariables <= mConstraints.size()) - { - mConstraints.resize(nbVariables); - } + const WatchedConstraint* a_raw = a.get(); + const WatchedConstraint* b_raw = b.get(); + return std::type_index(typeid(*a_raw)) == std::type_index(typeid(*b_raw)); } -void InfeasibleProblemReport::extractItems() +bool greaterValue(const std::shared_ptr a, std::shared_ptr b) { - for (auto& c: mConstraints) - { - if (c.extractItems() == 0) - { - return; - } - mTypes[c.getType()]++; - } + return a->slackValue() > b->slackValue(); } -void InfeasibleProblemReport::logSuspiciousConstraints() +void InfeasibleProblemReport::filterConstraintsToOneByType() { - Antares::logs.error() << "The following constraints are suspicious (first = most suspicious)"; - for (const auto& c: mConstraints) - { - Antares::logs.error() << c.prettyPrint(); - } - Antares::logs.error() << "Possible causes of infeasibility:"; - if (mTypes[ConstraintType::hydro_reservoir_level] > 0) - { - Antares::logs.error() << "* Hydro reservoir impossible to manage with cumulative options " - "\"hard bounds without heuristic\""; - } - if (mTypes[ConstraintType::fictitious_load] > 0) - { - Antares::logs.error() << "* Last resort shedding status,"; - } - if (mTypes[ConstraintType::short_term_storage_level] > 0) + // 1. Grouping constraints by C++ type (inside a group, order of instances remains unchanged) + std::ranges::stable_sort(constraints_, lessTypeName); + // 2. Keeping the first instances of each group, and rejecting others (= duplicates) to the end. + auto duplicates = std::ranges::unique(constraints_, sameType); + // 3. Removing trailing duplicates + constraints_.erase(duplicates.begin(), duplicates.end()); + // 4. Sorting remaining constraints by slack value (in descending order) + std::ranges::sort(constraints_, greaterValue); +} + +void InfeasibleProblemReport::storeSuspiciousConstraints() +{ + report_.push_back("Violated constraints:"); + for (const auto& c: constraints_) { - Antares::logs.error() - << "* Short-term storage reservoir level impossible to manage. Please check inflows, " - "lower & upper curves and initial level (if prescribed),"; + report_.push_back(c->infeasibility()); } +} - const unsigned int bcCount = mTypes[ConstraintType::binding_constraint_hourly] - + mTypes[ConstraintType::binding_constraint_daily] - + mTypes[ConstraintType::binding_constraint_weekly]; - if (bcCount > 0) +void InfeasibleProblemReport::storeInfeasibilityCauses() +{ + filterConstraintsToOneByType(); + report_.push_back("Possible causes of infeasibility:"); + for (const auto& c: constraints_) { - Antares::logs.error() << "* Binding constraints,"; + report_.push_back(c->infeasibilityCause()); } - - Antares::logs.error() << "* Negative hurdle costs on lines with infinite capacity (rare)."; } -void InfeasibleProblemReport::prettyPrint() +std::vector InfeasibleProblemReport::getLogs() { - extractItems(); - logSuspiciousConstraints(); + return report_; } } // namespace Antares::Optimization diff --git a/src/solver/infeasible-problem-analysis/watched-constraints.cpp b/src/solver/infeasible-problem-analysis/watched-constraints.cpp new file mode 100644 index 0000000000..3404dc06d2 --- /dev/null +++ b/src/solver/infeasible-problem-analysis/watched-constraints.cpp @@ -0,0 +1,191 @@ +#include "antares/solver/infeasible-problem-analysis/watched-constraints.h" + +#include + +#include +#include +#include + +class StringIsNotWellFormated: public std::runtime_error +{ +public: + StringIsNotWellFormated(const std::string& error_message): + std::runtime_error(error_message) + { + } +}; + +std::string StringBetweenAngleBrackets(const std::string& constraintName) +{ + std::vector split_name; + boost::split(split_name, constraintName, boost::is_any_of("<>")); + + std::string err_msg = "Error: "; + if (split_name.size() < 3) + { + err_msg += "constraint name '" + constraintName + "' misses '<' and/or '>' bracket"; + throw StringIsNotWellFormated(err_msg); + } + if (split_name[1].empty()) + { + err_msg += "constraint name '" + constraintName + "' must be of format '**'"; + throw StringIsNotWellFormated(err_msg); + } + return split_name[1]; +} + +std::string timeStep(std::vector splitName) +{ + return StringBetweenAngleBrackets(splitName.rbegin()[1]); +} + +std::string shortName(std::vector splitName) +{ + return splitName.at(0); +} + +std::string areaName(std::vector splitName) +{ + return StringBetweenAngleBrackets(splitName.at(1)); +} + +std::string STSname(std::vector splitName) +{ + return StringBetweenAngleBrackets(splitName.at(2)); +} + +namespace Antares::Optimization +{ + +// --- Generic constraint --- +WatchedConstraint::WatchedConstraint(const std::string& name, const double slackValue): + slack_value_(slackValue) +{ + boost::algorithm::split_regex(splitName_, name, boost::regex("::")); +} + +const std::vector& WatchedConstraint::splitName() const +{ + return splitName_; +} + +double WatchedConstraint::slackValue() const +{ + return slack_value_; +} + +std::string HourlyBC::infeasibility() +{ + return "Hourly BC '" + shortName(splitName()) + "' at hour " + timeStep(splitName()); +} + +std::string HourlyBC::infeasibilityCause() +{ + return "* Hourly binding constraints."; +} + +// --- Daily BC constraint --- +std::string DailyBC::infeasibility() +{ + return "Daily BC '" + shortName(splitName()) + "' at day " + timeStep(splitName()); +} + +std::string DailyBC::infeasibilityCause() +{ + return "* Daily binding constraints,"; +} + +// --- Weekly BC constraint --- +std::string WeeklyBC::infeasibility() +{ + return "Weekly BC '" + shortName(splitName()); +} + +std::string WeeklyBC::infeasibilityCause() +{ + return "* Weekly binding constraints."; +} + +// --- Fictitious load constraint --- +std::string FictitiousLoad::infeasibility() +{ + return "Last resort shedding status at area '" + areaName(splitName()) + "' at hour " + + timeStep(splitName()); +} + +std::string FictitiousLoad::infeasibilityCause() +{ + return "* Last resort shedding status."; +} + +// --- Hydro level constraint --- +std::string HydroLevel::infeasibility() +{ + return "Hydro level constraint at area '" + areaName(splitName()) + "' at hour " + + timeStep(splitName()); +} + +std::string HydroLevel::infeasibilityCause() +{ + return "* Hydro reservoir impossible to manage with cumulative options " + "\"hard bounds without heuristic\""; +} + +// --- Short term storage constraint --- +std::string STS::infeasibility() +{ + return "Short-term-storage reservoir constraint at area '" + areaName(splitName()) + + "' in STS '" + STSname(splitName()) + "' at hour " + timeStep(splitName()); +} + +std::string STS::infeasibilityCause() +{ + return "* Short-term storage reservoir level impossible to manage. Please check inflows, " + "lower & upper curves and initial level (if prescribed),"; +} + +// --- Hydro production constraint --- +std::string HydroProduction::infeasibility() +{ + return "Hydro weekly production at area '" + areaName(splitName()) + "'"; +} + +std::string HydroProduction::infeasibilityCause() +{ + return "* impossible to generate exactly the weekly hydro target"; +} + +// --- Constraints factory --- +ConstraintsFactory::ConstraintsFactory() +{ + regex_to_ctypes_ = { + {"::hourly::", std::make_unique}, + {"::daily::", std::make_unique}, + {"::weekly::", std::make_unique}, + {"^FictiveLoads::", std::make_unique}, + {"^AreaHydroLevel::", std::make_unique}, + {"^Level::", std::make_unique}, + {"^HydroPower::", std::make_unique}}; +} + +std::unique_ptr ConstraintsFactory::create(const std::string& name, + const double value) const +{ + auto it = std::ranges::find_if(regex_to_ctypes_, + [&name](auto& pair) + { return std::regex_search(name, std::regex(pair.first)); }); + if (it != regex_to_ctypes_.end()) + { + return it->second(name, value); + } + return nullptr; +} + +std::regex ConstraintsFactory::constraintsFilter() +{ + auto keyView = std::views::keys(regex_to_ctypes_); + std::vector regex_ids = {keyView.begin(), keyView.end()}; + return std::regex(boost::algorithm::join(regex_ids, "|")); +} + +} // namespace Antares::Optimization diff --git a/src/solver/lps/CMakeLists.txt b/src/solver/lps/CMakeLists.txt new file mode 100644 index 0000000000..8c3e48cab0 --- /dev/null +++ b/src/solver/lps/CMakeLists.txt @@ -0,0 +1,24 @@ +set(PROJ lps) +set(HEADERS + include/antares/solver/lps/LpsFromAntares.h +) +set(SRC_PROJ + ${HEADERS} + LpsFromAntares.cpp +) +source_group("solver\\lps" FILES ${SRC_PROJ}) + +add_library(${PROJ}) +target_sources(${PROJ} PRIVATE + ${SRC_PROJ} +) +add_library(Antares::${PROJ} ALIAS ${PROJ}) + +target_include_directories(${PROJ} + PUBLIC + $ +) + +install(DIRECTORY include/antares + DESTINATION "include" +) \ No newline at end of file diff --git a/src/solver/lps/LpsFromAntares.cpp b/src/solver/lps/LpsFromAntares.cpp new file mode 100644 index 0000000000..a32484038d --- /dev/null +++ b/src/solver/lps/LpsFromAntares.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include "antares/solver/lps/LpsFromAntares.h" + +namespace Antares::Solver +{ +bool LpsFromAntares::empty() const +{ + return constantProblemData.VariablesCount == 0 || weeklyProblems.empty(); +} + +void LpsFromAntares::setConstantData(const ConstantDataFromAntares& data) +{ + constantProblemData = data; +} + +void LpsFromAntares::addWeeklyData(WeeklyProblemId id, const WeeklyDataFromAntares& data) +{ + weeklyProblems.emplace(id, data); +} + +const WeeklyDataFromAntares& LpsFromAntares::weeklyData(WeeklyProblemId id) const +{ + auto it = weeklyProblems.find(id); + if (it == weeklyProblems.end()) + { + return WeeklyDataFromAntares(); // TODO Better error handling + } + return it->second; +} + +size_t LpsFromAntares::weekCount() const noexcept +{ + return weeklyProblems.size(); +} + +} // namespace Antares::Solver diff --git a/src/solver/lps/include/antares/solver/lps/LpsFromAntares.h b/src/solver/lps/include/antares/solver/lps/LpsFromAntares.h new file mode 100644 index 0000000000..f85d99b060 --- /dev/null +++ b/src/solver/lps/include/antares/solver/lps/LpsFromAntares.h @@ -0,0 +1,149 @@ + +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once +#include +#include +#include +#include +#include + +namespace Antares::Solver +{ + +/** + * @struct WeeklyProblemId + * @brief The WeeklyProblemId struct is used to identify a weekly problem by year and week. + */ +struct WeeklyProblemId +{ + unsigned int year = 0; + unsigned int week = 0; + // Order of comparison is order of member declaration + auto operator<=>(const WeeklyProblemId& other) const = default; +}; + +// Type de données inutile car les matrices de tous les pbs Weekly sont +// identiques. Cela pourra changer à l'avenir si des coefficients de contraintes +// couplantes peuvent varier au cours du temps (ex: rendement d'une pompe à +// chaleur qui varie selon la température, FlowBased ?, etc) +/** + * @class ConstantDataFromAntares + * @brief The ConstantDataFromAntares class is used to store constant data across all weeks + * of Antares problems. + */ +struct ConstantDataFromAntares +{ + unsigned VariablesCount = 0; // Mathématiquement : Nb colonnes de la matrice, + // Informatiquement = TypeDeVariable.size() + unsigned ConstraintesCount = 0; // Mathématiqument : Nb lignes de la matrice, + // Informatiquement = Mdeb.size() + unsigned CoeffCount = 0; // Mathématiquement : Nb coeffs non nuls de la + // matrice, Informatiquement = Nbterm.size() = + // IndicesColonnes.size()= + // CoefficientsDeLaMatriceDesContraintes.size() + + std::vector VariablesType; // Variables entières ou biniaires + std::vector Mdeb; // Indique dans les indices dans le vecteur IndicesColonnes qui + // correspondent au début de chaque ligne. Ex : Mdeb[3] = 8 et + // Mdeb[4] = 13 -> Les termes IndicesColonnes[8] à + // IndicesColonnes[12] correspondent à des Id de colonnes de la + // ligne 3 de la matrice (en supposant que les lignes sont indexées + // à partir de 0) + std::vector NotNullTermCount; // Nombre de termes non nuls sur chaque ligne. + // Inutile car NbTerm[i] = Mdeb[i+1] - Mdeb[i] + std::vector ColumnIndexes; // Id des colonnes des termes de + // CoefficientsDeLaMatriceDesContraintes : Ex + // IndicesColonnes[3] = 8 -> + // CoefficientsDeLaMatriceDesContraintes[8] donne la + // valeur du terme de la colonne 8, et de la ligne i où + // i est tel que Mdeb[i] <= 3 < Mdeb[i+1] + std::vector ConstraintsMatrixCoeff; // Coefficients de la matrice + + std::vector VariablesMeaning; + std::vector ConstraintsMeaning; + + auto operator<=>(const ConstantDataFromAntares& other) const = default; +}; + +/** + * @class WeeklyDataFromAntares + * @brief The WeeklyDataFromAntares class is used to store weekly data for an Antares Problem. + */ +struct WeeklyDataFromAntares +{ + std::vector Direction; // Sens de la contrainte : < ou > ou =, taille = + // NombreDeContraintes + std::vector Xmax; // Borne max des variables de la semaine + // considérée, taille = NombreDeVariables + std::vector Xmin; // Borne min des variables de la semaine + // considérée, taille = NombreDeVariables + std::vector LinearCost; // Coefficients du vecteur de coût de la fonction objectif, + // taille = NombreDeVariables + std::vector RHS; // Vecteur des second membre des contraintes, taille = + // NombreDeContraintes + std::string name; + + std::vector variables; + std::vector constraints; + + auto operator<=>(const WeeklyDataFromAntares& other) const = default; +}; + +using WeeklyDataByYearWeek = std::map; + +/** + * @class LpsFromAntares + * @brief The LpsFromAntares class is used to manage the constant and weekly data for Antares + * problems. + */ +class LpsFromAntares +{ +public: + /* + * @brief Checks if the LpsFromAntares object is empty. + * Emptiness is defined by either the constant data or the weekly data being empty. + */ + bool empty() const; + /* + * @brief Replaces the constant data in the LpsFromAntares object. + * Copy happens + */ + void setConstantData(const ConstantDataFromAntares& data); + /* + * @brief Adds weekly data to the LpsFromAntares object. + */ + void addWeeklyData(WeeklyProblemId id, const WeeklyDataFromAntares& data); + /* + * @brief Retrieves weekly data from the LpsFromAntares object. + */ + const WeeklyDataFromAntares& weeklyData(WeeklyProblemId id) const; + /* + * @brief Retrieves the number of weeks in the LpsFromAntares object. + */ + [[nodiscard]] size_t weekCount() const noexcept; + + ConstantDataFromAntares constantProblemData; + WeeklyDataByYearWeek weeklyProblems; +}; + +} // namespace Antares::Solver diff --git a/src/solver/main.cpp b/src/solver/main.cpp index 8d07e654b8..a0f012a9ef 100644 --- a/src/solver/main.cpp +++ b/src/solver/main.cpp @@ -105,7 +105,7 @@ void logAbortion() /*! ** \brief main */ -int main(int argc, char** argv) +int main(int argc, const char** argv) { try { @@ -130,9 +130,6 @@ int main(int argc, char** argv) application.execute(); application.writeExectutionInfo(); - // to avoid a bug from wxExecute, we should wait a little before returning - SuspendMilliSeconds(200 /*ms*/); - return EXIT_SUCCESS; } catch (const std::bad_alloc& exc) diff --git a/src/solver/misc/include/antares/solver/misc/cholesky.hxx b/src/solver/misc/include/antares/solver/misc/cholesky.hxx index 26c333d785..90418c17b2 100644 --- a/src/solver/misc/include/antares/solver/misc/cholesky.hxx +++ b/src/solver/misc/include/antares/solver/misc/cholesky.hxx @@ -42,7 +42,7 @@ bool Cholesky(U1& L, U2& A, uint size, T* temp) for (uint i = 0; i < size; ++i) { - typename MatrixSubColumn::Type Li = L[i]; + auto& Li = L[i]; // on calcule d'abord L[i][i] som = A[i][i]; @@ -58,8 +58,8 @@ bool Cholesky(U1& L, U2& A, uint size, T* temp) // maintenant on cherche L[k][i], k > i. for (uint k = i + 1; k < size; ++k) { - typename MatrixSubColumn::Type Lk = L[k]; - typename MatrixSubColumn::Type Ak = A[k]; + auto& Lk = L[k]; + auto& Ak = A[k]; if (temp[k] == Ak[k]) { diff --git a/src/solver/misc/include/antares/solver/misc/options.h b/src/solver/misc/include/antares/solver/misc/options.h index 2560a74d1c..00daf5aec7 100644 --- a/src/solver/misc/include/antares/solver/misc/options.h +++ b/src/solver/misc/include/antares/solver/misc/options.h @@ -27,8 +27,8 @@ #include #include -#include #include +#include /*! ** \brief Command line settings for launching the simulation diff --git a/src/solver/misc/include/antares/solver/misc/write-command-line.h b/src/solver/misc/include/antares/solver/misc/write-command-line.h index fa779ac257..b561d55efb 100644 --- a/src/solver/misc/include/antares/solver/misc/write-command-line.h +++ b/src/solver/misc/include/antares/solver/misc/write-command-line.h @@ -22,5 +22,5 @@ namespace Antares::Solver { -void WriteCommandLineIntoLogs(int argc, char** argv); +void WriteCommandLineIntoLogs(int argc, const char** argv); } diff --git a/src/solver/misc/options.cpp b/src/solver/misc/options.cpp index 9429b50e79..960b0dda6c 100644 --- a/src/solver/misc/options.cpp +++ b/src/solver/misc/options.cpp @@ -1,29 +1,29 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/solver/misc/options.h" #include -#include #include +#include #include #include @@ -45,7 +45,7 @@ std::unique_ptr CreateParser(Settings& settings, StudyLoad { settings.reset(); - auto parser = std::unique_ptr(new Yuni::GetOpt::Parser()); + auto parser = std::make_unique(); parser->addParagraph(Yuni::String() << "Antares Solver v" << ANTARES_VERSION_PUB_STR << "\n"); diff --git a/src/solver/misc/write-command-line.cpp b/src/solver/misc/write-command-line.cpp index 420999a51b..593c170657 100644 --- a/src/solver/misc/write-command-line.cpp +++ b/src/solver/misc/write-command-line.cpp @@ -24,7 +24,7 @@ namespace Antares::Solver { -void WriteCommandLineIntoLogs(int argc, char** argv) +void WriteCommandLineIntoLogs(int argc, const char** argv) { std::ostringstream buffer; for (int arg = 0; arg < argc; ++arg) diff --git a/src/solver/modeler/CMakeLists.txt b/src/solver/modeler/CMakeLists.txt new file mode 100644 index 0000000000..3c631240ac --- /dev/null +++ b/src/solver/modeler/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(api) +add_subdirectory(ortoolsImpl) diff --git a/src/solver/modeler/api/CMakeLists.txt b/src/solver/modeler/api/CMakeLists.txt new file mode 100644 index 0000000000..049c2dfa8e --- /dev/null +++ b/src/solver/modeler/api/CMakeLists.txt @@ -0,0 +1,27 @@ +set(PROJ optim_api) + +set(SRC_API + include/antares/solver/modeler/api/mipVariable.h + include/antares/solver/modeler/api/mipSolution.h + include/antares/solver/modeler/api/mipConstraint.h + + include/antares/solver/modeler/api/hasBounds.h + include/antares/solver/modeler/api/hasName.h + + include/antares/solver/modeler/api/linearProblem.h + include/antares/solver/modeler/api/linearProblemData.h + include/antares/solver/modeler/api/linearProblemFiller.h + include/antares/solver/modeler/api/linearProblemBuilder.h + + linearProblemData.cpp +) + +add_library(${PROJ} ${SRC_API}) +add_library(Antares::${PROJ} ALIAS ${PROJ}) + +set_target_properties(${PROJ} PROPERTIES LINKER_LANGUAGE CXX) + +target_include_directories(${PROJ} + PUBLIC + $ +) diff --git a/src/solver/simulation/include/antares/solver/simulation/adequacy_mode.h b/src/solver/modeler/api/include/antares/solver/modeler/api/hasBounds.h similarity index 64% rename from src/solver/simulation/include/antares/solver/simulation/adequacy_mode.h rename to src/solver/modeler/api/include/antares/solver/modeler/api/hasBounds.h index 260ba2c92f..474a34d74f 100644 --- a/src/solver/simulation/include/antares/solver/simulation/adequacy_mode.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/hasBounds.h @@ -1,4 +1,3 @@ - /* * Copyright 2007-2024, RTE (https://www.rte-france.com) * See AUTHORS.txt @@ -22,15 +21,22 @@ #pragma once -#include "antares/infoCollection/StudyInfoCollector.h" -#include "antares/solver/misc/options.h" -#include "antares/writer/i_writer.h" +namespace Antares::Solver::Modeler::Api +{ -namespace Antares::Solver +/// Used to handle bounds for IMipVariable and IMipConstraint +class IHasBounds { -void runSimulationInAdequacyMode(Antares::Data::Study& study, - const Settings& settings, - Benchmarking::DurationCollector& durationCollector, - IResultWriter& resultWriter, - Benchmarking::OptimizationInfo& info); -} +public: + virtual ~IHasBounds() = default; + + virtual void setLb(double lb) = 0; + virtual void setUb(double ub) = 0; + + virtual void setBounds(double lb, double ub) = 0; + + virtual double getLb() const = 0; + virtual double getUb() const = 0; +}; + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_period_string_generator_base.h b/src/solver/modeler/api/include/antares/solver/modeler/api/hasName.h similarity index 77% rename from src/solver/optimisation/include/antares/solver/optimisation/opt_period_string_generator_base.h rename to src/solver/modeler/api/include/antares/solver/modeler/api/hasName.h index 217d95db0c..0003dd6843 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_period_string_generator_base.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/hasName.h @@ -23,12 +23,15 @@ #include -// --------------------------------------------- -// Optimization period as string : base class -// -------------------------------------------- -class OptPeriodStringGenerator +namespace Antares::Solver::Modeler::Api +{ + +/// Inherited by IMipVariable and IMipConstraint +class IHasName { public: - virtual std::string to_string() const = 0; - virtual ~OptPeriodStringGenerator() = default; + virtual ~IHasName() = default; + virtual const std::string& getName() const = 0; }; + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h new file mode 100644 index 0000000000..b997242ec7 --- /dev/null +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblem.h @@ -0,0 +1,71 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include +#include + +#include "mipConstraint.h" +#include "mipSolution.h" +#include "mipVariable.h" + +/// Namespace for the classes related to the linear problem API +namespace Antares::Solver::Modeler::Api +{ + +/** + * Linear Problem + * This class is aimed at creating and manipulating variables/constraints + * Also used to to control the objective, maximization or minimization, and to solve the problem + */ +class ILinearProblem +{ +public: + virtual ~ILinearProblem() = default; + + /// Create a continuous variable + virtual IMipVariable* addNumVariable(double lb, double ub, const std::string& name) = 0; + /// Create a integer variable + virtual IMipVariable* addIntVariable(double lb, double ub, const std::string& name) = 0; + virtual IMipVariable* getVariable(const std::string& name) const = 0; + + /// Add a bounded constraint to the problem + virtual IMipConstraint* addConstraint(double lb, double ub, const std::string& name) = 0; + virtual IMipConstraint* getConstraint(const std::string& name) const = 0; + + /// Set the objective coefficient for a given variable + virtual void setObjectiveCoefficient(IMipVariable* var, double coefficient) = 0; + virtual double getObjectiveCoefficient(const IMipVariable* var) const = 0; + + /// Sets the optimization direction to minimize + virtual void setMinimization() = 0; + /// Sets the optimization direction to maximize + virtual void setMaximization() = 0; + + virtual bool isMinimization() const = 0; + virtual bool isMaximization() const = 0; + + /// Solve the problem, returns a IMipSolution + virtual IMipSolution* solve(bool verboseSolver) = 0; +}; + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h new file mode 100644 index 0000000000..b4131d4f6b --- /dev/null +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemBuilder.h @@ -0,0 +1,40 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include + +#include "linearProblemFiller.h" +#include "mipSolution.h" + +namespace Antares::Solver::Modeler::Api +{ + +class LinearProblemBuilder +{ +public: + virtual void LinearProblemBuilder(std::vector fillers) = 0; + virtual void build(LinearProblemData* data) = 0; + virtual MipSolution* solve() = 0; +}; + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemData.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemData.h new file mode 100644 index 0000000000..ff3cd2a4e3 --- /dev/null +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemData.h @@ -0,0 +1,47 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include +#include +#include + +namespace Antares::Solver::Modeler::Api +{ + +class LinearProblemData +{ +public: + unsigned getTimeResolutionInMinutes(); + bool hasScalarData(const std::string& key); + double getScalarData(const std::string& key, unsigned scenario); + bool hasTimedData(const std::string& key); + const std::vector& getTimedData(const std::string& key, unsigned scenario); + +private: + std::vector timeStamps_; + unsigned timeResolutionInMinutes_; + std::map> scalarData_; + std::map>> timedData_; +}; + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h new file mode 100644 index 0000000000..b337dea247 --- /dev/null +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/linearProblemFiller.h @@ -0,0 +1,38 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include +#include + +namespace Antares::Solver::Modeler::Api +{ + +class LinearProblemFiller +{ +public: + virtual void addVariables(LinearProblem* problem, LinearProblemData* data) = 0; + virtual void addConstraints(LinearProblem* problem, LinearProblemData* data) = 0; + virtual void addObjectiveCoefficients(LinearProblem* problem, LinearProblemData* data) = 0; +}; + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_spread_generator.h b/src/solver/modeler/api/include/antares/solver/modeler/api/mipConstraint.h similarity index 73% rename from src/solver/simulation/include/antares/solver/simulation/sim_spread_generator.h rename to src/solver/modeler/api/include/antares/solver/modeler/api/mipConstraint.h index c28ec9a75a..71baf95cd8 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_spread_generator.h +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/mipConstraint.h @@ -21,21 +21,17 @@ #pragma once -#include +#include "mipVariable.h" -namespace SIM +namespace Antares::Solver::Modeler::Api { -class SpreadGenerator -{ - static constexpr double rangeDefault = 1.e-3; +class IMipConstraint: public IHasBounds, public IHasName +{ public: - explicit SpreadGenerator(double range = rangeDefault); - void reset(unsigned int seed); - double generate(); + virtual void setCoefficient(IMipVariable* var, double coefficient) = 0; -private: - Antares::MersenneTwister mt_; - const double range_; + virtual double getCoefficient(IMipVariable* var) = 0; }; -} // namespace SIM + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/api/include/antares/solver/modeler/api/mipSolution.h b/src/solver/modeler/api/include/antares/solver/modeler/api/mipSolution.h new file mode 100644 index 0000000000..0018718de2 --- /dev/null +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/mipSolution.h @@ -0,0 +1,56 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include + +#include "mipVariable.h" + +namespace Antares::Solver::Modeler::Api +{ + +enum class MipStatus +{ + OPTIMAL, + FEASIBLE, + UNBOUNDED, + INFEASIBLE, + MIP_ERROR +}; + +/** + * MipSolution + * Used to get the return status of the solve + * Contains the problem's optimal values for each variable + */ +class IMipSolution +{ +public: + virtual ~IMipSolution() = default; + + virtual MipStatus getStatus() const = 0; + virtual double getObjectiveValue() const = 0; + virtual double getOptimalValue(const IMipVariable* var) const = 0; + virtual std::vector getOptimalValues(const std::vector& vars) const = 0; +}; + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/libs/antares/study/include/antares/study/runtime/runtime.hxx b/src/solver/modeler/api/include/antares/solver/modeler/api/mipVariable.h similarity index 73% rename from src/libs/antares/study/include/antares/study/runtime/runtime.hxx rename to src/solver/modeler/api/include/antares/solver/modeler/api/mipVariable.h index 0e04ed3b93..1caac002bf 100644 --- a/src/libs/antares/study/include/antares/study/runtime/runtime.hxx +++ b/src/solver/modeler/api/include/antares/solver/modeler/api/mipVariable.h @@ -18,20 +18,17 @@ * You should have received a copy of the Mozilla Public Licence 2.0 * along with Antares_Simulator. If not, see . */ -#ifndef __ANTARES_LIBS_STUDY_RUNTIME_RUNTIME_INFOS_HXX__ -#define __ANTARES_LIBS_STUDY_RUNTIME_RUNTIME_INFOS_HXX__ -namespace Antares -{ -namespace Data -{ -#ifdef NDEBUG -inline void StudyRangeLimits::checkIntegrity() const +#pragma once + +#include "hasBounds.h" +#include "hasName.h" + +namespace Antares::Solver::Modeler::Api { -} -#endif -} // namespace Data -} // namespace Antares +class IMipVariable: public IHasBounds, public IHasName +{ +}; -#endif // __ANTARES_LIBS_STUDY_RUNTIME_RUNTIME_INFOS_HXX__ +} // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/api/linearProblemData.cpp b/src/solver/modeler/api/linearProblemData.cpp new file mode 100644 index 0000000000..27cf9415c9 --- /dev/null +++ b/src/solver/modeler/api/linearProblemData.cpp @@ -0,0 +1,53 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include + +namespace Antares::Solver::Modeler::Api +{ + +unsigned LinearProblemData::getTimeResolutionInMinutes() +{ + return timeResolutionInMinutes_; +} + +bool LinearProblemData::hasScalarData(const std::string& key) +{ + return scalarData_.contains(key); +} + +double LinearProblemData::getScalarData(const std::string& key, unsigned scenario) +{ + return scalarData_.at(key)[scenario]; +} + +bool LinearProblemData::hasTimedData(const std::string& key) +{ + return timedData_.contains(key); +} + +const std::vector& LinearProblemData::getTimedData(const std::string& key, + unsigned scenario) +{ + return timedData_.at(key)[scenario]; +} + +} // namespace Antares::Solver::Modeler::Api diff --git a/src/solver/modeler/ortoolsImpl/CMakeLists.txt b/src/solver/modeler/ortoolsImpl/CMakeLists.txt new file mode 100644 index 0000000000..ef94b552cc --- /dev/null +++ b/src/solver/modeler/ortoolsImpl/CMakeLists.txt @@ -0,0 +1,35 @@ +set(PROJ modeler-ortools-impl) + +set(HEADERS + include/antares/solver/modeler/ortoolsImpl/mipVariable.h + include/antares/solver/modeler/ortoolsImpl/mipSolution.h + include/antares/solver/modeler/ortoolsImpl/mipConstraint.h + + include/antares/solver/modeler/ortoolsImpl/linearProblem.h +) +set(SRC_ORTOOLS_IMPL + ${HEADERS} + mipVariable.cpp + mipSolution.cpp + mipConstraint.cpp + + linearProblem.cpp +) + +source_group("solver\\modeler\\api" FILES ${SRC_ORTOOLS_IMPL}) + +add_library(${PROJ} ${SRC_ORTOOLS_IMPL}) +add_library(Antares::${PROJ} ALIAS ${PROJ}) + +target_link_libraries(${PROJ} + PUBLIC + Antares::optim_api + Antares::logs + Antares::solverUtils + ortools::ortools +) + +target_include_directories(${PROJ} + PUBLIC + $ +) diff --git a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h new file mode 100644 index 0000000000..6a34ccfcc5 --- /dev/null +++ b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/linearProblem.h @@ -0,0 +1,77 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include +#include +#include +#include + +namespace operations_research +{ +class MPSolver; +class MPSolverParameters; +class MPObjective; +} // namespace operations_research + +namespace Antares::Solver::Modeler::OrtoolsImpl +{ + +class OrtoolsLinearProblem final: public Api::ILinearProblem +{ +public: + OrtoolsLinearProblem(bool isMip, const std::string& solverName); + ~OrtoolsLinearProblem() override = default; + + OrtoolsMipVariable* addNumVariable(double lb, double ub, const std::string& name) override; + OrtoolsMipVariable* addIntVariable(double lb, double ub, const std::string& name) override; + + OrtoolsMipVariable* getVariable(const std::string& name) const override; + + OrtoolsMipConstraint* addConstraint(double lb, double ub, const std::string& name) override; + OrtoolsMipConstraint* getConstraint(const std::string& name) const override; + + void setObjectiveCoefficient(Api::IMipVariable* var, double coefficient) override; + double getObjectiveCoefficient(const Api::IMipVariable* var) const override; + + void setMinimization() override; + void setMaximization() override; + + bool isMinimization() const override; + bool isMaximization() const override; + + OrtoolsMipSolution* solve(bool verboseSolver) override; + +private: + OrtoolsMipVariable* addVariable(double lb, double ub, bool integer, const std::string& name); + + std::shared_ptr mpSolver_; + operations_research::MPObjective* objective_; + operations_research::MPSolverParameters params_; + + std::map> variables_; + std::map> constraints_; + + std::unique_ptr solution_; +}; + +} // namespace Antares::Solver::Modeler::OrtoolsImpl diff --git a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipConstraint.h b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipConstraint.h new file mode 100644 index 0000000000..cf5b501f60 --- /dev/null +++ b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipConstraint.h @@ -0,0 +1,58 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include + +namespace operations_research +{ +class MPConstraint; // forward declaration +} + +namespace Antares::Solver::Modeler::OrtoolsImpl +{ + +class OrtoolsMipConstraint final: public Api::IMipConstraint +{ +public: + void setLb(double lb) override; + void setUb(double ub) override; + + void setBounds(double lb, double ub) override; + void setCoefficient(Api::IMipVariable* var, double coefficient) override; + + double getLb() const override; + double getUb() const override; + + double getCoefficient(Api::IMipVariable* var) override; + + const std::string& getName() const override; + + ~OrtoolsMipConstraint() override = default; + + explicit OrtoolsMipConstraint(operations_research::MPConstraint* mpConstraint); + +private: + operations_research::MPConstraint* mpConstraint_; +}; + +} // namespace Antares::Solver::Modeler::OrtoolsImpl diff --git a/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/constraint.h b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h similarity index 51% rename from src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/constraint.h rename to src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h index aba82e7f21..c046c49ef6 100644 --- a/src/solver/infeasible-problem-analysis/include/antares/solver/infeasible-problem-analysis/constraint.h +++ b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipSolution.h @@ -18,48 +18,37 @@ * You should have received a copy of the Mozilla Public Licence 2.0 * along with Antares_Simulator. If not, see . */ + #pragma once +#include +#include #include #include -namespace Antares::Optimization -{ -enum class ConstraintType +#include + +namespace Antares::Solver::Modeler::OrtoolsImpl { - binding_constraint_hourly, - binding_constraint_daily, - binding_constraint_weekly, - fictitious_load, - hydro_reservoir_level, - short_term_storage_level, - none -}; -class Constraint +class OrtoolsMipSolution final: public Api::IMipSolution { public: - // Construct object - Constraint() = default; - Constraint(const std::string& input, const double slackValue); + OrtoolsMipSolution(operations_research::MPSolver::ResultStatus& responseStatus, + std::shared_ptr solver); - // Raw members - double getSlackValue() const; + ~OrtoolsMipSolution() override = default; - // Extract items, check consistency - std::size_t extractItems(); - std::string prettyPrint() const; - ConstraintType getType() const; + Api::MipStatus getStatus() const override; + double getObjectiveValue() const override; + double getOptimalValue(const Api::IMipVariable* var) const override; + std::vector getOptimalValues( + const std::vector& vars) const override; private: - std::string mInput; - std::vector mItems; - double mSlackValue; - - // Get specific items - std::string getAreaName() const; - std::string getSTSName() const; - std::string getTimeStepInYear() const; - std::string getBindingConstraintName() const; + operations_research::MPSolver::ResultStatus status_; + std::shared_ptr mpSolver_; + std::map solution_; }; -} // namespace Antares::Optimization + +} // namespace Antares::Solver::Modeler::OrtoolsImpl diff --git a/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipVariable.h b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipVariable.h new file mode 100644 index 0000000000..528ee0cd9e --- /dev/null +++ b/src/solver/modeler/ortoolsImpl/include/antares/solver/modeler/ortoolsImpl/mipVariable.h @@ -0,0 +1,57 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include + +namespace operations_research +{ +class MPVariable; // forward declaration +} + +namespace Antares::Solver::Modeler::OrtoolsImpl +{ + +class OrtoolsMipVariable final: public Api::IMipVariable +{ +public: + void setLb(double lb) override; + void setUb(double ub) override; + + void setBounds(double lb, double ub) override; + + double getLb() const override; + double getUb() const override; + + const std::string& getName() const override; + + const operations_research::MPVariable* getMpVar() const; + + ~OrtoolsMipVariable() override = default; + + explicit OrtoolsMipVariable(operations_research::MPVariable*); + +private: + operations_research::MPVariable* mpVar_; +}; + +} // namespace Antares::Solver::Modeler::OrtoolsImpl diff --git a/src/solver/modeler/ortoolsImpl/linearProblem.cpp b/src/solver/modeler/ortoolsImpl/linearProblem.cpp new file mode 100644 index 0000000000..7c6593fa52 --- /dev/null +++ b/src/solver/modeler/ortoolsImpl/linearProblem.cpp @@ -0,0 +1,178 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include +#include +#include + +#include +#include + +namespace Antares::Solver::Modeler::OrtoolsImpl +{ + +OrtoolsLinearProblem::OrtoolsLinearProblem(bool isMip, const std::string& solverName) +{ + auto* mpSolver = isMip ? MPSolver::CreateSolver( + (OrtoolsUtils::solverMap.at(solverName)).MIPSolverName) + : MPSolver::CreateSolver( + (OrtoolsUtils::solverMap.at(solverName)).LPSolverName); + + mpSolver_ = std::unique_ptr(mpSolver); + objective_ = mpSolver->MutableObjective(); + + params_.SetIntegerParam(MPSolverParameters::SCALING, 0); + params_.SetIntegerParam(MPSolverParameters::PRESOLVE, 0); +} + +class ElemAlreadyExists: public std::exception +{ +public: + const char* what() const noexcept override + { + return "Element name already exists in linear problem"; + } +}; + +OrtoolsMipVariable* OrtoolsLinearProblem::addVariable(double lb, + double ub, + bool integer, + const std::string& name) +{ + if (variables_.contains(name)) + { + logs.error() << "This variable already exists: " << name; + throw ElemAlreadyExists(); + } + + auto* mpVar = mpSolver_->MakeVar(lb, ub, integer, name); + + if (!mpVar) + { + logs.error() << "Couldn't add variable to Ortools MPSolver: " << name; + } + + const auto& pair = variables_.emplace(name, std::make_unique(mpVar)); + return pair.first->second.get(); // <, bool> +} + +OrtoolsMipVariable* OrtoolsLinearProblem::addNumVariable(double lb, + double ub, + const std::string& name) +{ + return addVariable(lb, ub, false, name); +} + +OrtoolsMipVariable* OrtoolsLinearProblem::addIntVariable(double lb, + double ub, + const std::string& name) +{ + return addVariable(lb, ub, true, name); +} + +OrtoolsMipVariable* OrtoolsLinearProblem::getVariable(const std::string& name) const +{ + return variables_.at(name).get(); +} + +OrtoolsMipConstraint* OrtoolsLinearProblem::addConstraint(double lb, + double ub, + const std::string& name) +{ + if (constraints_.contains(name)) + { + logs.error() << "This constraint already exists: " << name; + throw ElemAlreadyExists(); + } + + auto* mpConstraint = mpSolver_->MakeRowConstraint(lb, ub, name); + + if (!mpConstraint) + { + logs.error() << "Couldn't add variable to Ortools MPSolver: " << name; + } + + const auto& pair = constraints_.emplace(name, + std::make_unique(mpConstraint)); + return pair.first->second.get(); // <, bool> +} + +OrtoolsMipConstraint* OrtoolsLinearProblem::getConstraint(const std::string& name) const +{ + return constraints_.at(name).get(); +} + +static const operations_research::MPVariable* getMpVar(const Api::IMipVariable* var) + +{ + const auto* OrtoolsMipVar = dynamic_cast(var); + if (!OrtoolsMipVar) + { + logs.error() << "Invalid cast, tried from Api::IMipVariable to OrtoolsMipVariable"; + throw std::bad_cast(); + } + return OrtoolsMipVar->getMpVar(); +} + +void OrtoolsLinearProblem::setObjectiveCoefficient(Api::IMipVariable* var, double coefficient) +{ + objective_->SetCoefficient(getMpVar(var), coefficient); +} + +double OrtoolsLinearProblem::getObjectiveCoefficient(const Api::IMipVariable* var) const +{ + return objective_->GetCoefficient(getMpVar(var)); +} + +void OrtoolsLinearProblem::setMinimization() +{ + objective_->SetMinimization(); +} + +void OrtoolsLinearProblem::setMaximization() +{ + objective_->SetMaximization(); +} + +bool OrtoolsLinearProblem::isMinimization() const +{ + return objective_->minimization(); +} + +bool OrtoolsLinearProblem::isMaximization() const +{ + return objective_->maximization(); +} + +OrtoolsMipSolution* OrtoolsLinearProblem::solve(bool verboseSolver) +{ + if (verboseSolver) + { + mpSolver_->EnableOutput(); + } + + auto mpStatus = mpSolver_->Solve(params_); + + solution_ = std::make_unique(mpStatus, mpSolver_); + return solution_.get(); +} + +} // namespace Antares::Solver::Modeler::OrtoolsImpl diff --git a/src/solver/modeler/ortoolsImpl/mipConstraint.cpp b/src/solver/modeler/ortoolsImpl/mipConstraint.cpp new file mode 100644 index 0000000000..00a24069a4 --- /dev/null +++ b/src/solver/modeler/ortoolsImpl/mipConstraint.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include + +#include +#include +#include + +namespace Antares::Solver::Modeler::OrtoolsImpl +{ + +OrtoolsMipConstraint::OrtoolsMipConstraint(operations_research::MPConstraint* mpConstraint): + mpConstraint_(mpConstraint) +{ +} + +void OrtoolsMipConstraint::setLb(double lb) +{ + mpConstraint_->SetLB(lb); +} + +void OrtoolsMipConstraint::setUb(double ub) +{ + mpConstraint_->SetUB(ub); +} + +void OrtoolsMipConstraint::setBounds(double lb, double ub) +{ + mpConstraint_->SetBounds(lb, ub); +} + +double OrtoolsMipConstraint::getLb() const +{ + return mpConstraint_->lb(); +} + +double OrtoolsMipConstraint::getUb() const +{ + return mpConstraint_->ub(); +} + +void OrtoolsMipConstraint::setCoefficient(Api::IMipVariable* var, double coefficient) +{ + auto* mpvar = dynamic_cast(var); + if (!mpvar) + { + logs.error() << "Invalid cast, tried from Api::IMipVariable to OrtoolsMipVariable"; + throw std::bad_cast(); + } + + mpConstraint_->SetCoefficient(mpvar->getMpVar(), coefficient); +} + +double OrtoolsMipConstraint::getCoefficient(Api::IMipVariable* var) +{ + auto* mpvar = dynamic_cast(var); + if (!mpvar) + { + logs.error() << "Invalid cast, tried from Api::IMipVariable to OrtoolsMipVariable"; + throw std::bad_cast(); + } + + return mpConstraint_->GetCoefficient(mpvar->getMpVar()); +} + +const std::string& OrtoolsMipConstraint::getName() const +{ + return mpConstraint_->name(); +} + +} // namespace Antares::Solver::Modeler::OrtoolsImpl diff --git a/src/solver/modeler/ortoolsImpl/mipSolution.cpp b/src/solver/modeler/ortoolsImpl/mipSolution.cpp new file mode 100644 index 0000000000..8a04484522 --- /dev/null +++ b/src/solver/modeler/ortoolsImpl/mipSolution.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include +#include + +namespace Antares::Solver::Modeler::OrtoolsImpl +{ + +OrtoolsMipSolution::OrtoolsMipSolution(operations_research::MPSolver::ResultStatus& status, + std::shared_ptr solver): + status_(status), + mpSolver_(solver) +{ + for (const auto* var: mpSolver_->variables()) + { + solution_.try_emplace(var->name(), var->solution_value()); + } +} + +Api::MipStatus OrtoolsMipSolution::getStatus() const +{ + switch (status_) + { + case operations_research::MPSolver::ResultStatus::OPTIMAL: + return Api::MipStatus::OPTIMAL; + case operations_research::MPSolver::ResultStatus::FEASIBLE: + return Api::MipStatus::FEASIBLE; + case operations_research::MPSolver::ResultStatus::UNBOUNDED: + return Api::MipStatus::UNBOUNDED; + case operations_research::MPSolver::ResultStatus::INFEASIBLE: + return Api::MipStatus::INFEASIBLE; + default: + logs.warning() << "Solve returned an error status"; + break; + } + return Api::MipStatus::MIP_ERROR; +} + +double OrtoolsMipSolution::getObjectiveValue() const +{ + return mpSolver_->Objective().Value(); +} + +double OrtoolsMipSolution::getOptimalValue(const Api::IMipVariable* var) const +{ + if (!var) + { + return 0; + } + + try + { + return solution_.at(var->getName()); + } + catch (const std::out_of_range& ex) + { + logs.warning() << ex.what(); + logs.warning() << "Solution not found for variable: " << var->getName(); + } + return 0; +} + +std::vector OrtoolsMipSolution::getOptimalValues( + const std::vector& vars) const +{ + std::vector solution; + solution.reserve(vars.size()); + + for (const auto* var: vars) + { + solution.push_back(getOptimalValue(var)); + } + + return solution; +} + +} // namespace Antares::Solver::Modeler::OrtoolsImpl diff --git a/src/solver/modeler/ortoolsImpl/mipVariable.cpp b/src/solver/modeler/ortoolsImpl/mipVariable.cpp new file mode 100644 index 0000000000..5e21924a8f --- /dev/null +++ b/src/solver/modeler/ortoolsImpl/mipVariable.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include + +#include + +namespace Antares::Solver::Modeler::OrtoolsImpl +{ + +OrtoolsMipVariable::OrtoolsMipVariable(operations_research::MPVariable* mpVar): + mpVar_(mpVar) +{ +} + +void OrtoolsMipVariable::setLb(double lb) +{ + mpVar_->SetLB(lb); +} + +void OrtoolsMipVariable::setUb(double ub) +{ + mpVar_->SetUB(ub); +} + +void OrtoolsMipVariable::setBounds(double lb, double ub) +{ + mpVar_->SetBounds(lb, ub); +} + +double OrtoolsMipVariable::getLb() const +{ + return mpVar_->lb(); +} + +double OrtoolsMipVariable::getUb() const +{ + return mpVar_->ub(); +} + +const operations_research::MPVariable* OrtoolsMipVariable::getMpVar() const +{ + return mpVar_; +} + +const std::string& OrtoolsMipVariable::getName() const +{ + return mpVar_->name(); +} + +} // namespace Antares::Solver::Modeler::OrtoolsImpl diff --git a/src/solver/optimisation/CMakeLists.txt b/src/solver/optimisation/CMakeLists.txt index 0b5783ae92..a0d74288e7 100644 --- a/src/solver/optimisation/CMakeLists.txt +++ b/src/solver/optimisation/CMakeLists.txt @@ -20,7 +20,6 @@ set(RTESOLVER_OPT opt_construction_variables_optimisees_quadratique.cpp opt_decompte_variables_et_contraintes.cpp opt_decompte_variables_et_contraintes.cpp - opt_construction_matrice_des_contraintes_outils.cpp opt_gestion_des_bornes_cas_lineaire.cpp opt_verification_presence_reserve_jmoins1.cpp opt_init_contraintes_hydrauliques.cpp @@ -39,10 +38,6 @@ set(RTESOLVER_OPT opt_nombre_min_groupes_demarres_couts_demarrage.cpp include/antares/solver/optimisation/opt_export_structure.h opt_export_structure.cpp - include/antares/solver/optimisation/base_weekly_optimization.h - base_weekly_optimization.cpp - include/antares/solver/optimisation/adequacy_patch_local_matching/adequacy_patch_weekly_optimization.h - adequacy_patch_local_matching/adequacy_patch_weekly_optimization.cpp include/antares/solver/optimisation/weekly_optimization.h weekly_optimization.cpp include/antares/solver/optimisation/optim_post_process_list.h @@ -51,9 +46,9 @@ set(RTESOLVER_OPT post_process_commands.cpp include/antares/solver/optimisation/adequacy_patch_csr/hourly_csr_problem.h include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_post_process_list.h + include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h adequacy_patch_csr/adq_patch_post_process_list.cpp - include/antares/solver/optimisation/adequacy_patch_local_matching/adq_patch_local_matching.h - adequacy_patch_local_matching/adq_patch_local_matching.cpp + adequacy_patch_csr/post_processing.cpp include/antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h adequacy_patch_csr/adq_patch_curtailment_sharing.cpp adequacy_patch_csr/solve_problem.cpp @@ -72,7 +67,6 @@ set(RTESOLVER_OPT include/antares/solver/optimisation/adequacy_patch_csr/constraints/CsrBindingConstraintHour.h adequacy_patch_csr/constraints/CsrBindingConstraintHour.cpp - include/antares/solver/optimisation/opt_period_string_generator_base.h include/antares/solver/optimisation/opt_rename_problem.h opt_rename_problem.cpp @@ -174,7 +168,8 @@ set(RTESOLVER_OPT variables/VariableManagement.cpp variables/VariableManagerUtils.h variables/VariableManagerUtils.cpp - + include/antares/solver/optimisation/HebdoProblemToLpsTranslator.h + HebdoProblemToLpsTranslator.cpp ) @@ -198,6 +193,7 @@ target_link_libraries(model_antares antares-solver-simulation Antares::benchmarking Antares::optimization-options + Antares::lps PRIVATE infeasible_problem_analysis ) @@ -209,4 +205,4 @@ target_include_directories(model_antares install(DIRECTORY include/antares DESTINATION "include" -) \ No newline at end of file +) diff --git a/src/solver/optimisation/HebdoProblemToLpsTranslator.cpp b/src/solver/optimisation/HebdoProblemToLpsTranslator.cpp new file mode 100644 index 0000000000..9c67012c70 --- /dev/null +++ b/src/solver/optimisation/HebdoProblemToLpsTranslator.cpp @@ -0,0 +1,124 @@ + +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include "antares/solver/optimisation/HebdoProblemToLpsTranslator.h" + +#include "antares/solver/utils/filename.h" + +namespace Antares::Solver +{ + +namespace +{ +/** + * @brief Copies elements from one container to another. + * + * This function takes two containers as arguments. It copies elements from the first container to + * the second one. + * + * @param in The container from which to copy elements. + * @param out The container to which to copy elements. + */ +template +void copy(const T& in, U& out) +{ + std::ranges::copy(in, std::back_inserter(out)); +} +} // namespace + +WeeklyDataFromAntares HebdoProblemToLpsTranslator::translate( + const PROBLEME_ANTARES_A_RESOUDRE* problem, + std::string_view name) const +{ + if (problem == nullptr) + { + return {}; + } + auto ret = WeeklyDataFromAntares(); + + copy(problem->CoutLineaire, ret.LinearCost); + copy(problem->Xmax, ret.Xmax); + copy(problem->Xmin, ret.Xmin); + copy(problem->NomDesVariables, ret.variables); + copy(problem->NomDesContraintes, ret.constraints); + copy(problem->SecondMembre, ret.RHS); + copy(problem->Sens, ret.Direction); + + copy(name, ret.name); + + return ret; +} + +ConstantDataFromAntares HebdoProblemToLpsTranslator::commonProblemData( + const PROBLEME_ANTARES_A_RESOUDRE* problem) const +{ + if (problem == nullptr) + { + return ConstantDataFromAntares(); + } + + if (problem->NombreDeVariables <= 0) + { + throw WeeklyProblemTranslationException("VariablesCount must be strictly positive"); + } + if (problem->NombreDeContraintes <= 0) + { + throw WeeklyProblemTranslationException("ConstraintesCount must be strictly positive"); + } + + if (problem->NombreDeContraintes > (int)problem->IndicesDebutDeLigne.size()) + { + throw WeeklyProblemTranslationException( + "ConstraintesCount exceed IndicesDebutDeLigne size"); + } + + if (problem->NombreDeContraintes > (int)problem->NombreDeTermesDesLignes.size()) + { + throw WeeklyProblemTranslationException( + "ConstraintesCount exceed NombreDeTermesDesLignes size"); + } + + ConstantDataFromAntares ret; + + ret.VariablesCount = problem->NombreDeVariables; + ret.ConstraintesCount = problem->NombreDeContraintes; + + ret.CoeffCount = problem->IndicesDebutDeLigne[problem->NombreDeContraintes - 1] + + problem->NombreDeTermesDesLignes[problem->NombreDeContraintes - 1]; + + copy(problem->TypeDeVariable, ret.VariablesType); + + copy(problem->CoefficientsDeLaMatriceDesContraintes, ret.ConstraintsMatrixCoeff); + ret.ConstraintsMatrixCoeff.resize(ret.CoeffCount); + copy(problem->IndicesColonnes, ret.ColumnIndexes); + ret.ColumnIndexes.resize(ret.CoeffCount); + copy(problem->IndicesDebutDeLigne, ret.Mdeb); + ret.Mdeb.push_back(ret.CoeffCount); + return ret; +} + +WeeklyProblemTranslationException::WeeklyProblemTranslationException( + const std::string& string) noexcept: + std::runtime_error{string} +{ +} +} // namespace Antares::Solver diff --git a/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp b/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp index 63789a5c76..0aa61a969d 100644 --- a/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp +++ b/src/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.cpp @@ -125,7 +125,7 @@ void HourlyCSRProblem::calculateCsrParameters() // calculate netPositionInit and the RHS of the AreaBalance constraints std::tie(netPositionInit, std::ignore, std::ignore) = calculateAreaFlowBalance( problemeHebdo_, - adqPatchParams_.localMatching.setToZeroOutsideInsideLinks, + adqPatchParams_.setToZeroOutsideInsideLinks, Area, hour); double ensInit = problemeHebdo_->ResultatsHoraires[Area] diff --git a/src/solver/optimisation/adequacy_patch_csr/post_processing.cpp b/src/solver/optimisation/adequacy_patch_csr/post_processing.cpp new file mode 100644 index 0000000000..bc946a3c57 --- /dev/null +++ b/src/solver/optimisation/adequacy_patch_csr/post_processing.cpp @@ -0,0 +1,62 @@ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ +#include "antares/solver/optimisation/adequacy_patch_csr/post_processing.h" + +#include + +namespace Antares::Data::AdequacyPatch +{ +double recomputeDTG_MRG(bool triggered, double dtgMrg, double ens) +{ + if (triggered) + { + return std::max(0.0, dtgMrg - ens); + } + else + { + return dtgMrg; + } +} + +double recomputeENS_MRG(bool triggered, double dtgMrg, double ens) +{ + if (triggered) + { + return std::max(0.0, ens - dtgMrg); + } + else + { + return ens; + } +} + +double recomputeMRGPrice(double ensCsr, double originalCost, double unsuppliedEnergyCost) +{ + if (ensCsr > 0.5) + { + return -unsuppliedEnergyCost; + } + else + { + return originalCost; + } +} +} // namespace Antares::Data::AdequacyPatch diff --git a/src/solver/optimisation/adequacy_patch_csr/set_variable_boundaries.cpp b/src/solver/optimisation/adequacy_patch_csr/set_variable_boundaries.cpp index 1ec76ca553..c59f4f71e7 100644 --- a/src/solver/optimisation/adequacy_patch_csr/set_variable_boundaries.cpp +++ b/src/solver/optimisation/adequacy_patch_csr/set_variable_boundaries.cpp @@ -77,7 +77,7 @@ void HourlyCSRProblem::setBoundsOnSpilledEnergy() .ValeursHorairesDeDefaillanceNegative[triggeredHour]; double* AdresseDuResultat = &(problemeHebdo_->ResultatsHoraires[area] - .ValeursHorairesSpilledEnergyAfterCSR[triggeredHour]); + .ValeursHorairesDeDefaillanceNegative[triggeredHour]); problemeAResoudre_.AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = AdresseDuResultat; diff --git a/src/solver/optimisation/adequacy_patch_local_matching/adequacy_patch_weekly_optimization.cpp b/src/solver/optimisation/adequacy_patch_local_matching/adequacy_patch_weekly_optimization.cpp deleted file mode 100644 index 577cfa55b7..0000000000 --- a/src/solver/optimisation/adequacy_patch_local_matching/adequacy_patch_weekly_optimization.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ - -#include "antares/solver/optimisation/adequacy_patch_local_matching/adequacy_patch_weekly_optimization.h" - -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/simulation/adequacy_patch_runtime_data.h" -#include "antares/study/fwd.h" - -using namespace Antares::Data::AdequacyPatch; -using Antares::Constants::nbHoursInAWeek; - -namespace Antares::Solver::Optimization -{ -AdequacyPatchOptimization::AdequacyPatchOptimization(const Antares::Data::Study& study, - const OptimizationOptions& options, - PROBLEME_HEBDO* problemeHebdo, - AdqPatchParams& adqPatchParams, - uint thread_number, - IResultWriter& writer): - WeeklyOptimization(options, problemeHebdo, adqPatchParams, thread_number, writer), - study_(study) -{ -} - -void AdequacyPatchOptimization::solve() -{ - problemeHebdo_->adequacyPatchRuntimeData->AdequacyFirstStep = true; - OPT_OptimisationHebdomadaire(options_, problemeHebdo_, adqPatchParams_, writer_); - problemeHebdo_->adequacyPatchRuntimeData->AdequacyFirstStep = false; - - for (uint32_t pays = 0; pays < problemeHebdo_->NombreDePays; ++pays) - { - if (problemeHebdo_->adequacyPatchRuntimeData->areaMode[pays] - == Data::AdequacyPatch::physicalAreaInsideAdqPatch) - { - problemeHebdo_->ResultatsHoraires[pays].ValeursHorairesDENS - = problemeHebdo_->ResultatsHoraires[pays].ValeursHorairesDeDefaillancePositive; - } - else - { - std::ranges::fill(problemeHebdo_->ResultatsHoraires[pays].ValeursHorairesDENS, 0); - } - } - - OPT_OptimisationHebdomadaire(options_, problemeHebdo_, adqPatchParams_, writer_); -} - -} // namespace Antares::Solver::Optimization diff --git a/src/solver/optimisation/adequacy_patch_local_matching/adq_patch_local_matching.cpp b/src/solver/optimisation/adequacy_patch_local_matching/adq_patch_local_matching.cpp deleted file mode 100644 index e61b843403..0000000000 --- a/src/solver/optimisation/adequacy_patch_local_matching/adq_patch_local_matching.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ - -#include "antares/solver/optimisation/adequacy_patch_local_matching/adq_patch_local_matching.h" - -#include "antares/solver/simulation/adequacy_patch_runtime_data.h" - -namespace Antares::Data::AdequacyPatch -{ -/*! - * Determines restriction type for transmission links for first step of adequacy patch, when start - * node is inside adq path (type 2). - * - * @param ExtremityNodeAdequacyPatchType uint: The adq type of the node at the end of the link. - * - * @return uint from an enumeration that describes the type of restrictions to put on this link for - * adq purposes. - */ -static NtcSetToZeroStatus_AdqPatchStep1 SetNTCForAdequacyFirstStepOriginNodeInsideAdq( - AdequacyPatchMode ExtremityNodeAdequacyPatchType) -{ - switch (ExtremityNodeAdequacyPatchType) - { - case physicalAreaInsideAdqPatch: - case physicalAreaOutsideAdqPatch: - return NtcSetToZeroStatus_AdqPatchStep1::setToZero; - default: - return NtcSetToZeroStatus_AdqPatchStep1::leaveLocalValues; - } -} - -/*! - * Determines restriction type for transmission links for first step of adequacy patch, when start - * node is outside adq path (type 1). - * - * @param ExtremityNodeAdequacyPatchType uint: The adq type of the node at the end of the link. - * - * @param setToZeroNTCfromOutToIn_AdqPatch bool: Switch to cut links from nodes outside adq patch - * (type 1) towards nodes inside adq patch (type 2). - * - * @param setToZeroNTCfromOutToOut_AdqPatch bool: Switch to cut links between nodes outside adq - * patch (type 1). - * - * @return uint from an enumeration that describes the type of restrictions to put on this link for - * adq purposes. - */ -static NtcSetToZeroStatus_AdqPatchStep1 getNTCtoZeroStatusOriginNodeOutsideAdq( - AdequacyPatchMode ExtremityNodeAdequacyPatchType, - bool setToZeroNTCfromOutToIn_AdqPatch, - bool setToZeroNTCfromOutToOut_AdqPatch) -{ - switch (ExtremityNodeAdequacyPatchType) - { - case physicalAreaInsideAdqPatch: - return setToZeroNTCfromOutToIn_AdqPatch - ? NtcSetToZeroStatus_AdqPatchStep1::setToZero - : NtcSetToZeroStatus_AdqPatchStep1::setExtremityOriginToZero; - case physicalAreaOutsideAdqPatch: - return setToZeroNTCfromOutToOut_AdqPatch - ? NtcSetToZeroStatus_AdqPatchStep1::setToZero - : NtcSetToZeroStatus_AdqPatchStep1::leaveLocalValues; - default: - return NtcSetToZeroStatus_AdqPatchStep1::leaveLocalValues; - } -} - -/*! - * Determines restriction type for transmission links for first step of adequacy patch. - * - * @param problemeHebdo PROBLEME_HEBDO*: Weekly problem structure. - * - * @param Interco int: Index of the link. - * - * @return uint from an enumeration that describes the type of restrictions to put on this link for - * adq purposes. - */ -static NtcSetToZeroStatus_AdqPatchStep1 getNTCtoZeroStatus(PROBLEME_HEBDO* problemeHebdo, - const AdqPatchParams& adqPatchParams, - int Interco) -{ - AdequacyPatchMode OriginNodeAdequacyPatchType = problemeHebdo->adequacyPatchRuntimeData - ->originAreaMode[Interco]; - AdequacyPatchMode ExtremityNodeAdequacyPatchType = problemeHebdo->adequacyPatchRuntimeData - ->extremityAreaMode[Interco]; - bool setToZeroNTCfromOutToIn_AdqPatch = adqPatchParams.localMatching - .setToZeroOutsideInsideLinks; - bool setToZeroNTCfromOutToOut_AdqPatch = adqPatchParams.localMatching - .setToZeroOutsideOutsideLinks; - - switch (OriginNodeAdequacyPatchType) - { - case physicalAreaInsideAdqPatch: - return SetNTCForAdequacyFirstStepOriginNodeInsideAdq(ExtremityNodeAdequacyPatchType); - - case physicalAreaOutsideAdqPatch: - return getNTCtoZeroStatusOriginNodeOutsideAdq(ExtremityNodeAdequacyPatchType, - setToZeroNTCfromOutToIn_AdqPatch, - setToZeroNTCfromOutToOut_AdqPatch); - default: - return NtcSetToZeroStatus_AdqPatchStep1::leaveLocalValues; - } -} - -void setNTCbounds(double& Xmax, - double& Xmin, - const VALEURS_DE_NTC_ET_RESISTANCES& ValeursDeNTC, - const int Interco, - PROBLEME_HEBDO* problemeHebdo, - const AdqPatchParams& adqPatchParams) -{ - NtcSetToZeroStatus_AdqPatchStep1 ntcToZeroStatusForAdqPatch; - - // set as default values - Xmax = ValeursDeNTC.ValeurDeNTCOrigineVersExtremite[Interco]; - Xmin = -(ValeursDeNTC.ValeurDeNTCExtremiteVersOrigine[Interco]); - - // set for adq patch first step - if (adqPatchParams.enabled && adqPatchParams.localMatching.enabled - && problemeHebdo->adequacyPatchRuntimeData->AdequacyFirstStep) - { - ntcToZeroStatusForAdqPatch = getNTCtoZeroStatus(problemeHebdo, adqPatchParams, Interco); - - switch (ntcToZeroStatusForAdqPatch) - { - case NtcSetToZeroStatus_AdqPatchStep1::setToZero: - { - Xmax = 0.; - Xmin = 0.; - break; - } - case NtcSetToZeroStatus_AdqPatchStep1::setOriginExtremityToZero: - { - Xmax = 0.; - Xmin = -(ValeursDeNTC.ValeurDeNTCExtremiteVersOrigine[Interco]); - break; - } - case NtcSetToZeroStatus_AdqPatchStep1::setExtremityOriginToZero: - { - Xmax = ValeursDeNTC.ValeurDeNTCOrigineVersExtremite[Interco]; - Xmin = 0.; - break; - } - default: - return; - } - } -} - -} // namespace Antares::Data::AdequacyPatch diff --git a/src/solver/optimisation/base_weekly_optimization.cpp b/src/solver/optimisation/base_weekly_optimization.cpp deleted file mode 100644 index d4da2a1167..0000000000 --- a/src/solver/optimisation/base_weekly_optimization.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ - -#include "antares/solver/optimisation/base_weekly_optimization.h" - -#include - -#include "antares/solver/optimisation/adequacy_patch_local_matching/adequacy_patch_weekly_optimization.h" -#include "antares/solver/optimisation/weekly_optimization.h" - -using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams; - -namespace Antares::Solver::Optimization -{ -WeeklyOptimization::WeeklyOptimization(const OptimizationOptions& options, - PROBLEME_HEBDO* problemesHebdo, - AdqPatchParams& adqPatchParams, - uint thread_number, - IResultWriter& writer): - options_(options), - problemeHebdo_(problemesHebdo), - adqPatchParams_(adqPatchParams), - thread_number_(thread_number), - writer_(writer) -{ -} - -std::unique_ptr WeeklyOptimization::create(const Antares::Data::Study& study, - const OptimizationOptions& options, - AdqPatchParams& adqPatchParams, - PROBLEME_HEBDO* problemeHebdo, - uint thread_number, - IResultWriter& writer) -{ - if (adqPatchParams.enabled && adqPatchParams.localMatching.enabled) - { - return std::make_unique(study, - options, - problemeHebdo, - adqPatchParams, - thread_number, - writer); - } - else - { - return std::make_unique(options, - problemeHebdo, - adqPatchParams, - thread_number, - writer); - } -} - -} // namespace Antares::Solver::Optimization diff --git a/src/solver/optimisation/constraints/ShortTermStorageLevel.cpp b/src/solver/optimisation/constraints/ShortTermStorageLevel.cpp index 0faa565a8a..00a70e8dd9 100644 --- a/src/solver/optimisation/constraints/ShortTermStorageLevel.cpp +++ b/src/solver/optimisation/constraints/ShortTermStorageLevel.cpp @@ -42,8 +42,8 @@ void ShortTermStorageLevel::add(int pdt, int pays) -1.0, -1, builder.data.NombreDePasDeTempsPourUneOptimisation) - .ShortTermStorageInjection(index, -1.0 * storage.efficiency) - .ShortTermStorageWithdrawal(index, 1.0) + .ShortTermStorageInjection(index, -storage.injectionEfficiency) + .ShortTermStorageWithdrawal(index, storage.withdrawalEfficiency) .equalTo() .build(); } diff --git a/src/solver/optimisation/include/antares/solver/optimisation/HebdoProblemToLpsTranslator.h b/src/solver/optimisation/include/antares/solver/optimisation/HebdoProblemToLpsTranslator.h new file mode 100644 index 0000000000..7deb23a0ca --- /dev/null +++ b/src/solver/optimisation/include/antares/solver/optimisation/HebdoProblemToLpsTranslator.h @@ -0,0 +1,81 @@ + +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include "antares/solver/lps/LpsFromAntares.h" +#include "antares/solver/simulation/sim_structure_probleme_economique.h" + +namespace Antares::Solver +{ + +/** + * @class WeeklyProblemTranslationException + * @brief Exception class for errors during the translation of a weekly problem. + * + * This class is a custom exception class that is thrown when an error occurs during the translation + * of a weekly problem. + */ +class WeeklyProblemTranslationException: public std::runtime_error +{ +public: + explicit WeeklyProblemTranslationException(const std::string& string) noexcept; +}; + +/** + * @class HebdoProblemToLpsTranslator + * @brief Class for translating a weekly problem to a linear programming problem. + * + * This class is responsible for translating a weekly problem to a linear programming problem. + */ +class HebdoProblemToLpsTranslator +{ +public: + /** + * @brief Translates a weekly problem to a linear programming problem. + * + * This function takes a pointer to a PROBLEME_ANTARES_A_RESOUDRE object and a string_view + * representing the name of the problem. It translates the weekly problem to a linear + * programming problem and returns a WeeklyDataFromAntaresPtr to the translated problem. Datas + * from the PROBLEME_ANTARES_A_RESOUDRE are copied to the WeeklyDataFromAntaresPtr. + * + * @param problem A pointer to the weekly problem to be translated. + * @param name The name of the problem. + * @return WeeklyDataFromAntaresPtr A WeeklyDataFromAntaresPtr to the translated problem. + */ + [[nodiscard]] WeeklyDataFromAntares translate(const PROBLEME_ANTARES_A_RESOUDRE* problem, + std::string_view name) const; + + /** + * @brief Retrieves common problem data, the part common to every weekly problems + * + * This function takes a pointer to a PROBLEME_ANTARES_A_RESOUDRE object and retrieves the + * common problem data. It returns a ConstantDataFromAntaresPtr to the common problem data. + * + * @param problem A pointer to the problem from which to retrieve the common data. + * @return ConstantDataFromAntaresPtr A ConstantDataFromAntaresPtr to the common problem data. + */ + [[nodiscard]] ConstantDataFromAntares commonProblemData( + const PROBLEME_ANTARES_A_RESOUDRE* problem) const; +}; + +} // namespace Antares::Solver diff --git a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_local_matching/adq_patch_local_matching.h b/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h similarity index 68% rename from src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_local_matching/adq_patch_local_matching.h rename to src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h index eff8842d7b..3ae5ee2d91 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_local_matching/adq_patch_local_matching.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/adequacy_patch_csr/post_processing.h @@ -21,19 +21,9 @@ #pragma once -#include "antares/solver/simulation/sim_structure_probleme_economique.h" - namespace Antares::Data::AdequacyPatch { -/*! - * Sets link bounds for first step of adequacy patch or leaves default values if adequacy patch is - * not used. - */ -void setNTCbounds(double& Xmax, - double& Xmin, - const VALEURS_DE_NTC_ET_RESISTANCES& ValeursDeNTC, - const int Interco, - PROBLEME_HEBDO* problemeHebdo, - const AdqPatchParams& adqPatchParams); - +double recomputeDTG_MRG(bool triggered, double dtgMrg, double ens); +double recomputeENS_MRG(bool triggered, double dtgMrg, double ens); +double recomputeMRGPrice(double ensCsr, double originalCost, double unsuppliedEnergyCost); } // namespace Antares::Data::AdequacyPatch diff --git a/src/solver/optimisation/include/antares/solver/optimisation/base_weekly_optimization.h b/src/solver/optimisation/include/antares/solver/optimisation/base_weekly_optimization.h deleted file mode 100644 index 7f4b755bb5..0000000000 --- a/src/solver/optimisation/include/antares/solver/optimisation/base_weekly_optimization.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ - -#pragma once - -#include // for "uint" definition - -#include -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/sim_structure_probleme_economique.h" - -namespace Antares::Solver::Optimization -{ -class WeeklyOptimization -{ -public: - virtual void solve() = 0; - virtual ~WeeklyOptimization() = default; - static std::unique_ptr create( - const Antares::Data::Study& study, - const OptimizationOptions& options, - Antares::Data::AdequacyPatch::AdqPatchParams& adqPatchParams, - PROBLEME_HEBDO* problemesHebdo, - uint numSpace, - IResultWriter& writer); - -protected: - explicit WeeklyOptimization(const OptimizationOptions& options, - PROBLEME_HEBDO* problemesHebdo, - Antares::Data::AdequacyPatch::AdqPatchParams&, - uint numSpace, - IResultWriter& writer); - Antares::Solver::Optimization::OptimizationOptions options_; - PROBLEME_HEBDO* const problemeHebdo_ = nullptr; - Antares::Data::AdequacyPatch::AdqPatchParams& adqPatchParams_; - const uint thread_number_ = 0; - IResultWriter& writer_; -}; -} // namespace Antares::Solver::Optimization diff --git a/src/solver/optimisation/include/antares/solver/optimisation/constraints/constraint_builder_utils.h b/src/solver/optimisation/include/antares/solver/optimisation/constraints/constraint_builder_utils.h index 9e4981700e..9e940aa200 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/constraints/constraint_builder_utils.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/constraints/constraint_builder_utils.h @@ -22,6 +22,7 @@ #include #include "ConstraintBuilder.h" +struct PROBLEME_HEBDO; ConstraintBuilderData NewGetConstraintBuilderFromProblemHebdoAndProblemAResoudre( PROBLEME_HEBDO* problemeHebdo, diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_export_structure.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_export_structure.h index 4d69d8711e..47aa3838e1 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_export_structure.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_export_structure.h @@ -1,50 +1,32 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ -#ifndef __EXPORT_STRUCTURE__ -#define __EXPORT_STRUCTURE__ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ +#pragma once -#include -#include #include -#include - -#include #include "antares/antares/Enum.hpp" #include "antares/writer/i_writer.h" - -namespace Antares -{ -namespace Data -{ - -class Study; -} // namespace Data -} // namespace Antares - struct PROBLEME_HEBDO; void OPT_ExportInterco(Antares::Solver::IResultWriter& writer, PROBLEME_HEBDO* problemeHebdo); void OPT_ExportAreaName(Antares::Solver::IResultWriter& writer, const std::vector& areaNames); void OPT_ExportStructures(PROBLEME_HEBDO* problemeHebdo, Antares::Solver::IResultWriter& writer); - -#endif diff --git a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h index 308616f1c4..4be6b8e1d7 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/opt_fonctions.h @@ -1,42 +1,44 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #ifndef __SOLVER_OPTIMISATION_FUNCTIONS_H__ #define __SOLVER_OPTIMISATION_FUNCTIONS_H__ #include +#include #include #include "antares/config/config.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" +#include "antares/solver/simulation/ISimulationObserver.h" #include "antares/study/parameters/adq-patch-params.h" #include "adequacy_patch_csr/hourly_csr_problem.h" -#include "opt_period_string_generator_base.h" using AdqPatchParams = Antares::Data::AdequacyPatch::AdqPatchParams; using OptimizationOptions = Antares::Solver::Optimization::OptimizationOptions; void OPT_OptimisationHebdomadaire(const OptimizationOptions& options, - PROBLEME_HEBDO*, - const AdqPatchParams&, - Antares::Solver::IResultWriter& writer); + PROBLEME_HEBDO* pProblemeHebdo, + const AdqPatchParams& adqPatchParams, + Solver::IResultWriter& writer, + Solver::Simulation::ISimulationObserver& simulationObserver); void OPT_NumeroDeJourDuPasDeTemps(PROBLEME_HEBDO*); void OPT_NumeroDIntervalleOptimiseDuPasDeTemps(PROBLEME_HEBDO*); void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaire(PROBLEME_HEBDO*); @@ -65,9 +67,10 @@ bool ADQ_PATCH_CSR(PROBLEME_ANTARES_A_RESOUDRE&, int year); bool OPT_PilotageOptimisationLineaire(const OptimizationOptions& options, - PROBLEME_HEBDO*, - const AdqPatchParams&, - Antares::Solver::IResultWriter& writer); + PROBLEME_HEBDO* problemeHebdo, + const AdqPatchParams& adqPatchParams, + Solver::IResultWriter& writer, + Solver::Simulation::ISimulationObserver& simulationObserver); void OPT_VerifierPresenceReserveJmoins1(PROBLEME_HEBDO*); bool OPT_PilotageOptimisationQuadratique(PROBLEME_HEBDO*); @@ -85,25 +88,20 @@ bool OPT_AppelDuSimplexe(const OptimizationOptions& options, void OPT_LiberationProblemesSimplexe(const OptimizationOptions& options, const PROBLEME_HEBDO*); bool OPT_OptimisationLineaire(const OptimizationOptions& options, - PROBLEME_HEBDO*, - const AdqPatchParams&, - Antares::Solver::IResultWriter& writer); + PROBLEME_HEBDO* problemeHebdo, + const AdqPatchParams& adqPatchParams, + Solver::IResultWriter& writer, + Solver::Simulation::ISimulationObserver& simulationObserver); void OPT_RestaurerLesDonnees(PROBLEME_HEBDO*); /*------------------------------*/ void OPT_CalculerLesPminThermiquesEnFonctionDeMUTetMDT(PROBLEME_HEBDO*); double OPT_CalculerAireMaxPminJour(int, int, int, int, std::vector&, std::vector&); -void OPT_ChargerLaContrainteDansLaMatriceDesContraintes(PROBLEME_ANTARES_A_RESOUDRE*, - std::vector&, - std::vector&, - int, - char); void OPT_ChainagesDesIntercoPartantDUnNoeud(PROBLEME_HEBDO*); void OPT_AllocateFromNumberOfVariableConstraints(PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre, int); -void OPT_FreeOptimizationData(PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre); void OPT_AllocDuProblemeAOptimiser(PROBLEME_HEBDO*); int OPT_DecompteDesVariablesEtDesContraintesDuProblemeAOptimiser(PROBLEME_HEBDO*); void OPT_AugmenterLaTailleDeLaMatriceDesContraintes(PROBLEME_ANTARES_A_RESOUDRE*); diff --git a/src/solver/optimisation/include/antares/solver/optimisation/weekly_optimization.h b/src/solver/optimisation/include/antares/solver/optimisation/weekly_optimization.h index 1f9ae23137..c1f7774d5d 100644 --- a/src/solver/optimisation/include/antares/solver/optimisation/weekly_optimization.h +++ b/src/solver/optimisation/include/antares/solver/optimisation/weekly_optimization.h @@ -1,41 +1,49 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #pragma once +#include "antares/solver/simulation/ISimulationObserver.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" -#include "base_weekly_optimization.h" - namespace Antares::Solver::Optimization { -class DefaultWeeklyOptimization: public WeeklyOptimization + +class WeeklyOptimization { public: - explicit DefaultWeeklyOptimization(const OptimizationOptions& options, - PROBLEME_HEBDO* problemeHebdo, - Antares::Data::AdequacyPatch::AdqPatchParams&, - uint numSpace, - IResultWriter& writer); - ~DefaultWeeklyOptimization() override = default; - void solve() override; + WeeklyOptimization(const OptimizationOptions& options, + PROBLEME_HEBDO* problemeHebdo, + Antares::Data::AdequacyPatch::AdqPatchParams&, + uint numSpace, + IResultWriter& writer, + Simulation::ISimulationObserver& simulationObserver); + ~WeeklyOptimization() = default; + void solve(); + + Antares::Solver::Optimization::OptimizationOptions options_; + PROBLEME_HEBDO* const problemeHebdo_ = nullptr; + Antares::Data::AdequacyPatch::AdqPatchParams& adqPatchParams_; + const uint thread_number_ = 0; + IResultWriter& writer_; + std::reference_wrapper simulationObserver_; }; } // namespace Antares::Solver::Optimization diff --git a/src/solver/optimisation/opt_construction_matrice_des_contraintes_outils.cpp b/src/solver/optimisation/opt_construction_matrice_des_contraintes_outils.cpp deleted file mode 100644 index 80ef6f809c..0000000000 --- a/src/solver/optimisation/opt_construction_matrice_des_contraintes_outils.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ - -#include "antares/solver/optimisation/opt_fonctions.h" -#include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" -#include "antares/solver/simulation/sim_structure_donnees.h" - -void OPT_ChargerLaContrainteDansLaMatriceDesContraintes( - PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre, - std::vector& Pi, - std::vector& Colonne, - int NombreDeTermesDeLaContrainte, - char SensContrainte) -{ - int& nombreDeTermes = ProblemeAResoudre->NombreDeTermesDansLaMatriceDesContraintes; - int& nombreDeContraintes = ProblemeAResoudre->NombreDeContraintes; - - ProblemeAResoudre->IndicesDebutDeLigne[nombreDeContraintes] = nombreDeTermes; - for (int i = 0; i < NombreDeTermesDeLaContrainte; i++) - { - ProblemeAResoudre->CoefficientsDeLaMatriceDesContraintes[nombreDeTermes] = Pi[i]; - ProblemeAResoudre->IndicesColonnes[nombreDeTermes] = Colonne[i]; - nombreDeTermes++; - if (nombreDeTermes == ProblemeAResoudre->NombreDeTermesAllouesDansLaMatriceDesContraintes) - { - OPT_AugmenterLaTailleDeLaMatriceDesContraintes(ProblemeAResoudre); - } - } - ProblemeAResoudre->NombreDeTermesDesLignes[nombreDeContraintes] = NombreDeTermesDeLaContrainte; - - ProblemeAResoudre->Sens[nombreDeContraintes] = SensContrainte; - nombreDeContraintes++; - - return; -} diff --git a/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp b/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp index 6fe7e353da..98a259540d 100644 --- a/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp +++ b/src/solver/optimisation/opt_construction_variables_couts_demarrages.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_rename_problem.h" @@ -35,7 +35,7 @@ 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++) @@ -94,4 +94,5 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeLineaireCoutsDeDemarra } } } + ProblemeAResoudre->NombreDeVariables = nombreDeVariables; } diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp index 8b082d5b50..40736b5428 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_lineaire.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include #include "antares/solver/optimisation/opt_fonctions.h" diff --git a/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp b/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp index b067eb6431..10018bf29d 100644 --- a/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp +++ b/src/solver/optimisation/opt_construction_variables_optimisees_quadratique.cpp @@ -31,7 +31,7 @@ void OPT_ConstruireLaListeDesVariablesOptimiseesDuProblemeQuadratique(PROBLEME_HEBDO* problemeHebdo) { const auto& ProblemeAResoudre = problemeHebdo->ProblemeAResoudre; - assert(ProblemeAResoudre != NULL); + assert(ProblemeAResoudre); int nombreDeVariables = 0; auto variableManager = VariableManagerFromProblemHebdo(problemeHebdo); diff --git a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp index 3df1cc9d99..1f773bb9ea 100644 --- a/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp +++ b/src/solver/optimisation/opt_decompte_variables_et_contraintes.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include #include diff --git a/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp b/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp index 9e43f38023..a5c23adebb 100644 --- a/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_bornes_cas_lineaire.cpp @@ -21,7 +21,6 @@ #include -#include "antares/solver/optimisation/adequacy_patch_local_matching/adq_patch_local_matching.h" #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/adequacy_patch_runtime_data.h" @@ -133,17 +132,6 @@ void setBoundsForUnsuppliedEnergy(PROBLEME_HEBDO* problemeHebdo, Xmax[var] = 0.; } - // adq patch: update ENS <= DENS in 2nd run - if (adqPatchParams.enabled && adqPatchParams.localMatching.enabled - && !problemeHebdo->adequacyPatchRuntimeData->AdequacyFirstStep - && problemeHebdo->adequacyPatchRuntimeData->areaMode[pays] - == Data::AdequacyPatch::physicalAreaInsideAdqPatch) - { - Xmax[var] = std::min( - Xmax[var], - problemeHebdo->ResultatsHoraires[pays].ValeursHorairesDENS[pdtHebdo]); - } - problemeHebdo->ResultatsHoraires[pays].ValeursHorairesDeDefaillancePositive[pdtHebdo] = 0.0; @@ -249,12 +237,8 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob int var = variableManager.NTCDirect(interco, pdtJour); const COUTS_DE_TRANSPORT& CoutDeTransport = problemeHebdo->CoutDeTransport[interco]; - AdequacyPatch::setNTCbounds(Xmax[var], - Xmin[var], - ValeursDeNTC, - interco, - problemeHebdo, - adqPatchParams); + Xmax[var] = ValeursDeNTC.ValeurDeNTCOrigineVersExtremite[interco]; + Xmin[var] = -(ValeursDeNTC.ValeurDeNTCExtremiteVersOrigine[interco]); if (std::isinf(Xmax[var]) && Xmax[var] > 0) { @@ -308,8 +292,8 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob TypeDeVariable[var] = VARIABLE_BORNEE_INFERIEUREMENT; } Xmin[var] = 0.0; - AdresseOuPlacerLaValeurDesCoutsReduits[var] = NULL; - AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = NULL; + AdresseOuPlacerLaValeurDesCoutsReduits[var] = nullptr; + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = nullptr; var = variableManager.IntercoIndirectCost(interco, pdtJour); if (CoutDeTransport.IntercoGereeAvecLoopFlow) @@ -329,8 +313,8 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob TypeDeVariable[var] = VARIABLE_BORNEE_INFERIEUREMENT; } Xmin[var] = 0.0; - AdresseOuPlacerLaValeurDesCoutsReduits[var] = NULL; - AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = NULL; + AdresseOuPlacerLaValeurDesCoutsReduits[var] = nullptr; + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = nullptr; } } @@ -382,16 +366,16 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob { Xmin[var] = 0.0; Xmax[var] = LINFINI_ANTARES; - AdresseOuPlacerLaValeurDesCoutsReduits[var] = NULL; - AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = NULL; + AdresseOuPlacerLaValeurDesCoutsReduits[var] = nullptr; + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = nullptr; } var = variableManager.HydProdUp(pays, pdtJour); if (var >= 0 && var < ProblemeAResoudre->NombreDeVariables) { Xmin[var] = 0.0; Xmax[var] = LINFINI_ANTARES; - AdresseOuPlacerLaValeurDesCoutsReduits[var] = NULL; - AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = NULL; + AdresseOuPlacerLaValeurDesCoutsReduits[var] = nullptr; + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = nullptr; } } else if (problemeHebdo->TypeDeLissageHydraulique @@ -404,8 +388,8 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob Xmin[var] = 0.0; Xmax[var] = problemeHebdo->CaracteristiquesHydrauliques[pays] .MaxDesPmaxHydrauliques; - AdresseOuPlacerLaValeurDesCoutsReduits[var] = NULL; - AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = NULL; + AdresseOuPlacerLaValeurDesCoutsReduits[var] = nullptr; + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = nullptr; } var = variableManager.HydProdUp(pays, pdtJour); @@ -414,8 +398,8 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob Xmin[var] = 0.0; Xmax[var] = problemeHebdo->CaracteristiquesHydrauliques[pays] .MaxDesPmaxHydrauliques; - AdresseOuPlacerLaValeurDesCoutsReduits[var] = NULL; - AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = NULL; + AdresseOuPlacerLaValeurDesCoutsReduits[var] = nullptr; + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = nullptr; } } } @@ -454,7 +438,7 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob .NiveauHoraireSup[pdtHebdo]; double* adresseDuResultat = &( problemeHebdo->ResultatsHoraires[pays].niveauxHoraires[pdtHebdo]); - AdresseOuPlacerLaValeurDesCoutsReduits[var] = NULL; + AdresseOuPlacerLaValeurDesCoutsReduits[var] = nullptr; AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat; } @@ -472,9 +456,6 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob .ValeursHorairesDeDefaillanceNegative[pdtHebdo]); AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat; } - - problemeHebdo->ResultatsHoraires[pays].ValeursHorairesDeDefaillanceEnReserve[pdtHebdo] - = 0.0; } } @@ -496,14 +477,14 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob Xmin[var] = -(LINFINI_ANTARES); Xmax[var] = LINFINI_ANTARES; - AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = NULL; + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = nullptr; // Note: if there were a single optimization run instead of two; the following // could be used: adresseDuResultat = //&(problemeHebdo->CaracteristiquesHydrauliques[pays].LevelForTimeInterval); // AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = adresseDuResultat; - AdresseOuPlacerLaValeurDesCoutsReduits[var] = NULL; + AdresseOuPlacerLaValeurDesCoutsReduits[var] = nullptr; } for (uint nblayer = 0; nblayer < 100; nblayer++) { @@ -514,8 +495,8 @@ void OPT_InitialiserLesBornesDesVariablesDuProblemeLineaire(PROBLEME_HEBDO* prob Xmax[var] = problemeHebdo->CaracteristiquesHydrauliques[pays].TailleReservoir / double(100); - AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = NULL; - AdresseOuPlacerLaValeurDesCoutsReduits[var] = NULL; + AdresseOuPlacerLaValeurDesVariablesOptimisees[var] = nullptr; + AdresseOuPlacerLaValeurDesCoutsReduits[var] = nullptr; } } } diff --git a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp index 31a401e768..4ea8c80457 100644 --- a/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp +++ b/src/solver/optimisation/opt_gestion_des_couts_cas_lineaire.cpp @@ -24,7 +24,6 @@ #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/sim_extern_variables_globales.h" -#include "antares/solver/simulation/sim_spread_generator.h" #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/simulation.h" @@ -38,7 +37,6 @@ static void shortTermStorageCost( VariableManagement::VariableManager& variableManager, std::vector& linearCost) { - SIM::SpreadGenerator spreadGenerator; for (int pays = 0; pays < NombreDePays; ++pays) { for (const auto& storage: shortTermStorageInput[pays]) @@ -52,16 +50,15 @@ static void shortTermStorageCost( pdtJour); varLevel >= 0) { - linearCost[varLevel] = 0; + linearCost[varLevel] = storage.series->costLevel[pdtHebdo]; } - const double cost = spreadGenerator.generate(); if (const int varInjection = variableManager.ShortTermStorageInjection( clusterGlobalIndex, pdtJour); varInjection >= 0) { - linearCost[varInjection] = cost; + linearCost[varInjection] = storage.series->costInjection[pdtHebdo]; } if (const int varWithdrawal = variableManager.ShortTermStorageWithdrawal( @@ -69,7 +66,7 @@ static void shortTermStorageCost( pdtJour); varWithdrawal >= 0) { - linearCost[varWithdrawal] = storage.efficiency * cost; + linearCost[varWithdrawal] = storage.series->costWithdrawal[pdtHebdo]; } } } diff --git a/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp b/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp index 0ad9462dc4..df0a9b4e37 100644 --- a/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp +++ b/src/solver/optimisation/opt_liberation_problemes_simplexe.cpp @@ -64,12 +64,12 @@ void OPT_LiberationProblemesSimplexe(const OptimizationOptions& options, if (options.ortoolsUsed && solver) { ORTOOLS_LibererProbleme(solver); - solver = NULL; + solver = nullptr; } - else if (ProbSpx != NULL) + else if (ProbSpx) { SPX_LibererProbleme(ProbSpx); - ProbSpx = NULL; + ProbSpx = nullptr; } } } diff --git a/src/solver/optimisation/opt_optimisation_hebdo.cpp b/src/solver/optimisation/opt_optimisation_hebdo.cpp index 89c59ec57a..0abed9ff13 100644 --- a/src/solver/optimisation/opt_optimisation_hebdo.cpp +++ b/src/solver/optimisation/opt_optimisation_hebdo.cpp @@ -1,29 +1,30 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include #include #include #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" +#include "antares/solver/simulation/ISimulationObserver.h" #include "antares/solver/simulation/sim_extern_variables_globales.h" extern "C" @@ -39,11 +40,16 @@ using Antares::Solver::Optimization::OptimizationOptions; void OPT_OptimisationHebdomadaire(const OptimizationOptions& options, PROBLEME_HEBDO* pProblemeHebdo, const AdqPatchParams& adqPatchParams, - Solver::IResultWriter& writer) + Solver::IResultWriter& writer, + Solver::Simulation::ISimulationObserver& simulationObserver) { if (pProblemeHebdo->TypeDOptimisation == OPTIMISATION_LINEAIRE) { - if (!OPT_PilotageOptimisationLineaire(options, pProblemeHebdo, adqPatchParams, writer)) + if (!OPT_PilotageOptimisationLineaire(options, + pProblemeHebdo, + adqPatchParams, + writer, + simulationObserver)) { logs.error() << "Linear optimization failed"; throw UnfeasibleProblemError("Linear optimization failed"); diff --git a/src/solver/optimisation/opt_optimisation_lineaire.cpp b/src/solver/optimisation/opt_optimisation_lineaire.cpp index 67c475e396..b3ca1a3daa 100644 --- a/src/solver/optimisation/opt_optimisation_lineaire.cpp +++ b/src/solver/optimisation/opt_optimisation_lineaire.cpp @@ -1,29 +1,32 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include +#include "antares/solver/lps/LpsFromAntares.h" +#include "antares/solver/optimisation/HebdoProblemToLpsTranslator.h" #include "antares/solver/optimisation/LinearProblemMatrix.h" #include "antares/solver/optimisation/constraints/constraint_builder_utils.h" #include "antares/solver/optimisation/opt_export_structure.h" #include "antares/solver/optimisation/opt_fonctions.h" +#include "antares/solver/simulation/ISimulationObserver.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" #include "antares/solver/utils/filename.h" using namespace Antares; @@ -61,11 +64,26 @@ void OPT_EcrireResultatFonctionObjectiveAuFormatTXT( writer.addEntryFromBuffer(filename, buffer); } +namespace +{ +void notifyProblemHebdo(const PROBLEME_HEBDO* problemeHebdo, + int optimizationNumber, + Solver::Simulation::ISimulationObserver& simulationObserver, + const OptPeriodStringGenerator* optPeriodStringGenerator) +{ + simulationObserver.notifyHebdoProblem(*problemeHebdo, + optimizationNumber, + createMPSfilename(*optPeriodStringGenerator, + optimizationNumber)); +} +} // namespace + bool runWeeklyOptimization(const OptimizationOptions& options, PROBLEME_HEBDO* problemeHebdo, const AdqPatchParams& adqPatchParams, Solver::IResultWriter& writer, - int optimizationNumber) + int optimizationNumber, + Solver::Simulation::ISimulationObserver& simulationObserver) { const int NombreDePasDeTempsPourUneOptimisation = problemeHebdo ->NombreDePasDeTempsPourUneOptimisation; @@ -102,6 +120,11 @@ bool runWeeklyOptimization(const OptimizationOptions& options, problemeHebdo->weekInTheYear, problemeHebdo->year); + notifyProblemHebdo(problemeHebdo, + optimizationNumber, + simulationObserver, + optPeriodStringGenerator.get()); + if (!OPT_AppelDuSimplexe(options, problemeHebdo, numeroDeLIntervalle, @@ -137,12 +160,39 @@ void runThermalHeuristic(PROBLEME_HEBDO* problemeHebdo) OPT_CalculerLesPminThermiquesEnFonctionDeMUTetMDT(problemeHebdo); } } + +void resizeProbleme(PROBLEME_ANTARES_A_RESOUDRE* ProblemeAResoudre, + unsigned nombreDeVariables, + unsigned nombreDeContraintes) +{ + ProblemeAResoudre->CoutQuadratique.resize(nombreDeVariables); + ProblemeAResoudre->CoutLineaire.resize(nombreDeVariables); + ProblemeAResoudre->TypeDeVariable.resize(nombreDeVariables); + ProblemeAResoudre->Xmin.resize(nombreDeVariables); + ProblemeAResoudre->Xmax.resize(nombreDeVariables); + ProblemeAResoudre->X.resize(nombreDeVariables); + ProblemeAResoudre->AdresseOuPlacerLaValeurDesVariablesOptimisees.resize(nombreDeVariables); + ProblemeAResoudre->AdresseOuPlacerLaValeurDesCoutsReduits.resize(nombreDeVariables); + ProblemeAResoudre->PositionDeLaVariable.resize(nombreDeVariables); + ProblemeAResoudre->NomDesVariables.resize(nombreDeVariables); + ProblemeAResoudre->VariablesEntieres.resize(nombreDeVariables); + + ProblemeAResoudre->Sens.resize(nombreDeContraintes); + ProblemeAResoudre->IndicesDebutDeLigne.resize(nombreDeContraintes); + ProblemeAResoudre->NombreDeTermesDesLignes.resize(nombreDeContraintes); + ProblemeAResoudre->SecondMembre.resize(nombreDeContraintes); + ProblemeAResoudre->AdresseOuPlacerLaValeurDesCoutsMarginaux.resize(nombreDeContraintes); + ProblemeAResoudre->CoutsMarginauxDesContraintes.resize(nombreDeContraintes); + ProblemeAResoudre->ComplementDeLaBase.resize(nombreDeContraintes); + ProblemeAResoudre->NomDesContraintes.resize(nombreDeContraintes); +} } // namespace bool OPT_OptimisationLineaire(const OptimizationOptions& options, PROBLEME_HEBDO* problemeHebdo, const AdqPatchParams& adqPatchParams, - Solver::IResultWriter& writer) + Solver::IResultWriter& writer, + Solver::Simulation::ISimulationObserver& simulationObserver) { if (!problemeHebdo->OptimisationAuPasHebdomadaire) { @@ -166,6 +216,9 @@ bool OPT_OptimisationLineaire(const OptimizationOptions& options, ConstraintBuilder builder(builder_data); LinearProblemMatrix linearProblemMatrix(problemeHebdo, builder); linearProblemMatrix.Run(); + resizeProbleme(problemeHebdo->ProblemeAResoudre.get(), + problemeHebdo->ProblemeAResoudre->NombreDeVariables, + problemeHebdo->ProblemeAResoudre->NombreDeContraintes); if (problemeHebdo->ExportStructure && problemeHebdo->firstWeekOfSimulation) { OPT_ExportStructures(problemeHebdo, writer); @@ -175,7 +228,8 @@ bool OPT_OptimisationLineaire(const OptimizationOptions& options, problemeHebdo, adqPatchParams, writer, - PREMIERE_OPTIMISATION); + PREMIERE_OPTIMISATION, + simulationObserver); // We only need the 2nd optimization when NOT solving with integer variables // We also skip the 2nd optimization in the hidden 'Expansion' mode @@ -188,7 +242,8 @@ bool OPT_OptimisationLineaire(const OptimizationOptions& options, problemeHebdo, adqPatchParams, writer, - DEUXIEME_OPTIMISATION); + DEUXIEME_OPTIMISATION, + simulationObserver); } return ret; } diff --git a/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp b/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp index 79ce32f0cb..7d6bff0d80 100644 --- a/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp +++ b/src/solver/optimisation/opt_pilotage_optimisation_lineaire.cpp @@ -1,27 +1,28 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/optimization-options/options.h" #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" +#include "antares/solver/simulation/ISimulationObserver.h" #include "antares/solver/simulation/sim_extern_variables_globales.h" using Antares::Solver::Optimization::OptimizationOptions; @@ -29,7 +30,8 @@ using Antares::Solver::Optimization::OptimizationOptions; bool OPT_PilotageOptimisationLineaire(const OptimizationOptions& options, PROBLEME_HEBDO* problemeHebdo, const AdqPatchParams& adqPatchParams, - Solver::IResultWriter& writer) + Solver::IResultWriter& writer, + Solver::Simulation::ISimulationObserver& simulationObserver) { if (!problemeHebdo->LeProblemeADejaEteInstancie) { @@ -75,5 +77,9 @@ bool OPT_PilotageOptimisationLineaire(const OptimizationOptions& options, OPT_InitialiserNombreMinEtMaxDeGroupesCoutsDeDemarrage(problemeHebdo); } - return OPT_OptimisationLineaire(options, problemeHebdo, adqPatchParams, writer); + return OPT_OptimisationLineaire(options, + problemeHebdo, + adqPatchParams, + writer, + simulationObserver); } diff --git a/src/solver/optimisation/opt_rename_problem.cpp b/src/solver/optimisation/opt_rename_problem.cpp index 7a7553a59a..85edf581b8 100644 --- a/src/solver/optimisation/opt_rename_problem.cpp +++ b/src/solver/optimisation/opt_rename_problem.cpp @@ -21,6 +21,7 @@ #include "antares/solver/optimisation/opt_rename_problem.h" +#include #include const std::string HOUR("hour"); diff --git a/src/solver/optimisation/post_process_commands.cpp b/src/solver/optimisation/post_process_commands.cpp index c90c8b4809..fb628d694d 100644 --- a/src/solver/optimisation/post_process_commands.cpp +++ b/src/solver/optimisation/post_process_commands.cpp @@ -22,7 +22,7 @@ #include "antares/solver/optimisation/post_process_commands.h" #include "antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h" -#include "antares/solver/optimisation/adequacy_patch_local_matching/adequacy_patch_weekly_optimization.h" +#include "antares/solver/optimisation/adequacy_patch_csr/post_processing.h" #include "antares/solver/simulation/adequacy_patch_runtime_data.h" #include "antares/solver/simulation/common-eco-adq.h" @@ -47,7 +47,7 @@ void DispatchableMarginPostProcessCmd::execute(const optRuntimeData& opt_runtime unsigned int hourInYear = opt_runtime_data.hourInTheYear; unsigned int year = opt_runtime_data.year; area_list_.each( - [&](Data::Area& area) + [this, &hourInYear, &year](Data::Area& area) { double* dtgmrg = area.scratchpad[thread_number_].dispatchableGenerationMargin; for (uint h = 0; h != nbHoursInWeek; ++h) @@ -148,32 +148,23 @@ void DTGmarginForAdqPatchPostProcessCmd::execute(const optRuntimeData&) for (uint hour = 0; hour < nbHoursInWeek; hour++) { - // define access to the required variables + auto& hourlyResults = problemeHebdo_->ResultatsHoraires[Area]; const auto& scratchpad = area_list_[Area]->scratchpad[thread_number_]; - double dtgMrg = scratchpad.dispatchableGenerationMargin[hour]; + const double dtgMrg = scratchpad.dispatchableGenerationMargin[hour]; + const double ens = hourlyResults.ValeursHorairesDeDefaillancePositive[hour]; + const bool triggered = problemeHebdo_->adequacyPatchRuntimeData + ->wasCSRTriggeredAtAreaHour(Area, hour); + hourlyResults.ValeursHorairesDtgMrgCsr[hour] = recomputeDTG_MRG(triggered, dtgMrg, ens); + hourlyResults.ValeursHorairesDeDefaillancePositiveCSR[hour] = recomputeENS_MRG( + triggered, + dtgMrg, + ens); - auto& hourlyResults = problemeHebdo_->ResultatsHoraires[Area]; - double& dtgMrgCsr = hourlyResults.ValeursHorairesDtgMrgCsr[hour]; - double& ens = hourlyResults.ValeursHorairesDeDefaillancePositive[hour]; - double& mrgCost = hourlyResults.CoutsMarginauxHoraires[hour]; - // calculate DTG MRG CSR and adjust ENS if neccessary - if (problemeHebdo_->adequacyPatchRuntimeData->wasCSRTriggeredAtAreaHour(Area, hour)) - { - if (adqPatchParams_.curtailmentSharing.recomputeDTGMRG) - { - dtgMrgCsr = std::max(0.0, dtgMrg - ens); - ens = std::max(0.0, ens - dtgMrg); - } - // set MRG PRICE to value of unsupplied energy cost, if LOLD=1.0 (ENS>0.5) - if (ens > 0.5) - { - mrgCost = -area_list_[Area]->thermal.unsuppliedEnergyCost; - } - } - else - { - dtgMrgCsr = dtgMrg; - } + const double unsuppliedEnergyCost = area_list_[Area]->thermal.unsuppliedEnergyCost; + hourlyResults.CoutsMarginauxHoraires[hour] = recomputeMRGPrice( + hourlyResults.ValeursHorairesDtgMrgCsr[hour], + hourlyResults.CoutsMarginauxHoraires[hour], + unsuppliedEnergyCost); } } } @@ -261,7 +252,7 @@ double CurtailmentSharingPostProcessCmd::calculateDensNewAndTotalLmrViolation() { const auto [netPositionInit, densNew, totalNodeBalance] = calculateAreaFlowBalance( problemeHebdo_, - adqPatchParams_.localMatching.setToZeroOutsideInsideLinks, + adqPatchParams_.setToZeroOutsideInsideLinks, Area, hour); // adjust densNew according to the new specification/request by ELIA @@ -272,12 +263,7 @@ double CurtailmentSharingPostProcessCmd::calculateDensNewAndTotalLmrViolation() // write down densNew values for all the hours problemeHebdo_->ResultatsHoraires[Area].ValeursHorairesDENS[hour] = std::max( 0.0, - densNew - dtgMrg); - ; - // copy spilled Energy values into spilled Energy values after CSR - problemeHebdo_->ResultatsHoraires[Area].ValeursHorairesSpilledEnergyAfterCSR[hour] - = problemeHebdo_->ResultatsHoraires[Area] - .ValeursHorairesDeDefaillanceNegative[hour]; + densNew); // check LMR violations totalLmrViolation += LmrViolationAreaHour( problemeHebdo_, diff --git a/src/solver/optimisation/weekly_optimization.cpp b/src/solver/optimisation/weekly_optimization.cpp index 164cabf32f..0cf6ec84cd 100644 --- a/src/solver/optimisation/weekly_optimization.cpp +++ b/src/solver/optimisation/weekly_optimization.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/solver/optimisation/weekly_optimization.h" @@ -25,18 +25,28 @@ namespace Antares::Solver::Optimization { -DefaultWeeklyOptimization::DefaultWeeklyOptimization(const OptimizationOptions& options, - PROBLEME_HEBDO* problemeHebdo, - AdqPatchParams& adqPatchParams, - uint thread_number, - IResultWriter& writer): - WeeklyOptimization(options, problemeHebdo, adqPatchParams, thread_number, writer) +WeeklyOptimization::WeeklyOptimization(const OptimizationOptions& options, + PROBLEME_HEBDO* problemeHebdo, + AdqPatchParams& adqPatchParams, + uint thread_number, + IResultWriter& writer, + Simulation::ISimulationObserver& simulationObserver): + options_(options), + problemeHebdo_(problemeHebdo), + adqPatchParams_(adqPatchParams), + thread_number_(thread_number), + writer_(writer), + simulationObserver_(simulationObserver) { } -void DefaultWeeklyOptimization::solve() +void WeeklyOptimization::solve() { - OPT_OptimisationHebdomadaire(options_, problemeHebdo_, adqPatchParams_, writer_); + OPT_OptimisationHebdomadaire(options_, + problemeHebdo_, + adqPatchParams_, + writer_, + simulationObserver_.get()); } } // namespace Antares::Solver::Optimization diff --git a/src/solver/simulation/CMakeLists.txt b/src/solver/simulation/CMakeLists.txt index 3c59c59d55..b54d722e17 100644 --- a/src/solver/simulation/CMakeLists.txt +++ b/src/solver/simulation/CMakeLists.txt @@ -11,8 +11,6 @@ set(SRC_SIMULATION include/antares/solver/simulation/sim_structure_probleme_economique.h sim_variables_globales.cpp include/antares/solver/simulation/sim_constants.h - include/antares/solver/simulation/sim_spread_generator.h - sim_spread_generator.cpp include/antares/solver/simulation/simulation.h include/antares/solver/simulation/solver.h include/antares/solver/simulation/solver.hxx @@ -29,6 +27,8 @@ set(SRC_SIMULATION include/antares/solver/simulation/solver.hxx include/antares/solver/simulation/solver.data.h solver.data.cpp + include/antares/solver/simulation/simulation-run.h + simulation-run.cpp include/antares/solver/simulation/common-eco-adq.h common-eco-adq.cpp common-hydro-remix.cpp @@ -45,12 +45,8 @@ set(SRC_SIMULATION adequacy_patch_runtime_data.cpp include/antares/solver/simulation/ITimeSeriesNumbersWriter.h TimeSeriesNumbersWriter.cpp - include/antares/solver/simulation/BindingConstraintsTimeSeriesNumbersWriter.h - - economy_mode.cpp - adequacy_mode.cpp - include/antares/solver/simulation/economy_mode.h - include/antares/solver/simulation/adequacy_mode.h + include/antares/solver/simulation/BindingConstraintsTimeSeriesNumbersWriter.h + include/antares/solver/simulation/ISimulationObserver.h ) source_group("simulation" FILES ${SRC_SIMULATION}) diff --git a/src/solver/simulation/TimeSeriesNumbersWriter.cpp b/src/solver/simulation/TimeSeriesNumbersWriter.cpp index 31016bbc49..09122c32e0 100644 --- a/src/solver/simulation/TimeSeriesNumbersWriter.cpp +++ b/src/solver/simulation/TimeSeriesNumbersWriter.cpp @@ -22,7 +22,6 @@ // Created by marechaljas on 17/03/23. // -#include #include #include diff --git a/src/solver/simulation/adequacy.cpp b/src/solver/simulation/adequacy.cpp index 5d3a54b261..eed49029e8 100644 --- a/src/solver/simulation/adequacy.cpp +++ b/src/solver/simulation/adequacy.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/solver/simulation/adequacy.h" @@ -29,10 +29,12 @@ using Antares::Constants::nbHoursInAWeek; namespace Antares::Solver::Simulation { -Adequacy::Adequacy(Data::Study& study, IResultWriter& resultWriter): +Adequacy::Adequacy(Data::Study& study, + IResultWriter& resultWriter, + Simulation::ISimulationObserver& simulationObserver): study(study), - preproOnly(false), - resultWriter(resultWriter) + resultWriter(resultWriter), + simulationObserver_(simulationObserver) { } @@ -68,15 +70,10 @@ bool Adequacy::simulationBegin() pProblemesHebdo.resize(pNbMaxPerformedYearsInParallel); for (uint numSpace = 0; numSpace < pNbMaxPerformedYearsInParallel; numSpace++) { - SIM_InitialisationProblemeHebdo(study, pProblemesHebdo[numSpace], 168, numSpace); - - assert((uint)nbHoursInAWeek == (uint)pProblemesHebdo[numSpace].NombreDePasDeTemps - && "inconsistency"); - if ((uint)nbHoursInAWeek != (uint)pProblemesHebdo[numSpace].NombreDePasDeTemps) - { - logs.fatal() << "internal error"; - return false; - } + SIM_InitialisationProblemeHebdo(study, + pProblemesHebdo[numSpace], + nbHoursInAWeek, + numSpace); } } @@ -136,6 +133,7 @@ bool Adequacy::year(Progression::Task& progression, currentProblem.year = state.year; PrepareRandomNumbers(study, currentProblem, randomForYear); + SetInitialHydroLevel(study, currentProblem, hydroVentilationResults); state.startANewYear(); @@ -214,7 +212,8 @@ bool Adequacy::year(Progression::Task& progression, OPT_OptimisationHebdomadaire(createOptimizationOptions(study), ¤tProblem, study.parameters.adqPatchParams, - resultWriter); + resultWriter, + simulationObserver_.get()); computingHydroLevels(study.areas, currentProblem, false); @@ -259,7 +258,7 @@ bool Adequacy::year(Progression::Task& progression, state.resSpilled.zero(); auto nbAreas = study.areas.size(); - auto& runtime = *(study.runtime); + auto& runtime = study.runtime; for (uint i = 0; i != nbHoursInAWeek; ++i) { @@ -368,15 +367,13 @@ bool Adequacy::year(Progression::Task& progression, ++progression; } - updatingAnnualFinalHydroLevel(study.areas, currentProblem); - optWriter.finalize(); finalizeOptimizationStatistics(currentProblem, state); return true; } -void Adequacy::incrementProgression(Progression::Task& progression) +void Adequacy::incrementProgression(Progression::Task& progression) const { for (uint w = 0; w < pNbWeeks; ++w) { @@ -402,7 +399,7 @@ static std::vector retrieveBalance( void Adequacy::simulationEnd() { - if (!preproOnly && study.runtime->interconnectionsCount() > 0) + if (!preproOnly && study.runtime.interconnectionsCount() > 0) { auto balance = retrieveBalance(study, variables); ComputeFlowQuad(study, pProblemesHebdo[0], balance, pNbWeeks); @@ -411,7 +408,34 @@ void Adequacy::simulationEnd() void Adequacy::prepareClustersInMustRunMode(Data::Area::ScratchMap& scratchmap, uint year) { - PrepareDataFromClustersInMustrunMode(study, scratchmap, year); -} + for (uint i = 0; i < study.areas.size(); ++i) + { + auto& area = *study.areas[i]; + auto& scratchpad = scratchmap.at(&area); + + std::ranges::fill(scratchpad.mustrunSum, 0); + std::ranges::fill(scratchpad.originalMustrunSum, 0); + + auto& mrs = scratchpad.mustrunSum; + auto& adq = scratchpad.originalMustrunSum; + + for (const auto& cluster: area.thermal.list.each_mustrun_and_enabled()) + { + const auto& availableProduction = cluster->series.getColumn(year); + for (uint h = 0; h != cluster->series.timeSeries.height; ++h) + { + mrs[h] += availableProduction[h]; + } + if (cluster->mustrunOrigin) + { + for (uint h = 0; h != cluster->series.timeSeries.height; ++h) + { + adq[h] += 2 * availableProduction[h]; // Why do we add the available production + // twice ? + } + } + } + } +} } // namespace Antares::Solver::Simulation diff --git a/src/solver/simulation/adequacy_mode.cpp b/src/solver/simulation/adequacy_mode.cpp deleted file mode 100644 index 59048ddf7b..0000000000 --- a/src/solver/simulation/adequacy_mode.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2007-2024, RTE (https://www.rte-france.com) - * See AUTHORS.txt - * SPDX-License-Identifier: MPL-2.0 - * This file is part of Antares-Simulator, - * Adequacy and Performance assessment for interconnected energy networks. - * - * Antares_Simulator is free software: you can redistribute it and/or modify - * it under the terms of the Mozilla Public Licence 2.0 as published by - * the Mozilla Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Antares_Simulator is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Mozilla Public Licence 2.0 for more details. - * - * You should have received a copy of the Mozilla Public Licence 2.0 - * along with Antares_Simulator. If not, see . - */ - -#include "antares/solver/simulation/adequacy_mode.h" - -#include "antares/solver/simulation/adequacy.h" -#include "antares/solver/simulation/solver.h" - -namespace Antares::Solver -{ -void runSimulationInAdequacyMode(Antares::Data::Study& study, - const Settings& settings, - Benchmarking::DurationCollector& durationCollector, - IResultWriter& resultWriter, - Benchmarking::OptimizationInfo& info) -{ - // Type of the simulation - typedef Solver::Simulation::ISimulation SimulationType; - SimulationType simulation(study, settings, durationCollector, resultWriter); - simulation.checkWriter(); - simulation.run(); - - if (!(settings.noOutput || settings.tsGeneratorsOnly)) - { - durationCollector("synthesis_export") - << [&simulation] { simulation.writeResults(/*synthesis:*/ true); }; - - info = simulation.getOptimizationInfo(); - } -} -} // namespace Antares::Solver diff --git a/src/solver/simulation/common-eco-adq.cpp b/src/solver/simulation/common-eco-adq.cpp index 8abcb0cb98..bfc697372a 100644 --- a/src/solver/simulation/common-eco-adq.cpp +++ b/src/solver/simulation/common-eco-adq.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/solver/simulation/common-eco-adq.h" @@ -60,9 +60,9 @@ static void RecalculDesEchangesMoyens(Data::Study& study, std::vector avgDirect; std::vector avgIndirect; - for (uint j = 0; j < study.runtime->interconnectionsCount(); ++j) + for (uint j = 0; j < study.runtime.interconnectionsCount(); ++j) { - auto* link = study.runtime->areaLink[j]; + auto* link = study.runtime.areaLink[j]; int ret = retrieveAverageNTC(study, link->directCapacities.timeSeries, link->timeseriesNumbers, @@ -91,14 +91,16 @@ static void RecalculDesEchangesMoyens(Data::Study& study, try { NullResultWriter resultWriter; + NullSimulationObserver simulationObserver; OPT_OptimisationHebdomadaire(createOptimizationOptions(study), &problem, study.parameters.adqPatchParams, - resultWriter); + resultWriter, + simulationObserver); } catch (Data::UnfeasibleProblemError&) { - study.runtime->quadraticOptimizationHasFailed = true; + study.runtime.quadraticOptimizationHasFailed = true; } for (uint i = 0; i < (uint)problem.NombreDePasDeTemps; ++i) @@ -106,72 +108,13 @@ static void RecalculDesEchangesMoyens(Data::Study& study, const uint indx = i + PasDeTempsDebut; auto& ntcValues = problem.ValeursDeNTC[i]; - for (uint j = 0; j < study.runtime->interconnectionsCount(); ++j) + for (uint j = 0; j < study.runtime.interconnectionsCount(); ++j) { transitMoyenInterconnexionsRecalculQuadratique[j][indx] = ntcValues.ValeurDuFlux[j]; } } } -void PrepareDataFromClustersInMustrunMode(Data::Study& study, - Data::Area::ScratchMap& scratchmap, - uint year) -{ - bool inAdequacy = (study.parameters.mode == Data::SimulationMode::Adequacy); - - for (uint i = 0; i < study.areas.size(); ++i) - { - auto& area = *study.areas[i]; - auto& scratchpad = scratchmap.at(&area); - - memset(scratchpad.mustrunSum, 0, sizeof(double) * HOURS_PER_YEAR); - if (inAdequacy) - { - memset(scratchpad.originalMustrunSum, 0, sizeof(double) * HOURS_PER_YEAR); - } - - double* mrs = scratchpad.mustrunSum; - double* adq = scratchpad.originalMustrunSum; - - for (const auto& cluster: area.thermal.list.each_mustrun_and_enabled()) - { - const auto& availableProduction = cluster->series.getColumn(year); - if (inAdequacy && cluster->mustrunOrigin) - { - for (uint h = 0; h != cluster->series.timeSeries.height; ++h) - { - mrs[h] += availableProduction[h]; - adq[h] += availableProduction[h]; - } - } - else - { - for (uint h = 0; h != cluster->series.timeSeries.height; ++h) - { - mrs[h] += availableProduction[h]; - } - } - } - - if (inAdequacy) - { - for (const auto& cluster: area.thermal.list.each_mustrun_and_enabled()) - { - if (!cluster->mustrunOrigin) - { - continue; - } - - const auto& availableProduction = cluster->series.getColumn(year); - for (uint h = 0; h != cluster->series.timeSeries.height; ++h) - { - adq[h] += availableProduction[h]; - } - } - } - } -} - bool ShouldUseQuadraticOptimisation(const Data::Study& study) { const bool flowQuadEnabled = study.parameters.variablesPrintInfo.isPrinted("FLOW QUAD."); @@ -180,9 +123,9 @@ bool ShouldUseQuadraticOptimisation(const Data::Study& study) return false; } - for (uint j = 0; j < study.runtime->interconnectionsCount(); ++j) + for (uint j = 0; j < study.runtime.interconnectionsCount(); ++j) { - auto& lnk = *(study.runtime->areaLink[j]); + auto& lnk = *(study.runtime.areaLink[j]); auto& impedances = lnk.parameters[Data::fhlImpedances]; for (uint hour = 0; hour < HOURS_PER_YEAR; ++hour) @@ -219,7 +162,7 @@ void ComputeFlowQuad(Data::Study& study, { logs.info() << " The quadratic optimisation has been skipped"; - for (uint j = 0; j < study.runtime->interconnectionsCount(); ++j) + for (uint j = 0; j < study.runtime.interconnectionsCount(); ++j) { for (uint w = 0; w != nbWeeks; ++w) { @@ -395,10 +338,29 @@ void PrepareRandomNumbers(Data::Study& study, }); } +void SetInitialHydroLevel(Data::Study& study, + PROBLEME_HEBDO& problem, + const HYDRO_VENTILATION_RESULTS& hydroVentilationResults) +{ + uint firstDaySimu = study.parameters.simulationDays.first; + study.areas.each( + [&problem, &firstDaySimu, &hydroVentilationResults](const Data::Area& area) + { + if (area.hydro.reservoirManagement) + { + double capacity = area.hydro.reservoirCapacity; + problem.previousSimulationFinalLevel[area.index] = hydroVentilationResults[area.index] + .NiveauxReservoirsDebutJours + [firstDaySimu] + * capacity; + } + }); +} + void BuildThermalPartOfWeeklyProblem(Data::Study& study, PROBLEME_HEBDO& problem, const int PasDeTempsDebut, - double** thermalNoises, + std::vector>& thermalNoises, unsigned int year) { int hourInYear = PasDeTempsDebut; diff --git a/src/solver/simulation/common-hydro-levels.cpp b/src/solver/simulation/common-hydro-levels.cpp index 8564418f62..b0ba258b0e 100644 --- a/src/solver/simulation/common-hydro-levels.cpp +++ b/src/solver/simulation/common-hydro-levels.cpp @@ -33,54 +33,50 @@ void computingHydroLevels(const Data::AreaList& areas, bool remixWasRun, bool computeAnyway) { - areas.each( - [&](const Data::Area& area) - { - if (!area.hydro.reservoirManagement) - { - return; - } + for (const auto& [_, area]: areas) + { + if (!area->hydro.reservoirManagement) + { + continue; + } - if (not computeAnyway) - { - if (area.hydro.useHeuristicTarget != remixWasRun) - { - return; - } - } + if (!computeAnyway && area->hydro.useHeuristicTarget != remixWasRun) + { + continue; + } - uint index = area.index; + uint index = area->index; - double reservoirCapacity = area.hydro.reservoirCapacity; + double reservoirCapacity = area->hydro.reservoirCapacity; - std::vector& inflows = problem.CaracteristiquesHydrauliques[index] - .ApportNaturelHoraire; + std::vector& inflows = problem.CaracteristiquesHydrauliques[index] + .ApportNaturelHoraire; - RESULTATS_HORAIRES& weeklyResults = problem.ResultatsHoraires[index]; + RESULTATS_HORAIRES& weeklyResults = problem.ResultatsHoraires[index]; - std::vector& turb = weeklyResults.TurbinageHoraire; + std::vector& turb = weeklyResults.TurbinageHoraire; - std::vector& pump = weeklyResults.PompageHoraire; - double pumpingRatio = area.hydro.pumpingEfficiency; + std::vector& pump = weeklyResults.PompageHoraire; + double pumpingRatio = area->hydro.pumpingEfficiency; - double nivInit = problem.CaracteristiquesHydrauliques[index].NiveauInitialReservoir; - std::vector& niv = weeklyResults.niveauxHoraires; + double nivInit = problem.CaracteristiquesHydrauliques[index].NiveauInitialReservoir; + std::vector& niv = weeklyResults.niveauxHoraires; - std::vector& ovf = weeklyResults.debordementsHoraires; + std::vector& ovf = weeklyResults.debordementsHoraires; - computeTimeStepLevel - computeLvlObj(nivInit, inflows, ovf, turb, pumpingRatio, pump, reservoirCapacity); + computeTimeStepLevel + computeLvlObj(nivInit, inflows, ovf, turb, pumpingRatio, pump, reservoirCapacity); - for (uint h = 0; h < nbHoursInAWeek - 1; h++) - { - computeLvlObj.run(); - niv[h] = computeLvlObj.getLevel() * 100 / reservoirCapacity; - computeLvlObj.prepareNextStep(); - } + for (uint h = 0; h < nbHoursInAWeek - 1; h++) + { + computeLvlObj.run(); + niv[h] = computeLvlObj.getLevel() * 100 / reservoirCapacity; + computeLvlObj.prepareNextStep(); + } - computeLvlObj.run(); - niv[nbHoursInAWeek - 1] = computeLvlObj.getLevel() * 100 / reservoirCapacity; - }); + computeLvlObj.run(); + niv[nbHoursInAWeek - 1] = computeLvlObj.getLevel() * 100 / reservoirCapacity; + } } void interpolateWaterValue(const Data::AreaList& areas, @@ -98,94 +94,63 @@ void interpolateWaterValue(const Data::AreaList& areas, daysOfWeek[d] = weekFirstDay + d; } - areas.each( - [&](const Data::Area& area) - { - uint index = area.index; - - RESULTATS_HORAIRES& weeklyResults = problem.ResultatsHoraires[index]; - - std::vector& waterVal = weeklyResults.valeurH2oHoraire; - - for (uint h = 0; h < nbHoursInAWeek; h++) - { - waterVal[h] = 0.; - } - - if (!area.hydro.reservoirManagement || !area.hydro.useWaterValue) - { - return; - } - - if (!area.hydro.useWaterValue) - { - return; - } - - double reservoirCapacity = area.hydro.reservoirCapacity; - - std::vector& niv = weeklyResults.niveauxHoraires; - - Antares::Data::getWaterValue(problem.previousSimulationFinalLevel[index] * 100 - / reservoirCapacity, - area.hydro.waterValues, - weekFirstDay, - waterVal[0]); - for (uint h = 1; h < nbHoursInAWeek; h++) - { - Antares::Data::getWaterValue(niv[h - 1], - area.hydro.waterValues, - daysOfWeek[h / 24], - waterVal[h]); - } - }); -} + for (const auto& [_, area]: areas) + { + uint index = area->index; -void updatingWeeklyFinalHydroLevel(const Data::AreaList& areas, PROBLEME_HEBDO& problem) -{ - areas.each( - [&](const Data::Area& area) - { - if (!area.hydro.reservoirManagement) - { - return; - } + RESULTATS_HORAIRES& weeklyResults = problem.ResultatsHoraires[index]; + + auto& waterVal = weeklyResults.valeurH2oHoraire; + std::fill(waterVal.begin(), waterVal.end(), 0.); - uint index = area.index; + if (!area->hydro.reservoirManagement || !area->hydro.useWaterValue) + { + return; + } - double reservoirCapacity = area.hydro.reservoirCapacity; + if (!area->hydro.useWaterValue) + { + return; + } - RESULTATS_HORAIRES& weeklyResults = problem.ResultatsHoraires[index]; + double reservoirCapacity = area->hydro.reservoirCapacity; - std::vector& niv = weeklyResults.niveauxHoraires; + std::vector& niv = weeklyResults.niveauxHoraires; - problem.previousSimulationFinalLevel[index] = niv[nbHoursInAWeek - 1] * reservoirCapacity - / 100; - }); + waterVal[0] = Data::getWaterValue(problem.previousSimulationFinalLevel[index] * 100 + / reservoirCapacity, + area->hydro.waterValues, + weekFirstDay); + + for (uint h = 1; h < nbHoursInAWeek; h++) + { + waterVal[h] = Data::getWaterValue(niv[h - 1], + area->hydro.waterValues, + daysOfWeek[h / 24]); + } + } } -void updatingAnnualFinalHydroLevel(const Data::AreaList& areas, PROBLEME_HEBDO& problem) +void updatingWeeklyFinalHydroLevel(const Data::AreaList& areas, PROBLEME_HEBDO& problem) { - if (!problem.hydroHotStart) + for (const auto& [_, area]: areas) { - return; - } + if (!area->hydro.reservoirManagement) + { + continue; + } + + uint index = area->index; - areas.each( - [&](const Data::Area& area) - { - if (!area.hydro.reservoirManagement) - { - return; - } + double reservoirCapacity = area->hydro.reservoirCapacity; - uint index = area.index; + RESULTATS_HORAIRES& weeklyResults = problem.ResultatsHoraires[index]; - double reservoirCapacity = area.hydro.reservoirCapacity; + std::vector& niv = weeklyResults.niveauxHoraires; - problem.previousYearFinalLevels[index] = problem.previousSimulationFinalLevel[index] - / reservoirCapacity; - }); + problem.previousSimulationFinalLevel[index] = niv[nbHoursInAWeek - 1] * reservoirCapacity + / 100; + } } } // namespace Antares::Solver::Simulation diff --git a/src/solver/simulation/common-hydro-remix.cpp b/src/solver/simulation/common-hydro-remix.cpp index a94b8f1dfe..de8e3f5328 100644 --- a/src/solver/simulation/common-hydro-remix.cpp +++ b/src/solver/simulation/common-hydro-remix.cpp @@ -51,7 +51,7 @@ static bool Remix(const Data::AreaList& areas, bool status = true; areas.each( - [&](const Data::Area& area) + [&HE, &DE, &remix, &G, &status, &problem, &numSpace, &hourInYear](const Data::Area& area) { auto index = area.index; diff --git a/src/solver/simulation/economy.cpp b/src/solver/simulation/economy.cpp index 558c4f2095..4499c339dc 100644 --- a/src/solver/simulation/economy.cpp +++ b/src/solver/simulation/economy.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/solver/simulation/economy.h" @@ -33,10 +33,13 @@ using Antares::Constants::nbHoursInAWeek; namespace Antares::Solver::Simulation { -Economy::Economy(Data::Study& study, IResultWriter& resultWriter): +Economy::Economy(Data::Study& study, + IResultWriter& resultWriter, + Simulation::ISimulationObserver& simulationObserver): study(study), preproOnly(false), - resultWriter(resultWriter) + resultWriter(resultWriter), + simulationObserver_(simulationObserver) { } @@ -68,27 +71,25 @@ bool Economy::simulationBegin() if (!preproOnly) { pProblemesHebdo.resize(pNbMaxPerformedYearsInParallel); - weeklyOptProblems_.resize(pNbMaxPerformedYearsInParallel); + weeklyOptProblems_.clear(); postProcessesList_.resize(pNbMaxPerformedYearsInParallel); for (uint numSpace = 0; numSpace < pNbMaxPerformedYearsInParallel; numSpace++) { - SIM_InitialisationProblemeHebdo(study, pProblemesHebdo[numSpace], 168, numSpace); - - if ((uint)nbHoursInAWeek != (uint)pProblemesHebdo[numSpace].NombreDePasDeTemps) - { - logs.fatal() << "internal error"; - return false; - } + SIM_InitialisationProblemeHebdo(study, + pProblemesHebdo[numSpace], + nbHoursInAWeek, + numSpace); auto options = createOptimizationOptions(study); - weeklyOptProblems_[numSpace] = Antares::Solver::Optimization::WeeklyOptimization:: - create(study, - options, - study.parameters.adqPatchParams, - &pProblemesHebdo[numSpace], - numSpace, - resultWriter); + + weeklyOptProblems_.emplace_back(options, + &pProblemesHebdo[numSpace], + study.parameters.adqPatchParams, + numSpace, + resultWriter, + simulationObserver_.get()); + postProcessesList_[numSpace] = interfacePostProcessList::create( study.parameters.adqPatchParams, &pProblemesHebdo[numSpace], @@ -126,6 +127,7 @@ bool Economy::year(Progression::Task& progression, currentProblem.year = state.year; PrepareRandomNumbers(study, currentProblem, randomForYear); + SetInitialHydroLevel(study, currentProblem, hydroVentilationResults); state.startANewYear(); @@ -161,7 +163,7 @@ bool Economy::year(Progression::Task& progression, try { - weeklyOptProblems_[numSpace]->solve(); + weeklyOptProblems_[numSpace].solve(); // Runs all the post processes in the list of post-process commands optRuntimeData opt_runtime_data(state.year, w, hourInTheYear); @@ -229,8 +231,6 @@ bool Economy::year(Progression::Task& progression, ++progression; } - updatingAnnualFinalHydroLevel(study.areas, currentProblem); - optWriter.finalize(); finalizeOptimizationStatistics(currentProblem, state); @@ -263,7 +263,7 @@ static std::vector retrieveBalance( void Economy::simulationEnd() { - if (!preproOnly && study.runtime->interconnectionsCount() > 0) + if (!preproOnly && study.runtime.interconnectionsCount() > 0) { auto balance = retrieveBalance(study, variables); ComputeFlowQuad(study, pProblemesHebdo[0], balance, pNbWeeks); @@ -272,7 +272,23 @@ void Economy::simulationEnd() void Economy::prepareClustersInMustRunMode(Data::Area::ScratchMap& scratchmap, uint year) { - PrepareDataFromClustersInMustrunMode(study, scratchmap, year); + for (uint i = 0; i < study.areas.size(); ++i) + { + auto& area = *study.areas[i]; + auto& scratchpad = scratchmap.at(&area); + + std::ranges::fill(scratchpad.mustrunSum, 0); + + auto& mrs = scratchpad.mustrunSum; + for (const auto& cluster: area.thermal.list.each_mustrun_and_enabled()) + { + const auto& availableProduction = cluster->series.getColumn(year); + for (uint h = 0; h != cluster->series.timeSeries.height; ++h) + { + mrs[h] += availableProduction[h]; + } + } + } } } // namespace Antares::Solver::Simulation diff --git a/src/solver/simulation/economy_mode.cpp b/src/solver/simulation/economy_mode.cpp deleted file mode 100644 index e79d7a1363..0000000000 --- a/src/solver/simulation/economy_mode.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2007-2024, RTE (https://www.rte-france.com) - * See AUTHORS.txt - * SPDX-License-Identifier: MPL-2.0 - * This file is part of Antares-Simulator, - * Adequacy and Performance assessment for interconnected energy networks. - * - * Antares_Simulator is free software: you can redistribute it and/or modify - * it under the terms of the Mozilla Public Licence 2.0 as published by - * the Mozilla Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Antares_Simulator is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Mozilla Public Licence 2.0 for more details. - * - * You should have received a copy of the Mozilla Public Licence 2.0 - * along with Antares_Simulator. If not, see . - */ - -#include "antares/solver/simulation/economy_mode.h" - -#include "antares/solver/simulation/economy.h" -#include "antares/solver/simulation/solver.h" - -namespace Antares::Solver -{ -void runSimulationInEconomicMode(Antares::Data::Study& study, - const Settings& settings, - Benchmarking::DurationCollector& durationCollector, - IResultWriter& resultWriter, - Benchmarking::OptimizationInfo& info) -{ - // Type of the simulation - typedef Solver::Simulation::ISimulation SimulationType; - SimulationType simulation(study, settings, durationCollector, resultWriter); - simulation.checkWriter(); - simulation.run(); - - if (!(settings.noOutput || settings.tsGeneratorsOnly)) - { - durationCollector("synthesis_export") - << [&simulation] { simulation.writeResults(/*synthesis:*/ true); }; - - info = simulation.getOptimizationInfo(); - } -} -} // namespace Antares::Solver diff --git a/src/solver/simulation/include/antares/solver/simulation/ISimulationObserver.h b/src/solver/simulation/include/antares/solver/simulation/ISimulationObserver.h new file mode 100644 index 0000000000..fe6145dd0f --- /dev/null +++ b/src/solver/simulation/include/antares/solver/simulation/ISimulationObserver.h @@ -0,0 +1,66 @@ + +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#pragma once + +#include "sim_structure_probleme_economique.h" + +namespace Antares::Solver::Simulation +{ + +/** + * @class ISimulationObserver + * @brief The ISimulationObserver class is an interface for observing the simulation. + * @details It declares the notifyHebdoProblem method. + */ +class ISimulationObserver +{ +public: + virtual ~ISimulationObserver() = default; + /** + * @brief The notifyHebdoProblem method is used to notify of a problem during the simulation. + * @param problemeHebdo A pointer to a PROBLEME_HEBDO object representing the problem. + * @param optimizationNumber The number of the optimization. + * @param name The name of the problem. + */ + virtual void notifyHebdoProblem(const PROBLEME_HEBDO& problemeHebdo, + int optimizationNumber, + std::string_view name) + = 0; +}; + +/** + * @class NullSimulationObserver + * @brief The NullSimulationObserver class is a null object for the ISimulationObserver interface. + * @details It overrides the notifyHebdoProblem method with an empty implementation. + */ +class NullSimulationObserver: public ISimulationObserver +{ +public: + ~NullSimulationObserver() override = default; + + void notifyHebdoProblem(const PROBLEME_HEBDO&, int, std::string_view) override + { + // null object pattern + } +}; +} // namespace Antares::Solver::Simulation diff --git a/src/solver/simulation/include/antares/solver/simulation/adequacy.h b/src/solver/simulation/include/antares/solver/simulation/adequacy.h index 6d659103c3..4e04acdcbe 100644 --- a/src/solver/simulation/include/antares/solver/simulation/adequacy.h +++ b/src/solver/simulation/include/antares/solver/simulation/adequacy.h @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #ifndef __SOLVER_SIMULATION_ADEQUACY_H__ #define __SOLVER_SIMULATION_ADEQUACY_H__ @@ -41,7 +41,6 @@ class Adequacy return "adequacy"; } -public: //! \name Constructor & Destructor //@{ /*! @@ -49,20 +48,21 @@ class Adequacy ** ** \param study The current study */ - Adequacy(Data::Study& study, IResultWriter& resultWriter); + Adequacy(Data::Study& study, + IResultWriter& resultWriter, + Simulation::ISimulationObserver& simulationObserver); //! Destructor ~Adequacy() = default; //@} Benchmarking::OptimizationInfo getOptimizationInfo() const; -public: //! Current study Data::Study& study; //! All variables Solver::Variable::Adequacy::AllVariables variables; //! Prepro only - bool preproOnly; + bool preproOnly = false; protected: void setNbPerformedYearsInParallel(uint nbMaxPerformedYearsInParallel); @@ -79,7 +79,7 @@ class Adequacy OptimizationStatisticsWriter& optWriter, const Antares::Data::Area::ScratchMap& scratchmap); - void incrementProgression(Progression::Task& progression); + void incrementProgression(Progression::Task& progression) const; void simulationEnd(); @@ -102,6 +102,7 @@ class Adequacy Matrix<> pRES; IResultWriter& resultWriter; + std::reference_wrapper simulationObserver_; }; // class Adequacy } // namespace Antares::Solver::Simulation diff --git a/src/solver/simulation/include/antares/solver/simulation/adequacy_patch_runtime_data.h b/src/solver/simulation/include/antares/solver/simulation/adequacy_patch_runtime_data.h index f91576a233..5ae0f3f5fb 100644 --- a/src/solver/simulation/include/antares/solver/simulation/adequacy_patch_runtime_data.h +++ b/src/solver/simulation/include/antares/solver/simulation/adequacy_patch_runtime_data.h @@ -42,7 +42,6 @@ class AdequacyPatchRuntimeData std::vector originAreaMode; std::vector extremityAreaMode; std::vector hurdleCostCoefficients; - bool AdequacyFirstStep = true; bool wasCSRTriggeredAtAreaHour(int area, int hour) const; void addCSRTriggeredAtAreaHour(int area, int hour); diff --git a/src/solver/simulation/include/antares/solver/simulation/common-eco-adq.h b/src/solver/simulation/include/antares/solver/simulation/common-eco-adq.h index 2110c4cbe9..6a4dabd763 100644 --- a/src/solver/simulation/include/antares/solver/simulation/common-eco-adq.h +++ b/src/solver/simulation/include/antares/solver/simulation/common-eco-adq.h @@ -23,9 +23,6 @@ #include -#include -#include - #include #include "antares/solver/optimisation/opt_fonctions.h" #include "antares/solver/simulation/solver.h" // for definition of type yearRandomNumbers @@ -56,19 +53,16 @@ void PrepareRandomNumbers(Data::Study& study, PROBLEME_HEBDO& problem, yearRandomNumbers& randomForYear); +void SetInitialHydroLevel(Data::Study& study, + PROBLEME_HEBDO& problem, + const HYDRO_VENTILATION_RESULTS& hydroVentilationResults); + void BuildThermalPartOfWeeklyProblem(Data::Study& study, PROBLEME_HEBDO& problem, const int PasDeTempsDebut, - double** thermalNoises, + std::vector>& thermalNoises, unsigned int year); -/*! -** \brief Prepare data from clusters in mustrun mode (eco+adq) -*/ -void PrepareDataFromClustersInMustrunMode(Data::Study& study, - Data::Area::ScratchMap& scratchmap, - uint year); - /*! ** \brief Get if the quadratic optimization should be used according ** to the input data (eco+adq) @@ -137,14 +131,6 @@ void interpolateWaterValue(const Data::AreaList& areas, */ void updatingWeeklyFinalHydroLevel(const Data::AreaList& areas, PROBLEME_HEBDO& problem); -/* -** \brief Updating the year final reservoir level, to be used as a start for the year. -** -** \param areas : the areas of study -** \param problem The weekly problem, living over the whole simuation. -*/ -void updatingAnnualFinalHydroLevel(const Data::AreaList& areas, PROBLEME_HEBDO& problem); - /* ** \brief Compute the weighted average NTC for a link ** diff --git a/src/solver/simulation/include/antares/solver/simulation/economy.h b/src/solver/simulation/include/antares/solver/simulation/economy.h index b7661c3f11..0ff621e01a 100644 --- a/src/solver/simulation/include/antares/solver/simulation/economy.h +++ b/src/solver/simulation/include/antares/solver/simulation/economy.h @@ -1,28 +1,28 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #ifndef __SOLVER_SIMULATION_ECONOMY_H__ #define __SOLVER_SIMULATION_ECONOMY_H__ #include "antares/infoCollection/StudyInfoCollector.h" -#include "antares/solver/optimisation/base_weekly_optimization.h" +#include "antares/solver/optimisation/weekly_optimization.h" #include "antares/solver/simulation/opt_time_writer.h" #include "antares/solver/simulation/solver.h" // for definition of type yearRandomNumbers #include "antares/solver/variable/economy/all.h" @@ -50,7 +50,9 @@ class Economy ** ** \param study The current study */ - Economy(Data::Study& study, IResultWriter& resultWriter); + Economy(Data::Study& study, + IResultWriter& resultWriter, + Simulation::ISimulationObserver& simulationObserver); //! Destructor ~Economy() = default; //@} @@ -96,10 +98,10 @@ class Economy uint pStartTime; uint pNbMaxPerformedYearsInParallel; std::vector pProblemesHebdo; - std::vector> - weeklyOptProblems_; + std::vector weeklyOptProblems_; std::vector> postProcessesList_; IResultWriter& resultWriter; + std::reference_wrapper simulationObserver_; }; // class Economy } // namespace Antares::Solver::Simulation diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_extern_variables_globales.h b/src/solver/simulation/include/antares/solver/simulation/sim_extern_variables_globales.h index d6c526b37e..cfcc9ff1e6 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_extern_variables_globales.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_extern_variables_globales.h @@ -18,17 +18,8 @@ * You should have received a copy of the Mozilla Public Licence 2.0 * along with Antares_Simulator. If not, see . */ -#ifndef __SOLVER_SIMULATION_EXTERN_H__ -#define __SOLVER_SIMULATION_EXTERN_H__ +#pragma once -#include "antares/solver/simulation/sim_structure_probleme_economique.h" +#include -#include "sim_structure_donnees.h" - -/* Valeurs generees de maniere aleatoire */ - -/* Resultats */ -/*-Economique-*/ extern std::vector> transitMoyenInterconnexionsRecalculQuadratique; - -#endif /* __SOLVER_SIMULATION_EXTERN_H__ */ diff --git a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h index 489488486e..26b8e837ef 100644 --- a/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h +++ b/src/solver/simulation/include/antares/solver/simulation/sim_structure_probleme_economique.h @@ -23,7 +23,6 @@ #define __SOLVER_SIMULATION_ECO_STRUCTS_H__ #include -#include #include #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" @@ -169,7 +168,8 @@ struct PROPERTIES double reservoirCapacity; double injectionNominalCapacity; double withdrawalNominalCapacity; - double efficiency; + double injectionEfficiency; + double withdrawalEfficiency; double initialLevel; bool initialLevelOptim; @@ -250,9 +250,6 @@ struct PDISP_ET_COUTS_HORAIRES_PAR_PALIER std::vector CoutHoraireDeProductionDuPalierThermique; - std::vector CoutHoraireDuPalierThermiqueUp; - std::vector CoutHoraireDuPalierThermiqueDown; - std::vector NombreMaxDeGroupesEnMarcheDuPalierThermique; std::vector NombreMinDeGroupesEnMarcheDuPalierThermique; }; @@ -302,8 +299,6 @@ struct ENERGIES_ET_PUISSANCES_HYDRAULIQUES double PenalisationDeLaVariationDeProductionHydrauliqueSurVariationMax; double WeeklyWaterValueStateRegular; - double WeeklyWaterValueStateUp; - double WeeklyWaterValueStateDown; bool TurbinageEntreBornes; bool SansHeuristique; @@ -404,9 +399,6 @@ struct PRODUCTION_THERMIQUE_OPTIMALE { std::vector ProductionThermiqueDuPalier; - std::vector ProductionThermiqueDuPalierUp; - std::vector ProductionThermiqueDuPalierDown; - std::vector NombreDeGroupesEnMarcheDuPalier; std::vector NombreDeGroupesQuiDemarrentDuPalier; @@ -418,24 +410,15 @@ struct PRODUCTION_THERMIQUE_OPTIMALE struct RESULTATS_HORAIRES { std::vector ValeursHorairesDeDefaillancePositive; + std::vector ValeursHorairesDeDefaillancePositiveCSR; std::vector ValeursHorairesDENS; // adq patch domestic unsupplied energy std::vector ValeursHorairesLmrViolations; // adq patch lmr violations - std::vector ValeursHorairesSpilledEnergyAfterCSR; // adq patch spillage after CSR - std::vector ValeursHorairesDtgMrgCsr; // adq patch DTG MRG after CSR - std::vector ValeursHorairesDeDefaillancePositiveUp; - std::vector ValeursHorairesDeDefaillancePositiveDown; - std::vector ValeursHorairesDeDefaillancePositiveAny; + std::vector ValeursHorairesDtgMrgCsr; // adq patch DTG MRG after CSR std::vector ValeursHorairesDeDefaillanceNegative; - std::vector ValeursHorairesDeDefaillanceNegativeUp; - std::vector ValeursHorairesDeDefaillanceNegativeDown; - std::vector ValeursHorairesDeDefaillanceNegativeAny; - std::vector ValeursHorairesDeDefaillanceEnReserve; std::vector PompageHoraire; std::vector TurbinageHoraire; - std::vector TurbinageHoraireUp; - std::vector TurbinageHoraireDown; std::vector niveauxHoraires; std::vector valeurH2oHoraire; @@ -575,7 +558,6 @@ struct PROBLEME_HEBDO bool YaDeLaReserveJmoins1 = false; - std::vector previousYearFinalLevels; std::vector AllMustRunGeneration; OptimizationStatistics optimizationStatistics[2]; @@ -585,7 +567,6 @@ struct PROBLEME_HEBDO /* Hydro management */ std::vector CoefficientEcretementPMaxHydraulique; - bool hydroHotStart = false; std::vector previousSimulationFinalLevel; /* Results */ diff --git a/src/solver/simulation/include/antares/solver/simulation/economy_mode.h b/src/solver/simulation/include/antares/solver/simulation/simulation-run.h similarity index 67% rename from src/solver/simulation/include/antares/solver/simulation/economy_mode.h rename to src/solver/simulation/include/antares/solver/simulation/simulation-run.h index 5e1f454884..379959af05 100644 --- a/src/solver/simulation/include/antares/solver/simulation/economy_mode.h +++ b/src/solver/simulation/include/antares/solver/simulation/simulation-run.h @@ -1,4 +1,3 @@ - /* * Copyright 2007-2024, RTE (https://www.rte-france.com) * See AUTHORS.txt @@ -23,14 +22,15 @@ #pragma once #include "antares/infoCollection/StudyInfoCollector.h" -#include "antares/solver/misc/options.h" -#include "antares/writer/i_writer.h" +#include "antares/solver/simulation/solver.h" namespace Antares::Solver { -void runSimulationInEconomicMode(Antares::Data::Study& study, - const Settings& settings, - Benchmarking::DurationCollector& durationCollector, - IResultWriter& resultWriter, - Benchmarking::OptimizationInfo& info); -} + +Benchmarking::OptimizationInfo simulationRun(Antares::Data::Study& study, + const Settings& settings, + Benchmarking::DurationCollector& durationCollector, + IResultWriter& resultWriter, + Simulation::ISimulationObserver& simulationObserver); + +} // namespace Antares::Solver diff --git a/src/solver/simulation/include/antares/solver/simulation/simulation.h b/src/solver/simulation/include/antares/solver/simulation/simulation.h index 6d814157d1..bf214beff6 100644 --- a/src/solver/simulation/include/antares/solver/simulation/simulation.h +++ b/src/solver/simulation/include/antares/solver/simulation/simulation.h @@ -45,7 +45,7 @@ void SIM_AllocationProblemeHebdo(const Antares::Data::Study& study, */ void SIM_InitialisationProblemeHebdo(Antares::Data::Study& study, PROBLEME_HEBDO& problem, - int NombreDePasDeTemps, + unsigned int NombreDePasDeTemps, uint numspace); void SIM_RenseignementProblemeHebdo(const Antares::Data::Study& study, diff --git a/src/solver/simulation/include/antares/solver/simulation/solver.data.h b/src/solver/simulation/include/antares/solver/simulation/solver.data.h index 16de52d570..bb30ec4173 100644 --- a/src/solver/simulation/include/antares/solver/simulation/solver.data.h +++ b/src/solver/simulation/include/antares/solver/simulation/solver.data.h @@ -21,8 +21,6 @@ #ifndef __SOLVER_SIMULATION_SOLVER_DATA_H__ #define __SOLVER_SIMULATION_SOLVER_DATA_H__ -#include - #include namespace Antares::Solver::Private::Simulation diff --git a/src/solver/simulation/include/antares/solver/simulation/solver.h b/src/solver/simulation/include/antares/solver/simulation/solver.h index 29c087759f..4ea45461d8 100644 --- a/src/solver/simulation/include/antares/solver/simulation/solver.h +++ b/src/solver/simulation/include/antares/solver/simulation/solver.h @@ -1,31 +1,31 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #ifndef __SOLVER_SIMULATION_SOLVER_H__ #define __SOLVER_SIMULATION_SOLVER_H__ -#include #include #include #include +#include #include #include #include "antares/solver/hydro/management/management.h" @@ -54,7 +54,8 @@ class ISimulation: public Impl ISimulation(Data::Study& study, const ::Settings& settings, Benchmarking::DurationCollector& duration_collector, - IResultWriter& resultWriter); + IResultWriter& resultWriter, + Simulation::ISimulationObserver& simulationObserver); //! Destructor ~ISimulation(); //@} @@ -76,7 +77,6 @@ class ISimulation: public Impl */ void writeResults(bool synthesis, uint year = 0, uint numSpace = 9999); -public: //! Reference to the current study Data::Study& study; //! The global settings @@ -126,7 +126,7 @@ class ISimulation: public Impl ** Storing these costs to compute std deviation later. */ void computeAnnualCostsStatistics(std::vector& state, - std::vector::iterator& set_it); + setOfParallelYears& batch); /*! ** \brief Iterate through all MC years @@ -136,7 +136,6 @@ class ISimulation: public Impl */ void loopThroughYears(uint firstYear, uint endYear, std::vector& state); -private: //! Some temporary to avoid performing useless complex checks Solver::Private::Simulation::CacheData pData; //! @@ -145,8 +144,6 @@ class ISimulation: public Impl uint pNbMaxPerformedYearsInParallel; //! Year by year output results bool pYearByYear; - //! Hydro hot start - bool pHydroHotStart; //! The first set of parallel year(s) with a performed year was already run ? bool pFirstSetParallelWithAPerformedYearWasRun; @@ -162,6 +159,7 @@ class ISimulation: public Impl //! Result writer Antares::Solver::IResultWriter& pResultWriter; + std::reference_wrapper simulationObserver_; }; // class ISimulation } // namespace Antares::Solver::Simulation diff --git a/src/solver/simulation/include/antares/solver/simulation/solver.hxx b/src/solver/simulation/include/antares/solver/simulation/solver.hxx index 70d88c47af..c8ca4775df 100644 --- a/src/solver/simulation/include/antares/solver/simulation/solver.hxx +++ b/src/solver/simulation/include/antares/solver/simulation/solver.hxx @@ -21,23 +21,19 @@ #ifndef __SOLVER_SIMULATION_SOLVER_HXX__ #define __SOLVER_SIMULATION_SOLVER_HXX__ -#include #include -#include #include -#include #include #include #include #include "antares/concurrency/concurrency.h" -#include "antares/solver//variable/constants.h" -#include "antares/solver//variable/print.h" -#include "antares/solver/hydro/management/management.h" // Added for use of randomReservoirLevel(...) -#include "antares/solver/simulation/apply-scenario.h" +#include "antares/solver/hydro/management/HydroInputsChecker.h" +#include "antares/solver/hydro/management/management.h" #include "antares/solver/simulation/opt_time_writer.h" #include "antares/solver/simulation/timeseries-numbers.h" #include "antares/solver/ts-generator/generator.h" +#include "antares/solver/variable/print.h" namespace Antares::Solver::Simulation { @@ -55,10 +51,11 @@ public: randomNumbers& pRandomForParallelYears, bool pPerformCalculations, Data::Study& pStudy, - std::vector& pState, + Variable::State& pState, bool pYearByYear, Benchmarking::DurationCollector& durationCollector, - IResultWriter& resultWriter): + IResultWriter& resultWriter, + ISimulationObserver& simulationObserver): simulation_(simulation), y(pY), yearFailed(pYearFailed), @@ -72,13 +69,9 @@ public: yearByYear(pYearByYear), pDurationCollector(durationCollector), pResultWriter(resultWriter), - hydroManagement(study.areas, - study.parameters, - study.calendar, - study.maxNbYearsInParallel, - resultWriter) + simulationObserver_(simulationObserver), + hydroManagement(study.areas, study.parameters, study.calendar, resultWriter) { - hydroHotStart = (study.parameters.initialReservoirLevels.iniLevels == Data::irlHotStart); scratchmap = study.areas.buildScratchMap(numSpace); } @@ -96,11 +89,11 @@ private: randomNumbers& randomForParallelYears; bool performCalculations; Data::Study& study; - std::vector& state; + Variable::State& state; bool yearByYear; - bool hydroHotStart; Benchmarking::DurationCollector& pDurationCollector; IResultWriter& pResultWriter; + std::reference_wrapper simulationObserver_; HydroManagement hydroManagement; Antares::Data::Area::ScratchMap scratchmap; @@ -150,18 +143,9 @@ public: // Getting random tables for this year yearRandomNumbers& randomForCurrentYear = randomForParallelYears.pYears[indexYear]; - double* randomReservoirLevel = nullptr; // 1 - Applying random levels for current year - if (hydroHotStart && firstSetParallelWithAPerformedYearWasRun) - { - randomReservoirLevel = state[numSpace] - .problemeHebdo->previousYearFinalLevels.data(); - } - else - { - randomReservoirLevel = randomForCurrentYear.pReservoirLevels; - } + auto randomReservoirLevel = randomForCurrentYear.pReservoirLevels; // 2 - Preparing the Time-series numbers // removed @@ -170,15 +154,11 @@ public: simulation_->prepareClustersInMustRunMode(scratchmap, y); // 4 - Hydraulic ventilation - pDurationCollector("hydro_ventilation") << [&] { - hydroManagement.makeVentilation(randomReservoirLevel, - state[numSpace], - y, - scratchmap); - }; + pDurationCollector("hydro_ventilation") << [this, &randomReservoirLevel] + { hydroManagement.makeVentilation(randomReservoirLevel.data(), y, scratchmap); }; // Updating the state - state[numSpace].year = y; + state.year = y; // 5 - Resetting all variables for the output simulation_->variables.yearBegin(y, numSpace); @@ -190,7 +170,7 @@ public: OptimizationStatisticsWriter optWriter(pResultWriter, y); yearFailed[y] = !simulation_->year(progression, - state[numSpace], + state, numSpace, randomForCurrentYear, failedWeekList, @@ -202,7 +182,7 @@ public: // Log failing weeks logFailedWeek(y, study, failedWeekList); - simulation_->variables.yearEndBuild(state[numSpace], y, numSpace); + simulation_->variables.yearEndBuild(state, y, numSpace); // 7 - End of the year, this is the last stade where the variables can retrieve // their data for this year. @@ -217,7 +197,7 @@ public: // 9 - Write results for the current year if (yearByYear) { - pDurationCollector("yby_export") << [&] + pDurationCollector("yby_export") << [this] { // Before writing, some variable may require minor modifications simulation_->variables.beforeYearByYearExport(y, numSpace); @@ -244,8 +224,9 @@ inline ISimulation::ISimulation( Data::Study& study, const ::Settings& settings, Benchmarking::DurationCollector& duration_collector, - IResultWriter& resultWriter): - ImplementationType(study, resultWriter), + IResultWriter& resultWriter, + Simulation::ISimulationObserver& simulationObserver): + ImplementationType(study, resultWriter, simulationObserver), study(study), settings(settings), pNbYearsReallyPerformed(0), @@ -254,7 +235,8 @@ inline ISimulation::ISimulation( pFirstSetParallelWithAPerformedYearWasRun(false), pDurationCollector(duration_collector), pQueueService(study.pQueueService), - pResultWriter(resultWriter) + pResultWriter(resultWriter), + simulationObserver_(simulationObserver) { // Ask to the interface to show the messages logs.info(); @@ -268,8 +250,6 @@ inline ISimulation::ISimulation( { pYearByYear = false; } - - pHydroHotStart = (study.parameters.initialReservoirLevels.iniLevels == Data::irlHotStart); } template @@ -311,13 +291,8 @@ void ISimulation::run() // Determine if we have to use the preprocessors at least one time. pData.initialize(study.parameters); - // Prepro only ? - ImplementationType::preproOnly = settings.tsGeneratorsOnly; - ImplementationType::setNbPerformedYearsInParallel(pNbMaxPerformedYearsInParallel); - TSGenerator::ResizeGeneratedTimeSeries(study.areas, study.parameters); - if (settings.tsGeneratorsOnly) { // Only the preprocessors can be used @@ -333,6 +308,9 @@ void ISimulation::run() } else { + // Export ts-numbers into output + TimeSeriesNumbers::StoreTimeSeriesNumbersIntoOuput(study, pResultWriter); + if (not ImplementationType::simulationBegin()) { return; @@ -343,32 +321,10 @@ void ISimulation::run() // For beauty logs.info(); - // Sampled time-series Numbers - // We will resize all matrix related to the time-series numbers - // This operation can be done once since the number of years is constant - // for a single simulation - study.resizeAllTimeseriesNumbers(1 + study.runtime->rangeLimits.year[Data::rangeEnd]); - // Now, we will prepare the time-series numbers - if (not TimeSeriesNumbers::CheckNumberOfColumns(study.areas)) - { - throw FatalError( - "Inconsistent number of time-series detected. Please check your input data."); - } - - if (not TimeSeriesNumbers::Generate(study)) - { - throw FatalError("An unrecoverable error has occured. Can not continue."); - } - - if (study.parameters.useCustomScenario) - { - ApplyCustomScenario(study); - } - // Launching the simulation for all years - logs.info() << "MC-Years : [" << (study.runtime->rangeLimits.year[Data::rangeBegin] + 1) - << " .. " << (1 + study.runtime->rangeLimits.year[Data::rangeEnd]) - << "], total: " << study.runtime->rangeLimits.year[Data::rangeCount]; + logs.info() << "MC-Years : [" << (study.runtime.rangeLimits.year[Data::rangeBegin] + 1) + << " .. " << (1 + study.runtime.rangeLimits.year[Data::rangeEnd]) + << "], total: " << study.runtime.rangeLimits.year[Data::rangeCount]; // Current state std::vector state(pNbMaxPerformedYearsInParallel, Variable::State(study)); @@ -378,8 +334,7 @@ void ISimulation::run() ImplementationType::initializeState(state[numSpace], numSpace); } - logs.info() << " Starting the simulation"; - uint finalYear = 1 + study.runtime->rangeLimits.year[Data::rangeEnd]; + uint finalYear = 1 + study.runtime.rangeLimits.year[Data::rangeEnd]; { pDurationCollector("mc_years") << [finalYear, &state, this] { loopThroughYears(0, finalYear, state); }; @@ -393,9 +348,6 @@ void ISimulation::run() ImplementationType::variables.simulationEnd(); - // Export ts-numbers into output - TimeSeriesNumbers::StoreTimeSeriesNumbersIntoOuput(study, pResultWriter); - // Spatial clusters // Notifying all variables to perform the final spatial clusters. // This must be done only when all variables have finished to compute their @@ -498,15 +450,24 @@ void ISimulation::regenerateTimeSeries(uint year) if (refreshTSonCurrentYear) { auto clusters = getAllClustersToGen(study.areas, pData.haveToRefreshTSThermal); -#define SEP Yuni::IO::Separator - const std::string savePath = std::string("ts-generator") + SEP + "thermal" + SEP + "mc-" - + std::to_string(year); -#undef SEP - generateThermalTimeSeries(study, clusters, pResultWriter, savePath); + generateThermalTimeSeries(study, + clusters, + study.runtime.random[Data::seedTsGenThermal]); + + bool archive = study.parameters.timeSeriesToArchive & Data::timeSeriesThermal; + bool doWeWrite = archive && !study.parameters.noOutput; + if (doWeWrite) + { + fs::path savePath = fs::path(study.folderOutput.to()) / "ts-generator" + / "thermal" / "mc-" / std::to_string(year); + writeThermalTimeSeries(clusters, savePath); + } // apply the spinning if we generated some in memory clusters for (auto* cluster: clusters) + { cluster->calculationOfSpinning(); + } } }; } @@ -547,7 +508,7 @@ uint ISimulation::buildSetsOfParallelYears( // Some thermal clusters may override the global parameter. // Therefore, we may want to refresh TS even if pData.haveToRefreshTSThermal == false bool haveToRefreshTSThermal = pData.haveToRefreshTSThermal - || study.runtime->thermalTSRefresh; + || study.runtime.thermalTSRefresh; refreshing = refreshing || (haveToRefreshTSThermal && (y % pData.refreshIntervalThermal == 0)); @@ -641,43 +602,43 @@ void ISimulation::allocateMemoryForRandomNumbers( { // General : randomForParallelYears.pYears[y].setNbAreas(nbAreas); - randomForParallelYears.pYears[y].pNbClustersByArea = new size_t[nbAreas]; + randomForParallelYears.pYears[y].pNbClustersByArea.resize(nbAreas); // Thermal noises : - randomForParallelYears.pYears[y].pThermalNoisesByArea = new double*[nbAreas]; + randomForParallelYears.pYears[y].pThermalNoisesByArea.resize(nbAreas); for (uint a = 0; a != nbAreas; ++a) { // logs.info() << " area : " << a << " :"; auto& area = *(study.areas.byIndex[a]); size_t nbClusters = area.thermal.list.allClustersCount(); - randomForParallelYears.pYears[y].pThermalNoisesByArea[a] = new double[nbClusters]; + randomForParallelYears.pYears[y].pThermalNoisesByArea[a].resize(nbClusters); randomForParallelYears.pYears[y].pNbClustersByArea[a] = nbClusters; } // Reservoir levels - randomForParallelYears.pYears[y].pReservoirLevels = new double[nbAreas]; + randomForParallelYears.pYears[y].pReservoirLevels.resize(nbAreas); // Noises on unsupplied and spilled energy - randomForParallelYears.pYears[y].pUnsuppliedEnergy = new double[nbAreas]; - randomForParallelYears.pYears[y].pSpilledEnergy = new double[nbAreas]; + randomForParallelYears.pYears[y].pUnsuppliedEnergy.resize(nbAreas); + randomForParallelYears.pYears[y].pSpilledEnergy.resize(nbAreas); // Hydro costs noises switch (study.parameters.power.fluctuations) { case Data::lssFreeModulations: { - randomForParallelYears.pYears[y].pHydroCostsByArea_freeMod = new double*[nbAreas]; + randomForParallelYears.pYears[y].pHydroCostsByArea_freeMod.resize(nbAreas); for (uint a = 0; a != nbAreas; ++a) { - randomForParallelYears.pYears[y].pHydroCostsByArea_freeMod[a] = new double[8784]; + randomForParallelYears.pYears[y].pHydroCostsByArea_freeMod[a].resize(8784); } break; } case Data::lssMinimizeRamping: case Data::lssMinimizeExcursions: { - randomForParallelYears.pYears[y].pHydroCosts_rampingOrExcursion = new double[nbAreas]; + randomForParallelYears.pYears[y].pHydroCosts_rampingOrExcursion.resize(nbAreas); break; } case Data::lssUnknown: @@ -696,8 +657,6 @@ void ISimulation::computeRandomNumbers( std::map& isYearPerformed, MersenneTwister& randomHydroGenerator) { - auto& runtime = *study.runtime; - uint indexYear = 0; std::vector::iterator ity; @@ -722,7 +681,7 @@ void ISimulation::computeRandomNumbers( for (auto& cluster: area.thermal.list.all()) { uint clusterIndex = cluster->areaWideIndex; - double thermalNoise = runtime.random[Data::seedThermalCosts].next(); + double thermalNoise = study.runtime.random[Data::seedThermalCosts].next(); if (isPerformed) { randomForYears.pYears[indexYear].pThermalNoisesByArea[a][clusterIndex] @@ -761,41 +720,19 @@ void ISimulation::computeRandomNumbers( // Possibly update the intial level from scenario builder if (study.parameters.useCustomScenario) { - double levelFromScenarioBuilder = study.scenarioHydroLevels[areaIndex][y]; + double levelFromScenarioBuilder = study.scenarioInitialHydroLevels[areaIndex][y]; if (levelFromScenarioBuilder >= 0.) { randomLevel = levelFromScenarioBuilder; } } - if (pHydroHotStart) - { - if (!isPerformed || !area.hydro.reservoirManagement) - { - // This initial level should be unused, so -1, as impossible value, is - // suitable. - randomForYears.pYears[indexYear].pReservoirLevels[areaIndex] = -1.; - areaIndex++; - return; // Skipping the current area - } - - if (!pFirstSetParallelWithAPerformedYearWasRun) - { - randomForYears.pYears[indexYear].pReservoirLevels[areaIndex] = randomLevel; - } - // Else : means the start levels (multiple areas are affected) of a year are - // retrieved from a previous year and - // these levels are updated inside the year job (see year job). - } - else + // Current area's hydro starting (or initial) level computation + // (no matter if the year is performed or not, we always draw a random initial + // reservoir level to ensure the same results) + if (isPerformed) { - // Current area's hydro starting (or initial) level computation - // (no matter if the year is performed or not, we always draw a random initial - // reservoir level to ensure the same results) - if (isPerformed) - { - randomForYears.pYears[indexYear].pReservoirLevels[areaIndex] = randomLevel; - } + randomForYears.pYears[indexYear].pReservoirLevels[areaIndex] = randomLevel; } areaIndex++; @@ -803,8 +740,8 @@ void ISimulation::computeRandomNumbers( // ... Unsupplied and spilled energy costs noises (french : bruits sur la defaillance // positive et negatives) ... references to the random number generators - auto& randomUnsupplied = study.runtime->random[Data::seedUnsuppliedEnergyCosts]; - auto& randomSpilled = study.runtime->random[Data::seedSpilledEnergyCosts]; + auto& randomUnsupplied = study.runtime.random[Data::seedUnsuppliedEnergyCosts]; + auto& randomSpilled = study.runtime.random[Data::seedSpilledEnergyCosts]; int currentSpilledEnergySeed = study.parameters.seed[Data::seedSpilledEnergyCosts]; int defaultSpilledEnergySeed = Data::antaresSeedDefaultValue @@ -812,7 +749,13 @@ void ISimulation::computeRandomNumbers( bool SpilledEnergySeedIsDefault = (currentSpilledEnergySeed == defaultSpilledEnergySeed); areaIndex = 0; study.areas.each( - [&](Data::Area& area) + [&isPerformed, + &areaIndex, + &randomUnsupplied, + &randomSpilled, + &randomForYears, + &indexYear, + &SpilledEnergySeedIsDefault](Data::Area& area) { (void)area; // Avoiding warnings at compilation (unused variable) on linux if (isPerformed) @@ -838,7 +781,7 @@ void ISimulation::computeRandomNumbers( }); // each area // ... Hydro costs noises ... - auto& randomHydro = study.runtime->random[Data::seedHydroCosts]; + auto& randomHydro = study.runtime.random[Data::seedHydroCosts]; Data::PowerFluctuations powerFluctuations = study.parameters.power.fluctuations; switch (powerFluctuations) @@ -854,8 +797,8 @@ void ISimulation::computeRandomNumbers( { for (auto i = study.areas.begin(); i != end; ++i) { - double* noise = randomForYears.pYears[indexYear] - .pHydroCostsByArea_freeMod[areaIndex]; + auto& noise = randomForYears.pYears[indexYear] + .pHydroCostsByArea_freeMod[areaIndex]; std::set setHydroCostsNoises; for (uint j = 0; j != 8784; ++j) { @@ -944,18 +887,15 @@ void ISimulation::computeRandomNumbers( template void ISimulation::computeAnnualCostsStatistics( std::vector& state, - std::vector::iterator& set_it) + setOfParallelYears& batch) { // Loop over years contained in the set - std::vector::iterator year_it; - for (year_it = set_it->yearsIndices.begin(); year_it != set_it->yearsIndices.end(); ++year_it) + for (auto y: batch.yearsIndices) { - // Get the index of the year - unsigned int y = *year_it; - if (set_it->isYearPerformed[y]) + if (batch.isYearPerformed[y]) { // Get space number associated to the performed year - uint numSpace = set_it->performedYearToSpace[y]; + uint numSpace = batch.performedYearToSpace[y]; const Variable::State& s = state[numSpace]; pAnnualStatistics.systemCost.addCost(s.annualSystemCost); pAnnualStatistics.criterionCost1.addCost(s.optimalSolutionCost1); @@ -973,8 +913,9 @@ static inline void logPerformedYearsInAset(setOfParallelYears& set) << " perfomed)"; std::string performedYearsToLog = ""; + std::ranges::for_each(set.yearsIndices, - [&](const uint& y) + [&set, &performedYearsToLog](const uint& y) { if (set.isYearPerformed[y]) { @@ -1018,65 +959,81 @@ void ISimulation::loopThroughYears(uint firstYear, // Number of threads to perform the jobs waiting in the queue pQueueService->maximumThreadCount(pNbMaxPerformedYearsInParallel); + HydroInputsChecker hydroInputsChecker(study); + + logs.info() << " Doing hydro validation"; - // Loop over sets of parallel years - std::vector::iterator set_it; - for (set_it = setsOfParallelYears.begin(); set_it != setsOfParallelYears.end(); ++set_it) + // Loop over sets of parallel years to check hydro inputs + for (const auto& batch: setsOfParallelYears) + { + if (batch.regenerateTS) + { + break; + } + for (auto year: batch.yearsIndices) + { + hydroInputsChecker.Execute(year); + } + } + hydroInputsChecker.CheckForErrors(); + + logs.info() << " Starting the simulation"; + + // Loop over sets of parallel years to run the simulation + for (auto& batch: setsOfParallelYears) { // 1 - We may want to regenerate the time-series this year. // This is the case when the preprocessors are enabled from the // interface and/or the refresh is enabled. - if (set_it->regenerateTS) + if (batch.regenerateTS) { - regenerateTimeSeries(set_it->yearForTSgeneration); + regenerateTimeSeries(batch.yearForTSgeneration); } - computeRandomNumbers(randomForParallelYears, - set_it->yearsIndices, - set_it->isYearPerformed, + batch.yearsIndices, + batch.isYearPerformed, randomHydroGenerator); - 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) + for (auto y: batch.yearsIndices) { - // Get the index of the year - unsigned int y = *year_it; + // for each year not handled earlier + hydroInputsChecker.Execute(y); + hydroInputsChecker.CheckForErrors(); - bool performCalculations = set_it->isYearPerformed[y]; + bool performCalculations = batch.isYearPerformed[y]; unsigned int numSpace = 999999; if (performCalculations) { yearPerformed = true; - numSpace = set_it->performedYearToSpace[y]; + numSpace = batch.performedYearToSpace[y]; } // If the year has not to be rerun, we skip the computation of the year. // Note that, when we enter for the first time in the "for" loop, all years of the set - // have to be rerun (meaning : they must be run once). if(!set_it->yearFailed[y]) + // have to be rerun (meaning : they must be run once). if(!batch.yearFailed[y]) // continue; auto task = std::make_shared>( this, y, - set_it->yearFailed, - set_it->isFirstPerformedYearOfASet, + batch.yearFailed, + batch.isFirstPerformedYearOfASet, pFirstSetParallelWithAPerformedYearWasRun, numSpace, randomForParallelYears, performCalculations, study, - state, + state[numSpace], pYearByYear, pDurationCollector, - pResultWriter); + pResultWriter, + simulationObserver_.get()); results.add(Concurrency::AddTask(*pQueueService, task)); } // End loop over years of the current set of parallel years - logPerformedYearsInAset(*set_it); + logPerformedYearsInAset(batch); pQueueService->start(); @@ -1085,14 +1042,15 @@ void ISimulation::loopThroughYears(uint firstYear, results.join(); pResultWriter.flush(); - // At this point, the first set of parallel year(s) was run with at least one year performed + // At this point, the first set of parallel year(s) was run with at least one year + // performed if (!pFirstSetParallelWithAPerformedYearWasRun && yearPerformed) { pFirstSetParallelWithAPerformedYearWasRun = true; } // On regarde si au moins une année du lot n'a pas trouvé de solution - for (auto& [year, failed]: set_it->yearFailed) + for (auto& [year, failed]: batch.yearFailed) { // Si une année du lot d'années n'a pas trouvé de solution, on arrête tout if (failed) @@ -1104,17 +1062,17 @@ void ISimulation::loopThroughYears(uint firstYear, } // Computing the summary : adding the contribution of MC years // previously computed in parallel - ImplementationType::variables.computeSummary(set_it->spaceToPerformedYear, - set_it->nbPerformedYears); + ImplementationType::variables.computeSummary(batch.spaceToPerformedYear, + batch.nbPerformedYears); // Computing summary of spatial aggregations ImplementationType::variables.computeSpatialAggregatesSummary(ImplementationType::variables, - set_it->spaceToPerformedYear, - set_it->nbPerformedYears); + batch.spaceToPerformedYear, + batch.nbPerformedYears); // Computes statistics on annual (system and solution) costs, to be printed in output into // separate files - computeAnnualCostsStatistics(state, set_it); + computeAnnualCostsStatistics(state, batch); // Set to zero the random numbers of all parallel years randomForParallelYears.reset(); diff --git a/src/solver/simulation/include/antares/solver/simulation/solver_utils.h b/src/solver/simulation/include/antares/solver/simulation/solver_utils.h index 363b7839f8..a920ef1f47 100644 --- a/src/solver/simulation/include/antares/solver/simulation/solver_utils.h +++ b/src/solver/simulation/include/antares/solver/simulation/solver_utils.h @@ -21,14 +21,10 @@ #ifndef __SOLVER_SIMULATION_SOLVER_UTILS_H__ #define __SOLVER_SIMULATION_SOLVER_UTILS_H__ -#include // For setprecision -#include // For std numeric_limits +#include // For std numeric_limits #include -#include // For ostringstream #include -#include - #include #include @@ -118,52 +114,10 @@ class yearRandomNumbers public: yearRandomNumbers() { - pThermalNoisesByArea = nullptr; - pNbClustersByArea = nullptr; pNbAreas = 0; } - ~yearRandomNumbers() - { - // General - delete[] pNbClustersByArea; - - // Thermal noises - for (uint a = 0; a != pNbAreas; a++) - { - delete[] pThermalNoisesByArea[a]; - } - delete[] pThermalNoisesByArea; - - // Reservoir levels, spilled and unsupplied energy - delete[] pReservoirLevels; - delete[] pUnsuppliedEnergy; - delete[] pSpilledEnergy; - - // Hydro costs noises - switch (pPowerFluctuations) - { - case Data::lssFreeModulations: - { - for (uint a = 0; a != pNbAreas; a++) - { - delete[] pHydroCostsByArea_freeMod[a]; - } - delete[] pHydroCostsByArea_freeMod; - break; - } - - case Data::lssMinimizeRamping: - case Data::lssMinimizeExcursions: - { - delete[] pHydroCosts_rampingOrExcursion; - break; - } - - case Data::lssUnknown: - break; - } - } + ~yearRandomNumbers() = default; void setNbAreas(uint nbAreas) { @@ -177,19 +131,19 @@ class yearRandomNumbers void reset() { - // General - memset(pNbClustersByArea, 0, pNbAreas * sizeof(size_t)); - // Thermal noises for (uint a = 0; a != pNbAreas; a++) { - memset(pThermalNoisesByArea[a], 0, pNbClustersByArea[a] * sizeof(double)); + pThermalNoisesByArea[a].assign(pThermalNoisesByArea[a].size(), 0); } + // General + pNbClustersByArea.assign(pNbAreas, 0); + // Reservoir levels, spilled and unsupplied energy costs - memset(pReservoirLevels, 0, pNbAreas * sizeof(double)); - memset(pUnsuppliedEnergy, 0, pNbAreas * sizeof(double)); - memset(pSpilledEnergy, 0, pNbAreas * sizeof(double)); + pReservoirLevels.assign(pNbAreas, 0); + pUnsuppliedEnergy.assign(pNbAreas, 0); + pSpilledEnergy.assign(pNbAreas, 0); // Hydro costs noises switch (pPowerFluctuations) @@ -198,7 +152,7 @@ class yearRandomNumbers { for (uint a = 0; a != pNbAreas; a++) { - memset(pHydroCostsByArea_freeMod[a], 0, 8784 * sizeof(double)); + pHydroCostsByArea_freeMod[a].assign(8784, 0); } break; } @@ -206,7 +160,7 @@ class yearRandomNumbers case Data::lssMinimizeRamping: case Data::lssMinimizeExcursions: { - memset(pHydroCosts_rampingOrExcursion, 0, pNbAreas * sizeof(double)); + pHydroCosts_rampingOrExcursion.assign(pNbAreas, 0); break; } @@ -220,19 +174,19 @@ class yearRandomNumbers Data::PowerFluctuations pPowerFluctuations; // Data for thermal noises - double** pThermalNoisesByArea; - size_t* pNbClustersByArea; + std::vector> pThermalNoisesByArea; + std::vector pNbClustersByArea; // Data for reservoir levels - double* pReservoirLevels; + std::vector pReservoirLevels; // Data for unsupplied and spilled energy costs - double* pUnsuppliedEnergy; - double* pSpilledEnergy; + std::vector pUnsuppliedEnergy; + std::vector pSpilledEnergy; // Hydro costs noises - double** pHydroCostsByArea_freeMod; - double* pHydroCosts_rampingOrExcursion; + std::vector> pHydroCostsByArea_freeMod; + std::vector pHydroCosts_rampingOrExcursion; }; class randomNumbers @@ -242,7 +196,7 @@ class randomNumbers pMaxNbPerformedYears(maxNbPerformedYearsInAset) { // Allocate a table of parallel years structures - pYears = new yearRandomNumbers[maxNbPerformedYearsInAset]; + pYears.resize(maxNbPerformedYearsInAset); // Tells these structures their power fluctuations mode for (uint y = 0; y < maxNbPerformedYearsInAset; ++y) @@ -251,10 +205,7 @@ class randomNumbers } } - ~randomNumbers() - { - delete[] pYears; - } + ~randomNumbers() = default; void reset() { @@ -267,7 +218,7 @@ class randomNumbers } uint pMaxNbPerformedYears; - yearRandomNumbers* pYears; + std::vector pYears; // Associates : // year number (0, ..., total nb of years to compute - 1) --> index of the year's space diff --git a/src/solver/simulation/include/antares/solver/simulation/timeseries-numbers.h b/src/solver/simulation/include/antares/solver/simulation/timeseries-numbers.h index 2b087b65e6..47fae11d45 100644 --- a/src/solver/simulation/include/antares/solver/simulation/timeseries-numbers.h +++ b/src/solver/simulation/include/antares/solver/simulation/timeseries-numbers.h @@ -23,8 +23,6 @@ #include -#include - #include #include "ITimeSeriesNumbersWriter.h" diff --git a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp index aa1a5c90e3..305d5fb31b 100644 --- a/src/solver/simulation/sim_alloc_probleme_hebdo.cpp +++ b/src/solver/simulation/sim_alloc_probleme_hebdo.cpp @@ -20,8 +20,6 @@ */ #include "antares/solver/simulation/sim_alloc_probleme_hebdo.h" -#include - #include #include "antares/solver/optimisation/opt_structure_probleme_a_resoudre.h" #include "antares/solver/simulation/sim_extern_variables_globales.h" @@ -39,7 +37,7 @@ void SIM_AllocationProblemeHebdo(const Data::Study& study, { SIM_AllocationProblemeDonneesGenerales(problem, study, NombreDePasDeTemps); SIM_AllocationProblemePasDeTemps(problem, study, NombreDePasDeTemps); - SIM_AllocationLinks(problem, study.runtime->interconnectionsCount(), NombreDePasDeTemps); + SIM_AllocationLinks(problem, study.runtime.interconnectionsCount(), NombreDePasDeTemps); SIM_AllocationConstraints(problem, study, NombreDePasDeTemps); SIM_AllocateAreas(problem, study, NombreDePasDeTemps); } @@ -55,7 +53,7 @@ void SIM_AllocationProblemeDonneesGenerales(PROBLEME_HEBDO& problem, { uint nbPays = study.areas.size(); - const uint linkCount = study.runtime->interconnectionsCount(); + const uint linkCount = study.runtime.interconnectionsCount(); problem.DefaillanceNegativeUtiliserPMinThermique.assign(nbPays, false); problem.DefaillanceNegativeUtiliserHydro.assign(nbPays, false); @@ -119,20 +117,6 @@ void SIM_AllocationProblemeDonneesGenerales(PROBLEME_HEBDO& problem, problem.ShortTermStorage.resize(nbPays); - problem.previousYearFinalLevels.resize(0); - if (problem.hydroHotStart) - { - for (uint i = 0; i <= nbPays; i++) - { - auto& area = *(study.areas[i]); - if (area.hydro.reservoirManagement) - { - problem.previousYearFinalLevels.assign(nbPays, 0.); - break; - } - } - } - problem.ReserveJMoins1.resize(nbPays); problem.ResultatsHoraires.resize(nbPays); @@ -146,8 +130,8 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, { uint nbPays = study.areas.size(); - const uint linkCount = study.runtime->interconnectionsCount(); - const uint shortTermStorageCount = study.runtime->shortTermStorageCount; + const uint linkCount = study.runtime.interconnectionsCount(); + const uint shortTermStorageCount = study.runtime.shortTermStorageCount; auto activeConstraints = study.bindingConstraints.activeConstraints(); @@ -173,7 +157,7 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, 0); variablesMapping.NumeroDeVariableDuPalierThermique - .assign(study.runtime->thermalPlantTotalCount, 0); + .assign(study.runtime.thermalPlantTotalCount, 0); variablesMapping.NumeroDeVariablesDeLaProdHyd.assign(nbPays, 0); variablesMapping.NumeroDeVariablesDePompage.assign(nbPays, 0); variablesMapping.NumeroDeVariablesDeNiveau.assign(nbPays, 0); @@ -186,13 +170,13 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, variablesMapping.NumeroDeVariablesVariationHydALaHausse.assign(nbPays, 0); variablesMapping.NumeroDeVariableDuNombreDeGroupesEnMarcheDuPalierThermique - .assign(study.runtime->thermalPlantTotalCount, 0); + .assign(study.runtime.thermalPlantTotalCount, 0); variablesMapping.NumeroDeVariableDuNombreDeGroupesQuiDemarrentDuPalierThermique - .assign(study.runtime->thermalPlantTotalCount, 0); + .assign(study.runtime.thermalPlantTotalCount, 0); variablesMapping.NumeroDeVariableDuNombreDeGroupesQuiSArretentDuPalierThermique - .assign(study.runtime->thermalPlantTotalCount, 0); + .assign(study.runtime.thermalPlantTotalCount, 0); variablesMapping.NumeroDeVariableDuNombreDeGroupesQuiTombentEnPanneDuPalierThermique - .assign(study.runtime->thermalPlantTotalCount, 0); + .assign(study.runtime.thermalPlantTotalCount, 0); variablesMapping.SIM_ShortTermStorage.InjectionVariable.assign(shortTermStorageCount, 0); variablesMapping.SIM_ShortTermStorage.WithdrawalVariable.assign(shortTermStorageCount, 0); @@ -219,14 +203,14 @@ void SIM_AllocationProblemePasDeTemps(PROBLEME_HEBDO& problem, problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeContrainteDesContraintesDeDureeMinDeMarche - .assign(study.runtime->thermalPlantTotalCount, 0); + .assign(study.runtime.thermalPlantTotalCount, 0); problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeContrainteDesContraintesDeDureeMinDArret - .assign(study.runtime->thermalPlantTotalCount, 0); + .assign(study.runtime.thermalPlantTotalCount, 0); problem.CorrespondanceCntNativesCntOptim[k] .NumeroDeLaDeuxiemeContrainteDesContraintesDesGroupesQuiTombentEnPanne - .assign(study.runtime->thermalPlantTotalCount, 0); + .assign(study.runtime.thermalPlantTotalCount, 0); problem.VariablesDualesDesContraintesDeNTC[k] .VariableDualeParInterconnexion.assign(linkCount, 0.); @@ -292,7 +276,7 @@ void SIM_AllocationConstraints(PROBLEME_HEBDO& problem, problem.MatriceDesContraintesCouplantes[constraintIndex] .PaysDuPalierDispatch.assign(bc->clusterCount(), 0); - // TODO : create a numberOfTimeSteps method in class of runtime->bindingConstraint + // TODO : create a numberOfTimeSteps method in class of runtime.bindingConstraint unsigned int nbTimeSteps; switch (bc->type()) { @@ -379,34 +363,19 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, problem.ResultatsHoraires[k].ValeursHorairesDeDefaillancePositive.assign(NombreDePasDeTemps, 0.); + problem.ResultatsHoraires[k] + .ValeursHorairesDeDefaillancePositiveCSR.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].ValeursHorairesDENS.assign(NombreDePasDeTemps, 0.); // adq patch problem.ResultatsHoraires[k].ValeursHorairesLmrViolations.assign(NombreDePasDeTemps, 0); // adq patch - problem.ResultatsHoraires[k].ValeursHorairesSpilledEnergyAfterCSR.assign(NombreDePasDeTemps, - 0.); // adq patch problem.ResultatsHoraires[k].ValeursHorairesDtgMrgCsr.assign(NombreDePasDeTemps, 0.); // adq patch - problem.ResultatsHoraires[k] - .ValeursHorairesDeDefaillancePositiveUp.assign(NombreDePasDeTemps, 0.); - problem.ResultatsHoraires[k] - .ValeursHorairesDeDefaillancePositiveDown.assign(NombreDePasDeTemps, 0.); - problem.ResultatsHoraires[k] - .ValeursHorairesDeDefaillancePositiveAny.assign(NombreDePasDeTemps, 0.); + problem.ResultatsHoraires[k].ValeursHorairesDeDefaillanceNegative.assign(NombreDePasDeTemps, 0.); - problem.ResultatsHoraires[k] - .ValeursHorairesDeDefaillanceNegativeUp.assign(NombreDePasDeTemps, 0.); - problem.ResultatsHoraires[k] - .ValeursHorairesDeDefaillanceNegativeDown.assign(NombreDePasDeTemps, 0.); - problem.ResultatsHoraires[k] - .ValeursHorairesDeDefaillanceNegativeAny.assign(NombreDePasDeTemps, 0.); - problem.ResultatsHoraires[k] - .ValeursHorairesDeDefaillanceEnReserve.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].TurbinageHoraire.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].PompageHoraire.assign(NombreDePasDeTemps, 0.); - problem.ResultatsHoraires[k].TurbinageHoraireUp.assign(NombreDePasDeTemps, 0.); - problem.ResultatsHoraires[k].TurbinageHoraireDown.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].CoutsMarginauxHoraires.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].niveauxHoraires.assign(NombreDePasDeTemps, 0.); problem.ResultatsHoraires[k].valeurH2oHoraire.assign(NombreDePasDeTemps, 0.); @@ -438,25 +407,12 @@ void SIM_AllocateAreas(PROBLEME_HEBDO& problem, problem.PaliersThermiquesDuPays[k] .PuissanceDisponibleEtCout[j] .NombreMinDeGroupesEnMarcheDuPalierThermique.assign(NombreDePasDeTemps, 0); - - problem.PaliersThermiquesDuPays[k] - .PuissanceDisponibleEtCout[j] - .CoutHoraireDuPalierThermiqueUp.assign(NombreDePasDeTemps, 0.); - problem.PaliersThermiquesDuPays[k] - .PuissanceDisponibleEtCout[j] - .CoutHoraireDuPalierThermiqueDown.assign(NombreDePasDeTemps, 0.); } for (unsigned j = 0; j < NombreDePasDeTemps; j++) { problem.ResultatsHoraires[k].ProductionThermique[j].ProductionThermiqueDuPalier.assign( nbPaliers, 0.); - problem.ResultatsHoraires[k] - .ProductionThermique[j] - .ProductionThermiqueDuPalierUp.assign(nbPaliers, 0.); - problem.ResultatsHoraires[k] - .ProductionThermique[j] - .ProductionThermiqueDuPalierDown.assign(nbPaliers, 0.); problem.ResultatsHoraires[k] .ProductionThermique[j] .NombreDeGroupesEnMarcheDuPalier.assign(nbPaliers, 0.); diff --git a/src/solver/simulation/sim_allocation_tableaux.cpp b/src/solver/simulation/sim_allocation_tableaux.cpp index 4b8674639d..ebb711804d 100644 --- a/src/solver/simulation/sim_allocation_tableaux.cpp +++ b/src/solver/simulation/sim_allocation_tableaux.cpp @@ -19,8 +19,6 @@ ** along with Antares_Simulator. If not, see . */ -#include - #include #include "antares/solver/simulation/sim_extern_variables_globales.h" #include "antares/study/simulation.h" @@ -29,9 +27,9 @@ using namespace Antares; void SIM_AllocationTableaux(const Data::Study& study) { - transitMoyenInterconnexionsRecalculQuadratique.resize(study.runtime->interconnectionsCount()); + transitMoyenInterconnexionsRecalculQuadratique.resize(study.runtime.interconnectionsCount()); - for (uint i = 0; i != study.runtime->interconnectionsCount(); i++) + for (uint i = 0; i != study.runtime.interconnectionsCount(); i++) { transitMoyenInterconnexionsRecalculQuadratique[i].assign(HOURS_PER_YEAR, 0.); } diff --git a/src/solver/simulation/sim_calcul_economique.cpp b/src/solver/simulation/sim_calcul_economique.cpp index 0581436cb4..e14f85e945 100644 --- a/src/solver/simulation/sim_calcul_economique.cpp +++ b/src/solver/simulation/sim_calcul_economique.cpp @@ -53,7 +53,8 @@ static void importShortTermStorages( // Properties toInsert.reservoirCapacity = st.properties.reservoirCapacity.value(); - toInsert.efficiency = st.properties.efficiencyFactor; + toInsert.injectionEfficiency = st.properties.injectionEfficiency; + toInsert.withdrawalEfficiency = st.properties.withdrawalEfficiency; toInsert.injectionNominalCapacity = st.properties.injectionNominalCapacity.value(); toInsert.withdrawalNominalCapacity = st.properties.withdrawalNominalCapacity.value(); toInsert.initialLevel = st.properties.initialLevel; @@ -71,7 +72,7 @@ static void importShortTermStorages( void SIM_InitialisationProblemeHebdo(Data::Study& study, PROBLEME_HEBDO& problem, - int NombreDePasDeTemps, + unsigned int NombreDePasDeTemps, uint numspace) { int NombrePaliers; @@ -81,15 +82,12 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, problem.Expansion = (parameters.mode == Data::SimulationMode::Expansion); problem.firstWeekOfSimulation = false; - problem.hydroHotStart = (parameters.initialReservoirLevels.iniLevels - == Antares::Data::irlHotStart); - // gp adq : to be removed if (parameters.adqPatchParams.enabled) { problem.adequacyPatchRuntimeData = std::make_shared( study.areas, - study.runtime->areaLink); + study.runtime.areaLink); } problem.WaterValueAccurate = (study.parameters.hydroPricing.hpMode @@ -103,9 +101,9 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, problem.NombreDePays = study.areas.size(); - problem.NombreDInterconnexions = study.runtime->interconnectionsCount(); + problem.NombreDInterconnexions = study.runtime.interconnectionsCount(); - problem.NumberOfShortTermStorages = study.runtime->shortTermStorageCount; + problem.NumberOfShortTermStorages = study.runtime.shortTermStorageCount; auto activeConstraints = study.bindingConstraints.activeConstraints(); problem.NombreDeContraintesCouplantes = activeConstraints.size(); @@ -201,7 +199,7 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, problem.CaracteristiquesHydrauliques[i].TailleReservoir = area.hydro.reservoirCapacity; - for (int pdt = 0; pdt < NombreDePasDeTemps; pdt++) + for (unsigned pdt = 0; pdt < NombreDePasDeTemps; pdt++) { problem.CaracteristiquesHydrauliques[i].NiveauHoraireInf[pdt] = 0; problem.CaracteristiquesHydrauliques[i].NiveauHoraireSup[pdt] @@ -210,11 +208,6 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, problem.previousSimulationFinalLevel[i] = -1.; - if (!problem.previousYearFinalLevels.empty()) - { - problem.previousYearFinalLevels[i] = -1.; - } - problem.CaracteristiquesHydrauliques[i].WeeklyWaterValueStateRegular = 0.; problem.CaracteristiquesHydrauliques[i].WeeklyGeneratingModulation = 1.; @@ -226,9 +219,9 @@ void SIM_InitialisationProblemeHebdo(Data::Study& study, importShortTermStorages(study.areas, problem.ShortTermStorage); - for (uint i = 0; i < study.runtime->interconnectionsCount(); ++i) + for (uint i = 0; i < study.runtime.interconnectionsCount(); ++i) { - auto& link = *(study.runtime->areaLink[i]); + auto& link = *(study.runtime.areaLink[i]); problem.PaysOrigineDeLInterconnexion[i] = link.from->index; problem.PaysExtremiteDeLInterconnexion[i] = link.with->index; } @@ -418,7 +411,7 @@ void SIM_RenseignementProblemeHebdo(const Study& study, { const auto& parameters = study.parameters; - auto& studyruntime = *study.runtime; + auto& studyruntime = study.runtime; const uint nbPays = study.areas.size(); const size_t pasDeTempsSizeDouble = problem.NombreDePasDeTemps * sizeof(double); @@ -521,14 +514,14 @@ void SIM_RenseignementProblemeHebdo(const Study& study, if (area.hydro.useWaterValue) { - Antares::Data::getWaterValue( - problem.previousSimulationFinalLevel[k] * 100 / area.hydro.reservoirCapacity, - area.hydro.waterValues, - weekFirstDay, - problem.CaracteristiquesHydrauliques[k].WeeklyWaterValueStateRegular); + problem.CaracteristiquesHydrauliques[k].WeeklyWaterValueStateRegular + = getWaterValue(problem.previousSimulationFinalLevel[k] * 100 + / area.hydro.reservoirCapacity, + area.hydro.waterValues, + weekFirstDay); } - if (problem.CaracteristiquesHydrauliques[k].PresenceDHydrauliqueModulable > 0) + if (problem.CaracteristiquesHydrauliques[k].PresenceDHydrauliqueModulable) { if (area.hydro.hardBoundsOnRuleCurves && problem.CaracteristiquesHydrauliques[k].SuiviNiveauHoraire) @@ -655,7 +648,7 @@ void SIM_RenseignementProblemeHebdo(const Study& study, = +hourlyLoad - problem.AllMustRunGeneration[hourInWeek].AllMustRunGenerationOfArea[k]; - if (problem.CaracteristiquesHydrauliques[k].PresenceDHydrauliqueModulable > 0) + if (problem.CaracteristiquesHydrauliques[k].PresenceDHydrauliqueModulable) { problem.CaracteristiquesHydrauliques[k] .ContrainteDePmaxHydrauliqueHoraire[hourInWeek] @@ -680,7 +673,7 @@ void SIM_RenseignementProblemeHebdo(const Study& study, { for (uint k = 0; k < nbPays; ++k) { - if (problem.CaracteristiquesHydrauliques[k].PresenceDHydrauliqueModulable > 0) + if (problem.CaracteristiquesHydrauliques[k].PresenceDHydrauliqueModulable) { auto& area = *study.areas.byIndex[k]; const auto& scratchpad = scratchmap.at(&area); diff --git a/src/solver/simulation/sim_variables_globales.cpp b/src/solver/simulation/sim_variables_globales.cpp index 252c937631..1fdcc04fa3 100644 --- a/src/solver/simulation/sim_variables_globales.cpp +++ b/src/solver/simulation/sim_variables_globales.cpp @@ -19,7 +19,6 @@ ** along with Antares_Simulator. If not, see . */ -#include "antares/solver/simulation/sim_structure_donnees.h" -#include "antares/solver/simulation/sim_structure_probleme_economique.h" +#include std::vector> transitMoyenInterconnexionsRecalculQuadratique; diff --git a/src/solver/simulation/simulation-run.cpp b/src/solver/simulation/simulation-run.cpp new file mode 100644 index 0000000000..c227448f81 --- /dev/null +++ b/src/solver/simulation/simulation-run.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#include "include/antares/solver/simulation/simulation-run.h" + +#include "antares/solver/simulation/adequacy.h" +#include "antares/solver/simulation/economy.h" + +namespace Antares::Solver +{ + +template +Benchmarking::OptimizationInfo runSimulation(Antares::Data::Study& study, + const Settings& settings, + Benchmarking::DurationCollector& durationCollector, + IResultWriter& resultWriter, + Simulation::ISimulationObserver& simulationObserver) +{ + simulationType simulation(study, settings, durationCollector, resultWriter, simulationObserver); + simulation.checkWriter(); + simulation.run(); + + if (!(settings.noOutput || settings.tsGeneratorsOnly)) + { + durationCollector("synthesis_export") + << [&simulation] { simulation.writeResults(/*synthesis:*/ true); }; + + return simulation.getOptimizationInfo(); + } + return {}; +} + +Benchmarking::OptimizationInfo simulationRun(Antares::Data::Study& study, + const Settings& settings, + Benchmarking::DurationCollector& durationCollector, + IResultWriter& resultWriter, + Simulation::ISimulationObserver& simulationObserver) +{ + study.computePThetaInfForThermalClusters(); + + switch (study.runtime.mode) + { + case Data::SimulationMode::Adequacy: + return runSimulation>( + study, + settings, + durationCollector, + resultWriter, + simulationObserver); + case Data::SimulationMode::Economy: + case Data::SimulationMode::Expansion: + default: + return runSimulation>( + study, + settings, + durationCollector, + resultWriter, + simulationObserver); + } +} + +} // namespace Antares::Solver diff --git a/src/solver/simulation/solver_utils.cpp b/src/solver/simulation/solver_utils.cpp index 936957a224..76f5fc0ce3 100644 --- a/src/solver/simulation/solver_utils.cpp +++ b/src/solver/simulation/solver_utils.cpp @@ -27,7 +27,6 @@ #include #include -#include #include #define SEP Yuni::IO::Separator diff --git a/src/solver/simulation/timeseries-numbers.cpp b/src/solver/simulation/timeseries-numbers.cpp index 52b1213ada..fecb8ba4eb 100644 --- a/src/solver/simulation/timeseries-numbers.cpp +++ b/src/solver/simulation/timeseries-numbers.cpp @@ -329,8 +329,7 @@ bool checkInterModalConsistencyForArea(const Area& area, { logs.error() << "Inter-modal correlation: time-series numbers of inter-modal modes in area '" - << area.name << "'" - << " are not identical"; + << area.name << "'" << " are not identical"; return false; } @@ -476,7 +475,7 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (!isTSintramodal[indexTS]) { area.load.series.timeseriesNumbers[year] = (uint32_t)(floor( - study.runtime->random[seedTimeseriesNumbers].next() + study.runtime.random[seedTimeseriesNumbers].next() * area.load.series.timeSeries.width)); } @@ -488,7 +487,7 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (!isTSintramodal[indexTS]) { area.solar.series.timeseriesNumbers[year] = (uint32_t)(floor( - study.runtime->random[seedTimeseriesNumbers].next() + study.runtime.random[seedTimeseriesNumbers].next() * area.solar.series.timeSeries.width)); } @@ -500,7 +499,7 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (!isTSintramodal[indexTS]) { area.wind.series.timeseriesNumbers[year] = (uint32_t)(floor( - study.runtime->random[seedTimeseriesNumbers].next() + study.runtime.random[seedTimeseriesNumbers].next() * area.wind.series.timeSeries.width)); } @@ -512,8 +511,7 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (!isTSintramodal[indexTS]) { area.hydro.series->timeseriesNumbers[year] = (uint32_t)(floor( - study.runtime->random[seedTimeseriesNumbers].next() - * area.hydro.series->TScount())); + study.runtime.random[seedTimeseriesNumbers].next() * area.hydro.series->TScount())); } // ------------- @@ -525,14 +523,14 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i { if (!cluster->enabled) { - study.runtime->random[seedTimeseriesNumbers].next(); + study.runtime.random[seedTimeseriesNumbers].next(); } else { if (!isTSintramodal[indexTS]) { cluster->series.timeseriesNumbers[year] = (uint32_t)(floor( - study.runtime->random[seedTimeseriesNumbers].next() + study.runtime.random[seedTimeseriesNumbers].next() * cluster->series.timeSeries.width)); } } @@ -550,7 +548,7 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i // There is no TS generation for renewable clusters uint nbTimeSeries = cluster->series.timeSeries.width; cluster->series.timeseriesNumbers[year] = (uint32_t)(floor( - study.runtime->random[seedTimeseriesNumbers].next() * nbTimeSeries)); + study.runtime.random[seedTimeseriesNumbers].next() * nbTimeSeries)); } } @@ -568,7 +566,7 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i if (nbTimeSeries > 1) { link.timeseriesNumbers[year] = (uint32_t)(floor( - study.runtime->random[seedTimeseriesNumbers].next() * nbTimeSeries)); + study.runtime.random[seedTimeseriesNumbers].next() * nbTimeSeries)); } } } @@ -580,7 +578,7 @@ void drawAndStoreTSnumbersForNOTintraModal(const array& i auto& groupTsNumber = group->timeseriesNumbers[year]; if (nbTimeSeries > 1) { - groupTsNumber = (uint32_t)(floor(study.runtime->random[seedTimeseriesNumbers].next() + groupTsNumber = (uint32_t)(floor(study.runtime.random[seedTimeseriesNumbers].next() * nbTimeSeries)); } } @@ -754,7 +752,7 @@ bool TimeSeriesNumbers::Generate(Study& study) return GenerateDeratedMode(study); } - const uint years = 1 + study.runtime->rangeLimits.year[rangeEnd]; + const uint years = 1 + study.runtime.rangeLimits.year[rangeEnd]; const array isTSintramodal = { (bool)(timeSeriesLoad & parameters.intraModal), @@ -784,7 +782,7 @@ bool TimeSeriesNumbers::Generate(Study& study) drawTSnumbersForIntraModal(intramodal_draws, isTSintramodal, nbTimeseriesByMode, - study.runtime->random); + study.runtime.random); storeTSnumbersForIntraModal(intramodal_draws, isTSintramodal, year, study.areas); // NOT intra-modal TS : draw and store TS numbers diff --git a/src/solver/ts-generator/availability.cpp b/src/solver/ts-generator/availability.cpp index f9b50696df..1ac5e7675b 100644 --- a/src/solver/ts-generator/availability.cpp +++ b/src/solver/ts-generator/availability.cpp @@ -19,52 +19,61 @@ ** along with Antares_Simulator. If not, see . */ -#include -#include #include +#include // For Antares::IO::fileSetContent #include #include #include #include -#include -#include "antares/study/simulation.h" - -#define SEP Yuni::IO::Separator constexpr double FAILURE_RATE_EQ_1 = 0.999; namespace Antares::TSGenerator { -AvailabilityTSGeneratorData::AvailabilityTSGeneratorData(Data::ThermalCluster* source): - unitCount(source->unitCount), - nominalCapacity(source->nominalCapacity), - forcedVolatility(source->forcedVolatility), - plannedVolatility(source->plannedVolatility), - forcedLaw(source->forcedLaw), - plannedLaw(source->plannedLaw), - prepro(source->prepro), - series(source->series.timeSeries), - modulationCapacity(source->modulation[Data::thermalModulationCapacity]), - name(source->name()) +AvailabilityTSGeneratorData::AvailabilityTSGeneratorData(Data::ThermalCluster* cluster): + unitCount(cluster->unitCount), + nominalCapacity(cluster->nominalCapacity), + forcedVolatility(cluster->forcedVolatility), + plannedVolatility(cluster->plannedVolatility), + forcedLaw(cluster->forcedLaw), + plannedLaw(cluster->plannedLaw), + prepro(cluster->prepro.get()), + modulationCapacity(cluster->modulation[Data::thermalModulationCapacity]), + name(cluster->name()) +{ +} + +AvailabilityTSGeneratorData::AvailabilityTSGeneratorData(LinkTSgenerationParams& source, + Matrix<>& modulation, + const std::string& areaDestName): + unitCount(source.unitCount), + nominalCapacity(source.nominalCapacity), + forcedVolatility(source.forcedVolatility), + plannedVolatility(source.plannedVolatility), + forcedLaw(source.forcedLaw), + plannedLaw(source.plannedLaw), + prepro(source.prepro.get()), + modulationCapacity(modulation[0]), + name(areaDestName) { } namespace { -class GeneratorTempData final +class AvailabilityTSgenerator final { public: - explicit GeneratorTempData(Data::Study&, unsigned); + explicit AvailabilityTSgenerator(bool, unsigned, MersenneTwister&); - void generateTS(const Data::Area& area, AvailabilityTSGeneratorData& cluster) const; + Matrix run(AvailabilityTSGeneratorData&) const; private: bool derated; uint nbOfSeriesToGen_; - MersenneTwister& rndgenerator; + MersenneTwister& randomGenerator_; static constexpr int Log_size = 4000; @@ -82,19 +91,21 @@ class GeneratorTempData final const T& duration) const; }; -GeneratorTempData::GeneratorTempData(Data::Study& study, unsigned nbOfSeriesToGen): - derated(study.parameters.derated), +AvailabilityTSgenerator::AvailabilityTSgenerator(bool derated, + unsigned int nbOfSeriesToGen, + MersenneTwister& randomGenerator): + derated(derated), nbOfSeriesToGen_(nbOfSeriesToGen), - rndgenerator(study.runtime->random[Data::seedTsGenThermal]) + randomGenerator_(randomGenerator) { } template -void GeneratorTempData::prepareIndispoFromLaw(Data::StatisticalLaw law, - double volatility, - std::array& A, - std::array& B, - const T& duration) const +void AvailabilityTSgenerator::prepareIndispoFromLaw(Data::StatisticalLaw law, + double volatility, + std::array& A, + std::array& B, + const T& duration) const { switch (law) { @@ -135,18 +146,18 @@ void GeneratorTempData::prepareIndispoFromLaw(Data::StatisticalLaw law, } } -int GeneratorTempData::durationGenerator(Data::StatisticalLaw law, - int expec, - double volat, - double a, - double b) const +int AvailabilityTSgenerator::durationGenerator(Data::StatisticalLaw law, + int expec, + double volat, + double a, + double b) const { if (volat == 0 || expec == 1) { return expec; } - double rndnumber = rndgenerator.next(); + double rndnumber = randomGenerator_.next(); switch (law) { @@ -167,28 +178,21 @@ int GeneratorTempData::durationGenerator(Data::StatisticalLaw law, return 0; } -void GeneratorTempData::generateTS(const Data::Area& area, - AvailabilityTSGeneratorData& cluster) const +Matrix AvailabilityTSgenerator::run(AvailabilityTSGeneratorData& tsGenerationData) const { - if (!cluster.prepro) - { - logs.error() - << "Cluster: " << area.name << '/' << cluster.name - << ": The timeseries will not be regenerated. All data related to the ts-generator for " - << "'thermal' have been released."; - return; - } + assert(tsGenerationData.prepro); - assert(cluster.prepro); + Matrix to_return; + to_return.reset(nbOfSeriesToGen_, 24 * DAYS_PER_YEAR); - if (0 == cluster.unitCount || 0 == cluster.nominalCapacity) + if (0 == tsGenerationData.unitCount || 0 == tsGenerationData.nominalCapacity) { - return; + return to_return; } - const auto& preproData = *(cluster.prepro); + const auto& preproData = *(tsGenerationData.prepro); - int AUN = cluster.unitCount; + int AUN = tsGenerationData.unitCount; auto& FOD = preproData.data[Data::PreproAvailability::foDuration]; @@ -202,13 +206,13 @@ void GeneratorTempData::generateTS(const Data::Area& area, auto& NPOmax = preproData.data[Data::PreproAvailability::npoMax]; - double f_volatility = cluster.forcedVolatility; + double f_volatility = tsGenerationData.forcedVolatility; - double p_volatility = cluster.plannedVolatility; + double p_volatility = tsGenerationData.plannedVolatility; - auto f_law = cluster.forcedLaw; + auto f_law = tsGenerationData.forcedLaw; - auto p_law = cluster.plannedLaw; + auto p_law = tsGenerationData.plannedLaw; std::vector> FPOW(DAYS_PER_YEAR); std::vector> PPOW(DAYS_PER_YEAR); @@ -230,8 +234,8 @@ void GeneratorTempData::generateTS(const Data::Area& area, for (uint d = 0; d < DAYS_PER_YEAR; ++d) { - FPOW[d].resize(cluster.unitCount + 1); - PPOW[d].resize(cluster.unitCount + 1); + FPOW[d].resize(tsGenerationData.unitCount + 1); + PPOW[d].resize(tsGenerationData.unitCount + 1); PODOfTheDay = (int)POD[d]; FODOfTheDay = (int)FOD[d]; @@ -264,7 +268,7 @@ void GeneratorTempData::generateTS(const Data::Area& area, pp[d] = lp[d] / b; } - for (uint k = 0; k != cluster.unitCount + 1; ++k) + for (uint k = 0; k != tsGenerationData.unitCount + 1; ++k) { FPOW[d][k] = pow(a, (double)k); PPOW[d][k] = pow(b, (double)k); @@ -296,19 +300,12 @@ void GeneratorTempData::generateTS(const Data::Area& area, double cumul = 0; double last = 0; - auto& modulation = cluster.modulationCapacity; - double* dstSeries = nullptr; + auto& modulation = tsGenerationData.modulationCapacity; const uint tsCount = nbOfSeriesToGen_ + 2; for (uint tsIndex = 0; tsIndex != tsCount; ++tsIndex) { uint hour = 0; - - if (tsIndex > 1) - { - dstSeries = cluster.series[tsIndex - 2]; - } - for (uint dayInTheYear = 0; dayInTheYear < DAYS_PER_YEAR; ++dayInTheYear) { assert(dayInTheYear < 366); @@ -368,7 +365,7 @@ void GeneratorTempData::generateTS(const Data::Area& area, if (lf[dayInTheYear] > 0. && lf[dayInTheYear] <= FAILURE_RATE_EQ_1) { - A = rndgenerator.next(); + A = randomGenerator_.next(); last = FPOW[dayInTheYear][AUN]; if (A > last) @@ -404,7 +401,7 @@ void GeneratorTempData::generateTS(const Data::Area& area, } last = PPOW[dayInTheYear][AUN_app]; - A = rndgenerator.next(); + A = randomGenerator_.next(); if (A > last) { @@ -481,7 +478,7 @@ void GeneratorTempData::generateTS(const Data::Area& area, } } - if (cluster.unitCount == 1) + if (tsGenerationData.unitCount == 1) { if (POC == 1 && FOC == 1) { @@ -551,14 +548,14 @@ void GeneratorTempData::generateTS(const Data::Area& area, } NOW = (NOW + 1) % Log_size; - AVP[dayInTheYear] = AUN * cluster.nominalCapacity; + AVP[dayInTheYear] = AUN * tsGenerationData.nominalCapacity; if (tsIndex > 1) { double AVPDayInTheYear = AVP[dayInTheYear]; for (uint h = 0; h != 24; ++h) { - dstSeries[hour] = std::round(AVPDayInTheYear * modulation[hour]); + to_return[tsIndex - 2][hour] = std::round(AVPDayInTheYear * modulation[hour]); ++hour; } } @@ -567,8 +564,9 @@ void GeneratorTempData::generateTS(const Data::Area& area, if (derated) { - cluster.series.averageTimeseries(); + to_return.averageTimeseries(); } + return to_return; } } // namespace @@ -592,48 +590,96 @@ std::vector getAllClustersToGen(const Data::AreaList& are return clusters; } -void writeResultsToDisk(const Data::Study& study, - Solver::IResultWriter& writer, - const Matrix<>& series, - const std::string& savePath) +void writeTStoDisk(const Matrix<>& series, const std::filesystem::path savePath) { - if (study.parameters.noOutput) - { - return; - } - std::string buffer; series.saveToBuffer(buffer, 0); - writer.addEntryFromBuffer(savePath, buffer); + + std::filesystem::path parentDir = savePath.parent_path(); + if (!std::filesystem::exists(parentDir)) + { + std::filesystem::create_directories(parentDir); + } + Antares::IO::fileSetContent(savePath.string(), buffer); } bool generateThermalTimeSeries(Data::Study& study, const std::vector& clusters, - Solver::IResultWriter& writer, - const std::string& savePath) + MersenneTwister& thermalRandom) { logs.info(); logs.info() << "Generating the thermal time-series"; - bool archive = study.parameters.timeSeriesToArchive & Data::timeSeriesThermal; + auto generator = AvailabilityTSgenerator(study.parameters.derated, + study.parameters.nbTimeSeriesThermal, + thermalRandom); + + for (auto* cluster: clusters) + { + AvailabilityTSGeneratorData tsGenerationData(cluster); + cluster->series.timeSeries = generator.run(tsGenerationData); + } - auto generator = GeneratorTempData(study, study.parameters.nbTimeSeriesThermal); + return true; +} - // TODO VP: parallel +void writeThermalTimeSeries(const std::vector& clusters, + const fs::path& savePath) +{ for (auto* cluster: clusters) { - AvailabilityTSGeneratorData tsConfigData(cluster); - generator.generateTS(*cluster->parentArea, tsConfigData); + auto areaName = cluster->parentArea->id.to(); + auto clusterName = cluster->id(); + auto filePath = savePath / areaName / clusterName += ".txt"; + + writeTStoDisk(cluster->series.timeSeries, filePath); + } +} + +// gp : we should try to add const identifiers before args here +bool generateLinkTimeSeries(std::vector& links, + StudyParamsForLinkTS& generalParams, + const fs::path& savePath) +{ + logs.info(); + logs.info() << "Generation of links time-series"; - if (archive) // compatibilty with in memory + auto generator = AvailabilityTSgenerator(generalParams.derated, + generalParams.nbLinkTStoGenerate, + generalParams.random); + for (auto& link: links) + { + if (!link.hasValidData) { - std::string filePath = savePath + SEP + cluster->parentArea->id + SEP + cluster->id() - + ".txt"; - writeResultsToDisk(study, writer, cluster->series.timeSeries, filePath); + logs.error() << "Missing data for link " << link.namesPair.first << "/" + << link.namesPair.second; + return false; } + + if (link.forceNoGeneration) + { + continue; // Skipping the link + } + + // === DIRECT ======================= + AvailabilityTSGeneratorData tsConfigDataDirect(link, + link.modulationCapacityDirect, + link.namesPair.second); + auto generated_ts = generator.run(tsConfigDataDirect); + + auto filePath = savePath / link.namesPair.first / link.namesPair.second += "_direct.txt"; + writeTStoDisk(generated_ts, filePath); + + // === INDIRECT ======================= + AvailabilityTSGeneratorData tsConfigDataIndirect(link, + link.modulationCapacityIndirect, + link.namesPair.second); + generated_ts = generator.run(tsConfigDataIndirect); + + filePath = savePath / link.namesPair.first / link.namesPair.second += "_indirect.txt"; + writeTStoDisk(generated_ts, filePath); } return true; } - } // namespace Antares::TSGenerator diff --git a/src/solver/ts-generator/generator.cpp b/src/solver/ts-generator/generator.cpp index 2cb4227755..c682e412ab 100644 --- a/src/solver/ts-generator/generator.cpp +++ b/src/solver/ts-generator/generator.cpp @@ -27,7 +27,7 @@ namespace Antares::TSGenerator void ResizeGeneratedTimeSeries(Data::AreaList& areas, Data::Parameters& params) { areas.each( - [&](Data::Area& area) + [¶ms](Data::Area& area) { // Load if (params.timeSeriesToGenerate & Data::timeSeriesLoad) @@ -50,9 +50,7 @@ void ResizeGeneratedTimeSeries(Data::AreaList& areas, Data::Parameters& params) // Hydro if (params.timeSeriesToGenerate & Data::timeSeriesHydro) { - Data::DataSeriesHydro* const series = area.hydro.series; - const uint nbSeries = params.nbTimeSeriesHydro; - series->resizeTS(nbSeries); + area.hydro.series->resizeTS(params.nbTimeSeriesHydro); } // Thermal diff --git a/src/solver/ts-generator/hydro.cpp b/src/solver/ts-generator/hydro.cpp index 1b4ac3496d..6f5fd8dfc7 100644 --- a/src/solver/ts-generator/hydro.cpp +++ b/src/solver/ts-generator/hydro.cpp @@ -1,27 +1,28 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include #include +#include #include #include #include "antares/solver/misc/cholesky.h" @@ -42,7 +43,7 @@ static void PreproRoundAllEntriesPlusDerated(Data::Study& study) bool derated = study.parameters.derated; study.areas.each( - [&](Data::Area& area) + [&derated](Data::Area& area) { auto& hydroseries = *(area.hydro.series); @@ -63,16 +64,16 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, Solver::IResu Solver::Progression::Task progression(study, currentYear, Solver::Progression::sectTSGHydro); - auto& studyRTI = *(study.runtime); + auto& studyRTI = study.runtime; auto& calendar = study.calendar; - uint DIM = 12 * study.areas.size(); + uint DIM = MONTHS_PER_YEAR * study.areas.size(); uint DEM = DIM / 2; Matrix CHSKY; CHSKY.reset(DIM, DIM); - double* QCHOLTemp = new double[DIM]; + std::vector QCHOLTemp(DIM); Matrix B; B.reset(DIM, DIM); @@ -80,11 +81,11 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, Solver::IResu double** nullmatrx = nullptr; if (1. > Solver::MatrixDPMake(CHSKY.entry, - study.preproHydroCorrelation.annual->entry, + study.preproHydroCorrelation.annual.entry, B.entry, nullmatrx, study.areas.size(), - QCHOLTemp, + QCHOLTemp.data(), true)) { throw FatalError("TS Generator: Hydro: Invalid correlation matrix"); @@ -95,19 +96,19 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, Solver::IResu for (uint i = 0; i < DIM; i++) { - uint areaIndexI = i / 12; - auto* prepro = study.areas.byIndex[areaIndexI]->hydro.prepro; + uint areaIndexI = i / MONTHS_PER_YEAR; + auto* prepro = study.areas.byIndex[areaIndexI]->hydro.prepro.get(); auto& corre = CORRE[i]; - auto& annualCorrAreaI = (*study.preproHydroCorrelation.annual)[areaIndexI]; + auto& annualCorrAreaI = study.preproHydroCorrelation.annual[areaIndexI]; for (uint j = 0; j < DIM; j++) { - uint areaIndexJ = j / 12; - auto* preproJ = study.areas.byIndex[areaIndexJ]->hydro.prepro; + uint areaIndexJ = j / MONTHS_PER_YEAR; + auto* preproJ = study.areas.byIndex[areaIndexJ]->hydro.prepro.get(); - x = std::abs(((int)(i % 12) - (int)(j % 12)) / 2.); + x = std::abs(((int)(i % MONTHS_PER_YEAR) - (int)(j % MONTHS_PER_YEAR)) / 2.); corre[j] = annualCorrAreaI[areaIndexJ] * pow(prepro->intermonthlyCorrelation * preproJ->intermonthlyCorrelation, x); @@ -122,7 +123,7 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, Solver::IResu B.entry, nullmatrx, DIM, - QCHOLTemp, + QCHOLTemp.data(), true); if (r < 1.) { @@ -134,15 +135,13 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, Solver::IResu } } - Solver::Cholesky(CHSKY.entry, B.entry, DIM, QCHOLTemp); + Solver::Cholesky(CHSKY.entry, B.entry, DIM, QCHOLTemp.data()); B.clear(); CORRE.clear(); + QCHOLTemp.clear(); - delete[] QCHOLTemp; - QCHOLTemp = nullptr; - - double* NORM = new double[DIM]; + std::vector NORM(DIM); for (uint i = 0; i != DIM; ++i) { NORM[i] = 0.; @@ -167,7 +166,7 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, Solver::IResu } for (uint i = 0; i < DIM; ++i) { - auto& area = *(study.areas.byIndex[i / 12]); + auto& area = *(study.areas.byIndex[i / MONTHS_PER_YEAR]); auto& prepro = *area.hydro.prepro; auto& series = *area.hydro.series; auto ror = series.ror[l]; @@ -178,9 +177,8 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, Solver::IResu auto& colMaxEnergy = prepro.data[Data::PreproHydro::maximumEnergy]; auto& colPOW = prepro.data[Data::PreproHydro::powerOverWater]; - uint month = i % 12; + uint month = i % MONTHS_PER_YEAR; uint realmonth = calendar.months[month].realmonth; - uint daysPerMonth = calendar.months[month].days; assert(l < series.ror.timeSeries.width); assert(not std::isnan(colPOW[realmonth])); @@ -283,11 +281,11 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, Solver::IResu else { logs.info() << "Archiving the hydro time-series"; - const int precision = 0; - Yuni::String output; study.areas.each( - [&](const Data::Area& area) + [&study, ¤tYear, &writer, &progression](const Data::Area& area) { + const int precision = 0; + Yuni::String output; study.buffer.clear() << "ts-generator" << SEP << "hydro" << SEP << "mc-" << currentYear << SEP << area.id; @@ -309,8 +307,6 @@ bool GenerateHydroTimeSeries(Data::Study& study, uint currentYear, Solver::IResu } } - delete[] NORM; - return true; } diff --git a/src/solver/ts-generator/include/antares/solver/ts-generator/generator.h b/src/solver/ts-generator/include/antares/solver/ts-generator/generator.h index 77e09b9b79..5ffea85100 100644 --- a/src/solver/ts-generator/include/antares/solver/ts-generator/generator.h +++ b/src/solver/ts-generator/include/antares/solver/ts-generator/generator.h @@ -24,22 +24,60 @@ #include #include -#include #include #include #include #include -#include #include "xcast/xcast.h" +namespace fs = std::filesystem; +using LinkPair = std::pair; +using LinkPairs = std::vector; + namespace Antares::TSGenerator { + +struct StudyParamsForLinkTS +{ + unsigned int nbLinkTStoGenerate = 1; + bool derated = false; + // gp : we will have a problem with that if seed-tsgen-links not set in + // gp : generaldata.ini. In that case, our default value is wrong. + MersenneTwister random; +}; + +struct LinkTSgenerationParams +{ + LinkPair namesPair; + + unsigned unitCount = 1; + double nominalCapacity = 0; + + double forcedVolatility = 0.; + double plannedVolatility = 0.; + + Data::StatisticalLaw forcedLaw = Data::LawUniform; + Data::StatisticalLaw plannedLaw = Data::LawUniform; + + std::unique_ptr prepro; + + Matrix<> modulationCapacityDirect; + Matrix<> modulationCapacityIndirect; + + bool forceNoGeneration = false; + bool hasValidData = true; +}; + class AvailabilityTSGeneratorData { public: explicit AvailabilityTSGeneratorData(Data::ThermalCluster*); + AvailabilityTSGeneratorData(LinkTSgenerationParams&, + Matrix<>& modulation, + const std::string& name); + const unsigned& unitCount; const double& nominalCapacity; @@ -51,13 +89,13 @@ class AvailabilityTSGeneratorData Data::PreproAvailability* prepro; - Matrix<>& series; - Matrix<>::ColumnType& modulationCapacity; const std::string& name; }; +using listOfLinks = std::vector; + void ResizeGeneratedTimeSeries(Data::AreaList& areas, Data::Parameters& params); /*! @@ -68,8 +106,14 @@ bool GenerateTimeSeries(Data::Study& study, uint year, IResultWriter& writer); bool generateThermalTimeSeries(Data::Study& study, const std::vector& clusters, - Solver::IResultWriter& writer, - const std::string& savePath); + MersenneTwister& thermalRandom); + +void writeThermalTimeSeries(const std::vector& clusters, + const fs::path& savePath); + +bool generateLinkTimeSeries(std::vector& links, + StudyParamsForLinkTS&, + const fs::path& savePath); std::vector getAllClustersToGen(const Data::AreaList& areas, bool globalThermalTSgeneration); diff --git a/src/solver/ts-generator/include/antares/solver/ts-generator/generator.hxx b/src/solver/ts-generator/include/antares/solver/ts-generator/generator.hxx index 6596a4f7ab..7455c1accc 100644 --- a/src/solver/ts-generator/include/antares/solver/ts-generator/generator.hxx +++ b/src/solver/ts-generator/include/antares/solver/ts-generator/generator.hxx @@ -58,16 +58,16 @@ bool GenerateTimeSeries(Data::Study& study, uint year, IResultWriter& writer) switch (T) { case Data::timeSeriesLoad: - xcast->random = &(study.runtime->random[Data::seedTsGenLoad]); + xcast->random = &(study.runtime.random[Data::seedTsGenLoad]); break; case Data::timeSeriesSolar: - xcast->random = &(study.runtime->random[Data::seedTsGenSolar]); + xcast->random = &(study.runtime.random[Data::seedTsGenSolar]); break; case Data::timeSeriesWind: - xcast->random = &(study.runtime->random[Data::seedTsGenWind]); + xcast->random = &(study.runtime.random[Data::seedTsGenWind]); break; case Data::timeSeriesHydro: - xcast->random = &(study.runtime->random[Data::seedTsGenHydro]); + xcast->random = &(study.runtime.random[Data::seedTsGenHydro]); break; default: xcast->random = nullptr; diff --git a/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h b/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h index cc02a50619..4d93f56f8a 100644 --- a/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h +++ b/src/solver/ts-generator/include/antares/solver/ts-generator/prepro.h @@ -114,7 +114,6 @@ class PreproAvailability YString id; unsigned int unitCount; }; // class PreproAvailability - } // namespace Antares::Data #endif // __ANTARES_LIBS_STUDY_PARTS_THERMAL_PREPRO_HXX__ diff --git a/src/solver/ts-generator/include/antares/solver/ts-generator/xcast/studydata.h b/src/solver/ts-generator/include/antares/solver/ts-generator/xcast/studydata.h index 81c42be09a..1ff51a068d 100644 --- a/src/solver/ts-generator/include/antares/solver/ts-generator/xcast/studydata.h +++ b/src/solver/ts-generator/include/antares/solver/ts-generator/xcast/studydata.h @@ -40,7 +40,7 @@ class StudyData final /*! ** \brief Destructor */ - ~StudyData(); + ~StudyData() = default; //@} /*! @@ -77,7 +77,7 @@ class StudyData final //! List of all areas (sub-set of the complete list) Data::Area::Vector localareas; //! Correlation coefficients for each month - const Matrix* correlation[12]; + std::array, 12> correlation; /*! ** \brief Correlation mode (monthly / annual) ** diff --git a/src/solver/ts-generator/include/antares/solver/ts-generator/xcast/xcast.h b/src/solver/ts-generator/include/antares/solver/ts-generator/xcast/xcast.h index 55bb128e85..34b588b972 100644 --- a/src/solver/ts-generator/include/antares/solver/ts-generator/xcast/xcast.h +++ b/src/solver/ts-generator/include/antares/solver/ts-generator/xcast/xcast.h @@ -74,7 +74,7 @@ class XCast final: private Yuni::NonCopyable /*! ** \brief Destructor */ - ~XCast(); + ~XCast() = default; //@} //! \name Loading @@ -105,7 +105,6 @@ class XCast final: private Yuni::NonCopyable private: void allocateTemporaryData(); - void destroyTemporaryData(); template void updateMissingCoefficients(PredicateT& predicate); @@ -180,7 +179,7 @@ class XCast final: private Yuni::NonCopyable //! The correlation matrix for the current month const Matrix* pCorrMonth; - bool pNeverInitialized; + bool pNeverInitialized = true; uint Nombre_points_intermediaire; //! True when starting a new month (some data may have to be reinitialized) @@ -192,57 +191,58 @@ class XCast final: private Yuni::NonCopyable uint pNDPMatrixCount; uint pLevellingCount; - bool pAccuracyOnCorrelation; + bool pAccuracyOnCorrelation = false; bool All_normal; // all processes are Normal - float* A; // les variables de A à CO sont des vues de ALPH à CORR pour un mois particulier - float* B; - float* G; - float* D; - int* M; - float* T; - Data::XCast::Distribution* L; - bool* BO; - float* MA; - float* MI; - float** FO; // contrainte : FO >=0 + // les variables de A à CO sont des vues de ALPH à CORR pour un mois particulier + std::vector A; + std::vector B; + std::vector G; + std::vector D; + std::vector M; + std::vector T; + std::vector L; + std::vector BO; + std::vector MA; + std::vector MI; + std::vector> FO; // contrainte : FO >=0 float STEP; float SQST; - float* POSI; - float** CORR; - float* MAXI; - float* MINI; - float* Presque_maxi; - float* Presque_mini; - float* ESPE; - float* STDE; - float** LISS; - float** DATL; - - float* DIFF; - float* TREN; - float* WIEN; - float* BROW; - - float* BASI; // used only if all processes are Normal - float* ALPH; // used only if all processes are Normal - float* BETA; // used only if all processes are Normal - - float** Triangle_reference; - float** Triangle_courant; - float** Carre_reference; - float** Carre_courant; - - float* D_COPIE; - - float** DATA; + std::vector POSI; + std::vector> CORR; + std::vector MAXI; + std::vector MINI; + std::vector Presque_maxi; + std::vector Presque_mini; + std::vector ESPE; + std::vector STDE; + std::vector> LISS; + std::vector> DATL; + + std::vector DIFF; + std::vector TREN; + std::vector WIEN; + std::vector BROW; + + std::vector BASI; // used only if all processes are Normal + std::vector ALPH; // used only if all processes are Normal + std::vector BETA; // used only if all processes are Normal + + std::vector> Triangle_reference; + std::vector> Triangle_courant; + std::vector> Carre_reference; + std::vector> Carre_courant; + + std::vector D_COPIE; + + std::vector> DATA; // cholesky temporary data - float* pQCHOLTotal; + std::vector pQCHOLTotal; //! - bool* pUseConversion; + std::vector pUseConversion; //! Name of the current timeseries Yuni::CString<32, false> pTSName; diff --git a/src/solver/ts-generator/xcast/core.cpp b/src/solver/ts-generator/xcast/core.cpp index a3d373e2c1..1eab73d534 100644 --- a/src/solver/ts-generator/xcast/core.cpp +++ b/src/solver/ts-generator/xcast/core.cpp @@ -93,7 +93,7 @@ bool XCast::generateValuesForTheCurrentDay() // si les parametres ont change on reinitialise certaines variables intermediaires if (pNewMonth) { - if (Cholesky(Triangle_courant, pCorrMonth->entry, processCount, pQCHOLTotal)) + if (Cholesky(Triangle_courant, pCorrMonth->entry, processCount, pQCHOLTotal.data())) { // C n'est pas sdp, mais peut-etre proche de sdp // on tente un abattement de 0.999 @@ -107,7 +107,10 @@ bool XCast::generateValuesForTheCurrentDay() } } - if (Cholesky(Triangle_courant, pCorrMonth->entry, processCount, pQCHOLTotal)) + if (Cholesky(Triangle_courant, + pCorrMonth->entry, + processCount, + pQCHOLTotal.data())) { // la matrice C n'est pas admissible, on abandonne logs.error() << "TS " << pTSName << " generator: invalid correlation matrix"; @@ -227,7 +230,7 @@ bool XCast::generateValuesForTheCurrentDay() Carre_reference, pCorrMonth->entry, processCount, - pQCHOLTotal); + pQCHOLTotal.data()); if (shrink == -1.f) { // sortie impossible car on a v�rifi� que C est d.p @@ -414,7 +417,7 @@ bool XCast::generateValuesForTheCurrentDay() for (uint s = 0; s != processCount; ++s) { - float* corr_s = CORR[s]; + auto& corr_s = CORR[s]; auto& userMonthlyCorr = pCorrMonth->column(s); for (uint t = 0; t < s; ++t) { @@ -453,7 +456,7 @@ bool XCast::generateValuesForTheCurrentDay() Carre_courant, Carre_reference, processCount, - pQCHOLTotal); + pQCHOLTotal.data()); if (shrink <= 1.f) { if (shrink == -1.f) diff --git a/src/solver/ts-generator/xcast/math.cpp b/src/solver/ts-generator/xcast/math.cpp index 0205c170a0..e9d34559ac 100644 --- a/src/solver/ts-generator/xcast/math.cpp +++ b/src/solver/ts-generator/xcast/math.cpp @@ -30,7 +30,7 @@ namespace XCast { void XCast::normal(float& x, float& y) { - assert(random != NULL); + assert(random); double z; double xd; diff --git a/src/solver/ts-generator/xcast/studydata.cpp b/src/solver/ts-generator/xcast/studydata.cpp index 217f61fe14..9cf7e641ba 100644 --- a/src/solver/ts-generator/xcast/studydata.cpp +++ b/src/solver/ts-generator/xcast/studydata.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "antares/solver/ts-generator/xcast/studydata.h" @@ -32,32 +32,6 @@ namespace Antares::TSGenerator::XCast StudyData::StudyData(): mode(Data::Correlation::modeNone) { - for (uint realmonth = 0; realmonth != 12; ++realmonth) - { - correlation[realmonth] = nullptr; - } -} - -StudyData::~StudyData() -{ - switch (mode) - { - case Data::Correlation::modeMonthly: - { - for (uint realmonth = 0; realmonth != 12; ++realmonth) - { - delete correlation[realmonth]; - } - break; - } - case Data::Correlation::modeAnnual: - { - delete correlation[0]; - break; - } - case Data::Correlation::modeNone: - break; - } } void StudyData::prepareMatrix(Matrix& m, const Matrix& source) const @@ -92,12 +66,9 @@ void StudyData::reloadDataFromAreaList(const Data::Correlation& originalCorrelat { case Data::Correlation::modeAnnual: { - auto* m = new Matrix(); - prepareMatrix(*m, *(originalCorrelation.annual)); - for (uint realmonth = 0; realmonth != 12; ++realmonth) { - correlation[realmonth] = m; + prepareMatrix(correlation[realmonth], originalCorrelation.annual); } break; } @@ -105,9 +76,7 @@ void StudyData::reloadDataFromAreaList(const Data::Correlation& originalCorrelat { for (uint realmonth = 0; realmonth != 12; ++realmonth) { - auto* m = new Matrix(); - correlation[realmonth] = m; - prepareMatrix(*m, originalCorrelation.monthly[realmonth]); + prepareMatrix(correlation[realmonth], originalCorrelation.monthly[realmonth]); } break; } @@ -115,13 +84,6 @@ void StudyData::reloadDataFromAreaList(const Data::Correlation& originalCorrelat break; } } - else - { - for (uint realmonth = 0; realmonth != 12; ++realmonth) - { - correlation[realmonth] = nullptr; - } - } } } // namespace Antares::TSGenerator::XCast diff --git a/src/solver/ts-generator/xcast/xcast.cpp b/src/solver/ts-generator/xcast/xcast.cpp index feb8412f49..2c8a391a22 100644 --- a/src/solver/ts-generator/xcast/xcast.cpp +++ b/src/solver/ts-generator/xcast/xcast.cpp @@ -52,17 +52,10 @@ enum XCast::XCast(Data::Study& study, Data::TimeSeriesType ts, IResultWriter& writer): study(study), timeSeriesType(ts), - pNeverInitialized(true), - pAccuracyOnCorrelation(false), pWriter(writer) { } -XCast::~XCast() -{ - destroyTemporaryData(); -} - template void XCast::exportTimeSeriesToTheOutput(Progression::Task& progression, PredicateT& predicate) { @@ -86,7 +79,7 @@ void XCast::exportTimeSeriesToTheOutput(Progression::Task& progression, Predicat filename.reserve(output.size() + 80); study.areas.each( - [&](Data::Area& area) + [this, &filename, &progression, &predicate, &output](Data::Area& area) { filename.clear() << output << SEP << area.id << ".txt"; std::string buffer; @@ -114,8 +107,6 @@ void XCast::applyTransferFunction(PredicateT& predicate) float a[maxPoints]; float b[maxPoints]; - float* dailyResults; - const uint processCount = (uint)pData.localareas.size(); for (uint s = 0; s != processCount; ++s) @@ -145,7 +136,7 @@ void XCast::applyTransferFunction(PredicateT& predicate) b[i] = (p0[y] * p1[x] - p1[y] * p0[x]) / (p1[x] - p0[x]); } - dailyResults = DATA[s]; + auto& dailyResults = DATA[s]; for (h = 0; h != HOURS_PER_DAY; ++h) { for (i = 0; i != tf.width; ++i) @@ -200,162 +191,64 @@ void XCast::updateMissingCoefficients(PredicateT& predicate) } } -namespace -{ -template -class Allocator -{ -public: - Allocator(): - allocated(0) - { - } - - ~Allocator() - { - logs.debug() << " allocated " << (allocated / 1024) << "Ko"; - } - - template - inline T* allocate(const size_t s) - { - allocated += sizeof(T) * s; - return new T[s]; - } - -public: - size_t allocated; -}; - -template<> -class Allocator<0> -{ -public: - template - inline T* allocate(const size_t s) const - { - return new T[s]; - } -}; - -} // namespace - void XCast::allocateTemporaryData() { uint p = (uint)pData.localareas.size(); - Allocator m; - - A = m.allocate(p); - B = m.allocate(p); - G = m.allocate(p); - D = m.allocate(p); - M = m.allocate(p); - T = m.allocate(p); - BO = m.allocate(p); - MA = m.allocate(p); - MI = m.allocate(p); - L = m.allocate(p); - POSI = m.allocate(p); - MAXI = m.allocate(p); - MINI = m.allocate(p); - ESPE = m.allocate(p); - STDE = m.allocate(p); - DIFF = m.allocate(p); - TREN = m.allocate(p); - WIEN = m.allocate(p + 1); - BROW = m.allocate(p); - - BASI = m.allocate(p); - ALPH = m.allocate(p); - BETA = m.allocate(p); - - D_COPIE = m.allocate(p); - - pUseConversion = m.allocate(p); - - Presque_maxi = m.allocate(p); - Presque_mini = m.allocate(p); - pQCHOLTotal = m.allocate(p); - - CORR = m.allocate(p); - Triangle_reference = m.allocate(p); - Triangle_courant = m.allocate(p); - FO = m.allocate(p); - LISS = m.allocate(p); - DATL = m.allocate(p); - DATA = m.allocate(p); - Carre_courant = m.allocate(p); - Carre_reference = m.allocate(p); + A.resize(p); + B.resize(p); + G.resize(p); + D.resize(p); + M.resize(p); + T.resize(p); + BO.resize(p); + MA.resize(p); + MI.resize(p); + L.resize(p); + POSI.resize(p); + MAXI.resize(p); + MINI.resize(p); + ESPE.resize(p); + STDE.resize(p); + DIFF.resize(p); + TREN.resize(p); + WIEN.resize(p + 1); + BROW.resize(p); + + BASI.resize(p); + ALPH.resize(p); + BETA.resize(p); + + D_COPIE.resize(p); + + pUseConversion.resize(p); + + Presque_maxi.resize(p); + Presque_mini.resize(p); + pQCHOLTotal.resize(p); + + CORR.resize(p); + Triangle_reference.resize(p); + Triangle_courant.resize(p); + FO.resize(p); + LISS.resize(p); + DATL.resize(p); + DATA.resize(p); + Carre_courant.resize(p); + Carre_reference.resize(p); for (uint i = 0; i != p; ++i) { - Triangle_reference[i] = m.allocate(p); - Triangle_courant[i] = m.allocate(p); - Carre_courant[i] = m.allocate(p); - Carre_reference[i] = m.allocate(p); - - CORR[i] = m.allocate(p); - FO[i] = m.allocate(24); - LISS[i] = m.allocate(24); - DATL[i] = m.allocate(24); - DATA[i] = m.allocate(24); - } -} - -void XCast::destroyTemporaryData() -{ - if (!pNeverInitialized) - { - uint p = (uint)pData.localareas.size(); - for (uint i = 0; i != p; ++i) - { - delete[] CORR[i]; - delete[] FO[i]; - delete[] LISS[i]; - delete[] DATL[i]; - delete[] Triangle_reference[i]; - delete[] Triangle_courant[i]; - delete[] DATA[i]; - delete[] Carre_courant[i]; - delete[] Carre_reference[i]; - } - delete[] Carre_courant; - delete[] Carre_reference; - delete[] D_COPIE; - delete[] DATA; - delete[] Triangle_reference; - delete[] Triangle_courant; - delete[] LISS; - delete[] DATL; - delete[] CORR; - delete[] FO; - delete[] A; - delete[] B; - delete[] G; - delete[] D; - delete[] M; - delete[] T; - delete[] L; - delete[] BO; - delete[] MA; - delete[] MI; - delete[] POSI; - delete[] MAXI; - delete[] MINI; - delete[] Presque_maxi; - delete[] Presque_mini; - delete[] ESPE; - delete[] STDE; - delete[] DIFF; - delete[] TREN; - delete[] WIEN; - delete[] BROW; - delete[] BASI; - delete[] ALPH; - delete[] BETA; - delete[] pQCHOLTotal; - delete[] pUseConversion; + Triangle_reference[i].resize(p); + Triangle_courant[i].resize(p); + Carre_courant[i].resize(p); + Carre_reference[i].resize(p); + + CORR[i].resize(p); + FO[i].resize(24); + LISS[i].resize(24); + DATL[i].resize(24); + DATA[i].resize(24); } } @@ -432,7 +325,7 @@ bool XCast::runWithPredicate(PredicateT& predicate, Progression::Task& progressi pNewMonth = true; - pCorrMonth = pData.correlation[realmonth]; + pCorrMonth = &pData.correlation[realmonth]; for (uint s = 0; s != processCount; ++s) { @@ -476,7 +369,7 @@ bool XCast::runWithPredicate(PredicateT& predicate, Progression::Task& progressi MA[s] = +std::numeric_limits::max(); } } - memcpy(FO[s], xcastdata.K[realmonth], sizeof(float) * HOURS_PER_DAY); + memcpy(FO[s].data(), xcastdata.K[realmonth], sizeof(float) * HOURS_PER_DAY); } uint nbDaysPerMonth = study.calendar.months[month].days; @@ -491,7 +384,7 @@ bool XCast::runWithPredicate(PredicateT& predicate, Progression::Task& progressi for (uint s = 0; s != processCount; ++s) { - float* dailyResults = DATA[s]; + auto& dailyResults = DATA[s]; for (uint h = 0; h != HOURS_PER_DAY; ++h) { @@ -512,7 +405,7 @@ bool XCast::runWithPredicate(PredicateT& predicate, Progression::Task& progressi } auto& column = srcData.translation[0]; - float* dailyResults = DATA[s]; + auto& dailyResults = DATA[s]; assert(hourInTheYear + HOURS_PER_DAY <= srcData.translation.height && "Bound checking"); @@ -529,7 +422,7 @@ bool XCast::runWithPredicate(PredicateT& predicate, Progression::Task& progressi for (uint s = 0; s != processCount; ++s) { - float* dailyResults = DATA[s]; + auto& dailyResults = DATA[s]; for (uint h = 0; h != HOURS_PER_DAY; ++h) { @@ -548,7 +441,7 @@ bool XCast::runWithPredicate(PredicateT& predicate, Progression::Task& progressi auto& series = predicate.matrix(currentArea); assert(tsIndex < series.width); auto& column = series.column(tsIndex); - float* dailyResults = DATA[s]; + auto& dailyResults = DATA[s]; for (uint h = 0; h != HOURS_PER_DAY; ++h) { @@ -593,7 +486,8 @@ bool XCast::runWithPredicate(PredicateT& predicate, Progression::Task& progressi if (study.parameters.derated) { - study.areas.each([&](Data::Area& area) { predicate.matrix(area).averageTimeseries(); }); + study.areas.each([&predicate](Data::Area& area) + { predicate.matrix(area).averageTimeseries(); }); } if (study.parameters.timeSeriesToArchive & timeSeriesType) diff --git a/src/solver/utils/CMakeLists.txt b/src/solver/utils/CMakeLists.txt index e5ad63c05e..16cf2a96e5 100644 --- a/src/solver/utils/CMakeLists.txt +++ b/src/solver/utils/CMakeLists.txt @@ -35,7 +35,6 @@ target_link_libraries(utils Antares::result_writer #ortools_utils.h Antares::optimization-options antares-core #enum.h - model_antares #opt_period_string_generator.h -> antares/solver/optimisation/opt_period_string_generator_base.h ) target_include_directories(utils diff --git a/src/solver/utils/filename.cpp b/src/solver/utils/filename.cpp index 4e8b9e0482..cc71083350 100644 --- a/src/solver/utils/filename.cpp +++ b/src/solver/utils/filename.cpp @@ -22,10 +22,6 @@ #include -#include "antares/solver/optimisation/opt_period_string_generator_base.h" - -#include "include/antares/solver/utils/opt_period_string_generator.h" - // ------------------------------------ // Optimization period factory // ------------------------------------ diff --git a/src/solver/utils/include/antares/solver/utils/filename.h b/src/solver/utils/include/antares/solver/utils/filename.h index 0ce354bfab..472d8f8477 100644 --- a/src/solver/utils/include/antares/solver/utils/filename.h +++ b/src/solver/utils/include/antares/solver/utils/filename.h @@ -23,7 +23,7 @@ #include #include -#include "antares/solver/optimisation/opt_period_string_generator_base.h" +#include "opt_period_string_generator.h" std::shared_ptr createOptPeriodAsString(bool isOptimizationWeekly, unsigned int day, diff --git a/src/solver/utils/include/antares/solver/utils/name_translator.h b/src/solver/utils/include/antares/solver/utils/name_translator.h index e7a54b3614..5612e30c76 100644 --- a/src/solver/utils/include/antares/solver/utils/name_translator.h +++ b/src/solver/utils/include/antares/solver/utils/name_translator.h @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #pragma once #include diff --git a/src/solver/utils/include/antares/solver/utils/opt_period_string_generator.h b/src/solver/utils/include/antares/solver/utils/opt_period_string_generator.h index 36b5630211..f19a65bcfa 100644 --- a/src/solver/utils/include/antares/solver/utils/opt_period_string_generator.h +++ b/src/solver/utils/include/antares/solver/utils/opt_period_string_generator.h @@ -19,6 +19,7 @@ ** along with Antares_Simulator. If not, see . */ #pragma once +#include /* MPS and criterion generated files wear the same time interval sequence in their names. @@ -35,7 +36,12 @@ called. */ -#include "antares/solver/optimisation/opt_period_string_generator_base.h" +class OptPeriodStringGenerator +{ +public: + virtual std::string to_string() const = 0; + virtual ~OptPeriodStringGenerator() = default; +}; // ------------------------------------ // Daily optimization diff --git a/src/solver/utils/ortools_utils.cpp b/src/solver/utils/ortools_utils.cpp index 1f2f5e4169..2cc81b80fa 100644 --- a/src/solver/utils/ortools_utils.cpp +++ b/src/solver/utils/ortools_utils.cpp @@ -56,10 +56,9 @@ static void checkSetSolverSpecificParameters(bool status, } } -static void TuneSolverSpecificOptions( - MPSolver* solver, - const std::string& solverName, - const std::string& solverParameters) +static void TuneSolverSpecificOptions(MPSolver* solver, + const std::string& solverName, + const std::string& solverParameters) { if (!solver) { @@ -135,7 +134,6 @@ MPSolver* ProblemSimplexeNommeConverter::Convert() return solver; } - void ProblemSimplexeNommeConverter::CopyMatrix(const MPSolver* solver) const { auto variables = solver->variables(); diff --git a/src/solver/variable/CMakeLists.txt b/src/solver/variable/CMakeLists.txt index 58009ba7b4..5022d5b542 100644 --- a/src/solver/variable/CMakeLists.txt +++ b/src/solver/variable/CMakeLists.txt @@ -16,7 +16,6 @@ set(SRC_VARIABLE include/antares/solver/variable/setofareas.hxx include/antares/solver/variable/bindConstraints.h include/antares/solver/variable/bindConstraints.hxx - include/antares/solver/variable/constants.h include/antares/solver/variable/categories.h include/antares/solver/variable/surveyresults.h include/antares/solver/variable/surveyresults/reportbuilder.hxx @@ -99,9 +98,9 @@ set(SRC_VARIABLE_ECONOMY include/antares/solver/variable/economy/STStorageLevelsByCluster.h include/antares/solver/variable/economy/STStorageCashFlowByCluster.h include/antares/solver/variable/economy/unsupliedEnergy.h + include/antares/solver/variable/economy/unsupliedEnergyCsr.h include/antares/solver/variable/economy/domesticUnsuppliedEnergy.h include/antares/solver/variable/economy/localMatchingRuleViolations.h - include/antares/solver/variable/economy/spilledEnergyAfterCSR.h include/antares/solver/variable/economy/dtgMarginAfterCsr.h include/antares/solver/variable/economy/spilledEnergy.h include/antares/solver/variable/economy/dispatchableGeneration.h @@ -183,4 +182,4 @@ target_link_libraries(antares-solver-variable-info install(DIRECTORY include/antares DESTINATION "include" -) \ No newline at end of file +) diff --git a/src/solver/variable/include/antares/solver/variable/adequacy/overallCost.h b/src/solver/variable/include/antares/solver/variable/adequacy/overallCost.h index f730a3d865..3bdcee903b 100644 --- a/src/solver/variable/include/antares/solver/variable/adequacy/overallCost.h +++ b/src/solver/variable/include/antares/solver/variable/adequacy/overallCost.h @@ -194,7 +194,7 @@ class OverallCost: public Variable::IVariable, NextT, VCardOv void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) { // Get end year calculations - for (unsigned int i = 0; i < state.study.runtime->rangeLimits.hour[Data::rangeCount]; ++i) + for (unsigned int i = 0; i < state.study.runtime.rangeLimits.hour[Data::rangeCount]; ++i) { pValuesForTheCurrentYear[numSpace][i] += state.thermalClusterOperatingCostForYear[i]; } diff --git a/src/solver/variable/include/antares/solver/variable/area.hxx b/src/solver/variable/include/antares/solver/variable/area.hxx index 4fdeb096c0..d3b34bb973 100644 --- a/src/solver/variable/include/antares/solver/variable/area.hxx +++ b/src/solver/variable/include/antares/solver/variable/area.hxx @@ -369,7 +369,7 @@ void Areas::hourForEachArea(State& state, uint numSpace) { // For each area... state.study.areas.each( - [&](Data::Area& area) + [this, &state, &numSpace](Data::Area& area) { state.area = &area; // the current area @@ -402,7 +402,7 @@ void Areas::weekForEachArea(State& state, uint numSpace) { // For each area... state.study.areas.each( - [&](Data::Area& area) + [this, &state, &numSpace](Data::Area& area) { state.area = &area; // the current area @@ -437,7 +437,7 @@ void Areas::yearEndBuild(State& state, uint year, uint numSpace) { // For each area... state.study.areas.each( - [&](Data::Area& area) + [this, &state, &year, &numSpace](Data::Area& area) { state.area = &area; // the current area diff --git a/src/solver/variable/include/antares/solver/variable/categories.h b/src/solver/variable/include/antares/solver/variable/categories.h index d14b457e76..3c2df86b22 100644 --- a/src/solver/variable/include/antares/solver/variable/categories.h +++ b/src/solver/variable/include/antares/solver/variable/categories.h @@ -21,15 +21,9 @@ #ifndef __SOLVER_VARIABLE_CATEGORIES_H__ #define __SOLVER_VARIABLE_CATEGORIES_H__ -#include "constants.h" +#include -namespace Antares -{ -namespace Solver -{ -namespace Variable -{ -namespace Category +namespace Antares::Solver::Variable::Category { namespace DataLevel { @@ -266,53 +260,6 @@ inline void PrecisionLevelToStream(StreamT& out, int precisionLevel) } } -template -struct MaxRowCount -{ - enum - { - value = 0 - }; -}; - -template<> -struct MaxRowCount -{ - enum - { - value = maxHoursInAYear - }; -}; - -template<> -struct MaxRowCount -{ - enum - { - value = maxDaysInAYear - }; -}; - -template<> -struct MaxRowCount -{ - enum - { - value = maxWeeksInAYear - }; -}; - -template<> -struct MaxRowCount -{ - enum - { - value = maxMonths - }; -}; -} // namespace Category -} // namespace Variable -} // namespace Solver -} // namespace Antares +} // namespace Antares::Solver::Variable::Category #endif // __SOLVER_VARIABLE_CATEGORIES_H__ diff --git a/src/solver/variable/include/antares/solver/variable/commons/spatial-aggregate.h b/src/solver/variable/include/antares/solver/variable/commons/spatial-aggregate.h index ea966c4977..851dbb9999 100644 --- a/src/solver/variable/include/antares/solver/variable/commons/spatial-aggregate.h +++ b/src/solver/variable/include/antares/solver/variable/commons/spatial-aggregate.h @@ -221,7 +221,7 @@ class SpatialAggregate VariableAccessorType::InitializeAndReset(pValuesForTheCurrentYear[numSpace], study); } - auto& limits = study.runtime->rangeLimits; + auto& limits = study.runtime.rangeLimits; pRatioYear = 100. / (double)limits.year[Data::rangeCount]; pRatioDay = 100. / (double)limits.day[Data::rangeCount]; diff --git a/src/solver/variable/include/antares/solver/variable/constants.h b/src/solver/variable/include/antares/solver/variable/constants.h deleted file mode 100644 index 89f9dcf70e..0000000000 --- a/src/solver/variable/include/antares/solver/variable/constants.h +++ /dev/null @@ -1,137 +0,0 @@ -/* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ -#ifndef __SOLVER_VARIABLE_CONSTANT_H__ -#define __SOLVER_VARIABLE_CONSTANT_H__ - -namespace Antares -{ -namespace Solver -{ -namespace Variable -{ -enum Constant -{ - maxHoursInAYear = 8785, - maxDaysInAYear = 7 * 53 + 1, // 366, - maxWeeksInAYear = 53, - maxHoursInADay = 24, - maxMonths = 12, - maxDaysInAWeek = 7, - maxHoursInAWeek = 24 * 7, // 168, -}; - -template -struct PrecisionToPrintfFormat -{ - static const char* Value() - { - return "%.6f"; - } -}; - -template<> -struct PrecisionToPrintfFormat<0> -{ - static const char* Value() - { - return "%.0f"; - } -}; - -template<> -struct PrecisionToPrintfFormat<1> -{ - static const char* Value() - { - return "%.1f"; - } -}; - -template<> -struct PrecisionToPrintfFormat<2> -{ - static const char* Value() - { - return "%.2f"; - } -}; - -template<> -struct PrecisionToPrintfFormat<3> -{ - static const char* Value() - { - return "%.3f"; - } -}; - -template<> -struct PrecisionToPrintfFormat<4> -{ - static const char* Value() - { - return "%.4f"; - } -}; - -template<> -struct PrecisionToPrintfFormat<5> -{ - static const char* Value() - { - return "%.5f"; - } -}; - -template -static inline void AssignPrecisionToPrintfFormat(StringT& out, uint precision) -{ - switch (precision) - { - case 0: - out.assign("%.0f", 4); - break; - case 1: - out.assign("%.1f", 4); - break; - case 2: - out.assign("%.2f", 4); - break; - case 3: - out.assign("%.3f", 4); - break; - case 4: - out.assign("%.4f", 4); - break; - case 5: - out.assign("%.5f", 4); - break; - default: - out.assign("%.6f", 4); - break; - } -} - -} // namespace Variable -} // namespace Solver -} // namespace Antares - -#endif // __SOLVER_VARIABLE_CONSTANT_H__ diff --git a/src/solver/variable/include/antares/solver/variable/economy/STSbyGroup.h b/src/solver/variable/include/antares/solver/variable/economy/STSbyGroup.h index 70adaea52a..4e3ad6ee7c 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/STSbyGroup.h +++ b/src/solver/variable/include/antares/solver/variable/economy/STSbyGroup.h @@ -341,7 +341,7 @@ class STSbyGroup: public Variable::IVariable, NextT, VCardSTSb { uint64_t r = (sizeof(IntermediateValues) * nbColumns_ + IntermediateValues::MemoryUsage()) * pNbYearsParallel; - r += sizeof(double) * nbColumns_ * maxHoursInAYear * pNbYearsParallel; + r += sizeof(double) * nbColumns_ * HOURS_PER_YEAR * pNbYearsParallel; r += AncestorType::memoryUsage(); return r; } diff --git a/src/solver/variable/include/antares/solver/variable/economy/STStorageCashFlowByCluster.h b/src/solver/variable/include/antares/solver/variable/economy/STStorageCashFlowByCluster.h index db6beb4c95..eb2eaa48b9 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/STStorageCashFlowByCluster.h +++ b/src/solver/variable/include/antares/solver/variable/economy/STStorageCashFlowByCluster.h @@ -263,7 +263,7 @@ class STstorageCashFlowByCluster: public Variable::IVariable>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VariablesPerArea; /*! @@ -203,38 +205,36 @@ typedef // Prices LMRViolations, Common::SpatialAggregate< SpilledEnergy, + // LOLD Common::SpatialAggregate< - SpilledEnergyAfterCSR, - // LOLD + LOLD, Common::SpatialAggregate< - LOLD, + LOLP, Common::SpatialAggregate< - LOLP, + AvailableDispatchGen, Common::SpatialAggregate< - AvailableDispatchGen, + DispatchableGenMargin, Common::SpatialAggregate< - DispatchableGenMargin, + DtgMarginCsr, Common::SpatialAggregate< - DtgMarginCsr, + Marge, + + // Detail Prices Common::SpatialAggregate< - Marge, + NonProportionalCost, // MBO + // 13/05/2014 + // - + // refs: + // #21 - // Detail Prices + // Number Of Dispatched Units Common::SpatialAggregate< - NonProportionalCost, // MBO - // 13/05/2014 - // - - // refs: - // #21 - - // Number Of Dispatched Units - Common::SpatialAggregate< - NbOfDispatchedUnits // MBO - // 25/02/2016 - // - - // refs: - // #55 - >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + NbOfDispatchedUnits // MBO + // 25/02/2016 + // - + // refs: + // #55 + >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> VariablesPerSetOfAreas; typedef BindingConstMarginCost< // Marginal cost for a binding constraint @@ -248,8 +248,8 @@ typedef Variable::Join< Variable::Areas, // Variables for each set of areas Variable::Join, - // Variables for each binding constraint - Variable::BindingConstraints>> + // Variables for each binding constraint + Variable::BindingConstraints>> ItemList; /*! diff --git a/src/solver/variable/include/antares/solver/variable/economy/bindingConstraints/bindingConstraintsMarginalCost.h b/src/solver/variable/include/antares/solver/variable/economy/bindingConstraints/bindingConstraintsMarginalCost.h index 6d7e02fa3e..8a1f97676f 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/bindingConstraints/bindingConstraintsMarginalCost.h +++ b/src/solver/variable/include/antares/solver/variable/economy/bindingConstraints/bindingConstraintsMarginalCost.h @@ -147,7 +147,6 @@ class BindingConstMarginCost NextType::simulationEnd(); } - void initializeFromStudy(Data::Study& study) { pNbYearsParallel = study.maxNbYearsInParallel; @@ -257,8 +256,8 @@ class BindingConstMarginCost for (int dayInTheWeek = 0; dayInTheWeek < 7; dayInTheWeek++) { pValuesForTheCurrentYear[numSpace].day[dayInTheYear] - -= state.problemeHebdo - ->ResultatsContraintesCouplantes[associatedBC_][dayInTheWeek]; + -= state.problemeHebdo + ->ResultatsContraintesCouplantes[associatedBC_][dayInTheWeek]; dayInTheYear++; } @@ -270,7 +269,7 @@ class BindingConstMarginCost { uint weekInTheYear = state.weekInTheYear; double weeklyValue = -state.problemeHebdo - ->ResultatsContraintesCouplantes[associatedBC_][0]; + ->ResultatsContraintesCouplantes[associatedBC_][0]; pValuesForTheCurrentYear[numSpace].week[weekInTheYear] = weeklyValue; diff --git a/src/solver/variable/include/antares/solver/variable/economy/links/congestionProbability.h b/src/solver/variable/include/antares/solver/variable/economy/links/congestionProbability.h index eba398bc73..f44809d927 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/links/congestionProbability.h +++ b/src/solver/variable/include/antares/solver/variable/economy/links/congestionProbability.h @@ -301,7 +301,7 @@ class CongestionProbability { for (uint i = 0; i != VCardType::columnCount; ++i) { - for (uint h = 0; h != maxHoursInAYear; ++h) + for (uint h = 0; h != HOURS_PER_YEAR; ++h) { pValuesForYearLocalReport[numSpace][i].hour[h] = (pValuesForTheCurrentYear[numSpace] [i] @@ -311,7 +311,7 @@ class CongestionProbability : 0.; } - for (uint d = 0; d != maxDaysInAYear; ++d) + for (uint d = 0; d != DAYS_PER_YEAR; ++d) { pValuesForYearLocalReport[numSpace][i].day[d] = (pValuesForTheCurrentYear[numSpace] [i] @@ -321,7 +321,7 @@ class CongestionProbability : 0.; } - for (uint w = 0; w != maxWeeksInAYear; ++w) + for (uint w = 0; w != WEEKS_PER_YEAR; ++w) { pValuesForYearLocalReport[numSpace][i].week[w] = (pValuesForTheCurrentYear[numSpace] [i] @@ -331,7 +331,7 @@ class CongestionProbability : 0.; } - for (uint m = 0; m != maxMonths; ++m) + for (uint m = 0; m != MONTHS_PER_YEAR; ++m) { pValuesForYearLocalReport[numSpace][i].month[m] = (pValuesForTheCurrentYear [numSpace][i] diff --git a/src/solver/variable/include/antares/solver/variable/economy/links/flowQuad.h b/src/solver/variable/include/antares/solver/variable/economy/links/flowQuad.h index b7d00a3fb8..b6de8329ae 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/links/flowQuad.h +++ b/src/solver/variable/include/antares/solver/variable/economy/links/flowQuad.h @@ -129,7 +129,7 @@ class FlowQuad: public Variable::IVariable, NextT, VCardFlowQuad void initializeFromStudy(Data::Study& study) { // Average on all years - pNbHours = study.runtime->rangeLimits.hour[Data::rangeEnd] + 1; + pNbHours = study.runtime.rangeLimits.hour[Data::rangeEnd] + 1; AncestorType::pResults.initializeFromStudy(study); AncestorType::pResults.reset(); diff --git a/src/solver/variable/include/antares/solver/variable/economy/nbOfDispatchedUnits.h b/src/solver/variable/include/antares/solver/variable/economy/nbOfDispatchedUnits.h index a2af682a67..173343f61f 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/nbOfDispatchedUnits.h +++ b/src/solver/variable/include/antares/solver/variable/economy/nbOfDispatchedUnits.h @@ -198,8 +198,8 @@ class NbOfDispatchedUnits void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) { // Get end year calculations - for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; - i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + for (unsigned int i = state.study.runtime.rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; ++i) { pValuesForTheCurrentYear[numSpace][i] += state.thermalClusterDispatchedUnitsCountForYear diff --git a/src/solver/variable/include/antares/solver/variable/economy/nbOfDispatchedUnitsByPlant.h b/src/solver/variable/include/antares/solver/variable/economy/nbOfDispatchedUnitsByPlant.h index 2bc519a94c..37f19ea3d6 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/nbOfDispatchedUnitsByPlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/nbOfDispatchedUnitsByPlant.h @@ -234,7 +234,7 @@ class NbOfDispatchedUnitsByPlant: public Variable::IVariablerangeLimits.hour[Data::rangeEnd]; ++i) + for (unsigned int i = 0; i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; ++i) { state.thermalClusterDispatchedUnitsCountForYear[i] += static_cast( pValuesForTheCurrentYear[numSpace][state.thermalCluster->areaWideIndex].hour[i]); @@ -247,8 +247,8 @@ class NbOfDispatchedUnitsByPlant: public Variable::IVariablerangeLimits.hour[Data::rangeBegin]; - i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + for (unsigned int i = state.study.runtime.rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; ++i) { pValuesForTheCurrentYear[numSpace][state.thermalCluster->areaWideIndex].hour[i] diff --git a/src/solver/variable/include/antares/solver/variable/economy/nonProportionalCost.h b/src/solver/variable/include/antares/solver/variable/economy/nonProportionalCost.h index be8436d29a..8d26594739 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/nonProportionalCost.h +++ b/src/solver/variable/include/antares/solver/variable/economy/nonProportionalCost.h @@ -198,8 +198,8 @@ class NonProportionalCost void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) { // Get end year calculations - for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; - i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + for (unsigned int i = state.study.runtime.rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; ++i) { pValuesForTheCurrentYear[numSpace][i] += state diff --git a/src/solver/variable/include/antares/solver/variable/economy/npCostByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/npCostByDispatchablePlant.h index b0587d51a2..79304684b3 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/npCostByDispatchablePlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/npCostByDispatchablePlant.h @@ -236,8 +236,8 @@ class NonProportionalCostByDispatchablePlant void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) { // Get end year calculations - for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; - i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + for (unsigned int i = state.study.runtime.rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; ++i) { pValuesForTheCurrentYear[numSpace][state.thermalCluster->areaWideIndex].hour[i] diff --git a/src/solver/variable/include/antares/solver/variable/economy/operatingCost.h b/src/solver/variable/include/antares/solver/variable/economy/operatingCost.h index 0df88e6711..df95f6d65c 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/operatingCost.h +++ b/src/solver/variable/include/antares/solver/variable/economy/operatingCost.h @@ -196,8 +196,8 @@ class OperatingCost: public Variable::IVariable, NextT, VCa void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) { // Get end year calculations - for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; - i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + for (unsigned int i = state.study.runtime.rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; ++i) { pValuesForTheCurrentYear[numSpace][i] += state.thermalClusterOperatingCostForYear[i]; diff --git a/src/solver/variable/include/antares/solver/variable/economy/overallCost.h b/src/solver/variable/include/antares/solver/variable/economy/overallCost.h index 43c13f6620..ccb6632e9e 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/overallCost.h +++ b/src/solver/variable/include/antares/solver/variable/economy/overallCost.h @@ -194,8 +194,8 @@ class OverallCost: public Variable::IVariable, NextT, VCardOv void yearEndBuildForEachThermalCluster(State& state, uint year, unsigned int numSpace) { // Get end year calculations - for (unsigned int i = state.study.runtime->rangeLimits.hour[Data::rangeBegin]; - i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; + for (unsigned int i = state.study.runtime.rangeLimits.hour[Data::rangeBegin]; + i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; ++i) { pValuesForTheCurrentYear[numSpace][i] += state.thermalClusterOperatingCostForYear[i]; diff --git a/src/solver/variable/include/antares/solver/variable/economy/productionByDispatchablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/productionByDispatchablePlant.h index 65d8c4ef53..b54245b644 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/productionByDispatchablePlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/productionByDispatchablePlant.h @@ -182,7 +182,7 @@ class ProductionByDispatchablePlant for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) { - pminOfTheClusterForYear[numSpace] = new double[pSize * maxHoursInAYear]; + pminOfTheClusterForYear[numSpace] = new double[pSize * HOURS_PER_YEAR]; } for (unsigned int numSpace = 0; numSpace < pNbYearsParallel; numSpace++) @@ -242,9 +242,9 @@ class ProductionByDispatchablePlant { pValuesForTheCurrentYear[numSpace][i].reset(); - for (unsigned int j = 0; j != maxHoursInAYear; ++j) + for (unsigned int j = 0; j != HOURS_PER_YEAR; ++j) { - pminOfTheClusterForYear[numSpace][i * maxHoursInAYear + j] = 0; + pminOfTheClusterForYear[numSpace][i * HOURS_PER_YEAR + j] = 0; } } // Next variable @@ -255,14 +255,14 @@ class ProductionByDispatchablePlant uint year, unsigned int numSpace) { - for (unsigned int i = 0; i <= state.study.runtime->rangeLimits.hour[Data::rangeEnd]; ++i) + for (unsigned int i = 0; i <= state.study.runtime.rangeLimits.hour[Data::rangeEnd]; ++i) { state.thermalClusterProductionForYear[i] += pValuesForTheCurrentYear [numSpace] [state.thermalCluster->areaWideIndex] .hour[i]; state.thermalClusterPMinOfTheClusterForYear[i] += pminOfTheClusterForYear - [numSpace][(state.thermalCluster->areaWideIndex * maxHoursInAYear) + i]; + [numSpace][(state.thermalCluster->areaWideIndex * HOURS_PER_YEAR) + i]; } // Next variable @@ -322,8 +322,8 @@ class ProductionByDispatchablePlant pValuesForTheCurrentYear[numSpace][cluster->areaWideIndex].hour[state.hourInTheYear] += thermal[area->index].thermalClustersProductions[cluster->areaWideIndex]; - pminOfTheClusterForYear[numSpace][(cluster->areaWideIndex * maxHoursInAYear) - + state.hourInTheYear] + pminOfTheClusterForYear[numSpace] + [(cluster->areaWideIndex * HOURS_PER_YEAR) + state.hourInTheYear] = thermal[area->index].PMinOfClusters[cluster->areaWideIndex]; } @@ -348,7 +348,7 @@ class ProductionByDispatchablePlant { uint64_t r = (sizeof(IntermediateValues) * pSize + IntermediateValues::MemoryUsage()) * pNbYearsParallel; - r += sizeof(double) * pSize * maxHoursInAYear * pNbYearsParallel; + r += sizeof(double) * pSize * HOURS_PER_YEAR * pNbYearsParallel; r += AncestorType::memoryUsage(); return r; } diff --git a/src/solver/variable/include/antares/solver/variable/economy/productionByRenewablePlant.h b/src/solver/variable/include/antares/solver/variable/economy/productionByRenewablePlant.h index 8da6244e49..82ce7b3dcf 100644 --- a/src/solver/variable/include/antares/solver/variable/economy/productionByRenewablePlant.h +++ b/src/solver/variable/include/antares/solver/variable/economy/productionByRenewablePlant.h @@ -312,7 +312,7 @@ class ProductionByRenewablePlant: public Variable::IVariable. */ -#ifndef __SOLVER_VARIABLE_ECONOMY_SpilledEnergyAfterCSR_H__ -#define __SOLVER_VARIABLE_ECONOMY_SpilledEnergyAfterCSR_H__ +#pragma once #include "antares/solver/variable/variable.h" -namespace Antares::Solver::Variable::Economy +namespace Antares { -struct VCardSpilledEnergyAfterCSR +namespace Solver +{ +namespace Variable +{ +namespace Economy +{ +struct VCardUnsupliedEnergyCSR { //! Caption static std::string Caption() { - return "SPIL. ENRG. CSR"; + return "UNSP. ENRG CSR"; } //! Unit @@ -42,8 +47,7 @@ struct VCardSpilledEnergyAfterCSR //! The short description of the variable static std::string Description() { - return "Spilled Energy After CSR Optimization (generation that cannot be satisfied) " - "after CSR optimization"; + return "Unsuplied Energy after CSR (demand that cannot be satisfied)"; } //! The expecte results @@ -55,7 +59,7 @@ struct VCardSpilledEnergyAfterCSR ResultsType; //! The VCard to look for for calculating spatial aggregates - typedef VCardSpilledEnergyAfterCSR VCardForSpatialAggregate; + typedef VCardUnsupliedEnergyCSR VCardForSpatialAggregate; //! Data Level static constexpr uint8_t categoryDataLevel = Category::DataLevel::area; @@ -87,21 +91,17 @@ struct VCardSpilledEnergyAfterCSR }; // class VCard -/*! -** \brief C02 Average value of the overrall SpilledEnergyAfterCSR emissions expected from all -** the thermal dispatchable clusters -*/ template -class SpilledEnergyAfterCSR - : public Variable::IVariable, NextT, VCardSpilledEnergyAfterCSR> +class UnsupliedEnergyCSR + : public Variable::IVariable, NextT, VCardUnsupliedEnergyCSR> { public: //! Type of the next static variable typedef NextT NextType; //! VCard - typedef VCardSpilledEnergyAfterCSR VCardType; + typedef VCardUnsupliedEnergyCSR VCardType; //! Ancestor - typedef Variable::IVariable, NextT, VCardType> AncestorType; + typedef Variable::IVariable, NextT, VCardType> AncestorType; //! List of expected results typedef typename VCardType::ResultsType ResultsType; @@ -127,7 +127,8 @@ class SpilledEnergyAfterCSR }; }; - ~SpilledEnergyAfterCSR() +public: + ~UnsupliedEnergyCSR() { delete[] pValuesForTheCurrentYear; } @@ -228,10 +229,8 @@ class SpilledEnergyAfterCSR void hourForEachArea(State& state, unsigned int numSpace) { - // Total SpilledEnergyAfterCSR emissions pValuesForTheCurrentYear[numSpace][state.hourInTheYear] - = state.hourlyResults->ValeursHorairesSpilledEnergyAfterCSR[state.hourInTheWeek]; - + = state.hourlyResults->ValeursHorairesDeDefaillancePositiveCSR[state.hourInTheWeek]; // Next variable NextType::hourForEachArea(state, numSpace); } @@ -266,8 +265,9 @@ class SpilledEnergyAfterCSR typename VCardType::IntermediateValuesType pValuesForTheCurrentYear; unsigned int pNbYearsParallel; -}; // class SpilledEnergyAfterCSR - -} // namespace Antares::Solver::Variable::Economy +}; // class UnsupliedEnergyCSR -#endif // __SOLVER_VARIABLE_ECONOMY_SpilledEnergyAfterCSR_H__ +} // namespace Economy +} // namespace Variable +} // namespace Solver +} // namespace Antares diff --git a/src/solver/variable/include/antares/solver/variable/endoflist.h b/src/solver/variable/include/antares/solver/variable/endoflist.h index 7c32c32ecb..d8cb5dd69d 100644 --- a/src/solver/variable/include/antares/solver/variable/endoflist.h +++ b/src/solver/variable/include/antares/solver/variable/endoflist.h @@ -254,7 +254,6 @@ class EndOfList static void computeSpatialAggregateWith(O&, const Data::Area*, uint numSpace) { UNUSED_VARIABLE(numSpace); - assert(false); } template diff --git a/src/solver/variable/include/antares/solver/variable/info.h b/src/solver/variable/include/antares/solver/variable/info.h index 739aeac2a6..39c6a43e42 100644 --- a/src/solver/variable/include/antares/solver/variable/info.h +++ b/src/solver/variable/include/antares/solver/variable/info.h @@ -75,7 +75,7 @@ struct VariableAccessor for (uint i = 0; i != ColumnCountT; ++i) { Antares::Memory::Stored::ReturnType array = intermediateValues[i].hour; - for (uint y = 0; y != maxHoursInAYear; ++y) + for (uint y = 0; y != HOURS_PER_YEAR; ++y) { array[y] *= v; } @@ -88,7 +88,7 @@ struct VariableAccessor for (uint i = 0; i != ColumnCountT; ++i) { Antares::Memory::Stored::ReturnType array = intermediateValues[i].hour; - for (uint y = 0; y != maxHoursInAYear; ++y) + for (uint y = 0; y != HOURS_PER_YEAR; ++y) { array[y] = std::abs(array[y]) > 0. ? 1. : 0.; } @@ -101,7 +101,7 @@ struct VariableAccessor for (uint i = 0; i != ColumnCountT; ++i) { Antares::Memory::Stored::ReturnType array = intermediateValues[i].hour; - for (uint y = 0; y != maxHoursInAYear; ++y) + for (uint y = 0; y != HOURS_PER_YEAR; ++y) { array[y] = std::abs(array[y]) > 0. ? 100. : 0.; } @@ -247,7 +247,7 @@ struct VariableAccessor = var.retrieveRawHourlyValuesForCurrentYear(i, numSpace); assert(src != NULL); - for (uint h = 0; h != maxHoursInAYear; ++h) + for (uint h = 0; h != HOURS_PER_YEAR; ++h) { out[i].hour[h] += src[h]; } @@ -263,7 +263,7 @@ struct VariableAccessor = var.retrieveRawHourlyValuesForCurrentYear(i, numSpace); assert(src != NULL); - for (uint h = 0; h != maxHoursInAYear; ++h) + for (uint h = 0; h != HOURS_PER_YEAR; ++h) { if (out[i].hour[h] < src[h]) { @@ -289,7 +289,7 @@ struct VariableAccessor for (typename Type::const_iterator i = intermediateValues.begin(); i != end; ++i) { array = (*i).hour; - for (uint y = 0; y != maxHoursInAYear; ++y) + for (uint y = 0; y != HOURS_PER_YEAR; ++y) { array[y] *= v; } @@ -304,7 +304,7 @@ struct VariableAccessor for (typename Type::const_iterator i = intermediateValues.begin(); i != end; ++i) { array = (*i).hour; - for (uint y = 0; y != maxHoursInAYear; ++y) + for (uint y = 0; y != HOURS_PER_YEAR; ++y) { array[y] = std::abs(array[y]) > 0. ? 1. : 0.; } @@ -319,7 +319,7 @@ struct VariableAccessor for (typename Type::const_iterator i = intermediateValues.begin(); i != end; ++i) { array = (*i).hour; - for (uint y = 0; y != maxHoursInAYear; ++y) + for (uint y = 0; y != HOURS_PER_YEAR; ++y) { array[y] = std::abs(array[y]) > 0. ? 100. : 0.; } @@ -516,7 +516,7 @@ struct VariableAccessor = var.retrieveRawHourlyValuesForCurrentYear(i, numSpace); assert(src != NULL); - for (uint h = 0; h != maxHoursInAYear; ++h) + for (uint h = 0; h != HOURS_PER_YEAR; ++h) { out[i].hour[h] += src[h]; } @@ -532,7 +532,7 @@ struct VariableAccessor = var.retrieveRawHourlyValuesForCurrentYear(i, numSpace); assert(src != NULL); - for (uint h = 0; h != maxHoursInAYear; ++h) + for (uint h = 0; h != HOURS_PER_YEAR; ++h) { if (out[i].hour[h] < src[h]) { @@ -553,7 +553,7 @@ struct VariableAccessor static void MultiplyHourlyResultsBy(U& intermediateValues, const double v) { assert(!std::isnan(v)); - for (uint y = 0; y != maxHoursInAYear; ++y) + for (uint y = 0; y != HOURS_PER_YEAR; ++y) { intermediateValues.hour[y] *= v; } @@ -562,7 +562,7 @@ struct VariableAccessor template static void SetTo1IfPositive(U& intermediateValues) { - for (uint y = 0; y != maxHoursInAYear; ++y) + for (uint y = 0; y != HOURS_PER_YEAR; ++y) { intermediateValues.hour[y] = std::abs(intermediateValues.hour[y]) > 0. ? 1. : 0.; } @@ -571,7 +571,7 @@ struct VariableAccessor template static void Or(U& intermediateValues) { - for (uint y = 0; y != maxHoursInAYear; ++y) + for (uint y = 0; y != HOURS_PER_YEAR; ++y) { intermediateValues.hour[y] = std::abs(intermediateValues.hour[y]) > 0. ? 100. : 0.; } @@ -683,7 +683,7 @@ struct VariableAccessor = var.retrieveRawHourlyValuesForCurrentYear(-1, numSpace); assert(src != NULL); - for (uint h = 0; h != maxHoursInAYear; ++h) + for (uint h = 0; h != HOURS_PER_YEAR; ++h) { out.hour[h] += src[h]; } @@ -696,7 +696,7 @@ struct VariableAccessor = var.retrieveRawHourlyValuesForCurrentYear(-1, numSpace); assert(src != NULL); - for (uint h = 0; h != maxHoursInAYear; ++h) + for (uint h = 0; h != HOURS_PER_YEAR; ++h) { if (out.hour[h] < src[h]) { diff --git a/src/solver/variable/include/antares/solver/variable/print.h b/src/solver/variable/include/antares/solver/variable/print.h index 9f398ab86b..5ac4b0617a 100644 --- a/src/solver/variable/include/antares/solver/variable/print.h +++ b/src/solver/variable/include/antares/solver/variable/print.h @@ -23,11 +23,7 @@ #include -namespace Antares -{ -namespace Solver -{ -namespace Variable +namespace Antares::Solver::Variable { class PrintInfosStdCout final { @@ -86,8 +82,98 @@ class PrintInfosStdCout final Yuni::String pBuffer; }; -} // namespace Variable -} // namespace Solver -} // namespace Antares +template +struct PrecisionToPrintfFormat +{ + static const char* Value() + { + return "%.6f"; + } +}; + +template<> +struct PrecisionToPrintfFormat<0> +{ + static const char* Value() + { + return "%.0f"; + } +}; + +template<> +struct PrecisionToPrintfFormat<1> +{ + static const char* Value() + { + return "%.1f"; + } +}; + +template<> +struct PrecisionToPrintfFormat<2> +{ + static const char* Value() + { + return "%.2f"; + } +}; + +template<> +struct PrecisionToPrintfFormat<3> +{ + static const char* Value() + { + return "%.3f"; + } +}; + +template<> +struct PrecisionToPrintfFormat<4> +{ + static const char* Value() + { + return "%.4f"; + } +}; + +template<> +struct PrecisionToPrintfFormat<5> +{ + static const char* Value() + { + return "%.5f"; + } +}; + +template +static inline void AssignPrecisionToPrintfFormat(StringT& out, uint precision) +{ + switch (precision) + { + case 0: + out.assign("%.0f", 4); + break; + case 1: + out.assign("%.1f", 4); + break; + case 2: + out.assign("%.2f", 4); + break; + case 3: + out.assign("%.3f", 4); + break; + case 4: + out.assign("%.4f", 4); + break; + case 5: + out.assign("%.5f", 4); + break; + default: + out.assign("%.6f", 4); + break; + } +} + +} // namespace Antares::Solver::Variable #endif // __SOLVER_VARIABLE_PRINT_H__ diff --git a/src/solver/variable/include/antares/solver/variable/setofareas.h b/src/solver/variable/include/antares/solver/variable/setofareas.h index d2444df247..1263b986f3 100644 --- a/src/solver/variable/include/antares/solver/variable/setofareas.h +++ b/src/solver/variable/include/antares/solver/variable/setofareas.h @@ -204,7 +204,7 @@ class SetsOfAreas //! Area list SetOfAreasVector pSetsOfAreas; //! Reference to the origina set - std::vector pOriginalSets; + std::vector pOriginalSets; //! An iterator for the begining of the list typename SetOfAreasVector::iterator pBegin; //! An iterator to the end of the list diff --git a/src/solver/variable/include/antares/solver/variable/state.h b/src/solver/variable/include/antares/solver/variable/state.h index 597b692d9e..eb3edda98c 100644 --- a/src/solver/variable/include/antares/solver/variable/state.h +++ b/src/solver/variable/include/antares/solver/variable/state.h @@ -32,8 +32,6 @@ #include "antares/solver/simulation/sim_structure_donnees.h" #include "antares/solver/simulation/sim_structure_probleme_economique.h" -#include "constants.h" - namespace Antares::Solver::Variable { class ThermalState @@ -115,14 +113,14 @@ class State void yearEndBuildThermalClusterCalculateStartupCosts( const uint& maxDurationON, - const std::array& ON_min, - const std::array& ON_opt, + const std::array& ON_min, + const std::array& ON_opt, const Data::ThermalCluster* currentCluster); - std::array computeEconomicallyOptimalNbClustersONforEachHour( + std::array computeEconomicallyOptimalNbClustersONforEachHour( const uint& maxDurationON, - const std::array& ON_min, - const std::array& ON_max) const; + const std::array& ON_min, + const std::array& ON_max) const; /*! ** \brief Smooth the thermal units run after resolutions @@ -182,17 +180,17 @@ class State VALEURS_DE_NTC_ET_RESISTANCES ntc; //! Thermal production for the current thermal cluster for the whole year - double thermalClusterProductionForYear[Variable::maxHoursInAYear]; + double thermalClusterProductionForYear[HOURS_PER_YEAR]; //! Number of unit dispatched for all clusters for the whole year for ucHeruistic (fast) or //! ucMILP (accurate) - uint thermalClusterDispatchedUnitsCountForYear[Variable::maxHoursInAYear]; + uint thermalClusterDispatchedUnitsCountForYear[HOURS_PER_YEAR]; //! Thermal operating cost for the current thermal cluster for the whole year - double thermalClusterOperatingCostForYear[Variable::maxHoursInAYear]; + double thermalClusterOperatingCostForYear[HOURS_PER_YEAR]; //! Thermal NP Cost for the current thermal cluster for the whole year - double thermalClusterNonProportionalCostForYear[Variable::maxHoursInAYear]; + double thermalClusterNonProportionalCostForYear[HOURS_PER_YEAR]; //! Minimum power of the cluster for the whole year - double thermalClusterPMinOfTheClusterForYear[Variable::maxHoursInAYear]; + double thermalClusterPMinOfTheClusterForYear[HOURS_PER_YEAR]; double renewableClusterProduction; diff --git a/src/solver/variable/include/antares/solver/variable/storage/average.h b/src/solver/variable/include/antares/solver/variable/storage/average.h index 0597d121b8..fbeaf16a5b 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/average.h +++ b/src/solver/variable/include/antares/solver/variable/storage/average.h @@ -100,23 +100,23 @@ struct Average: public NextT switch (precision) { case Category::hourly: - InternalExportValues(report, - Memory::RawPointer( - avgdata.hourly)); + InternalExportValues(report, + Memory::RawPointer( + avgdata.hourly)); break; case Category::daily: - InternalExportValues(report, - avgdata.daily); + InternalExportValues(report, avgdata.daily); break; case Category::weekly: - InternalExportValues(report, - avgdata.weekly); + InternalExportValues(report, + avgdata.weekly); break; case Category::monthly: - InternalExportValues(report, avgdata.monthly); + InternalExportValues(report, + avgdata.monthly); break; case Category::annual: - InternalExportValues<1, VCardT, Category::annual>(report, avgdata.year); + InternalExportValues<1, VCardT, Category::annual>(report, avgdata.year.data()); break; } } diff --git a/src/solver/variable/include/antares/solver/variable/storage/averagedata.h b/src/solver/variable/include/antares/solver/variable/storage/averagedata.h index 22de3ff8c8..132b70317d 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/averagedata.h +++ b/src/solver/variable/include/antares/solver/variable/storage/averagedata.h @@ -54,15 +54,15 @@ class AverageData uint64_t dynamicMemoryUsage() const { - return sizeof(double) * maxHoursInAYear + sizeof(double) * nbYearsCapacity; + return sizeof(double) * HOURS_PER_YEAR + sizeof(double) * nbYearsCapacity; } public: - double monthly[maxMonths]; - double weekly[maxWeeksInAYear]; - double daily[maxDaysInAYear]; + double monthly[MONTHS_PER_YEAR]; + double weekly[WEEKS_PER_YEAR]; + double daily[DAYS_PER_YEAR]; Antares::Memory::Stored::Type hourly; - double* year; + std::vector year; unsigned int nbYearsCapacity; mutable double allYears; // FIX MEEE - Remove the mutable as soon as possible std::vector yearsWeight; diff --git a/src/solver/variable/include/antares/solver/variable/storage/intermediate.h b/src/solver/variable/include/antares/solver/variable/storage/intermediate.h index 44f54918ad..e7c1757c62 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/intermediate.h +++ b/src/solver/variable/include/antares/solver/variable/storage/intermediate.h @@ -133,11 +133,11 @@ class IntermediateValues final Antares::Data::StudyRuntimeInfos* pRuntimeInfo; //! Values for each month - Type month[maxMonths]; + Type month[MONTHS_PER_YEAR]; //! Values for each week - Type week[maxWeeksInAYear]; + Type week[WEEKS_PER_YEAR]; //! Values for each day in the year - Type day[maxDaysInAYear]; + Type day[DAYS_PER_YEAR]; //! Values for each hour in the year mutable Antares::Memory::Stored::Type hour; //! Year diff --git a/src/solver/variable/include/antares/solver/variable/storage/intermediate.hxx b/src/solver/variable/include/antares/solver/variable/storage/intermediate.hxx index 132b2caba5..9dd74a235a 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/intermediate.hxx +++ b/src/solver/variable/include/antares/solver/variable/storage/intermediate.hxx @@ -21,6 +21,8 @@ #ifndef __SOLVER_VARIABLE_STORAGE_INTERMEDIATE_HXX__ #define __SOLVER_VARIABLE_STORAGE_INTERMEDIATE_HXX__ +#include + namespace Antares { namespace Solver @@ -34,7 +36,7 @@ inline IntermediateValues::~IntermediateValues() inline void IntermediateValues::reset() { - Antares::Memory::Zero(maxHoursInAYear, hour); + Antares::Memory::Zero(HOURS_PER_YEAR, hour); memset(month, 0, sizeof(month)); memset(week, 0, sizeof(week)); memset(day, 0, sizeof(day)); @@ -53,7 +55,7 @@ inline const IntermediateValues::Type& IntermediateValues::operator[]( inline uint64_t IntermediateValues::MemoryUsage() { - return +sizeof(Type) * maxHoursInAYear; + return +sizeof(Type) * HOURS_PER_YEAR; } template @@ -66,16 +68,16 @@ inline void IntermediateValues::buildAnnualSurveyReport(SurveyResults& report, switch (precision) { case Category::hourly: - internalExportAnnualValues(report, hour, false); + internalExportAnnualValues(report, hour, false); break; case Category::daily: - internalExportAnnualValues(report, day, false); + internalExportAnnualValues(report, day, false); break; case Category::weekly: - internalExportAnnualValues(report, week, false); + internalExportAnnualValues(report, week, false); break; case Category::monthly: - internalExportAnnualValues(report, month, false); + internalExportAnnualValues(report, month, false); break; case Category::annual: internalExportAnnualValues<1, VCardT>(report, &year, true); diff --git a/src/solver/variable/include/antares/solver/variable/storage/minmax-data.h b/src/solver/variable/include/antares/solver/variable/storage/minmax-data.h index c444ca73c9..27bc3e89b4 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/minmax-data.h +++ b/src/solver/variable/include/antares/solver/variable/storage/minmax-data.h @@ -21,19 +21,11 @@ #ifndef __SOLVER_VARIABLE_STORAGE_MINMAX_DATA_H__ #define __SOLVER_VARIABLE_STORAGE_MINMAX_DATA_H__ -#include -#include +#include + #include "antares/solver/variable/storage/intermediate.h" -namespace Antares -{ -namespace Solver -{ -namespace Variable -{ -namespace R -{ -namespace AllYears +namespace Antares::Solver::Variable::R::AllYears { class MinMaxData { @@ -44,17 +36,8 @@ class MinMaxData uint32_t indice; }; -public: - //! \name Constructor & Destructor - //@{ - /*! - ** \brief Default constructor - */ - MinMaxData(); - //! Destructor - ~MinMaxData(); - - void initialize(); + MinMaxData() = default; + ~MinMaxData() = default; void resetInf(); void resetSup(); @@ -62,19 +45,14 @@ class MinMaxData void mergeInf(uint year, const IntermediateValues& rhs); void mergeSup(uint year, const IntermediateValues& rhs); -public: - Data annual; - Data monthly[maxMonths]; - Data weekly[maxWeeksInAYear]; - Data daily[maxDaysInAYear]; - Antares::Memory::Stored::Type hourly; + std::vector annual{1}; + std::vector monthly{MONTHS_PER_YEAR}; + std::vector weekly{WEEKS_PER_YEAR}; + std::vector daily{DAYS_PER_YEAR}; + std::vector hourly{HOURS_PER_YEAR}; }; // class MinMaxData -} // namespace AllYears -} // namespace R -} // namespace Variable -} // namespace Solver -} // namespace Antares +} // namespace Antares::Solver::Variable::R::AllYears #endif // __SOLVER_VARIABLE_STORAGE_MINMAX_DATA_H__ diff --git a/src/solver/variable/include/antares/solver/variable/storage/minmax.h b/src/solver/variable/include/antares/solver/variable/storage/minmax.h index b9aaba7bc3..6095863374 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/minmax.h +++ b/src/solver/variable/include/antares/solver/variable/storage/minmax.h @@ -83,21 +83,28 @@ struct MinMaxBase: public NextT switch (precision) { case Category::hourly: - InternalExportIndices(report, - Memory::RawPointer(minmax.hourly), - fileLevel); + InternalExportIndices(report, + Memory::RawPointer( + minmax.hourly.data()), + fileLevel); break; case Category::daily: - InternalExportIndices(report, minmax.daily, fileLevel); + InternalExportIndices(report, + minmax.daily.data(), + fileLevel); break; case Category::weekly: - InternalExportIndices(report, minmax.weekly, fileLevel); + InternalExportIndices(report, + minmax.weekly.data(), + fileLevel); break; case Category::monthly: - InternalExportIndices(report, minmax.monthly, fileLevel); + InternalExportIndices(report, + minmax.monthly.data(), + fileLevel); break; case Category::annual: - InternalExportIndices<1, VCardT>(report, &minmax.annual, fileLevel); + InternalExportIndices<1, VCardT>(report, minmax.annual.data(), fileLevel); break; } } @@ -106,20 +113,21 @@ struct MinMaxBase: public NextT switch (precision) { case Category::hourly: - InternalExportValues(report, - Memory::RawPointer(minmax.hourly)); + InternalExportValues(report, + Memory::RawPointer( + minmax.hourly.data())); break; case Category::daily: - InternalExportValues(report, minmax.daily); + InternalExportValues(report, minmax.daily.data()); break; case Category::weekly: - InternalExportValues(report, minmax.weekly); + InternalExportValues(report, minmax.weekly.data()); break; case Category::monthly: - InternalExportValues(report, minmax.monthly); + InternalExportValues(report, minmax.monthly.data()); break; case Category::annual: - InternalExportValues<1, VCardT>(report, &minmax.annual); + InternalExportValues<1, VCardT>(report, minmax.annual.data()); break; } } @@ -137,7 +145,7 @@ struct MinMaxBase: public NextT uint64_t memoryUsage() const { - return sizeof(double) * maxHoursInAYear + NextType::memoryUsage(); + return sizeof(double) * HOURS_PER_YEAR + NextType::memoryUsage(); } template class DecoratorT> diff --git a/src/solver/variable/include/antares/solver/variable/storage/minmax.hxx b/src/solver/variable/include/antares/solver/variable/storage/minmax.hxx index de94f1d571..741e56cbba 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/minmax.hxx +++ b/src/solver/variable/include/antares/solver/variable/storage/minmax.hxx @@ -36,7 +36,6 @@ namespace AllYears template inline void MinMaxBase::initializeFromStudy(Data::Study& study) { - minmax.initialize(); // Next NextType::initializeFromStudy(study); } diff --git a/src/solver/variable/include/antares/solver/variable/storage/raw.h b/src/solver/variable/include/antares/solver/variable/storage/raw.h index be1c3d9699..fe6c444840 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/raw.h +++ b/src/solver/variable/include/antares/solver/variable/storage/raw.h @@ -104,23 +104,23 @@ struct Raw: public NextT switch (precision) { case Category::hourly: - InternalExportValues( + InternalExportValues( report, ::Antares::Memory::RawPointer(rawdata.hourly)); break; case Category::daily: - InternalExportValues(report, - rawdata.daily); + InternalExportValues(report, rawdata.daily); break; case Category::weekly: - InternalExportValues(report, - rawdata.weekly); + InternalExportValues(report, + rawdata.weekly); break; case Category::monthly: - InternalExportValues(report, rawdata.monthly); + InternalExportValues(report, + rawdata.monthly); break; case Category::annual: - InternalExportValues(report, rawdata.year); + InternalExportValues(report, rawdata.year.data()); break; } } @@ -161,7 +161,7 @@ struct Raw: public NextT uint64_t memoryUsage() const { - return +sizeof(double) * maxHoursInAYear + NextType::memoryUsage(); + return +sizeof(double) * HOURS_PER_YEAR + NextType::memoryUsage(); } template class DecoratorT> diff --git a/src/solver/variable/include/antares/solver/variable/storage/rawdata.h b/src/solver/variable/include/antares/solver/variable/storage/rawdata.h index c559dd57dc..a0c60cc89d 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/rawdata.h +++ b/src/solver/variable/include/antares/solver/variable/storage/rawdata.h @@ -56,11 +56,11 @@ class RawData void merge(unsigned int year, const IntermediateValues& rhs); public: - double monthly[maxMonths]; - double weekly[maxWeeksInAYear]; - double daily[maxDaysInAYear]; + double monthly[MONTHS_PER_YEAR]; + double weekly[WEEKS_PER_YEAR]; + double daily[DAYS_PER_YEAR]; Antares::Memory::Stored::Type hourly; - double* year; + std::vector year; mutable double allYears; unsigned int nbYearsCapacity; diff --git a/src/solver/variable/include/antares/solver/variable/storage/stdDeviation.h b/src/solver/variable/include/antares/solver/variable/storage/stdDeviation.h index a80ac39fdc..44159d9cba 100644 --- a/src/solver/variable/include/antares/solver/variable/storage/stdDeviation.h +++ b/src/solver/variable/include/antares/solver/variable/storage/stdDeviation.h @@ -77,7 +77,7 @@ struct StdDeviation: public NextT protected: void initializeFromStudy(Antares::Data::Study& study) { - Antares::Memory::Allocate(stdDeviationHourly, maxHoursInAYear); + Antares::Memory::Allocate(stdDeviationHourly, HOURS_PER_YEAR); // Next NextType::initializeFromStudy(study); @@ -88,10 +88,10 @@ struct StdDeviation: public NextT void reset() { // Reset - (void)::memset(stdDeviationMonthly, 0, sizeof(double) * maxMonths); - (void)::memset(stdDeviationWeekly, 0, sizeof(double) * maxWeeksInAYear); - (void)::memset(stdDeviationDaily, 0, sizeof(double) * maxDaysInAYear); - Antares::Memory::Zero(maxHoursInAYear, stdDeviationHourly); + (void)::memset(stdDeviationMonthly, 0, sizeof(double) * MONTHS_PER_YEAR); + (void)::memset(stdDeviationWeekly, 0, sizeof(double) * WEEKS_PER_YEAR); + (void)::memset(stdDeviationDaily, 0, sizeof(double) * DAYS_PER_YEAR); + Antares::Memory::Zero(HOURS_PER_YEAR, stdDeviationHourly); stdDeviationYear = 0.; // Next NextType::reset(); @@ -104,22 +104,22 @@ struct StdDeviation: public NextT unsigned int i; // StdDeviation value for each hour throughout all years - for (i = 0; i != maxHoursInAYear; ++i) + for (i = 0; i != HOURS_PER_YEAR; ++i) { stdDeviationHourly[i] += rhs.hour[i] * rhs.hour[i] * pRatio; } // StdDeviation value for each day throughout all years - for (i = 0; i != maxDaysInAYear; ++i) + for (i = 0; i != DAYS_PER_YEAR; ++i) { stdDeviationDaily[i] += rhs.day[i] * rhs.day[i] * pRatio; } // StdDeviation value for each week throughout all years - for (i = 0; i != maxWeeksInAYear; ++i) + for (i = 0; i != WEEKS_PER_YEAR; ++i) { stdDeviationWeekly[i] += rhs.week[i] * rhs.week[i] * pRatio; } // StdDeviation value for each month throughout all years - for (i = 0; i != maxMonths; ++i) + for (i = 0; i != MONTHS_PER_YEAR; ++i) { stdDeviationMonthly[i] += rhs.month[i] * rhs.month[i] * pRatio; } @@ -142,26 +142,27 @@ struct StdDeviation: public NextT switch (precision) { case Category::hourly: - InternalExportValues( + InternalExportValues( report, results, Memory::RawPointer(stdDeviationHourly)); break; case Category::daily: - InternalExportValues(report, - results, - stdDeviationDaily); + InternalExportValues(report, + results, + stdDeviationDaily); break; case Category::weekly: - InternalExportValues( + InternalExportValues( report, results, stdDeviationWeekly); break; case Category::monthly: - InternalExportValues(report, - results, - stdDeviationMonthly); + InternalExportValues( + report, + results, + stdDeviationMonthly); break; case Category::annual: InternalExportValues(report, @@ -180,7 +181,7 @@ struct StdDeviation: public NextT uint64_t memoryUsage() const { - return sizeof(double) * maxHoursInAYear + NextType::memoryUsage(); + return sizeof(double) * HOURS_PER_YEAR + NextType::memoryUsage(); } template class DecoratorT> @@ -194,9 +195,9 @@ struct StdDeviation: public NextT } public: - double stdDeviationMonthly[maxMonths]; - double stdDeviationWeekly[maxWeeksInAYear]; - double stdDeviationDaily[maxDaysInAYear]; + double stdDeviationMonthly[MONTHS_PER_YEAR]; + double stdDeviationWeekly[WEEKS_PER_YEAR]; + double stdDeviationDaily[DAYS_PER_YEAR]; Antares::Memory::Stored::Type stdDeviationHourly; double stdDeviationYear; diff --git a/src/solver/variable/include/antares/solver/variable/variable.h b/src/solver/variable/include/antares/solver/variable/variable.h index 536af9107f..279ba9da3d 100644 --- a/src/solver/variable/include/antares/solver/variable/variable.h +++ b/src/solver/variable/include/antares/solver/variable/variable.h @@ -30,7 +30,6 @@ #include #include "categories.h" -#include "constants.h" #include "container.h" #include "endoflist.h" #include "info.h" diff --git a/src/solver/variable/state.cpp b/src/solver/variable/state.cpp index 9318e49f21..6657a5a23b 100644 --- a/src/solver/variable/state.cpp +++ b/src/solver/variable/state.cpp @@ -230,24 +230,24 @@ void State::yearEndBuildFromThermalClusterIndex(const uint clusterAreaWideIndex) uint maxDurationON; // nombre d'heures de fonctionnement d'un groupe au delà duquel un // arrêt/redémarrage est préférable uint maxUnitNeeded = 0; - uint startHourForCurrentYear = study.runtime->rangeLimits.hour[Data::rangeBegin]; + uint startHourForCurrentYear = study.runtime.rangeLimits.hour[Data::rangeBegin]; uint endHourForCurrentYear = startHourForCurrentYear - + study.runtime->rangeLimits.hour[Data::rangeCount]; + + study.runtime.rangeLimits.hour[Data::rangeCount]; - assert(endHourForCurrentYear <= Variable::maxHoursInAYear); + assert(endHourForCurrentYear <= HOURS_PER_YEAR); // Nombre minimal de groupes en fonctionnement à l'heure h (determiné par Peff et Pnom) - std::array ON_min; + std::array ON_min; // Nombre maximal de groupes en fonctionnement à l'heure h (determine par Peff et Pmin) - std::array ON_max; + std::array ON_max; // Nombre de groupes économiquement optimal en fonctionnement à l'heure h - std::array ON_opt{}; + std::array ON_opt{}; // Get cluster properties Data::ThermalCluster* currentCluster = area->thermal.list.enabledClusterAt(clusterAreaWideIndex) .get(); - assert(endHourForCurrentYear <= Variable::maxHoursInAYear); + assert(endHourForCurrentYear <= HOURS_PER_YEAR); assert(endHourForCurrentYear <= currentCluster->series.timeSeries.height); assert(currentCluster); @@ -373,13 +373,13 @@ void State::yearEndBuildFromThermalClusterIndex(const uint clusterAreaWideIndex) void State::yearEndBuildThermalClusterCalculateStartupCosts( const uint& maxDurationON, - const std::array& ON_min, - const std::array& ON_opt, + const std::array& ON_min, + const std::array& ON_opt, const Data::ThermalCluster* currentCluster) { - uint startHourForCurrentYear = study.runtime->rangeLimits.hour[Data::rangeBegin]; + uint startHourForCurrentYear = study.runtime.rangeLimits.hour[Data::rangeBegin]; uint endHourForCurrentYear = startHourForCurrentYear - + study.runtime->rangeLimits.hour[Data::rangeCount]; + + study.runtime.rangeLimits.hour[Data::rangeCount]; for (uint hour = startHourForCurrentYear; hour < endHourForCurrentYear; ++hour) { @@ -422,18 +422,17 @@ void State::yearEndBuildThermalClusterCalculateStartupCosts( } } -std::array -State::computeEconomicallyOptimalNbClustersONforEachHour( +std::array State::computeEconomicallyOptimalNbClustersONforEachHour( const uint& maxDurationON, - const std::array& ON_min, - const std::array& ON_max) const + const std::array& ON_min, + const std::array& ON_max) const { - uint startHourForCurrentYear = study.runtime->rangeLimits.hour[Data::rangeBegin]; + uint startHourForCurrentYear = study.runtime.rangeLimits.hour[Data::rangeBegin]; uint endHourForCurrentYear = startHourForCurrentYear - + study.runtime->rangeLimits.hour[Data::rangeCount]; + + study.runtime.rangeLimits.hour[Data::rangeCount]; // Nombre de groupes économiquement optimal en fonctionnement à l'heure h - std::array ON_opt; + std::array ON_opt; uint nivmax; // valeur maximale de ON_opt[h] , progressivement réactualisée à la baisse uint nivmin; // valeur minimale de ON_opt[h] , progressivement réactualisée à la hausse diff --git a/src/solver/variable/storage/averagedata.cpp b/src/solver/variable/storage/averagedata.cpp index aceaf26dcc..fac0080bf1 100644 --- a/src/solver/variable/storage/averagedata.cpp +++ b/src/solver/variable/storage/averagedata.cpp @@ -31,7 +31,6 @@ namespace Antares::Solver::Variable::R::AllYears { AverageData::AverageData(): hourly(nullptr), - year(nullptr), nbYearsCapacity(0), allYears(0.) { @@ -40,23 +39,22 @@ AverageData::AverageData(): AverageData::~AverageData() { Antares::Memory::Release(hourly); - delete[] year; } void AverageData::reset() { - Antares::Memory::Zero(maxHoursInAYear, hourly); - (void)::memset(monthly, 0, sizeof(double) * maxMonths); - (void)::memset(weekly, 0, sizeof(double) * maxWeeksInAYear); - (void)::memset(daily, 0, sizeof(double) * maxDaysInAYear); - (void)::memset(year, 0, sizeof(double) * nbYearsCapacity); + Antares::Memory::Zero(HOURS_PER_YEAR, hourly); + (void)::memset(monthly, 0, sizeof(double) * MONTHS_PER_YEAR); + (void)::memset(weekly, 0, sizeof(double) * WEEKS_PER_YEAR); + (void)::memset(daily, 0, sizeof(double) * DAYS_PER_YEAR); + year.assign(nbYearsCapacity, 0); } void AverageData::initializeFromStudy(Data::Study& study) { - Antares::Memory::Allocate(hourly, maxHoursInAYear); - nbYearsCapacity = study.runtime->rangeLimits.year[Data::rangeEnd] + 1; - year = new double[nbYearsCapacity]; + Antares::Memory::Allocate(hourly, HOURS_PER_YEAR); + nbYearsCapacity = study.runtime.rangeLimits.year[Data::rangeEnd] + 1; + year.resize(nbYearsCapacity); yearsWeight = study.parameters.getYearsWeight(); yearsWeightSum = study.parameters.getYearsWeightSum(); @@ -70,22 +68,22 @@ void AverageData::merge(unsigned int y, const IntermediateValues& rhs) double ratio = (double)yearsWeight[y] / (double)yearsWeightSum; // Average value for each hour throughout all years - for (i = 0; i != maxHoursInAYear; ++i) + for (i = 0; i != HOURS_PER_YEAR; ++i) { hourly[i] += rhs.hour[i] * ratio; } // Average value for each day throughout all years - for (i = 0; i != maxDaysInAYear; ++i) + for (i = 0; i != DAYS_PER_YEAR; ++i) { daily[i] += rhs.day[i] * ratio; } // Average value for each week throughout all years - for (i = 0; i != maxWeeksInAYear; ++i) + for (i = 0; i != WEEKS_PER_YEAR; ++i) { weekly[i] += rhs.week[i] * ratio; } // Average value for each month throughout all years - for (i = 0; i != maxMonths; ++i) + for (i = 0; i != MONTHS_PER_YEAR; ++i) { monthly[i] += rhs.month[i] * ratio; } diff --git a/src/solver/variable/storage/intermediate.cpp b/src/solver/variable/storage/intermediate.cpp index 5fb15cc2f4..a796b9676d 100644 --- a/src/solver/variable/storage/intermediate.cpp +++ b/src/solver/variable/storage/intermediate.cpp @@ -35,18 +35,18 @@ IntermediateValues::IntermediateValues(): calendar(nullptr), year(0.) { - Antares::Memory::Allocate(hour, maxHoursInAYear); - Antares::Memory::Zero(maxHoursInAYear, hour); - (void)::memset(month, 0, sizeof(Type) * maxMonths); - (void)::memset(week, 0, sizeof(Type) * maxWeeksInAYear); - (void)::memset(day, 0, sizeof(Type) * maxDaysInAYear); + Antares::Memory::Allocate(hour, HOURS_PER_YEAR); + Antares::Memory::Zero(HOURS_PER_YEAR, hour); + (void)::memset(month, 0, sizeof(Type) * MONTHS_PER_YEAR); + (void)::memset(week, 0, sizeof(Type) * WEEKS_PER_YEAR); + (void)::memset(day, 0, sizeof(Type) * DAYS_PER_YEAR); } void IntermediateValues::initializeFromStudy(Data::Study& study) { - pRange = &study.runtime->rangeLimits; + pRange = &study.runtime.rangeLimits; calendar = &study.calendarOutput; - pRuntimeInfo = study.runtime; + pRuntimeInfo = &study.runtime; } void IntermediateValues::computeStatisticsAdequacyForTheCurrentYear() @@ -87,9 +87,9 @@ void IntermediateValues::computeStatisticsForTheCurrentYear() { double d = 0.; // One day - for (j = 0; j != maxHoursInADay; ++j) + for (j = 0; j != HOURS_PER_DAY; ++j) { - assert(indx < maxHoursInAYear); + assert(indx < HOURS_PER_YEAR); d += hour[indx]; ++indx; } @@ -98,7 +98,7 @@ void IntermediateValues::computeStatisticsForTheCurrentYear() } // weeks - for (i = 0; i != maxWeeksInAYear; ++i) + for (i = 0; i != WEEKS_PER_YEAR; ++i) { week[i] = 0.; } @@ -142,9 +142,9 @@ void IntermediateValues::computeStatisticsOrForTheCurrentYear() { day[i] = 0.; // One day - for (j = 0; j != maxHoursInADay; ++j) + for (j = 0; j != HOURS_PER_DAY; ++j) { - assert(indx < maxHoursInAYear); + assert(indx < HOURS_PER_YEAR); if (hour[indx] > 0.) { day[i] = 100.; @@ -154,7 +154,7 @@ void IntermediateValues::computeStatisticsOrForTheCurrentYear() } // weeks - for (i = 0; i != maxWeeksInAYear; ++i) + for (i = 0; i != WEEKS_PER_YEAR; ++i) { week[i] = 0.; } @@ -220,19 +220,19 @@ void IntermediateValues::computeDailyAveragesForCurrentYear() { // Compute sum of hourly values on the current day of year day_sum = 0.; - for (uint h = 0; h != maxHoursInADay; ++h) + for (uint h = 0; h != HOURS_PER_DAY; ++h) { day_sum += hour[indx]; ++indx; } - day[d] = day_sum / maxHoursInADay; + day[d] = day_sum / HOURS_PER_DAY; } } void IntermediateValues::computeWeeklyAveragesForCurrentYear() { // Re-initialization (a previous MC year could have left non-nil values) - for (int w = 0; w != maxWeeksInAYear; ++w) + for (int w = 0; w != WEEKS_PER_YEAR; ++w) { week[w] = 0.; } @@ -303,7 +303,7 @@ void IntermediateValues::computeProbabilitiesForTheCurrentYear() { d = 0.; // One day - for (j = 0; j != maxHoursInADay; ++j) + for (j = 0; j != HOURS_PER_DAY; ++j) { if (hour[indx] > 0.) { @@ -324,7 +324,7 @@ void IntermediateValues::computeProbabilitiesForTheCurrentYear() } // weeks - for (i = 0; i != maxWeeksInAYear; ++i) + for (i = 0; i != WEEKS_PER_YEAR; ++i) { week[i] = 0.; } diff --git a/src/solver/variable/storage/minmax-data.cpp b/src/solver/variable/storage/minmax-data.cpp index 7d6e3f0565..ea59610820 100644 --- a/src/solver/variable/storage/minmax-data.cpp +++ b/src/solver/variable/storage/minmax-data.cpp @@ -21,135 +21,40 @@ #include "antares/solver/variable/storage/minmax-data.h" -#include - -#include - #include "antares/solver/variable/storage/intermediate.h" -using namespace Yuni; - namespace Antares::Solver::Variable::R::AllYears { -namespace // anonymous -{ constexpr double eps = 1.e-7; -template -struct ArrayInitializer +static void initArray(bool opInferior, std::vector& array) { - static void Init(Antares::Memory::Array& array) - { - for (uint i = 0; i != Size; ++i) - { - MinMaxData::Data& data = array[i]; - data.value = DBL_MAX; // +inf - data.indice = (uint32_t)(-1); // invalid indice - } - } - - static void Init(MinMaxData::Data* array) + for (auto& data: array) { - for (uint i = 0; i != Size; ++i) - { - MinMaxData::Data& data = array[i]; - data.value = DBL_MAX; // +inf - data.indice = (uint32_t)(-1); // invalid indice - } + data.value = opInferior ? DBL_MAX : -DBL_MAX; // +inf or -inf + data.indice = (uint32_t)(-1); // invalid indice } +} -}; // class ArrayInitializer - -template -struct ArrayInitializer +static void mergeArray(bool opInferior, + unsigned year, + std::vector& results, + const double* values) { - static void Init(Antares::Memory::Array& array) - { - for (uint i = 0; i != Size; ++i) - { - // Contrary to what we could guess, DBL_MIN is not the smallest number - // you can hold in a double, but the smallest positive number you can - // hold in a double - MinMaxData::Data& data = array[i]; - data.value = -DBL_MAX; // -inf - data.indice = (uint32_t)(-1); // invalid indice - } - } - - static void Init(MinMaxData::Data* array) + for (unsigned i = 0; i != results.size(); ++i) { - for (uint i = 0; i != Size; ++i) - { - // Contrary to what we could guess, DBL_MIN is not the smallest number - // you can hold in a double, but the smallest positive number you can - // hold in a double - MinMaxData::Data& data = array[i]; - data.value = -DBL_MAX; // -inf - data.indice = (uint32_t)(-1); // invalid indice - } - } + MinMaxData::Data& data = results[i]; -}; // class ArrayInitializer - -template -struct MergeArray -{ - template - static void Do(const uint year, - Antares::Memory::Array& results, - const U& values) - { - for (uint i = 0; i != Size; ++i) + if (opInferior) { - MinMaxData::Data& data = results[i]; if (values[i] < data.value - eps) { data.value = values[i]; data.indice = year + 1; // The year is zero-based } } - } - - template - static void Do(const uint year, MinMaxData::Data* results, const U& values) - { - for (uint i = 0; i != Size; ++i) - { - if (values[i] < results[i].value - eps) - { - results[i].value = values[i]; - results[i].indice = year + 1; // The year is zero-based - } - } - } - -}; // class MergeArray - -template -struct MergeArray<0, Size> -{ - template - static void Do(const uint year, - Antares::Memory::Array& results, - const U& values) - { - for (uint i = 0; i != Size; ++i) - { - MinMaxData::Data& data = results[i]; - if (values[i] > data.value + eps) - { - data.value = values[i]; - data.indice = year + 1; // The year is zero-based - } - } - } - - template - static void Do(const uint year, MinMaxData::Data* results, const U& values) - { - for (uint i = 0; i != Size; ++i) + else { - MinMaxData::Data& data = results[i]; if (values[i] > data.value + eps) { data.value = values[i]; @@ -157,60 +62,42 @@ struct MergeArray<0, Size> } } } - -}; // class MergeArray - -} // anonymous namespace - -MinMaxData::MinMaxData(): - hourly(nullptr) -{ -} - -MinMaxData::~MinMaxData() -{ - Antares::Memory::Release(hourly); } void MinMaxData::resetInf() { - ArrayInitializer<1, true>::Init(&annual); - ArrayInitializer::Init(monthly); - ArrayInitializer::Init(weekly); - ArrayInitializer::Init(daily); - ArrayInitializer::Init(hourly); + initArray(true, annual); + initArray(true, monthly); + initArray(true, weekly); + initArray(true, daily); + initArray(true, hourly); } void MinMaxData::resetSup() { - ArrayInitializer<1, false>::Init(&annual); - ArrayInitializer::Init(monthly); - ArrayInitializer::Init(weekly); - ArrayInitializer::Init(daily); - ArrayInitializer::Init(hourly); -} - -void MinMaxData::initialize() -{ - Antares::Memory::Allocate(hourly, maxHoursInAYear); + initArray(false, annual); + initArray(false, monthly); + initArray(false, weekly); + initArray(false, daily); + initArray(false, hourly); } void MinMaxData::mergeInf(uint year, const IntermediateValues& rhs) { - MergeArray::Do(year, monthly, rhs.month); - MergeArray::Do(year, weekly, rhs.week); - MergeArray::Do(year, daily, rhs.day); - MergeArray::Do(year, hourly, rhs.hour); - MergeArray::Do(year, &annual, &rhs.year); + mergeArray(true, year, monthly, rhs.month); + mergeArray(true, year, weekly, rhs.week); + mergeArray(true, year, daily, rhs.day); + mergeArray(true, year, hourly, rhs.hour); + mergeArray(true, year, annual, &rhs.year); } void MinMaxData::mergeSup(uint year, const IntermediateValues& rhs) { - MergeArray::Do(year, monthly, rhs.month); - MergeArray::Do(year, weekly, rhs.week); - MergeArray::Do(year, daily, rhs.day); - MergeArray::Do(year, hourly, rhs.hour); - MergeArray::Do(year, &annual, &rhs.year); + mergeArray(false, year, monthly, rhs.month); + mergeArray(false, year, weekly, rhs.week); + mergeArray(false, year, daily, rhs.day); + mergeArray(false, year, hourly, rhs.hour); + mergeArray(false, year, annual, &rhs.year); } } // namespace Antares::Solver::Variable::R::AllYears diff --git a/src/solver/variable/storage/rawdata.cpp b/src/solver/variable/storage/rawdata.cpp index 117d117bb2..a1b4c2fecf 100644 --- a/src/solver/variable/storage/rawdata.cpp +++ b/src/solver/variable/storage/rawdata.cpp @@ -29,7 +29,6 @@ namespace Antares::Solver::Variable::R::AllYears { RawData::RawData(): hourly(nullptr), - year(nullptr), allYears(0.) { } @@ -37,46 +36,45 @@ RawData::RawData(): RawData::~RawData() { Antares::Memory::Release(hourly); - delete[] year; } void RawData::initializeFromStudy(const Data::Study& study) { - Antares::Memory::Allocate(hourly, maxHoursInAYear); - nbYearsCapacity = study.runtime->rangeLimits.year[Data::rangeEnd] + 1; - year = new double[nbYearsCapacity]; + Antares::Memory::Allocate(hourly, HOURS_PER_YEAR); + nbYearsCapacity = study.runtime.rangeLimits.year[Data::rangeEnd] + 1; + year.resize(nbYearsCapacity); } void RawData::reset() { // Reset - Antares::Memory::Zero(maxHoursInAYear, hourly); - (void)::memset(monthly, 0, sizeof(double) * maxMonths); - (void)::memset(weekly, 0, sizeof(double) * maxWeeksInAYear); - (void)::memset(daily, 0, sizeof(double) * maxDaysInAYear); - (void)::memset(year, 0, sizeof(double) * nbYearsCapacity); + Antares::Memory::Zero(HOURS_PER_YEAR, hourly); + (void)::memset(monthly, 0, sizeof(double) * MONTHS_PER_YEAR); + (void)::memset(weekly, 0, sizeof(double) * WEEKS_PER_YEAR); + (void)::memset(daily, 0, sizeof(double) * DAYS_PER_YEAR); + year.assign(nbYearsCapacity, 0); } void RawData::merge(unsigned int y, const IntermediateValues& rhs) { unsigned int i; // StdDeviation value for each hour throughout all years - for (i = 0; i != maxHoursInAYear; ++i) + for (i = 0; i != HOURS_PER_YEAR; ++i) { hourly[i] += rhs.hour[i]; } // StdDeviation value for each day throughout all years - for (i = 0; i != maxDaysInAYear; ++i) + for (i = 0; i != DAYS_PER_YEAR; ++i) { daily[i] += rhs.day[i]; } // StdDeviation value for each week throughout all years - for (i = 0; i != maxWeeksInAYear; ++i) + for (i = 0; i != WEEKS_PER_YEAR; ++i) { weekly[i] += rhs.week[i]; } // StdDeviation value for each month throughout all years - for (i = 0; i != maxMonths; ++i) + for (i = 0; i != MONTHS_PER_YEAR; ++i) { monthly[i] += rhs.month[i]; } diff --git a/src/solver/variable/surveyresults/surveyresults.cpp b/src/solver/variable/surveyresults/surveyresults.cpp index e05283ff5a..8df87678e4 100644 --- a/src/solver/variable/surveyresults/surveyresults.cpp +++ b/src/solver/variable/surveyresults/surveyresults.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -127,7 +128,7 @@ static void ExportGridInfosAreas(const Data::Study& study, "marginal cost\tfixed cost\tstartup cost\tmarket bid cost\tspread cost\n"; study.areas.each( - [&](const Data::Area& area) + [&out, &outLinks, &outThermal](const Data::Area& area) { out << area.id << '\t'; out << area.name << '\n'; @@ -230,17 +231,16 @@ namespace Variable { static inline uint GetRangeLimit(const Data::Study& study, int precisionLevel, int index) { - assert(study.runtime && "invalid runtime data"); switch (precisionLevel) { case Category::hourly: - return study.runtime->rangeLimits.hour[index]; + return study.runtime.rangeLimits.hour[index]; case Category::daily: - return study.runtime->rangeLimits.day[index]; + return study.runtime.rangeLimits.day[index]; case Category::weekly: - return study.runtime->rangeLimits.week[index]; + return study.runtime.rangeLimits.week[index]; case Category::monthly: - return study.runtime->rangeLimits.month[index]; + return study.runtime.rangeLimits.month[index]; case Category::annual: return 0; default: @@ -356,13 +356,10 @@ inline void SurveyResults::AppendDoubleValue(uint& error, if (std::isnan(v)) { buffer.append("\tNaN", 4); - if (++error == 1) + // We should disabled errors on NaN if the quadratic optimization has failed + if (++error == 1 && !data.study.runtime.quadraticOptimizationHasFailed) { - // We should disabled errors on NaN if the quadratic optimization has failed - if (not data.study.runtime->quadraticOptimizationHasFailed) - { - logs.error() << "'NaN' value detected"; - } + logs.error() << "'NaN' value detected"; } } else @@ -533,8 +530,8 @@ SurveyResults::SurveyResults(const Data::Study& s, const String& o, IResultWrite values = new ValueType[maxVariables]; for (uint i = 0; i != maxVariables; ++i) { - values[i] = new double[maxHoursInAYear]; - memset(values[i], 0, sizeof(double) * maxHoursInAYear); + values[i] = new double[HOURS_PER_YEAR]; + memset(values[i], 0, sizeof(double) * HOURS_PER_YEAR); } // captions @@ -607,7 +604,7 @@ void SurveyResults::exportDigestAllYears(std::string& buffer) { // Main Header { - const unsigned int nbLinks = data.study.runtime->interconnectionsCount(); + const unsigned int nbLinks = data.study.runtime.interconnectionsCount(); buffer.append("\tdigest\n\tVARIABLES\tAREAS\tLINKS\n") .append("\t") .append(std::to_string(data.columnIndex)) @@ -638,7 +635,7 @@ void SurveyResults::exportDigestAllYears(std::string& buffer) for (auto j = data.rowCaptions.begin(); j != end; ++j, ++y) { // asserts - assert(y < maxHoursInAYear); + assert(y < HOURS_PER_YEAR); buffer.append("\t").append(j->c_str()); @@ -646,7 +643,7 @@ void SurveyResults::exportDigestAllYears(std::string& buffer) for (uint i = 0; i != data.columnIndex; ++i) { assert(i < maxVariables && "i greater can not be greater than maxVariables"); - assert(y < maxHoursInAYear && "y can not be greater than maxHoursInAYear"); + assert(y < HOURS_PER_YEAR && "y can not be greater than HOURS_PER_YEAR"); if (digestNonApplicableStatus[y][i]) { @@ -791,7 +788,7 @@ void SurveyResults::saveToFile(int dataLevel, int fileLevel, int precisionLevel) for (uint y = heightBegin; y < heightEnd; ++y) { // Asserts - assert(y < maxHoursInAYear); + assert(y < HOURS_PER_YEAR); // Index writeDateToFileDescriptor(y + 1, precisionLevel); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index a771c25503..2babe91fab 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -9,8 +9,7 @@ if (Boost_FOUND) set_target_properties(Boost::unit_test_framework PROPERTIES IMPORTED_GLOBAL TRUE) endif() - - +add_subdirectory(cucumber) # end to end test require boost 1.6.x because of boost::test_tools::tolerance, BOOST_TEST # old versions of Boost don't contain a '.', also ignore them @@ -34,6 +33,7 @@ if (${RECENT_BOOST}) add_subdirectory(end-to-end) add_subdirectory(src) add_subdirectory(kirchhoff-cbuilder) + add_subdirectory(inmemory-study) else() message(STATUS "Boost >= 1.60.0 is required for end-to-end tests, found ${Boost_VERSION}. Skipping") endif() diff --git a/src/tests/cucumber/CMakeLists.txt b/src/tests/cucumber/CMakeLists.txt new file mode 100644 index 0000000000..cf22c8415b --- /dev/null +++ b/src/tests/cucumber/CMakeLists.txt @@ -0,0 +1,2 @@ +file(GENERATE OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/conf.yaml CONTENT "antares-solver : $" + CONDITION $,${CMAKE_BUILD_TYPE}>) \ No newline at end of file diff --git a/src/tests/cucumber/features/medium_tests.feature b/src/tests/cucumber/features/medium_tests.feature new file mode 100644 index 0000000000..98e8a6fb26 --- /dev/null +++ b/src/tests/cucumber/features/medium_tests.feature @@ -0,0 +1,15 @@ +Feature: medium tests + + @fast @medium @incomplete + Scenario: 035 Mixed Expansion - Smart grid model 2 + Given the study path is "medium-tests/035 Mixed Expansion - Smart grid model 2" + When I run antares simulator + Then the simulation takes less than 15 seconds + And the simulation succeeds + And the expected value of the annual system cost is 3.725e+10 + And the minimum annual system cost is 3.642e+10 + And the maximum annual system cost is 4.011e+10 + And the annual system cost is + | EXP | STD | MIN | MAX | + | 3.725e+10 | 1.063e+09 | 3.642e+10 | 4.011e+10 | + # TODO : add steps when we understand what this test is supposed to test \ No newline at end of file diff --git a/src/tests/cucumber/features/short_tests.feature b/src/tests/cucumber/features/short_tests.feature new file mode 100644 index 0000000000..8a1d65d6c7 --- /dev/null +++ b/src/tests/cucumber/features/short_tests.feature @@ -0,0 +1,45 @@ +Feature: short tests + + @fast @short + Scenario: 001 One node - passive + Given the study path is "short-tests/001 One node - passive" + When I run antares simulator + Then the simulation takes less than 5 seconds + And the simulation succeeds + And the annual system cost is + | EXP | STD | MIN | MAX | + | 0 | 0 | 0 | 0 | + + @fast @short + Scenario: 002 Thermal fleet - Base + Given the study path is "short-tests/002 Thermal fleet - Base" + When I run antares simulator + Then the simulation takes less than 5 seconds + And the simulation succeeds + And the annual system cost is + | EXP | STD | MIN | MAX | + | 2.729e+7 | 0 | 2.729e+7 | 2.729e+7 | + And in area "AREA", during year 1, loss of load lasts 1 hours + And in area "AREA", unsupplied energy on "02 JAN 09:00" of year 1 is of 52 MW + + @fast @short + Scenario: 003 Thermal fleet - Must-run + Given the study path is "short-tests/003 Thermal fleet - Must-run" + When I run antares simulator + Then the simulation takes less than 5 seconds + And the simulation succeeds + And the annual system cost is + | EXP | STD | MIN | MAX | + | 2.751e+7 | 0 | 2.751e+7 | 2.751e+7 | + And in area "AREA", during year 1, loss of load lasts 1 hours + And in area "AREA", unsupplied energy on "02 JAN 09:00" of year 1 is of 52 MW + + @fast @short + Scenario: 021 Four areas - DC law + Given the study path is "short-tests/021 Four areas - DC law" + When I run antares simulator + Then the simulation takes less than 20 seconds + And the simulation succeeds + And the annual system cost is + | EXP | STD | MIN | MAX | + | 7.972e+10 | 2.258e+10 | 5.613e+10 | 1.082e+11 | \ No newline at end of file diff --git a/src/tests/cucumber/features/steps/assertions.py b/src/tests/cucumber/features/steps/assertions.py new file mode 100644 index 0000000000..dda7d0232c --- /dev/null +++ b/src/tests/cucumber/features/steps/assertions.py @@ -0,0 +1,4 @@ +# Custom assertions + +def assert_double_close(expected, actual, relative_tolerance): + assert abs((actual - expected) / max(1e-6, expected)) <= relative_tolerance \ No newline at end of file diff --git a/src/tests/cucumber/features/steps/context_utils.py b/src/tests/cucumber/features/steps/context_utils.py new file mode 100644 index 0000000000..5a7af9dfe3 --- /dev/null +++ b/src/tests/cucumber/features/steps/context_utils.py @@ -0,0 +1,22 @@ +# Manage cached output data in "context" object + +from output_utils import * + +def get_annual_system_cost(context): + if context.annual_system_cost is None: + context.annual_system_cost = parse_annual_system_cost(context.output_path) + return context.annual_system_cost + +def get_hourly_values_for_specific_hour(context, area : str, year : int, date : str): + df = get_hourly_values(context, area, year) + day, month, hour = date.split(" ") + return df.loc[(df['Unnamed: 2'] == int(day)) & (df['Unnamed: 3'] == month) & (df['Unnamed: 4'] == hour)] + +def get_hourly_values(context, area : str, year : int): + if context.hourly_values is None: + context.hourly_values = {} + if area not in context.hourly_values: + context.hourly_values[area] = {} + if year not in context.hourly_values[area]: + context.hourly_values[area][year] = parse_hourly_values(context.output_path, area, year) + return context.hourly_values[area][year] \ No newline at end of file diff --git a/src/tests/cucumber/features/steps/output_utils.py b/src/tests/cucumber/features/steps/output_utils.py new file mode 100644 index 0000000000..778a1d36b9 --- /dev/null +++ b/src/tests/cucumber/features/steps/output_utils.py @@ -0,0 +1,37 @@ +# Antares outputs parsing + +import os +import pandas +import configparser + +def parse_output_folder_from_logs(logs: bytes) -> str: + for line in logs.splitlines(): + if b'Output folder : ' in line: + return line.split(b'Output folder : ')[1].decode('ascii') + raise LookupError("Could not parse output folder in output logs") + + +def parse_annual_system_cost(output_path: str) -> dict: + file = open(os.path.join(output_path, "annualSystemCost.txt"), 'r') + keys = ["EXP", "STD", "MIN", "MAX"] + annual_system_cost = {} + for line in file.readlines(): + for key in keys: + if key in line: + annual_system_cost[key] = float(line.split(key + " : ")[1]) + return annual_system_cost + + +def parse_simu_time(output_path: str) -> float: + execution_info = configparser.ConfigParser() + execution_info.read(os.path.join(output_path, "execution_info.ini")) + return float(execution_info['durations_ms']['total']) / 1000 + + +def parse_hourly_values(output_path: str, area: str, year: int): + return read_csv(os.path.join(output_path, "economy", "mc-ind", f"{year:05d}", "areas", area, "values-hourly.txt")) + + +def read_csv(file_name): + ignore_rows = [0, 1, 2, 3, 5, 6] + return pandas.read_csv(file_name, skiprows=ignore_rows, sep='\t', low_memory=False) \ No newline at end of file diff --git a/src/tests/cucumber/features/steps/simulator_utils.py b/src/tests/cucumber/features/steps/simulator_utils.py new file mode 100644 index 0000000000..91da69a5ad --- /dev/null +++ b/src/tests/cucumber/features/steps/simulator_utils.py @@ -0,0 +1,47 @@ +# Methods to run Antares simulator + +import subprocess +import glob +import yaml +from pathlib import Path +from study_input_handler import study_input_handler +from output_utils import parse_output_folder_from_logs + + +def get_solver_path(): + with open("conf.yaml") as file: + content = yaml.full_load(file) + return content.get("antares-solver") + +SOLVER_PATH = get_solver_path() # we only need to run this once + + +def run_simulation(context): + activate_simu_outputs(context) # TODO : remove this and update studies instead + command = build_antares_solver_command(context) + print(f"Running command: {command}") + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) + out, err = process.communicate() + context.output_path = parse_output_folder_from_logs(out) + context.return_code = process.returncode + context.annual_system_cost = None + context.hourly_values = None + + +def activate_simu_outputs(context): + sih = study_input_handler(Path(context.study_path)) + sih.set_value(variable="synthesis", value="true", file_nick_name="general") + sih.set_value(variable="year-by-year", value="true", file_nick_name="general") + + +def build_antares_solver_command(context): + command = [SOLVER_PATH, "-i", str(context.study_path)] + if context.use_ortools: + command.append('--use-ortools') + command.append('--ortools-solver=' + context.ortools_solver) + if context.named_mps_problems: + command.append('--named-mps-problems') + if context.parallel: + command.append('--force-parallel=4') + return command + diff --git a/src/tests/cucumber/features/steps/steps.py b/src/tests/cucumber/features/steps/steps.py new file mode 100644 index 0000000000..f49bed8868 --- /dev/null +++ b/src/tests/cucumber/features/steps/steps.py @@ -0,0 +1,67 @@ +# Gherkins test steps definitions + +import os +from behave import * +from simulator_utils import * +from assertions import * +from context_utils import * + +@given('the study path is "{string}"') +def study_path_is(context, string): + context.study_path = os.path.join("..", "resources", "Antares_Simulator_Tests_NR" , string.replace("/", os.sep)) + +@when('I run antares simulator') +def run_antares(context): + context.use_ortools = True + context.ortools_solver = "sirius" + context.named_mps_problems = False + context.parallel = False + run_simulation(context) + +@then('the simulation succeeds') +def simu_success(context): + assert context.return_code == 0 + +@then('the simulation fails') +def simu_success(context): + assert context.return_code != 0 + +@then('the expected value of the annual system cost is {value}') +def check_annual_cost_expected(context, value): + assert_double_close(float(value), get_annual_system_cost(context)["EXP"], 0.001) + +@then('the minimum annual system cost is {value}') +def check_annual_cost_min(context, value): + assert_double_close(float(value), get_annual_system_cost(context)["MIN"], 0.001) + +@then('the maximum annual system cost is {value}') +def check_annual_cost_max(context, value): + assert_double_close(float(value), get_annual_system_cost(context)["MAX"], 0.001) + +@then('the annual system cost is') +def check_annual_cost(context): + for row in context.table: + assert_double_close(float(row["EXP"]), get_annual_system_cost(context)["EXP"], 0.001) + assert_double_close(float(row["STD"]), get_annual_system_cost(context)["STD"], 0.001) + assert_double_close(float(row["MIN"]), get_annual_system_cost(context)["MIN"], 0.001) + assert_double_close(float(row["MAX"]), get_annual_system_cost(context)["MAX"], 0.001) + +@then('the simulation takes less than {seconds} seconds') +def check_simu_time(context, seconds): + actual_simu_time = parse_simu_time(context.output_path) + assert actual_simu_time <= float(seconds) + +@then('in area "{area}", during year {year}, loss of load lasts {lold_hours} hours') +def check_lold_duration(context, area, year, lold_hours): + assert int(lold_hours) == get_hourly_values(context, area.lower(), int(year))["LOLD"].sum() + +@then('in area "{area}", unsupplied energy on "{date}" of year {year} is of {lold_value_mw} MW') +def check_lold_value(context, area, date, year, lold_value_mw): + actual_unsp_energ = get_hourly_values_for_specific_hour(context, area.lower(), int(year), date)["UNSP. ENRG"].sum() + assert_double_close(float(lold_value_mw), actual_unsp_energ, 0.001) + +def after_feature(context, feature): + # post-processing a test: clean up output files to avoid taking up all the disk space + if (context.output_path != None): + pathlib.Path.rmdir(context.output_path) + diff --git a/src/tests/cucumber/features/steps/study_input_handler.py b/src/tests/cucumber/features/steps/study_input_handler.py new file mode 100644 index 0000000000..90f27d7221 --- /dev/null +++ b/src/tests/cucumber/features/steps/study_input_handler.py @@ -0,0 +1,31 @@ +# Currently used to activate simulation outputs +# TODO : remove this and update parameters in simulation input files + +import os + + +class study_input_handler: + def __init__(self, study_root_directory): + self.study_root_dir = study_root_directory + self.name = os.path.basename(study_root_directory) + self.files_path = {} + self.files_path["desktop"] = self.study_root_dir / "Desktop.ini" + self.files_path["general"] = self.study_root_dir / "settings" / "generaldata.ini" + self.files_path["study"] = self.study_root_dir / "study.antares" + + def set_value(self, variable, value, file_nick_name): + # File path + file = self.files_path[file_nick_name] + # Content to print in file (tmp content) + content_out = [] + # Reading the file content (content in) + with open(file) as f: + # Searching variable and setting its value in a tmp content + for line in f: + if line.strip().startswith(variable): + content_out.append(variable + " = " + value + "\n") + else: + content_out.append(line) + # Erasing file content with the tmp content (content out) + with open(file, "w") as f: + f.writelines(content_out) diff --git a/src/tests/cucumber/readme.md b/src/tests/cucumber/readme.md new file mode 100644 index 0000000000..7ed6304d9f --- /dev/null +++ b/src/tests/cucumber/readme.md @@ -0,0 +1,70 @@ +# Antares Cucumber Tests + +This module contains non-regression functional tests for Antares written in the [Gherkin language](https://cucumber.io/docs/gherkin/). + +## Tests structure + +### Features, scenarios and tags +Features are supposed to represent big-picture features of the application. Every feature can have its own set of tests, +defined in a `.feature` file. Features are under the [features](./features) folder. +Every feature has multiple scenarios (every scenario represents a test case). +A scenario can be tagged in order to add it to a category, allowing us to run the tests on a filtered subset of the +scenarios later. The tags currently used in Antares are: +- @fast: tests that run fast +- @slow: tests that run slow +- @short: tests from the legacy "short-tests" batch +- @medium: tests from the legacy "medium-tests" batch +- @flaky: quarantine for flaky tests (i.e. sometimes pass, sometimes fail) that are to be skipped by the CI + +### Steps structure +Currently, tests are being migrated from the [legacy non-regression testing process](../run-study-tests). Thus, they +all begin by defining the path to the study to run and then call antares, through the following "steps": +~~~gherkin +Given the study path is "someFolder/someStudy" +When I run antares simulator +~~~ +The test will load the study, run antares-simulator, and hold on to its outputs. +Next, assertion "steps" can be added. For example, this next assertion checks that the simulation time (as measured by +antares-simulator and reported in its logs) is less than 15 seconds: +~~~gherkin +Then the simulation takes less than 15 seconds +~~~ +And the next step checks the expected value of the annual system cost: +~~~gherkin +Then the expected value of the annual system cost is 3.725e+10 +~~~ + +## Running the tests +### On your PC +First, you need to build antares-simulator. The tests will run the last antares-simulator executable built by the Cmake +projet. +Then, if needed, install the requirements by running: +~~~bash +pip install -r requirements.txt +~~~ +Then just run the following to execute the tests: +~~~bash +cd src/tests/cucumber +behave +~~~ +If you want to filter on a feature file and given tags, you can use: +~~~bash +behave --tags @some-tag features/some_feature.feature +~~~ +Refer to the [behave documentation](https://behave.readthedocs.io/en/latest/) for more information. + +### In the CI +Cucumber tests are run in the same way as the legacy tests in the Ubuntu & Windows CIs, except that they don't need the +reference values from the SimTest repository, since reference values are stored explicitly in the feature files. +Note that tests marked as "@flaky" are skipped by default. +Workflow file: [here](../../../.github/workflows/cucumber-tests/action.yml) + +## Under the hood +### Test files +Tests are hosted in the [Antares_Simulator_Tests_NR submodule](https://github.com/AntaresSimulatorTeam/Antares_Simulator_Tests_NR) +into the `src/test/resources` folder. Adding or modifying a study should thus change contents of this submodule. + +### Code-behind +All Gherkin steps have a code-behind definition called "step definitions". These are defined in the python files under +[features/steps](./features/steps) and use the [behave](https://behave.readthedocs.io/en/latest/) implementation of +cucumber. Feel free to add extra steps for your tests. diff --git a/src/tests/cucumber/requirements.txt b/src/tests/cucumber/requirements.txt new file mode 100644 index 0000000000..fd5e363e68 --- /dev/null +++ b/src/tests/cucumber/requirements.txt @@ -0,0 +1,2 @@ +behave +pyyaml \ No newline at end of file diff --git a/src/tests/end-to-end/CMakeLists.txt b/src/tests/end-to-end/CMakeLists.txt index 9830013131..6c2031e372 100644 --- a/src/tests/end-to-end/CMakeLists.txt +++ b/src/tests/end-to-end/CMakeLists.txt @@ -1,3 +1,2 @@ -add_subdirectory(utils) add_subdirectory(simple_study) add_subdirectory(binding_constraints) \ No newline at end of file diff --git a/src/tests/end-to-end/binding_constraints/CMakeLists.txt b/src/tests/end-to-end/binding_constraints/CMakeLists.txt index 1b7cf52e86..72e2e46f62 100644 --- a/src/tests/end-to-end/binding_constraints/CMakeLists.txt +++ b/src/tests/end-to-end/binding_constraints/CMakeLists.txt @@ -12,18 +12,17 @@ add_executable(tests-binding_constraints target_link_libraries(tests-binding_constraints PRIVATE - test_utils Boost::unit_test_framework model_antares antares-solver-simulation antares-solver-hydro antares-solver-ts-generator + Antares::tests::in-memory-study ) target_include_directories(tests-binding_constraints PRIVATE ${CMAKE_SOURCE_DIR}/solver - ${CMAKE_CURRENT_SOURCE_DIR}/../utils ) add_test(NAME end-to-end-binding_constraints COMMAND 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 a40157091a..10f91f2a40 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 @@ -1,31 +1,29 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ -#include // Fix for Boost < 1.67 - + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test - end - to - end tests_binding_constraints #define WIN32_LEAN_AND_MEAN #include #include -#include "utils.h" +#include "in-memory-study.h" namespace utf = boost::unit_test; namespace tt = boost::test_tools; diff --git a/src/tests/end-to-end/simple_study/CMakeLists.txt b/src/tests/end-to-end/simple_study/CMakeLists.txt index 670cb16187..cc5c93b410 100644 --- a/src/tests/end-to-end/simple_study/CMakeLists.txt +++ b/src/tests/end-to-end/simple_study/CMakeLists.txt @@ -12,19 +12,18 @@ add_executable(tests-simple-study target_link_libraries(tests-simple-study PRIVATE - test_utils antares-solver-hydro antares-solver-variable antares-solver-simulation antares-solver-ts-generator model_antares ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} + Antares::tests::in-memory-study ) target_include_directories(tests-simple-study PRIVATE ${CMAKE_SOURCE_DIR}/solver - ${CMAKE_CURRENT_SOURCE_DIR}/../utils ) add_test(NAME end-to-end-simple-study COMMAND tests-simple-study) 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 5c9181ddbf..2664dc97d0 100644 --- a/src/tests/end-to-end/simple_study/simple-study.cpp +++ b/src/tests/end-to-end/simple_study/simple-study.cpp @@ -1,30 +1,28 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ -#include // Fix for Boost < 1.67 - + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test - end - to - end tests #include #include -#include "utils.h" +#include "in-memory-study.h" namespace utf = boost::unit_test; namespace tt = boost::test_tools; @@ -80,11 +78,12 @@ struct HydroMaxPowerStudy: public StudyBuilder HydroMaxPowerStudy::HydroMaxPowerStudy() { simulationBetweenDays(0, 14); - setNumberMCyears(1); area = addAreaToStudy("Area"); area->thermal.unsuppliedEnergyCost = 1; + setNumberMCyears(1); + TimeSeriesConfigurer loadTSconfig(area->load.series.timeSeries); loadTSconfig.setColumnCount(1).fillColumnWith(0, loadInArea); @@ -108,7 +107,6 @@ BOOST_AUTO_TEST_SUITE(ONE_AREA__ONE_THERMAL_CLUSTER) BOOST_FIXTURE_TEST_CASE(thermal_cluster_fullfills_area_demand, StudyFixture) { setNumberMCyears(1); - simulation->create(); simulation->run(); @@ -284,13 +282,13 @@ BOOST_FIXTURE_TEST_CASE(error_on_wrong_hydro_data, StudyFixture) { 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 + builder.setNumberMCyears(1); auto simulation = builder.simulation; simulation->create(); BOOST_CHECK_THROW(simulation->run(), Antares::FatalError); @@ -310,7 +308,8 @@ BOOST_FIXTURE_TEST_CASE(STS_initial_level_is_also_weekly_final_level, StudyFixtu props.injectionNominalCapacity = 10; props.withdrawalNominalCapacity = 10; props.reservoirCapacity = 100; - props.efficiencyFactor = .9; + props.injectionEfficiency = .9; + props.withdrawalEfficiency = .8; props.initialLevel = .443; props.groupName = std::string("Some STS group"); // Default values for series @@ -319,17 +318,16 @@ BOOST_FIXTURE_TEST_CASE(STS_initial_level_is_also_weekly_final_level, StudyFixtu storages.push_back(sts); // Fatal gen at h=1 + auto& windTS = area->wind.series.timeSeries; + TimeSeriesConfigurer(windTS).setColumnCount(1).fillColumnWith(0, 0.); + windTS[0][1] = 100; + + // Fatal load at h=2-10 + auto& loadTS = area->load.series.timeSeries; + TimeSeriesConfigurer(loadTS).setColumnCount(1).fillColumnWith(0, 0.); + for (int i = 2; i < 10; i++) { - auto& windTS = area->wind.series.timeSeries; - TimeSeriesConfigurer(windTS).setColumnCount(1).fillColumnWith(0, 0.); - windTS[0][1] = 100; - } - - // Fatal load at h=2 - { - auto& loadTS = area->load.series.timeSeries; - TimeSeriesConfigurer(loadTS).setColumnCount(1).fillColumnWith(0, 0.); - loadTS[0][2] = 100; + loadTS[0][i] = 100; } // Usual values, avoid spillage & unsupplied energy @@ -345,6 +343,51 @@ BOOST_FIXTURE_TEST_CASE(STS_initial_level_is_also_weekly_final_level, StudyFixtu == props.initialLevel * props.reservoirCapacity.value(), tt::tolerance(0.001)); } + +BOOST_FIXTURE_TEST_CASE(STS_efficiency_for_injection_and_withdrawal, StudyFixture) +{ + using namespace Antares::Data::ShortTermStorage; + setNumberMCyears(1); + auto& storages = area->shortTermStorage.storagesByIndex; + STStorageCluster sts; + auto& props = sts.properties; + props.name = "my-sts"; + props.injectionNominalCapacity = 10; + props.withdrawalNominalCapacity = 10; + props.reservoirCapacity = 100; + props.injectionEfficiency = .6; + props.withdrawalEfficiency = .8; + props.initialLevel = .5; + props.groupName = std::string("Some STS group"); + // Default values for series + sts.series->fillDefaultSeriesIfEmpty(); + + storages.push_back(sts); + + // Fatal gen at h=1 + auto& windTS = area->wind.series.timeSeries; + TimeSeriesConfigurer(windTS).setColumnCount(1).fillColumnWith(0, 0.); + windTS[0][1] = 100; + + // Fatal load at h=2 + auto& loadTS = area->load.series.timeSeries; + TimeSeriesConfigurer(loadTS).setColumnCount(1).fillColumnWith(0, 0.); + loadTS[0][2] = 100; + + // Usual values, avoid spillage & unsupplied energy + area->thermal.unsuppliedEnergyCost = 1.e3; + area->thermal.spilledEnergyCost = 1.; + + simulation->create(); + simulation->run(); + + unsigned int groupNb = 0; // Used to reach the first group of STS results + OutputRetriever output(simulation->rawSimu()); + + BOOST_CHECK_EQUAL(output.levelForSTSgroup(area, groupNb).hour(1), 56); // injection + BOOST_CHECK_EQUAL(output.levelForSTSgroup(area, groupNb).hour(2), 48); // withdrawal +} + BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE(HYDRO_MAX_POWER) diff --git a/src/tests/end-to-end/utils/CMakeLists.txt b/src/tests/end-to-end/utils/CMakeLists.txt deleted file mode 100644 index 166e083bc0..0000000000 --- a/src/tests/end-to-end/utils/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -add_library(test_utils - utils.cpp - utils.h - ) - -target_link_libraries(test_utils - PUBLIC - ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} - Antares::infoCollection - antares-solver-simulation - ) - -target_include_directories(test_utils - PRIVATE - ${CMAKE_SOURCE_DIR}/solver - ) - -set_target_properties(test_utils PROPERTIES FOLDER Unit-tests/end_to_end) - -target_include_directories(test_utils PUBLIC ${Boost_INCLUDE_DIRS}) diff --git a/src/tests/inmemory-study/CMakeLists.txt b/src/tests/inmemory-study/CMakeLists.txt new file mode 100644 index 0000000000..bb7cd26e13 --- /dev/null +++ b/src/tests/inmemory-study/CMakeLists.txt @@ -0,0 +1,26 @@ +add_library(in-memory-study) +add_library(Antares::tests::in-memory-study ALIAS in-memory-study) + +target_sources(in-memory-study + PRIVATE + in-memory-study.cpp + include/in-memory-study.h +) + +target_link_libraries(in-memory-study + PUBLIC + ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY} + antares-solver-simulation + Antares::application + PRIVATE + Antares::infoCollection +) + +target_include_directories(in-memory-study + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include +) + +set_target_properties(in-memory-study PROPERTIES FOLDER Unit-tests) + +target_include_directories(in-memory-study PUBLIC ${Boost_INCLUDE_DIRS}) diff --git a/src/tests/end-to-end/utils/utils.cpp b/src/tests/inmemory-study/in-memory-study.cpp similarity index 84% rename from src/tests/end-to-end/utils/utils.cpp rename to src/tests/inmemory-study/in-memory-study.cpp index 769683412d..cfe1c1d130 100644 --- a/src/tests/end-to-end/utils/utils.cpp +++ b/src/tests/inmemory-study/in-memory-study.cpp @@ -1,27 +1,30 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define WIN32_LEAN_AND_MEAN -#include "utils.h" -void initializeStudy(Study::Ptr study) +#include "in-memory-study.h" + +#include "antares/application/ScenarioBuilderOwner.h" + +void initializeStudy(Study* study) { study->parameters.reset(); } @@ -53,7 +56,7 @@ void addScratchpadToEachArea(Study& study) { for (unsigned int i = 0; i < study.maxNbYearsInParallel; ++i) { - area->scratchpad.emplace_back(*study.runtime, *area); + area->scratchpad.emplace_back(study.runtime, *area); } } } @@ -169,7 +172,7 @@ averageResults OutputRetriever::thermalNbUnitsON(ThermalCluster* cluster) ScenarioBuilderRule::ScenarioBuilderRule(Study& study) { study.scenarioRulesCreate(); - ScenarioBuilder::Sets* sets = study.scenarioRules; + auto sets = study.scenarioRules.get(); if (sets && !sets->empty()) { rules_ = sets->createNew("Custom"); @@ -187,11 +190,13 @@ void SimulationHandler::create() { study_.initializeRuntimeInfos(); addScratchpadToEachArea(study_); - simulation_ = std::make_shared>(study_, settings_, durationCollector_, - resultWriter_); + resultWriter_, + observer_); + Antares::Solver::ScenarioBuilderOwner(study_).callScenarioBuilder(); + SIM_AllocationTableaux(study_); } @@ -203,10 +208,10 @@ StudyBuilder::StudyBuilder() // Make logs shrink to errors (and higher) only logs.verbosityLevel = Logs::Verbosity::Error::level; - study = std::make_shared(); + study = std::make_unique(true); simulation = std::make_shared(*study); - initializeStudy(study); + initializeStudy(study.get()); } void StudyBuilder::simulationBetweenDays(const unsigned int firstDay, const unsigned int lastDay) @@ -219,6 +224,8 @@ void StudyBuilder::setNumberMCyears(unsigned int nbYears) { study->parameters.resetPlaylist(nbYears); study->areas.resizeAllTimeseriesNumbers(nbYears); + study->areas.each([&](Data::Area& area) + { area.hydro.deltaBetweenFinalAndInitialLevels.resize(nbYears); }); } void StudyBuilder::playOnlyYear(unsigned int year) diff --git a/src/tests/end-to-end/utils/utils.h b/src/tests/inmemory-study/include/in-memory-study.h similarity index 86% rename from src/tests/end-to-end/utils/utils.h rename to src/tests/inmemory-study/include/in-memory-study.h index 1fa55efbff..920d28f261 100644 --- a/src/tests/end-to-end/utils/utils.h +++ b/src/tests/inmemory-study/include/in-memory-study.h @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #pragma once #define WIN32_LEAN_AND_MEAN #include "antares/solver/simulation/economy.h" @@ -30,7 +30,7 @@ using namespace Antares::Solver; using namespace Antares::Solver::Simulation; using namespace Antares::Data::ScenarioBuilder; -void initializeStudy(Study::Ptr study); +void initializeStudy(Study* study); void configureLinkCapacities(AreaLink* link); class TimeSeriesConfigurer @@ -164,14 +164,17 @@ class ScenarioBuilderRule { return rules_->load; } + BindingConstraintsTSNumberData& bcGroup() { return rules_->binding_constraints; } + hydroTSNumberData& hydro() { return rules_->hydro; } + private: Rules::Ptr rules_; }; @@ -207,6 +210,7 @@ class SimulationHandler Settings settings_; Study& study_; NullResultWriter resultWriter_; + NullSimulationObserver observer_; }; // ========================= @@ -224,7 +228,7 @@ struct StudyBuilder void giveWeightToYear(float weight, unsigned int year); // Data members - std::shared_ptr study; + std::unique_ptr study; std::shared_ptr simulation; }; diff --git a/src/tests/resources/Antares_Simulator_Tests_NR b/src/tests/resources/Antares_Simulator_Tests_NR new file mode 160000 index 0000000000..9983782bc0 --- /dev/null +++ b/src/tests/resources/Antares_Simulator_Tests_NR @@ -0,0 +1 @@ +Subproject commit 9983782bc07c62f99854b1c7394d320830a40e14 diff --git a/src/tests/run-study-tests/actions_on_study/study_run.py b/src/tests/run-study-tests/actions_on_study/study_run.py index 9abafdb066..8867aafda5 100644 --- a/src/tests/run-study-tests/actions_on_study/study_run.py +++ b/src/tests/run-study-tests/actions_on_study/study_run.py @@ -39,7 +39,7 @@ def run(self): if not self.raise_exception_on_failure: return - check(self.return_code == 0, "Solver returned error") + check(self.success(), f"Solver returned error {self.return_code}") def get_return_code(self): diff --git a/src/tests/run-study-tests/readme.md b/src/tests/run-study-tests/readme.md index 5701d722d7..d2536dab64 100644 --- a/src/tests/run-study-tests/readme.md +++ b/src/tests/run-study-tests/readme.md @@ -212,7 +212,7 @@ The schema can be found at : **src/tests/run-study-tests/parse_studies/json_sche ```bash > cd src/tests/run-study-tests -> python -m pytest -m mps --solver-path=/path/to/the/Antares/solver/antares-x.y-solver.exe +> python -m pytest -m json --solver-path=/path/to/the/Antares/solver/antares-x.y-solver.exe ``` # TO DO diff --git a/src/tests/src/CMakeLists.txt b/src/tests/src/CMakeLists.txt index f6275f8386..14c9929f56 100644 --- a/src/tests/src/CMakeLists.txt +++ b/src/tests/src/CMakeLists.txt @@ -1,3 +1,5 @@ +add_subdirectory(api_internal) +add_subdirectory(api_lib) add_subdirectory(utils) add_subdirectory(libs) diff --git a/src/tests/src/api_internal/CMakeLists.txt b/src/tests/src/api_internal/CMakeLists.txt new file mode 100644 index 0000000000..2186dc6f4b --- /dev/null +++ b/src/tests/src/api_internal/CMakeLists.txt @@ -0,0 +1,27 @@ +set(EXECUTABLE_NAME test-api) +add_executable(${EXECUTABLE_NAME}) + +target_sources(${EXECUTABLE_NAME} + PRIVATE + test_api.cpp +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + Antares::solver_api + Antares::tests::in-memory-study +) + +target_include_directories(${EXECUTABLE_NAME} + PRIVATE + #Allow to use the private headers + $ +) + +# Storing tests-ts-numbers under the folder Unit-tests in the IDE +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) + +add_test(NAME test-api COMMAND ${EXECUTABLE_NAME}) + +set_property(TEST test-api PROPERTY LABELS unit) diff --git a/src/tests/src/api_internal/test_api.cpp b/src/tests/src/api_internal/test_api.cpp new file mode 100644 index 0000000000..d8b52d3332 --- /dev/null +++ b/src/tests/src/api_internal/test_api.cpp @@ -0,0 +1,98 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define BOOST_TEST_MODULE test_api +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include "API.h" +#include "in-memory-study.h" + +class InMemoryStudyLoader: public Antares::IStudyLoader +{ +public: + explicit InMemoryStudyLoader(bool success = true): + success_(success) + { + } + + [[nodiscard]] std::unique_ptr load() const override + { + if (!success_) + { + return nullptr; + } + StudyBuilder builder; + builder.addAreaToStudy("area1"); + builder.addAreaToStudy("area2"); + builder.study->initializeRuntimeInfos(); + builder.setNumberMCyears(1); + builder.study->parameters.resultFormat = ResultFormat::inMemory; + builder.study->prepareOutput(); + return std::move(builder.study); + } + + bool success_ = true; +}; + +BOOST_AUTO_TEST_CASE(simulation_path_points_to_results) +{ + Antares::API::APIInternal api; + auto study_loader = std::make_unique(); + auto results = api.run(*study_loader.get()); + BOOST_CHECK_EQUAL(results.simulationPath, std::filesystem::path{"no_output"}); + // Testing for "no_output" is a bit weird, but it's the only way to test this without actually + // running the simulation +} + +BOOST_AUTO_TEST_CASE(api_run_contains_antares_problem) +{ + Antares::API::APIInternal api; + auto study_loader = std::make_unique(); + auto results = api.run(*study_loader.get()); + + BOOST_CHECK(!results.antares_problems.empty()); + BOOST_CHECK(!results.error); +} + +BOOST_AUTO_TEST_CASE(result_failure_when_study_is_null) +{ + Antares::API::APIInternal api; + auto study_loader = std::make_unique(false); + auto results = api.run(*study_loader.get()); + + BOOST_CHECK(results.error); +} + +// Test where data in problems are consistant with data in study +BOOST_AUTO_TEST_CASE(result_contains_problems) +{ + Antares::API::APIInternal api; + auto study_loader = std::make_unique(); + auto results = api.run(*study_loader.get()); + + BOOST_CHECK(!results.antares_problems.empty()); + BOOST_CHECK(!results.error); + BOOST_CHECK_EQUAL(results.antares_problems.weeklyProblems.size(), 52); +} diff --git a/src/tests/src/api_lib/CMakeLists.txt b/src/tests/src/api_lib/CMakeLists.txt new file mode 100644 index 0000000000..b5ce633955 --- /dev/null +++ b/src/tests/src/api_lib/CMakeLists.txt @@ -0,0 +1,20 @@ +set(EXECUTABLE_NAME test-client-api) +add_executable(${EXECUTABLE_NAME}) + +target_sources(${EXECUTABLE_NAME} + PRIVATE + test_api.cpp +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + Antares::solver_api +) + +# Storing tests-ts-numbers under the folder Unit-tests in the IDE +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) + +add_test(NAME test-client-api COMMAND ${EXECUTABLE_NAME}) + +set_property(TEST test-client-api PROPERTY LABELS unit) diff --git a/src/tests/src/api_lib/test_api.cpp b/src/tests/src/api_lib/test_api.cpp new file mode 100644 index 0000000000..0dbddfae7f --- /dev/null +++ b/src/tests/src/api_lib/test_api.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define BOOST_TEST_MODULE test_api +#define WIN32_LEAN_AND_MEAN + +#include + +#include "antares/api/solver.h" + +BOOST_AUTO_TEST_CASE(result_failure_when_study_path_invalid) +{ + using namespace std::string_literals; + auto results = Antares::API::PerformSimulation("dummy"s); + BOOST_CHECK(results.error); + BOOST_CHECK(!results.error->reason.empty()); +} diff --git a/src/tests/src/libs/CMakeLists.txt b/src/tests/src/libs/CMakeLists.txt index b97a7df1bc..81b6173280 100644 --- a/src/tests/src/libs/CMakeLists.txt +++ b/src/tests/src/libs/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(antares) \ No newline at end of file +add_subdirectory(antares) diff --git a/src/tests/src/libs/antares/antlr4-interface/test_antlr_interface.cpp b/src/tests/src/libs/antares/antlr4-interface/test_antlr_interface.cpp index e97f4e3524..04d1c7be9f 100644 --- a/src/tests/src/libs/antares/antlr4-interface/test_antlr_interface.cpp +++ b/src/tests/src/libs/antares/antlr4-interface/test_antlr_interface.cpp @@ -19,15 +19,17 @@ ** along with Antares_Simulator. If not, see . */ #define BOOST_TEST_MODULE antlr_interface tests -#include -#include -#include "antlr4-runtime.h" #include +#include +#include + #include "ExprLexer.h" #include "ExprParser.h" +#include "antlr4-runtime.h" using namespace antlr4; + BOOST_AUTO_TEST_CASE(test_antlr_interface) { const std::string my_input = "y = b + a*x"; diff --git a/src/tests/src/libs/antares/array/fill-matrix.h b/src/tests/src/libs/antares/array/fill-matrix.h index 167e943715..29681740e3 100644 --- a/src/tests/src/libs/antares/array/fill-matrix.h +++ b/src/tests/src/libs/antares/array/fill-matrix.h @@ -31,16 +31,6 @@ using namespace std; using namespace Antares; -namespace Antares -{ -namespace Statistics -{ -void HasWrittenToDisk(uint64_t /* size */) -{ -} -} // namespace Statistics -} // namespace Antares - template class Matrix_easy_to_fill: public Matrix { diff --git a/src/tests/src/libs/antares/array/matrix-bypass-load.h b/src/tests/src/libs/antares/array/matrix-bypass-load.h index 387dcfdc8a..543c4d848a 100644 --- a/src/tests/src/libs/antares/array/matrix-bypass-load.h +++ b/src/tests/src/libs/antares/array/matrix-bypass-load.h @@ -41,16 +41,6 @@ struct PredicateIdentity } // namespace UnitTests } // namespace Antares -namespace Antares -{ -namespace Statistics -{ -void HasReadFromDisk(uint64_t /* size */) -{ -} -} // namespace Statistics -} // namespace Antares - template class Matrix_load_bypass: public Matrix_easy_to_fill { @@ -59,15 +49,21 @@ class Matrix_load_bypass: public Matrix_easy_to_fill public: Matrix_load_bypass(): Matrix_easy_to_fill(), - loadFromCSVFile_called(false){}; + loadFromCSVFile_called(false) + { + } Matrix_load_bypass(uint height, uint width): Matrix_easy_to_fill(height, width), - loadFromCSVFile_called(false){}; + loadFromCSVFile_called(false) + { + } Matrix_load_bypass(uint height, uint width, const vector& vec): Matrix_easy_to_fill(height, width, vec), - loadFromCSVFile_called(false){}; + loadFromCSVFile_called(false) + { + } bool loadFromCSVFile(const AnyString& /* filename */, uint /* minWidth */, @@ -138,15 +134,21 @@ class Matrix_mock_load_to_buffer: public Matrix public: Matrix_mock_load_to_buffer(): Matrix(), - fake_mtx_error_when_loading_(IO::errNone){}; + fake_mtx_error_when_loading_(IO::errNone) + { + } Matrix_mock_load_to_buffer(uint height, uint width): Matrix(height, width), - fake_mtx_error_when_loading_(IO::errNone){}; + fake_mtx_error_when_loading_(IO::errNone) + { + } Matrix_mock_load_to_buffer(uint height, uint width, const vector& vec): Matrix(height, width, vec), - fake_mtx_error_when_loading_(IO::errNone){}; + fake_mtx_error_when_loading_(IO::errNone) + { + } IO::Error loadFromFileToBuffer(typename Matrix::BufferType& /* buffer */, const AnyString& /* filename */) const override diff --git a/src/tests/src/libs/antares/array/tests-matrix-load.cpp b/src/tests/src/libs/antares/array/tests-matrix-load.cpp index 1dfecf1517..2c427890eb 100644 --- a/src/tests/src/libs/antares/array/tests-matrix-load.cpp +++ b/src/tests/src/libs/antares/array/tests-matrix-load.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test - lib - antares - matrix tests #define WIN32_LEAN_AND_MEAN diff --git a/src/tests/src/libs/antares/array/tests-matrix-save.cpp b/src/tests/src/libs/antares/array/tests-matrix-save.cpp index 13560a047e..d1af11d387 100644 --- a/src/tests/src/libs/antares/array/tests-matrix-save.cpp +++ b/src/tests/src/libs/antares/array/tests-matrix-save.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test - lib - antares - matrix tests #define WIN32_LEAN_AND_MEAN diff --git a/src/tests/src/libs/antares/benchmarking/test_duration_collector.cpp b/src/tests/src/libs/antares/benchmarking/test_duration_collector.cpp index d213dc64d5..4fc74bcda9 100644 --- a/src/tests/src/libs/antares/benchmarking/test_duration_collector.cpp +++ b/src/tests/src/libs/antares/benchmarking/test_duration_collector.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test - benchmarking #define WIN32_LEAN_AND_MEAN diff --git a/src/tests/src/libs/antares/concurrency/test_concurrency.cpp b/src/tests/src/libs/antares/concurrency/test_concurrency.cpp index 26923159c7..c1188c7a9d 100644 --- a/src/tests/src/libs/antares/concurrency/test_concurrency.cpp +++ b/src/tests/src/libs/antares/concurrency/test_concurrency.cpp @@ -1,27 +1,24 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ -#include // Fix for Boost < 1.67 - + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test - concurrency tests - #include #include diff --git a/src/tests/src/libs/antares/study/area/test-save-area-optimization-ini.cpp b/src/tests/src/libs/antares/study/area/test-save-area-optimization-ini.cpp index 40fcb4b5fd..77672b88c2 100644 --- a/src/tests/src/libs/antares/study/area/test-save-area-optimization-ini.cpp +++ b/src/tests/src/libs/antares/study/area/test-save-area-optimization-ini.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test save area optimization.ini #define WIN32_LEAN_AND_MEAN diff --git a/src/tests/src/libs/antares/study/area/test-save-link-properties.cpp b/src/tests/src/libs/antares/study/area/test-save-link-properties.cpp index af30689f4b..305241cd3e 100644 --- a/src/tests/src/libs/antares/study/area/test-save-link-properties.cpp +++ b/src/tests/src/libs/antares/study/area/test-save-link-properties.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test save link properties.ini #define WIN32_LEAN_AND_MEAN diff --git a/src/tests/src/libs/antares/study/constraint/test_constraint.cpp b/src/tests/src/libs/antares/study/constraint/test_constraint.cpp index 25322ae361..e6e5cd54c3 100644 --- a/src/tests/src/libs/antares/study/constraint/test_constraint.cpp +++ b/src/tests/src/libs/antares/study/constraint/test_constraint.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ // // Created by marechaljas on 13/03/23. // diff --git a/src/tests/src/libs/antares/study/constraint/test_group.cpp b/src/tests/src/libs/antares/study/constraint/test_group.cpp index 3e87707fe2..21f5c7377a 100644 --- a/src/tests/src/libs/antares/study/constraint/test_group.cpp +++ b/src/tests/src/libs/antares/study/constraint/test_group.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ // // Created by marechaljas on 28/06/23. // diff --git a/src/tests/src/libs/antares/study/output-folder/study.cpp b/src/tests/src/libs/antares/study/output-folder/study.cpp index eba613c781..1675ae7909 100644 --- a/src/tests/src/libs/antares/study/output-folder/study.cpp +++ b/src/tests/src/libs/antares/study/output-folder/study.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE output folder #define WIN32_LEAN_AND_MEAN diff --git a/src/tests/src/libs/antares/study/parameters/parameters-tests.cpp b/src/tests/src/libs/antares/study/parameters/parameters-tests.cpp index 3dde6f5784..5e0da57a10 100644 --- a/src/tests/src/libs/antares/study/parameters/parameters-tests.cpp +++ b/src/tests/src/libs/antares/study/parameters/parameters-tests.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE "test parameters" #include @@ -69,7 +69,9 @@ BOOST_FIXTURE_TEST_CASE(loadValid, Fixture) options.optOptions.ortoolsSolver = "xpress"; writeValidFile(); - p.loadFromFile(path.string(), version, options); + p.loadFromFile(path.string(), version); + p.validateOptions(options); + p.fixBadValues(); BOOST_CHECK_EQUAL(p.nbYears, 5); BOOST_CHECK_EQUAL(p.seed[seedTsGenThermal], 5489); @@ -92,7 +94,9 @@ BOOST_FIXTURE_TEST_CASE(fixBadValue, Fixture) BOOST_FIXTURE_TEST_CASE(invalidValues, Fixture) { writeInvalidFile(); - BOOST_CHECK(p.loadFromFile(path.string(), version, options)); + BOOST_CHECK(p.loadFromFile(path.string(), version)); + p.validateOptions(options); + p.fixBadValues(); BOOST_CHECK_EQUAL(p.nbYears, 1); BOOST_CHECK_EQUAL(p.useCustomScenario, 0); @@ -189,7 +193,6 @@ void Fixture::writeValidFile() threshold-csr-variable-bounds-relaxation = 3 [other preferences] - initial-reservoir-levels = cold start hydro-heuristic-policy = accommodate rule curves hydro-pricing-mode = fast power-fluctuations = free modulations diff --git a/src/tests/src/libs/antares/study/parts/hydro/test-hydro-series.cpp b/src/tests/src/libs/antares/study/parts/hydro/test-hydro-series.cpp index 9e28c98df0..d534ca7d53 100644 --- a/src/tests/src/libs/antares/study/parts/hydro/test-hydro-series.cpp +++ b/src/tests/src/libs/antares/study/parts/hydro/test-hydro-series.cpp @@ -1,3 +1,24 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + #define BOOST_TEST_MODULE test hydro series #define WIN32_LEAN_AND_MEAN diff --git a/src/tests/src/libs/antares/study/parts/hydro/test-hydroreader-class.cpp b/src/tests/src/libs/antares/study/parts/hydro/test-hydroreader-class.cpp index a933b5a3c0..cf519c3cb7 100644 --- a/src/tests/src/libs/antares/study/parts/hydro/test-hydroreader-class.cpp +++ b/src/tests/src/libs/antares/study/parts/hydro/test-hydroreader-class.cpp @@ -1,3 +1,24 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + #define BOOST_TEST_MODULE test hydro reader #define WIN32_LEAN_AND_MEAN 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 003a24b22a..de09d007d1 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 @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test read scenario - builder.dat #define WIN32_LEAN_AND_MEAN @@ -346,7 +346,7 @@ BOOST_FIXTURE_TEST_CASE( } // ======================== -// Tests on Hydro levels +// Tests on Hydro initial levels // ======================== BOOST_FIXTURE_TEST_CASE(on_area1_and_on_year_17__hydro_level_0_123_is_chosen__reading_OK, Fixture) { @@ -355,11 +355,11 @@ BOOST_FIXTURE_TEST_CASE(on_area1_and_on_year_17__hydro_level_0_123_is_chosen__re AreaName::Vector splitKey = {"hl", "area 1", yearNumber}; my_rule.readLine(splitKey, level); - BOOST_CHECK_EQUAL(my_rule.hydroLevels.get_value(yearNumber.to(), area_1->index), + BOOST_CHECK_EQUAL(my_rule.hydroInitialLevels.get_value(yearNumber.to(), area_1->index), level.to()); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(study->scenarioHydroLevels[area_1->index][yearNumber.to()], + BOOST_CHECK_EQUAL(study->scenarioInitialHydroLevels[area_1->index][yearNumber.to()], level.to()); } @@ -372,10 +372,11 @@ BOOST_FIXTURE_TEST_CASE( AreaName::Vector splitKey = {"hl", "area 2", yearNumber}; BOOST_CHECK(my_rule.readLine(splitKey, level)); - BOOST_CHECK_EQUAL(my_rule.hydroLevels.get_value(yearNumber.to(), area_2->index), 1.); + BOOST_CHECK_EQUAL(my_rule.hydroInitialLevels.get_value(yearNumber.to(), area_2->index), + 1.); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(study->scenarioHydroLevels[area_2->index][yearNumber.to()], 1.); + BOOST_CHECK_EQUAL(study->scenarioInitialHydroLevels[area_2->index][yearNumber.to()], 1.); } BOOST_FIXTURE_TEST_CASE( @@ -387,10 +388,59 @@ BOOST_FIXTURE_TEST_CASE( AreaName::Vector splitKey = {"hl", "area 3", yearNumber}; BOOST_CHECK(my_rule.readLine(splitKey, level)); - BOOST_CHECK_EQUAL(my_rule.hydroLevels.get_value(yearNumber.to(), area_3->index), 0.); + BOOST_CHECK_EQUAL(my_rule.hydroInitialLevels.get_value(yearNumber.to(), area_3->index), + 0.); BOOST_CHECK(my_rule.apply()); - BOOST_CHECK_EQUAL(study->scenarioHydroLevels[area_3->index][yearNumber.to()], 0.); + BOOST_CHECK_EQUAL(study->scenarioInitialHydroLevels[area_3->index][yearNumber.to()], 0.); +} + +// ======================== +// Tests on Hydro final levels +// ======================== +BOOST_FIXTURE_TEST_CASE(on_area1_and_on_year_8__hydro_level_0_342_is_chosen__reading_OK, Fixture) +{ + AreaName yearNumber = "8"; + String level = "0.342"; + AreaName::Vector splitKey = {"hfl", "area 1", yearNumber}; + my_rule.readLine(splitKey, level, false); + + BOOST_CHECK_EQUAL(my_rule.hydroFinalLevels.get_value(yearNumber.to(), area_1->index), + level.to()); + + BOOST_CHECK(my_rule.apply()); + BOOST_CHECK_EQUAL(study->scenarioFinalHydroLevels[area_1->index][yearNumber.to()], + level.to()); +} + +BOOST_FIXTURE_TEST_CASE( + on_area2_and_on_year_1__hydro_level_2_4_is_chosen_level_lowered_to_1__reading_OK, + Fixture) +{ + AreaName yearNumber = "1"; + String level = "2.4"; + AreaName::Vector splitKey = {"hfl", "area 2", yearNumber}; + BOOST_CHECK(my_rule.readLine(splitKey, level, false)); + + BOOST_CHECK_EQUAL(my_rule.hydroFinalLevels.get_value(yearNumber.to(), area_2->index), 1.); + + BOOST_CHECK(my_rule.apply()); + BOOST_CHECK_EQUAL(study->scenarioFinalHydroLevels[area_2->index][yearNumber.to()], 1.); +} + +BOOST_FIXTURE_TEST_CASE( + on_area3_and_on_year_3__hydro_level_neg_5_2_is_chosen__level_raised_to_0__reading_OK, + Fixture) +{ + AreaName yearNumber = "3"; + String level = "-5.2"; + AreaName::Vector splitKey = {"hfl", "area 3", yearNumber}; + BOOST_CHECK(my_rule.readLine(splitKey, level, false)); + + BOOST_CHECK_EQUAL(my_rule.hydroFinalLevels.get_value(yearNumber.to(), area_3->index), 0.); + + BOOST_CHECK(my_rule.apply()); + BOOST_CHECK_EQUAL(study->scenarioFinalHydroLevels[area_3->index][yearNumber.to()], 0.); } // ====================== 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 b0fd157f03..e9a410b983 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 @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test save scenario - builder.dat #include #include @@ -188,7 +188,7 @@ struct commonFixture study->bindingConstraintsGroups.add("group3"); // Scenario builder initialization - study->scenarioRules = new ScenarioBuilder::Sets(); + study->scenarioRules = std::make_unique(); study->scenarioRules->setStudy(*study); my_rule = study->scenarioRules->createNew("my rule name"); BOOST_CHECK(my_rule->reset()); @@ -411,15 +411,15 @@ BOOST_FIXTURE_TEST_CASE( } // ======================== -// Tests on Hydro levels +// Tests on Hydro initial levels // ======================== BOOST_FIXTURE_TEST_CASE( HYDRO_LEVEL__TS_number_for_many_areas_and_years__generated_and_ref_sc_buider_files_are_identical, saveFixture) { - my_rule->hydroLevels.setTSnumber(area_1->index, 9, 9); - my_rule->hydroLevels.setTSnumber(area_3->index, 18, 7); - my_rule->hydroLevels.setTSnumber(area_1->index, 5, 8); + my_rule->hydroInitialLevels.setTSnumber(area_1->index, 9, 9); + my_rule->hydroInitialLevels.setTSnumber(area_3->index, 18, 7); + my_rule->hydroInitialLevels.setTSnumber(area_1->index, 5, 8); saveScenarioBuilder(); @@ -433,6 +433,29 @@ BOOST_FIXTURE_TEST_CASE( BOOST_CHECK(files_identical(path_to_generated_file, referenceFile.path())); } +// ======================== +// Tests on Hydro final levels +// ======================== +BOOST_FIXTURE_TEST_CASE( + HYDRO_FINAL_LEVEL__TS_number_for_many_areas_and_years__generated_and_ref_sc_buider_files_are_identical, + saveFixture) +{ + my_rule->hydroFinalLevels.setTSnumber(area_1->index, 4, 8); + my_rule->hydroFinalLevels.setTSnumber(area_2->index, 11, 3); + my_rule->hydroFinalLevels.setTSnumber(area_3->index, 15, 2); + + saveScenarioBuilder(); + + // Build reference scenario builder file + referenceFile.append("[my rule name]"); + referenceFile.append("hfl,area 1,4 = 8"); + referenceFile.append("hfl,area 2,11 = 3"); + referenceFile.append("hfl,area 3,15 = 2"); + referenceFile.write(); + + BOOST_CHECK(files_identical(path_to_generated_file, referenceFile.path())); +} + // ====================== // Tests on Links NTC // ====================== @@ -496,7 +519,7 @@ BOOST_FIXTURE_TEST_CASE( my_rule->renewable[area_3->index].setTSnumber(rnCluster_32.get(), 5, 13); my_rule->linksNTC[area_1->index].setDataForLink(link_13, 19, 8); my_rule->linksNTC[area_2->index].setDataForLink(link_23, 2, 4); - my_rule->hydroLevels.setTSnumber(area_1->index, 5, 8); + my_rule->hydroInitialLevels.setTSnumber(area_1->index, 5, 8); my_rule->binding_constraints.setTSnumber("group3", 10, 6); saveScenarioBuilder(); diff --git a/src/tests/src/libs/antares/study/series/CMakeLists.txt b/src/tests/src/libs/antares/study/series/CMakeLists.txt index f525878822..27c31d1728 100644 --- a/src/tests/src/libs/antares/study/series/CMakeLists.txt +++ b/src/tests/src/libs/antares/study/series/CMakeLists.txt @@ -8,6 +8,7 @@ add_executable(timeseries-tests ${SRC_TIMESERIES_TESTS}) target_link_libraries(timeseries-tests PRIVATE + Antares::array Boost::unit_test_framework Antares::series antares-solver-simulation diff --git a/src/tests/src/libs/antares/study/series/timeseries-tests.cpp b/src/tests/src/libs/antares/study/series/timeseries-tests.cpp index 4e49aea134..4908d10601 100644 --- a/src/tests/src/libs/antares/study/series/timeseries-tests.cpp +++ b/src/tests/src/libs/antares/study/series/timeseries-tests.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE "test time series" #define WIN32_LEAN_AND_MEAN diff --git a/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp b/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp index fed4f02570..d7de940912 100644 --- a/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp +++ b/src/tests/src/libs/antares/study/short-term-storage-input/short-term-storage-input-output.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE "test short term storage" #define WIN32_LEAN_AND_MEAN @@ -51,6 +51,10 @@ void resizeFillVectors(ShortTermStorage::Series& series, double value, unsigned series.inflows.resize(size, value); series.lowerRuleCurve.resize(size, value); series.upperRuleCurve.resize(size, value); + + series.costInjection.resize(size, value); + series.costWithdrawal.resize(size, value); + series.costLevel.resize(size, value); } void createIndividualFileSeries(const std::string& path, double value, unsigned int size) @@ -88,6 +92,10 @@ void createFileSeries(double value, unsigned int size) createIndividualFileSeries(folder + SEP + "inflows.txt", value, size); createIndividualFileSeries(folder + SEP + "lower-rule-curve.txt", value, size); createIndividualFileSeries(folder + SEP + "upper-rule-curve.txt", value, size); + + createIndividualFileSeries(folder + SEP + "cost-injection.txt", value, size); + createIndividualFileSeries(folder + SEP + "cost-withdrawal.txt", value, size); + createIndividualFileSeries(folder + SEP + "cost-level.txt", value, size); } void createFileSeries(unsigned int size) @@ -99,6 +107,10 @@ void createFileSeries(unsigned int size) createIndividualFileSeries(folder + SEP + "inflows.txt", size); createIndividualFileSeries(folder + SEP + "lower-rule-curve.txt", size); createIndividualFileSeries(folder + SEP + "upper-rule-curve.txt", size); + + createIndividualFileSeries(folder + SEP + "cost-injection.txt", size); + createIndividualFileSeries(folder + SEP + "cost-withdrawal.txt", size); + createIndividualFileSeries(folder + SEP + "cost-level.txt", size); } void createIniFile(bool enabled) @@ -115,6 +127,7 @@ void createIniFile(bool enabled) outfile << "withdrawalnominalcapacity = 900.000000" << std::endl; outfile << "reservoircapacity = 31200.000000" << std::endl; outfile << "efficiency = 0.75" << std::endl; + outfile << "efficiencywithdrawal = 0.9" << std::endl; outfile << "initiallevel = 0.50000" << std::endl; outfile << "enabled = " << (enabled ? "true" : "false") << std::endl; outfile.close(); @@ -134,6 +147,7 @@ void createIniFileWrongValue() outfile << "withdrawalnominalcapacity = -900.000000" << std::endl; outfile << "reservoircapacity = -31200.000000" << std::endl; outfile << "efficiency = 4" << std::endl; + outfile << "efficiencywithdrawal = -2" << std::endl; outfile << "initiallevel = -0.50000" << std::endl; outfile.close(); @@ -174,6 +188,10 @@ struct Fixture std::filesystem::remove(folder + SEP + "inflows.txt"); std::filesystem::remove(folder + SEP + "lower-rule-curve.txt"); std::filesystem::remove(folder + SEP + "upper-rule-curve.txt"); + + std::filesystem::remove(folder + SEP + "cost-injection.txt"); + std::filesystem::remove(folder + SEP + "cost-withdrawal.txt"); + std::filesystem::remove(folder + SEP + "cost-level.txt"); } std::string folder = getFolder(); diff --git a/src/tests/src/libs/antares/study/test_study.cpp b/src/tests/src/libs/antares/study/test_study.cpp index 77c30ed914..fa0348467d 100644 --- a/src/tests/src/libs/antares/study/test_study.cpp +++ b/src/tests/src/libs/antares/study/test_study.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE study #define WIN32_LEAN_AND_MEAN @@ -139,7 +139,7 @@ BOOST_FIXTURE_TEST_CASE(short_term_storage_delete, OneAreaStudy) BOOST_CHECK(findDisabledCluster("Cluster1") != sts.end()); BOOST_CHECK(findDisabledCluster("Cluster2") != sts.end()); - study->initializeRuntimeInfos(); // This should remove all disabled short-term storages + study->initializeRuntimeInfos(); // Check that only "Cluster1" is found BOOST_CHECK(findDisabledCluster("Cluster1") != sts.end()); @@ -291,4 +291,37 @@ BOOST_AUTO_TEST_CASE(version_parsing) BOOST_CHECK(!v.fromString("4.5")); BOOST_CHECK(v == StudyVersion::unknown()); } + +BOOST_FIXTURE_TEST_CASE(check_filename_limit, OneAreaStudy) +{ + auto s = std::make_unique(); + BOOST_CHECK(s->checkForFilenameLimits(true)); // empty areas should return true + + BOOST_CHECK(study->checkForFilenameLimits(true)); + BOOST_CHECK(study->checkForFilenameLimits(false)); + BOOST_CHECK(study->checkForFilenameLimits(true, "abc")); + +#ifdef YUNI_OS_WINDOWS + std::string area1name(128, 'a'); + std::string area2name(128, 'b'); + auto areaB = study->areaAdd(area1name); + auto areaC = study->areaAdd(area2name); + AreaAddLinkBetweenAreas(areaB, areaC); + BOOST_CHECK(!study->checkForFilenameLimits(true)); +#endif +} + +BOOST_FIXTURE_TEST_CASE(cpu_count, OneAreaStudy) +{ + BOOST_CHECK_EQUAL(study->getNumberOfCoresPerMode(75, ncMin), 1); + BOOST_CHECK_EQUAL(study->getNumberOfCoresPerMode(10, ncLow), 3); + BOOST_CHECK_EQUAL(study->getNumberOfCoresPerMode(6, ncAvg), 3); + BOOST_CHECK_EQUAL(study->getNumberOfCoresPerMode(16, ncHigh), 12); + BOOST_CHECK_EQUAL(study->getNumberOfCoresPerMode(128, ncMax), 128); + + // error cases + BOOST_CHECK_EQUAL(study->getNumberOfCoresPerMode(0, ncMax), 0); + BOOST_CHECK_EQUAL(study->getNumberOfCoresPerMode(10, 120), 0); +} + BOOST_AUTO_TEST_SUITE_END() // version 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 e2473fc986..cfef5909e5 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 @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE "test thermal price definition" #define WIN32_LEAN_AND_MEAN diff --git a/src/tests/src/libs/antares/test_utils.cpp b/src/tests/src/libs/antares/test_utils.cpp index 9e101e34a3..5cb05e27c4 100644 --- a/src/tests/src/libs/antares/test_utils.cpp +++ b/src/tests/src/libs/antares/test_utils.cpp @@ -1,32 +1,32 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test utils +#include #include #include -#include - #include -#include + +#include namespace fs = std::filesystem; @@ -99,7 +99,8 @@ BOOST_AUTO_TEST_CASE(yuni_normalize_vs_std_lexically_normal) { Yuni::String yuniNorm; Yuni::IO::Normalize(yuniNorm, path.string()); - BOOST_CHECK_MESSAGE(path.lexically_normal().string() == yuniNorm, std::string("Check failed for ") + path.string()); + BOOST_CHECK_MESSAGE(path.lexically_normal().string() == yuniNorm, + std::string("Check failed for ") + path.string()); }; helper(fs::path("a/./b/..")); helper(fs::path("a/.///b/../")); diff --git a/src/tests/src/libs/antares/writer/CMakeLists.txt b/src/tests/src/libs/antares/writer/CMakeLists.txt index 6487355a81..b85bcce05c 100644 --- a/src/tests/src/libs/antares/writer/CMakeLists.txt +++ b/src/tests/src/libs/antares/writer/CMakeLists.txt @@ -2,11 +2,11 @@ add_executable(test-writer test_writer.cpp) target_link_libraries(test-writer - PRIVATE - Boost::unit_test_framework - Antares::result_writer - test_utils_unit - MINIZIP::minizip + PRIVATE + Boost::unit_test_framework + Antares::result_writer + test_utils_unit + MINIZIP::minizip ) set_target_properties(test-writer PROPERTIES FOLDER Unit-tests/test-writer) diff --git a/src/tests/src/libs/antares/writer/test_writer.cpp b/src/tests/src/libs/antares/writer/test_writer.cpp index 3a87905607..4450b4d937 100644 --- a/src/tests/src/libs/antares/writer/test_writer.cpp +++ b/src/tests/src/libs/antares/writer/test_writer.cpp @@ -1,25 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ -#include // Fix for Boost < 1.67 - + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test - writer tests #include #include @@ -63,7 +61,7 @@ std::shared_ptr createThreadPool(int size) std::string removeExtension(const std::string& name, const std::string& ext) { - int length = name.size(); + size_t length = name.size(); if (name.size() > ext.size() && name.substr(length - ext.size()) == ext) { return name.substr(0, length - ext.size()); diff --git a/src/tests/src/libs/antares/yaml-parser/test_yaml_parser.cpp b/src/tests/src/libs/antares/yaml-parser/test_yaml_parser.cpp index ebfbc4bba8..87978fbcaa 100644 --- a/src/tests/src/libs/antares/yaml-parser/test_yaml_parser.cpp +++ b/src/tests/src/libs/antares/yaml-parser/test_yaml_parser.cpp @@ -19,19 +19,22 @@ ** along with Antares_Simulator. If not, see . */ #define BOOST_TEST_MODULE yamlcpp tests -#include -#include -#include "yaml-cpp/yaml.h" -#include #include +#include #include #include +#include +#include + +#include "yaml-cpp/yaml.h" + // our data types struct Vec3 { float x, y, z; }; + struct Power { std::string name; @@ -44,6 +47,7 @@ struct Monster Vec3 position; std::vector powers; }; + namespace YAML { template<> @@ -71,6 +75,7 @@ struct convert return true; } }; + template<> struct convert { @@ -89,6 +94,7 @@ struct convert return true; } }; + template<> struct convert { @@ -108,7 +114,7 @@ struct convert rhs.name = node["name"].as(); rhs.position = node["position"].as(); const YAML::Node& powers = node["powers"]; - for (const auto power : powers) + for (const auto power: powers) { rhs.powers.push_back(power.as()); } diff --git a/src/tests/src/solver/CMakeLists.txt b/src/tests/src/solver/CMakeLists.txt index 690cf4fa68..bf920cb80b 100644 --- a/src/tests/src/solver/CMakeLists.txt +++ b/src/tests/src/solver/CMakeLists.txt @@ -1,5 +1,7 @@ - add_subdirectory(simulation) add_subdirectory(optimisation) add_subdirectory(utils) add_subdirectory(infeasible-problem-analysis) +add_subdirectory(lps) +add_subdirectory(modeler) +add_subdirectory(expressions) diff --git a/src/tests/src/solver/expressions/CMakeLists.txt b/src/tests/src/solver/expressions/CMakeLists.txt new file mode 100644 index 0000000000..f2166a71ad --- /dev/null +++ b/src/tests/src/solver/expressions/CMakeLists.txt @@ -0,0 +1,30 @@ +set(EXECUTABLE_NAME test-expressions) +add_executable(${EXECUTABLE_NAME}) + +target_sources(${EXECUTABLE_NAME} + PRIVATE + test_main.cpp + test_nodes.cpp + test_PrintAndEvalNodes.cpp + test_TimeIndexVisitor.cpp + test_SubstitutionVisitor.cpp + test_LinearVisitor.cpp + test_CompareVisitor.cpp + test_CloneVisitor.cpp + test_DeepWideTrees.cpp + test_Iterators.cpp +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + antares-solver-expressions + antares-solver-expressions-iterators +) + +# Storing tests-ts-numbers under the folder Unit-tests in the IDE +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) + +add_test(NAME test-expressions COMMAND ${EXECUTABLE_NAME}) + +set_property(TEST test-expressions PROPERTY LABELS unit) diff --git a/src/tests/src/solver/expressions/test_CloneVisitor.cpp b/src/tests/src/solver/expressions/test_CloneVisitor.cpp new file mode 100644 index 0000000000..b78fe098c6 --- /dev/null +++ b/src/tests/src/solver/expressions/test_CloneVisitor.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; +using namespace Antares::Solver::Visitors; + +BOOST_AUTO_TEST_SUITE(_CloneVisitor_) + +BOOST_FIXTURE_TEST_CASE(cloneVisitor_With_Add_Neg_ComponentVariableNode, Registry) +{ + std::string cpvar_name("var"), cpvar_id("id1"); + std::string cp_para_name("par"), cp_para_id("id2"); + ComponentVariableNode cpv(cpvar_id, cpvar_name); + ComponentParameterNode cpp(cp_para_id, cp_para_name); + double num1 = 22.0, num2 = 8.; + // (num1+num2) + Node* edge = create(create(num1), create(num2)); + // -((num1+num2)) + Node* negative_edge = create(edge); + // (-((num1+num2))+id1.var) + Node* add_node = create(negative_edge, &cpv); + // (-((-((num1+num2))+id1.var))+id2.par) == + // (-((-((22.000000+8.000000))+id1.var))+id2.par) + Node* root = create(create(add_node), &cpp); + + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(root); + + BOOST_CHECK_EQUAL(printed, "(-((-((22.000000+8.000000))+id1.var))+id2.par)"); + CloneVisitor cloneVisitor(*this); + Node* cloned = cloneVisitor.dispatch(root); + BOOST_CHECK_EQUAL(printed, printVisitor.dispatch(cloned)); +} + +BOOST_FIXTURE_TEST_CASE(CloneVisitor_name, Registry) +{ + CloneVisitor cloneVisitor(*this); + BOOST_CHECK_EQUAL(cloneVisitor.name(), "CloneVisitor"); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_CompareVisitor.cpp b/src/tests/src/solver/expressions/test_CompareVisitor.cpp new file mode 100644 index 0000000000..da814fdc13 --- /dev/null +++ b/src/tests/src/solver/expressions/test_CompareVisitor.cpp @@ -0,0 +1,133 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; +using namespace Antares::Solver::Visitors; + +struct ComparisonFixture +{ + Node* createSimpleExpression(double param); + Node* createComplexExpression(); + + Registry registry_; +}; + +Node* ComparisonFixture::createSimpleExpression(double param) +{ + Node* var1 = registry_.create(param); + Node* param1 = registry_.create("param1"); + Node* expr = registry_.create(var1, param1); + return expr; +} + +Node* ComparisonFixture::createComplexExpression() +{ + // NOTE : this expression makes no sense, only for testing purposes + // NOTE2 : Some elements are re-used (e.g simple), this is valid since memory is handled + // separately (no double free) + + Node* simple = createSimpleExpression(42.); + Node* neg = registry_.create(simple); + Node* mult = registry_.create(simple, neg); + Node* comp = registry_.create("hello", "world"); + Node* div = registry_.create(mult, comp); + Node* div2 = registry_.create(div, simple); + Node* add = registry_.create(div, div2); + Node* sub = registry_.create(add, neg); + Node* cmp = registry_.create(sub, add); + Node* pf = registry_.create("port", "field"); + Node* addf = registry_.create(pf, cmp); + return addf; +} + +BOOST_AUTO_TEST_SUITE(_CompareVisitor_) + +BOOST_FIXTURE_TEST_CASE(simple_comparison_to_itself, ComparisonFixture) +{ + CompareVisitor cmp; + Node* expr = createSimpleExpression(65.); + BOOST_CHECK(cmp.dispatch(expr, expr)); +} + +BOOST_FIXTURE_TEST_CASE(comparison_to_other_same, ComparisonFixture) +{ + CompareVisitor cmp; + Node* expr1 = createSimpleExpression(65.); + Node* expr2 = createSimpleExpression(65.); + BOOST_CHECK(cmp.dispatch(expr1, expr2)); +} + +BOOST_FIXTURE_TEST_CASE(comparison_to_other_different, ComparisonFixture) +{ + CompareVisitor cmp; + Node* expr1 = createSimpleExpression(64.); + Node* expr2 = createSimpleExpression(65.); + BOOST_CHECK(!cmp.dispatch(expr1, expr2)); +} + +BOOST_FIXTURE_TEST_CASE(comparison_to_self_complex, ComparisonFixture) +{ + CompareVisitor cmp; + Node* expr = createComplexExpression(); + BOOST_CHECK(cmp.dispatch(expr, expr)); +} + +BOOST_FIXTURE_TEST_CASE(comparison_to_clone_complex, ComparisonFixture) +{ + CompareVisitor cmp; + Node* expr = createComplexExpression(); + CloneVisitor cloneVisitor(registry_); + Node* expr_cloned = cloneVisitor.dispatch(expr); + BOOST_CHECK(cmp.dispatch(expr, expr_cloned)); +} + +BOOST_FIXTURE_TEST_CASE(comparison_to_other_complex, ComparisonFixture) +{ + CompareVisitor cmp; + Node* expr1 = createComplexExpression(); + Node* expr2 = createComplexExpression(); + BOOST_CHECK(cmp.dispatch(expr1, expr2)); +} + +BOOST_FIXTURE_TEST_CASE(comparison_to_other_different_complex, ComparisonFixture) +{ + CompareVisitor cmp; + Node* expr1 = createComplexExpression(); + Node* expr2 = registry_.create(expr1); + BOOST_CHECK(!cmp.dispatch(expr1, expr2)); +} + +BOOST_FIXTURE_TEST_CASE(CompareVisitor_name, Registry) +{ + CompareVisitor compareVisitor; + BOOST_CHECK_EQUAL(compareVisitor.name(), "CompareVisitor"); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_DeepWideTrees.cpp b/src/tests/src/solver/expressions/test_DeepWideTrees.cpp new file mode 100644 index 0000000000..957996641b --- /dev/null +++ b/src/tests/src/solver/expressions/test_DeepWideTrees.cpp @@ -0,0 +1,87 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; +using namespace Antares::Solver::Visitors; + +BOOST_AUTO_TEST_SUITE(_DeepTree_) + +static Node* deepNegationTree(Registry& registry, double litValue, size_t depth) +{ + Node* node = registry.create(litValue); + for (size_t c = 0; c < depth; c++) + { + node = registry.create(node); + } + return node; +} + +BOOST_FIXTURE_TEST_CASE(deep_tree_even, Registry) +{ + Node* node = deepNegationTree(*this, 42., 1000); + EvalVisitor evalVisitor; + // (-1)^1000 = 1 + BOOST_CHECK_EQUAL(evalVisitor.dispatch(node), 42.); +} + +BOOST_FIXTURE_TEST_CASE(deep_tree_odd, Registry) +{ + Node* node = deepNegationTree(*this, 42., 1001); + EvalVisitor evalVisitor; + // (-1)^1001 = -1 + BOOST_CHECK_EQUAL(evalVisitor.dispatch(node), -42.); +} + +static Node* deepAddTree(Registry& registry, AddNode* root, int depth) +{ + if (depth > 0) + { + Node* left = deepAddTree(registry, root, depth - 1); + Node* right = deepAddTree(registry, root, depth - 1); + return registry.create(left, right); + } + else + { + return registry.create(42.); + } +} + +BOOST_FIXTURE_TEST_CASE(binary_tree, Registry) +{ + // AddNode's children are not mutable, so we'll replace this empty root with an actual one + AddNode* root = create(nullptr, nullptr); + Node* node = deepAddTree(*this, root, 10); + EvalVisitor evalVisitor; + // We expect 1024 = 2^10 literal nodes, each carrying value 42. + BOOST_CHECK_EQUAL(evalVisitor.dispatch(node), 42. * 1024); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_Iterators.cpp b/src/tests/src/solver/expressions/test_Iterators.cpp new file mode 100644 index 0000000000..df0a4ddd18 --- /dev/null +++ b/src/tests/src/solver/expressions/test_Iterators.cpp @@ -0,0 +1,136 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; + +BOOST_AUTO_TEST_SUITE(_Iterator_) + +static Node* simpleExpression(Registry& registry) +{ + return registry.create(registry.create(2.), + registry.create(21.)); +} + +BOOST_FIXTURE_TEST_CASE(empty_ast_begin_is_end, Registry) +{ + AST ast(nullptr); + BOOST_CHECK(ast.begin() == ast.end()); +} + +BOOST_FIXTURE_TEST_CASE(simple_end_is_end, Registry) +{ + AST ast(create(32.)); + BOOST_CHECK(ast.end() == ast.end()); +} + +BOOST_FIXTURE_TEST_CASE(dereference_op, Registry) +{ + AST ast(create(21.)); + auto it = ast.begin(); + const std::string expected("LiteralNode"); + BOOST_CHECK_EQUAL(it->name(), expected); + BOOST_CHECK_EQUAL((*it).name(), expected); +} + +BOOST_FIXTURE_TEST_CASE(unary_dereference, Registry) +{ + AST ast(create(nullptr)); + auto it = ast.begin(); + BOOST_CHECK(!it->name().empty()); + BOOST_CHECK(!(*it).name().empty()); +} + +BOOST_FIXTURE_TEST_CASE(count_literal_nodes_for_loop, Registry) +{ + int count_lit = 0; + for (auto& node: AST(simpleExpression(*this))) + { + if (dynamic_cast(&node)) + { + count_lit++; + } + } + BOOST_CHECK_EQUAL(count_lit, 2); +} + +BOOST_FIXTURE_TEST_CASE(count_literal_nodes_count_if, Registry) +{ + AST ast(simpleExpression(*this)); + int count_lit = std::count_if(ast.begin(), + ast.end(), + [](Node& node) + { return dynamic_cast(&node) != nullptr; }); + + BOOST_CHECK_EQUAL(count_lit, 2); +} + +BOOST_FIXTURE_TEST_CASE(find_if_not_found, Registry) +{ + AST ast(simpleExpression(*this)); + auto it = std::find_if(ast.begin(), + ast.end(), + [](Node& node) + { return dynamic_cast(&node) != nullptr; }); + BOOST_CHECK(it == ast.end()); +} + +BOOST_FIXTURE_TEST_CASE(find_if_found, Registry) +{ + AST ast(simpleExpression(*this)); + auto it = std::find_if(ast.begin(), + ast.end(), + [](Node& node) { return dynamic_cast(&node) != nullptr; }); + BOOST_CHECK(it != ast.end()); + auto* res = dynamic_cast(&*it); + BOOST_REQUIRE(res); + BOOST_CHECK_EQUAL(res->value(), 2.); +} + +BOOST_FIXTURE_TEST_CASE(distance_is_3, Registry) +{ + AST ast(simpleExpression(*this)); + BOOST_CHECK_EQUAL(std::distance(ast.begin(), ast.end()), 3); +} + +BOOST_FIXTURE_TEST_CASE(distance_unary, Registry) +{ + AST ast(create(create(create(32.)))); + BOOST_CHECK_EQUAL(std::distance(ast.begin(), ast.end()), 3); +} + +BOOST_FIXTURE_TEST_CASE(distance_nullptr_is_3, Registry) +{ + AST ast(create(nullptr, create(2.))); + BOOST_CHECK_EQUAL(std::distance(ast.begin(), ast.end()), 3); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_LinearVisitor.cpp b/src/tests/src/solver/expressions/test_LinearVisitor.cpp new file mode 100644 index 0000000000..7bc67ce8ed --- /dev/null +++ b/src/tests/src/solver/expressions/test_LinearVisitor.cpp @@ -0,0 +1,293 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; +using namespace Antares::Solver::Visitors; + +namespace bdata = boost::unit_test::data; + +// Only necessary for BOOST_CHECK_EQUAL +namespace Antares::Solver::Visitors +{ +static std::ostream& operator<<(std::ostream& os, LinearStatus s) +{ + switch (s) + { + case LinearStatus::CONSTANT: + return os << "LinearStatus::CONSTANT"; + case LinearStatus::LINEAR: + return os << "LinearStatus::LINEAR"; + case LinearStatus::NON_LINEAR: + return os << "LinearStatus::NON_LINEAR"; + default: + return os << ""; + } +} +} // namespace Antares::Solver::Visitors + +BOOST_AUTO_TEST_SUITE(_LinearVisitor_) + +BOOST_AUTO_TEST_CASE(linear_status_plus) +{ + BOOST_CHECK_EQUAL(LinearStatus::LINEAR + LinearStatus::LINEAR, LinearStatus::LINEAR); + BOOST_CHECK_EQUAL(LinearStatus::LINEAR + LinearStatus::CONSTANT, LinearStatus::LINEAR); + BOOST_CHECK_EQUAL(LinearStatus::LINEAR + LinearStatus::NON_LINEAR, LinearStatus::NON_LINEAR); + + BOOST_CHECK_EQUAL(LinearStatus::CONSTANT + LinearStatus::CONSTANT, LinearStatus::CONSTANT); + BOOST_CHECK_EQUAL(LinearStatus::CONSTANT + LinearStatus::NON_LINEAR, LinearStatus::NON_LINEAR); + + BOOST_CHECK_EQUAL(LinearStatus::NON_LINEAR + LinearStatus::NON_LINEAR, + LinearStatus::NON_LINEAR); +} + +BOOST_AUTO_TEST_CASE(linear_status_mult) +{ + BOOST_CHECK_EQUAL(LinearStatus::LINEAR * LinearStatus::LINEAR, LinearStatus::NON_LINEAR); + BOOST_CHECK_EQUAL(LinearStatus::LINEAR * LinearStatus::CONSTANT, LinearStatus::LINEAR); + BOOST_CHECK_EQUAL(LinearStatus::LINEAR * LinearStatus::NON_LINEAR, LinearStatus::NON_LINEAR); + + BOOST_CHECK_EQUAL(LinearStatus::CONSTANT * LinearStatus::CONSTANT, LinearStatus::CONSTANT); + BOOST_CHECK_EQUAL(LinearStatus::CONSTANT * LinearStatus::NON_LINEAR, LinearStatus::NON_LINEAR); + + BOOST_CHECK_EQUAL(LinearStatus::NON_LINEAR * LinearStatus::NON_LINEAR, + LinearStatus::NON_LINEAR); +} + +BOOST_AUTO_TEST_CASE(linear_status_divide) +{ + BOOST_CHECK_EQUAL(LinearStatus::LINEAR / LinearStatus::LINEAR, LinearStatus::NON_LINEAR); + BOOST_CHECK_EQUAL(LinearStatus::LINEAR / LinearStatus::CONSTANT, LinearStatus::LINEAR); + BOOST_CHECK_EQUAL(LinearStatus::LINEAR / LinearStatus::NON_LINEAR, LinearStatus::NON_LINEAR); + + BOOST_CHECK_EQUAL(LinearStatus::CONSTANT / LinearStatus::CONSTANT, LinearStatus::CONSTANT); + BOOST_CHECK_EQUAL(LinearStatus::CONSTANT / LinearStatus::NON_LINEAR, LinearStatus::NON_LINEAR); + + BOOST_CHECK_EQUAL(LinearStatus::NON_LINEAR / LinearStatus::NON_LINEAR, + LinearStatus::NON_LINEAR); +} + +static const std::vector LinearStatus_ALL = {LinearStatus::LINEAR, + LinearStatus::NON_LINEAR, + LinearStatus::CONSTANT}; + +BOOST_DATA_TEST_CASE(linear_status_minus, bdata::make(LinearStatus_ALL), x) +{ + BOOST_CHECK_EQUAL(x, -x); +} + +BOOST_DATA_TEST_CASE(linear_plus_commutative, + bdata::make(LinearStatus_ALL) * bdata::make(LinearStatus_ALL), + x, + y) +{ + BOOST_CHECK_EQUAL(x + y, y + x); +} + +BOOST_DATA_TEST_CASE(linear_subtract_same_as_plus, + bdata::make(LinearStatus_ALL) * bdata::make(LinearStatus_ALL), + x, + y) +{ + BOOST_CHECK_EQUAL(x - y, x + y); +} + +BOOST_DATA_TEST_CASE(linear_multiply_commutative, + bdata::make(LinearStatus_ALL) * bdata::make(LinearStatus_ALL), + x, + y) +{ + BOOST_CHECK_EQUAL(x * y, y * x); +} + +BOOST_FIXTURE_TEST_CASE(comparison_nodes_variable_variable_is_linear, Registry) +{ + PrintVisitor printVisitor; + LinearityVisitor linearVisitor; + + VariableNode var1("x"); + // variable + VariableNode var2("y"); + // x==y + Node* eq = create(&var1, &var2); + BOOST_CHECK_EQUAL(printVisitor.dispatch(eq), "x==y"); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(eq), LinearStatus::LINEAR); + // x<=y + Node* lt = create(&var1, &var2); + BOOST_CHECK_EQUAL(printVisitor.dispatch(lt), "x<=y"); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(lt), LinearStatus::LINEAR); + // x>=y + Node* gt = create(&var1, &var2); + BOOST_CHECK_EQUAL(printVisitor.dispatch(gt), "x>=y"); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(gt), LinearStatus::LINEAR); +} + +BOOST_FIXTURE_TEST_CASE(comparison_nodes_variable_constant_is_linear, Registry) +{ + PrintVisitor printVisitor; + LinearityVisitor linearVisitor; + + VariableNode var1("x"); + // variable + LiteralNode literal(21.); + // x==21 + Node* eq = create(&var1, &literal); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(eq), LinearStatus::LINEAR); + // x<=21 + Node* lt = create(&var1, &literal); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(lt), LinearStatus::LINEAR); + // x>=21 + Node* gt = create(&var1, &literal); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(gt), LinearStatus::LINEAR); +} + +BOOST_FIXTURE_TEST_CASE(comparison_nodes_constant_constant_is_constant, Registry) +{ + PrintVisitor printVisitor; + LinearityVisitor linearVisitor; + + LiteralNode literal1(2.); + LiteralNode literal2(21.); + // 2==21 + Node* eq = create(&literal1, &literal2); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(eq), LinearStatus::CONSTANT); + // 2<=21 + Node* lt = create(&literal1, &literal2); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(lt), LinearStatus::CONSTANT); + // 2>=21 + Node* gt = create(&literal1, &literal2); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(gt), LinearStatus::CONSTANT); +} + +BOOST_FIXTURE_TEST_CASE(comparison_nodes_non_lin_constant_is_constant, Registry) +{ + PrintVisitor printVisitor; + LinearityVisitor linearVisitor; + + VariableNode var1("x"); + // variable + VariableNode var2("y"); + MultiplicationNode mult(&var1, &var2); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(&mult), LinearStatus::NON_LINEAR); + + AddNode add(&mult, &var1); + Node* gt = create(&mult, &var2); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(gt), LinearStatus::NON_LINEAR); +} + +BOOST_FIXTURE_TEST_CASE(simple_linear, Registry) +{ + LiteralNode literalNode1(10.); + VariableNode var1("x"); + // 10.*x + Node* u = create(&literalNode1, &var1); + + LiteralNode literalNode2(20.); + ComponentVariableNode var2("id", "y"); + // 20.*id.y + Node* v = create(&literalNode2, &var2); + // 10.*x+20.*id.y + Node* expr = create(u, v); + + PrintVisitor printVisitor; + BOOST_CHECK_EQUAL(printVisitor.dispatch(expr), "((10.000000*x)+(20.000000*id.y))"); + LinearityVisitor linearVisitor; + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::LINEAR); +} + +BOOST_FIXTURE_TEST_CASE(simple_not_linear, Registry) +{ + VariableNode var1("x"); + ComponentVariableNode var2("id", "y"); + // x*id.y + Node* expr = create(&var1, &var2); + + PrintVisitor printVisitor; + BOOST_CHECK_EQUAL(printVisitor.dispatch(expr), "(x*id.y)"); + LinearityVisitor linearVisitor; + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::NON_LINEAR); +} + +BOOST_FIXTURE_TEST_CASE(simple_linear_division, Registry) +{ + VariableNode var1("x"); + // constant + ParameterNode param("y"); + // x/y + Node* expr = create(&var1, ¶m); + + PrintVisitor printVisitor; + BOOST_CHECK_EQUAL(printVisitor.dispatch(expr), "(x/y)"); + LinearityVisitor linearVisitor; + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::LINEAR); +} + +BOOST_FIXTURE_TEST_CASE(simple_non_linear_division, Registry) +{ + VariableNode var1("x"); + // variable + VariableNode var2("y"); + // x/y + Node* expr = create(&var1, &var2); + + PrintVisitor printVisitor; + BOOST_CHECK_EQUAL(printVisitor.dispatch(expr), "(x/y)"); + LinearityVisitor linearVisitor; + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::NON_LINEAR); +} + +BOOST_FIXTURE_TEST_CASE(simple_constant_expression, Registry) +{ + PrintVisitor printVisitor; + LinearityVisitor linearVisitor; + LiteralNode var1(65.); + // Parameter + ParameterNode par("p1"); + + // Port field + PortFieldNode portFieldNode("port", "field"); + + // 65.*p1 + Node* mult = create(&var1, &par); + // ((65.*p1)+port.field) + Node* expr = create(mult, &portFieldNode); + BOOST_CHECK_EQUAL(printVisitor.dispatch(expr), "((65.000000*p1)+port.field)"); + BOOST_CHECK_EQUAL(linearVisitor.dispatch(expr), LinearStatus::CONSTANT); +} + +BOOST_FIXTURE_TEST_CASE(LinearityVisitor_name, Registry) +{ + LinearityVisitor linearityVisitor; + BOOST_CHECK_EQUAL(linearityVisitor.name(), "LinearityVisitor"); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp b/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp new file mode 100644 index 0000000000..8ad5a49a60 --- /dev/null +++ b/src/tests/src/solver/expressions/test_PrintAndEvalNodes.cpp @@ -0,0 +1,294 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; +using namespace Antares::Solver::Visitors; + +BOOST_AUTO_TEST_SUITE(_PrintAndEvalNodes_) + +BOOST_AUTO_TEST_CASE(print_single_literal) +{ + LiteralNode literal(21); + + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(&literal); + + BOOST_CHECK_EQUAL(printed, "21.000000"); // TODO Number of decimals implementation dependent ? +} + +BOOST_AUTO_TEST_CASE(eval_single_literal) +{ + LiteralNode literal(21); + + EvalVisitor evalVisitor; + const double eval = evalVisitor.dispatch(&literal); + + BOOST_CHECK_EQUAL(eval, 21.); // TODO Number of decimals implementation dependent ? +} + +/* +Fixtures are used for the Registry that manages the memory allocations of nodes + +So instead of writing + Registry mem; + Node* root = mem.create(mem.create(21), mem.create(2)); +We can just write + Node* root = create(create(21), create(2)); + +since create is short for this->create. +*/ + +BOOST_FIXTURE_TEST_CASE(print_add_two_literals, Registry) +{ + Node* root = create(create(21), create(2)); + + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(root); + + BOOST_CHECK_EQUAL(printed, + "(21.000000+2.000000)"); // TODO Number of decimals implementation dependent ? +} + +BOOST_FIXTURE_TEST_CASE(eval_add_two_literals, Registry) +{ + Node* root = create(create(21), create(2)); + EvalVisitor evalVisitor; + double eval = evalVisitor.dispatch(root); + + BOOST_CHECK_EQUAL(eval, 23.); +} + +BOOST_FIXTURE_TEST_CASE(eval_negation_literal, Registry) +{ + const double num = 1428.0; + Node* root = create(create(num)); + EvalVisitor evalVisitor; + double eval = evalVisitor.dispatch(root); + + BOOST_CHECK_EQUAL(eval, -num); +} + +BOOST_FIXTURE_TEST_CASE(eval_Add_And_Negation_Nodes, Registry) +{ + const double num1 = 1428; + const double num2 = 8241; + Node* negative_num2 = create(create(num2)); + Node* root = create(create(num1), negative_num2); + EvalVisitor evalVisitor; + double eval = evalVisitor.dispatch(root); + + BOOST_CHECK_EQUAL(eval, num1 - num2); +} + +BOOST_FIXTURE_TEST_CASE(Negative_of_AddNode, Registry) +{ + const double num1 = 1428; + const double num2 = 8241; + Node* add_node = create(create(num1), create(num2)); + Node* neg = create(add_node); + EvalVisitor evalVisitor; + double eval = evalVisitor.dispatch(neg); + + BOOST_CHECK_EQUAL(eval, -(num1 + num2)); +} + +BOOST_FIXTURE_TEST_CASE(print_port_field_node, Registry) +{ + PortFieldNode pt_fd("august", "2024"); + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(&pt_fd); + + BOOST_CHECK_EQUAL(printed, "august.2024"); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_param, Registry) +{ + ParameterNode root("my-param"); + const double value = 221.3; + EvaluationContext context({{"my-param", value}}, {}); + + EvalVisitor evalVisitor(context); + const double eval = evalVisitor.dispatch(&root); + + BOOST_CHECK_EQUAL(value, eval); +} + +BOOST_FIXTURE_TEST_CASE(evaluate_variable, Registry) +{ + VariableNode root("my-variable"); + const double value = 221.3; + EvaluationContext context({}, {{"my-variable", value}}); + + EvalVisitor evalVisitor(context); + const double eval = evalVisitor.dispatch(&root); + + BOOST_CHECK_EQUAL(value, eval); +} + +BOOST_FIXTURE_TEST_CASE(multiplication_node, Registry) +{ + double num1 = 22.0, num2 = 8; + Node* mult = create(create(num1), create(num2)); + + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(mult); + + BOOST_CHECK_EQUAL(printed, "(22.000000*8.000000)"); + EvalVisitor evalVisitor; + BOOST_CHECK_EQUAL(evalVisitor.dispatch(mult), num1 * num2); +} + +BOOST_FIXTURE_TEST_CASE(division_node, Registry) +{ + double num1 = 22.0, num2 = 8; + Node* div = create(create(num1), create(num2)); + + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(div); + + BOOST_CHECK_EQUAL(printed, "(22.000000/8.000000)"); + EvalVisitor evalVisitor; + BOOST_CHECK_EQUAL(evalVisitor.dispatch(div), num1 / num2); +} + +BOOST_FIXTURE_TEST_CASE(division_by_zero, Registry) +{ + double num1 = 22.0, num2 = 0.; + Node* div = create(create(num1), create(num2)); + + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(div); + + BOOST_CHECK_EQUAL(printed, "(22.000000/0.000000)"); + EvalVisitor evalVisitor; + + BOOST_CHECK_THROW(evalVisitor.dispatch(div), EvalVisitorDivisionException); +} + +BOOST_AUTO_TEST_CASE(DivisionNodeFull) +{ + EvalVisitor evalVisitor; + LiteralNode literalNode1(23.); + LiteralNode literalNode2(-23.); + + DivisionNode divisionNode1(&literalNode1, &literalNode1); + BOOST_CHECK_EQUAL(evalVisitor.dispatch(&divisionNode1), 1.0); + + DivisionNode divisionNode2(&literalNode1, &literalNode2); + BOOST_CHECK_EQUAL(evalVisitor.dispatch(&divisionNode2), -1.0); + + LiteralNode* literalNull = nullptr; + + DivisionNode divisionNode3(&literalNode1, literalNull); + + BOOST_CHECK_THROW(evalVisitor.dispatch(&divisionNode3), InvalidNode); + + // truncated to zero + LiteralNode literalVerySmall(1.e-324); + + DivisionNode divisionNode4(&literalNode1, &literalVerySmall); + + BOOST_CHECK_THROW(evalVisitor.dispatch(&divisionNode4), EvalVisitorDivisionException); +} + +BOOST_FIXTURE_TEST_CASE(subtraction_node, Registry) +{ + double num1 = 22.0, num2 = 8; + Node* sub = create(create(num1), create(num2)); + + PrintVisitor printVisitor; + const auto printed = printVisitor.dispatch(sub); + + BOOST_CHECK_EQUAL(printed, "(22.000000-8.000000)"); + EvalVisitor evalVisitor; + BOOST_CHECK_EQUAL(evalVisitor.dispatch(sub), num1 - num2); +} + +BOOST_FIXTURE_TEST_CASE(comparison_node, Registry) +{ + double num1 = 22.0, num2 = 8; + // (num1-num2) = (22.000000-8.000000) + SubtractionNode sub1(create(num1), create(num2)); + // (num2-num1) = (8.000000-22.000000) + SubtractionNode sub2(create(num2), create(num1)); + + PrintVisitor printVisitor; + + EqualNode equ(&sub1, &sub2); + auto printed = printVisitor.dispatch(&equ); + BOOST_CHECK_EQUAL(printed, "(22.000000-8.000000)==(8.000000-22.000000)"); + + LessThanOrEqualNode lt(&sub1, &sub2); + printed = printVisitor.dispatch(<); + BOOST_CHECK_EQUAL(printed, "(22.000000-8.000000)<=(8.000000-22.000000)"); + + GreaterThanOrEqualNode gt(&sub1, &sub2); + printed = printVisitor.dispatch(>); + BOOST_CHECK_EQUAL(printed, "(22.000000-8.000000)>=(8.000000-22.000000)"); +} + +BOOST_AUTO_TEST_CASE(invalidNode) +{ + AddNode* null_node = nullptr; + EvalVisitor evalVisitor; + BOOST_CHECK_THROW(evalVisitor.dispatch(null_node), InvalidNode); +} + +BOOST_FIXTURE_TEST_CASE(NotEvaluableNodes, Registry) +{ + LiteralNode literalNode(23.); + std::string component_id("id"); + std::string name("name"); + std::vector nodes = {create(&literalNode, &literalNode), + create(&literalNode, &literalNode), + create(&literalNode, &literalNode), + create(name, name), + create(component_id, name), + create(component_id, name)}; + EvalVisitor evalVisitor; + for (auto* node: nodes) + { + BOOST_CHECK_THROW(evalVisitor.dispatch(node), EvalVisitorNotImplemented); + } +} + +BOOST_AUTO_TEST_CASE(PrintVisitor_name) +{ + PrintVisitor printVisitor; + BOOST_CHECK_EQUAL(printVisitor.name(), "PrintVisitor"); +} + +BOOST_AUTO_TEST_CASE(EvalVisitor_name) +{ + EvalVisitor evalVisitor; + BOOST_CHECK_EQUAL(evalVisitor.name(), "EvalVisitor"); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp b/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp new file mode 100644 index 0000000000..8a4080fc0c --- /dev/null +++ b/src/tests/src/solver/expressions/test_SubstitutionVisitor.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; +using namespace Antares::Solver::Visitors; + +// Only necessary for BOOST_CHECK_EQUAL + +BOOST_AUTO_TEST_SUITE(_SubstitutionVisitor_) + +std::pair fillContext( + SubstitutionContext& ctx, + Registry& registry) +{ + auto add = [&ctx, ®istry](const std::string& component, const std::string& variable) + { + auto* in = registry.create(component, variable); + ctx.variables.insert(in); + return in; + }; + return {add("component1", "variable1"), add("component2", "variable1")}; +} + +BOOST_FIXTURE_TEST_CASE(SubstitutionVisitor_substitute_one_node, Registry) +{ + SubstitutionContext ctx; + auto variables = fillContext(ctx, *this); + + auto* component_original = create("component1", "notInThere"); + + Node* root = create(create("component1", "variable1"), + component_original); + SubstitutionVisitor sub(*this, ctx); + Node* subsd = sub.dispatch(root); + + // The root of the new tree should be different + BOOST_CHECK_NE(root, subsd); + + // We expect to find a substituted node on the left + BOOST_CHECK_EQUAL(dynamic_cast(subsd)->left(), variables.first); + + // We expect to find an original node on the right + auto* right_substituted = dynamic_cast(subsd)->right(); + BOOST_CHECK_NE(right_substituted, variables.first); + BOOST_CHECK_NE(right_substituted, variables.second); + + auto* component = dynamic_cast(right_substituted); + BOOST_REQUIRE(component); + // We don't use BOOST_CHECK_EQUAL because operator<<(..., const ComponentVariableNode&) is + // not implemented + BOOST_CHECK(*component == *component_original); +} + +BOOST_FIXTURE_TEST_CASE(SubstitutionVisitor_name, Registry) +{ + SubstitutionContext ctx; + + SubstitutionVisitor substitutionVisitor(*this, ctx); + BOOST_CHECK_EQUAL(substitutionVisitor.name(), "SubstitutionVisitor"); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp b/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp new file mode 100644 index 0000000000..21920db288 --- /dev/null +++ b/src/tests/src/solver/expressions/test_TimeIndexVisitor.cpp @@ -0,0 +1,200 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#include +#include +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; +using namespace Antares::Solver::Visitors; + +namespace bdata = boost::unit_test::data; + +namespace Antares::Solver::Visitors +{ +static std::ostream& operator<<(std::ostream& os, TimeIndex s) +{ + switch (s) + { + case TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO: + return os << "TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO"; + case TimeIndex::VARYING_IN_TIME_ONLY: + return os << "TimeIndex::VARYING_IN_TIME_ONLY"; + case TimeIndex::VARYING_IN_SCENARIO_ONLY: + return os << "TimeIndex::VARYING_IN_SCENARIO_ONLY"; + case TimeIndex::VARYING_IN_TIME_AND_SCENARIO: + return os << "TimeIndex::VARYING_IN_TIME_AND_SCENARIO"; + default: + return os << ""; + } +} +} // namespace Antares::Solver::Visitors +BOOST_AUTO_TEST_SUITE(_TimeIndexVisitor_) + +BOOST_FIXTURE_TEST_CASE(simple_time_dependant_expression, Registry) +{ + PrintVisitor printVisitor; + std::unordered_map context; + // LiteralNode --> constant in time and for all scenarios + LiteralNode literalNode(65.); + + // Parameter --> constant in time and varying scenarios + ParameterNode parameterNode1("p1"); + context[¶meterNode1] = TimeIndex::VARYING_IN_SCENARIO_ONLY; + + // Variable time varying but constant across scenarios + VariableNode variableNode1("v1"); + context[&variableNode1] = TimeIndex::VARYING_IN_TIME_ONLY; + TimeIndexVisitor timeIndexVisitor(context); + + BOOST_CHECK_EQUAL(timeIndexVisitor.dispatch(&literalNode), + TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO); + BOOST_CHECK_EQUAL(timeIndexVisitor.dispatch(¶meterNode1), + TimeIndex::VARYING_IN_SCENARIO_ONLY); + BOOST_CHECK_EQUAL(timeIndexVisitor.dispatch(&variableNode1), TimeIndex::VARYING_IN_TIME_ONLY); + + // addition of parameterNode1 and variableNode1 is time and scenario dependent + Node* expr = create(¶meterNode1, &variableNode1); + BOOST_CHECK_EQUAL(timeIndexVisitor.dispatch(expr), TimeIndex::VARYING_IN_TIME_AND_SCENARIO); +} + +static const std::vector TimeIndex_ALL{TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO, + TimeIndex::VARYING_IN_TIME_ONLY, + TimeIndex::VARYING_IN_SCENARIO_ONLY, + TimeIndex::VARYING_IN_TIME_AND_SCENARIO}; + +template +static std::pair s_(Registry& registry) +{ + Node* left = registry.create(42.); + ParameterNode* right = registry.create("param"); + return {registry.create(left, right), right}; +} + +static const std::vector (*)(Registry& registry)> + operator_ALL{&s_, + &s_, + &s_, + &s_, + &s_, + &s_, + &s_}; + +BOOST_DATA_TEST_CASE_F(Registry, + simple_all, + bdata::make(TimeIndex_ALL) * bdata::make(operator_ALL), + timeIndex, + binaryOperator) +{ + auto [root, parameter] = binaryOperator(*this); + std::unordered_map context; + context[parameter] = timeIndex; + TimeIndexVisitor timeIndexVisitor(context); + BOOST_CHECK_EQUAL(timeIndexVisitor.dispatch(root), timeIndex); + Node* neg = create(root); + BOOST_CHECK_EQUAL(timeIndexVisitor.dispatch(neg), timeIndex); +} + +template +static Node* singleNode(Registry& registry) +{ + return registry.create("hello", "world"); +} + +static const std::vector& registry)> singleNode_ALL{ + &singleNode, + &singleNode, + &singleNode}; + +BOOST_DATA_TEST_CASE_F(Registry, + signe_node, + bdata::make(TimeIndex_ALL) * bdata::make(singleNode_ALL), + timeIndex, + singleNode) +{ + Node* root = singleNode(*this); + std::unordered_map context; + context[root] = timeIndex; + TimeIndexVisitor timeIndexVisitor(context); + BOOST_CHECK_EQUAL(timeIndexVisitor.dispatch(root), timeIndex); + Node* neg = create(root); + BOOST_CHECK_EQUAL(timeIndexVisitor.dispatch(neg), timeIndex); +} + +BOOST_AUTO_TEST_CASE(test_time_index_logical_operator) +{ + BOOST_CHECK_EQUAL(TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO + | TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO, + TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO); + BOOST_CHECK_EQUAL(TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO | TimeIndex::VARYING_IN_TIME_ONLY, + TimeIndex::VARYING_IN_TIME_ONLY); + BOOST_CHECK_EQUAL(TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO + | TimeIndex::VARYING_IN_SCENARIO_ONLY, + TimeIndex::VARYING_IN_SCENARIO_ONLY); + BOOST_CHECK_EQUAL(TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO + | TimeIndex::VARYING_IN_TIME_AND_SCENARIO, + TimeIndex::VARYING_IN_TIME_AND_SCENARIO); + + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_TIME_ONLY | TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO, + TimeIndex::VARYING_IN_TIME_ONLY); + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_TIME_ONLY | TimeIndex::VARYING_IN_TIME_ONLY, + TimeIndex::VARYING_IN_TIME_ONLY); + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_TIME_ONLY | TimeIndex::VARYING_IN_SCENARIO_ONLY, + TimeIndex::VARYING_IN_TIME_AND_SCENARIO); + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_TIME_ONLY | TimeIndex::VARYING_IN_TIME_AND_SCENARIO, + TimeIndex::VARYING_IN_TIME_AND_SCENARIO); + + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_SCENARIO_ONLY + | TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO, + TimeIndex::VARYING_IN_SCENARIO_ONLY); + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_SCENARIO_ONLY | TimeIndex::VARYING_IN_TIME_ONLY, + TimeIndex::VARYING_IN_TIME_AND_SCENARIO); + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_SCENARIO_ONLY | TimeIndex::VARYING_IN_SCENARIO_ONLY, + TimeIndex::VARYING_IN_SCENARIO_ONLY); + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_SCENARIO_ONLY | TimeIndex::VARYING_IN_TIME_AND_SCENARIO, + TimeIndex::VARYING_IN_TIME_AND_SCENARIO); + + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_TIME_AND_SCENARIO + | TimeIndex::CONSTANT_IN_TIME_AND_SCENARIO, + TimeIndex::VARYING_IN_TIME_AND_SCENARIO); + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_TIME_AND_SCENARIO | TimeIndex::VARYING_IN_TIME_ONLY, + TimeIndex::VARYING_IN_TIME_AND_SCENARIO); + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_TIME_AND_SCENARIO | TimeIndex::VARYING_IN_SCENARIO_ONLY, + TimeIndex::VARYING_IN_TIME_AND_SCENARIO); + BOOST_CHECK_EQUAL(TimeIndex::VARYING_IN_TIME_AND_SCENARIO + | TimeIndex::VARYING_IN_TIME_AND_SCENARIO, + TimeIndex::VARYING_IN_TIME_AND_SCENARIO); +} + +BOOST_FIXTURE_TEST_CASE(TimeIndexVisitor_name, Registry) +{ + std::unordered_map context; + TimeIndexVisitor timeIndexVisitor(context); + BOOST_CHECK_EQUAL(timeIndexVisitor.name(), "TimeIndexVisitor"); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/expressions/test_main.cpp b/src/tests/src/solver/expressions/test_main.cpp new file mode 100644 index 0000000000..e304a39422 --- /dev/null +++ b/src/tests/src/solver/expressions/test_main.cpp @@ -0,0 +1,25 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define BOOST_TEST_MODULE expressions +#define WIN32_LEAN_AND_MEAN + +#include diff --git a/src/tests/src/solver/expressions/test_nodes.cpp b/src/tests/src/solver/expressions/test_nodes.cpp new file mode 100644 index 0000000000..01e4a5b41c --- /dev/null +++ b/src/tests/src/solver/expressions/test_nodes.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#include +#include + +using namespace Antares::Solver; +using namespace Antares::Solver::Nodes; + +BOOST_AUTO_TEST_SUITE(_Nodes_) + +// BOOST_AUTO_TEST_CASE(UnaryNodeTest) +// { +// LiteralNode literalNode(23.); +// UnaryNode unaryNodeWithNullChild(nullptr); +// BOOST_CHECK_EQUAL(unaryNodeWithNullChild.child(), nullptr); +// UnaryNode unaryNode(&literalNode); +// BOOST_CHECK_EQUAL(unaryNode.child(), &literalNode); +// } + +BOOST_AUTO_TEST_CASE(PortFieldNodeTest) +{ + LiteralNode literalNode(23.); + std::string portName1("p1"); + std::string portName2("p2"); + std::string fieldName1("f1"); + std::string fieldName2("f2"); + + PortFieldNode portFieldNode1(portName1, fieldName1); + PortFieldNode portFieldNode1TwinNode(portName1, fieldName1); + BOOST_CHECK_EQUAL(portFieldNode1 == portFieldNode1TwinNode, true); + + PortFieldNode shareNameWithPortField1(portName1, fieldName2); + BOOST_CHECK_EQUAL(portFieldNode1 == shareNameWithPortField1, false); + + PortFieldNode shareFieldNameWithPortField1(portName2, fieldName1); + BOOST_CHECK_EQUAL(portFieldNode1 == shareFieldNameWithPortField1, false); + + PortFieldNode portFieldNode2(portName2, fieldName2); + BOOST_CHECK_EQUAL(portFieldNode1 == portFieldNode2, false); +} + +BOOST_FIXTURE_TEST_CASE(nodes_name, Registry) +{ + auto literalNode = create(2024.2); + std::map nodes = { + {literalNode, "LiteralNode"}, + {create(literalNode, literalNode), "AddNode"}, + {create(literalNode, literalNode), "SubtractionNode"}, + {create(literalNode, literalNode), "MultiplicationNode"}, + {create(literalNode, literalNode), "DivisionNode"}, + {create(literalNode, literalNode), "EqualNode"}, + {create(literalNode, literalNode), "LessThanOrEqualNode"}, + {create(literalNode, literalNode), "GreaterThanOrEqualNode"}, + {create(literalNode), "NegationNode"}, + {create(literalNode->name(), literalNode->name()), + "ComponentVariableNode"}, + {create(literalNode->name(), literalNode->name()), + "ComponentParameterNode"}, + {create(literalNode->name()), "ParameterNode"}, + {create(literalNode->name()), "VariableNode"}, + {create(literalNode->name(), literalNode->name()), "PortFieldNode"}}; + + for (auto [node, name]: nodes) + { + BOOST_CHECK_EQUAL(node->name(), name); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/infeasible-problem-analysis/test-unfeasible-problem-analyzer.cpp b/src/tests/src/solver/infeasible-problem-analysis/test-unfeasible-problem-analyzer.cpp index 8d56ec12f2..2155fd48c4 100644 --- a/src/tests/src/solver/infeasible-problem-analysis/test-unfeasible-problem-analyzer.cpp +++ b/src/tests/src/solver/infeasible-problem-analysis/test-unfeasible-problem-analyzer.cpp @@ -18,26 +18,27 @@ * You should have received a copy of the Mozilla Public Licence 2.0 * along with Antares_Simulator. If not, see . */ -#include // Fix for Boost < 1.67 - #define WIN32_LEAN_AND_MEAN #define BOOST_TEST_MODULE unfeasible_problem_analyzer +#include +#include + #include #include #include #include "antares/solver/infeasible-problem-analysis/constraint-slack-analysis.h" +#include "antares/solver/infeasible-problem-analysis/report.h" #include "antares/solver/infeasible-problem-analysis/unfeasible-pb-analyzer.h" #include "antares/solver/infeasible-problem-analysis/variables-bounds-consistency.h" -#include "ortools/linear_solver/linear_solver.h" - namespace bdata = boost::unit_test::data; -using operations_research::MPSolver; +using namespace operations_research; using Antares::Optimization::ConstraintSlackAnalysis; +using Antares::Optimization::InfeasibleProblemReport; using Antares::Optimization::UnfeasibilityAnalysis; using Antares::Optimization::UnfeasiblePbAnalyzer; using Antares::Optimization::VariableBounds; @@ -85,7 +86,50 @@ class AnalysisMock: public UnfeasibilityAnalysis bool& hasPrinted_; }; -BOOST_AUTO_TEST_SUITE(unfeasible_problem_analyzer) +void addOneVarConstraintToProblem(MPSolver* problem, + const std::string& constraintName, + double varLowBnd, + double varUpBnd, + double ConstLowBnd) +{ + std::string varName = "lonely-var-in-" + constraintName; + auto* var = problem->MakeNumVar(varLowBnd, varUpBnd, varName); + auto* constraint = problem->MakeRowConstraint(constraintName); + constraint->SetCoefficient(var, 1); + constraint->SetBounds(ConstLowBnd, problem->infinity()); +} + +std::unique_ptr createFeasibleProblem(const std::string& constraintName) +{ + std::unique_ptr problem(MPSolver::CreateSolver("GLOP")); + // Following constraint is easily satisfied + addOneVarConstraintToProblem(problem.get(), constraintName, 0., 1., 0.); + return problem; +} + +std::unique_ptr createUnfeasibleProblem(const std::string& constraintName) +{ + std::unique_ptr problem(MPSolver::CreateSolver("GLOP")); + // Following constraint cannot be satisfied + addOneVarConstraintToProblem(problem.get(), constraintName, 0., 1., 2.); + return problem; +} + +std::unique_ptr createProblemWith_n_violatedConstraints(const int n) +{ + std::unique_ptr problem(MPSolver::CreateSolver("GLOP")); + for (auto i: std::ranges::iota_view(1, n + 1)) // From 1 to n included + { + std::stringstream name; + name << "BC-name-" << i << "::hourly::hour<" << 5 * i << ">"; + // Make a constraint that can never be satisfied, of type : var > A, + // where : bound_inf(var) = 0, bound_sup(var) = 1 and A > 1. + addOneVarConstraintToProblem(problem.get(), name.str(), 0., 1., double(i + 2)); + } + return problem; +} + +BOOST_AUTO_TEST_SUITE(general_unfeasible_problem_analyzer) BOOST_AUTO_TEST_CASE(analyzer_should_call_analysis_and_print_detected_issues) { @@ -118,6 +162,9 @@ BOOST_AUTO_TEST_CASE(analyzer_should_call_analysis_and_print_detected_issues) BOOST_CHECK(hasRun2); BOOST_CHECK(hasPrinted2); } +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(variable_bounds_consistency_analyzer) BOOST_AUTO_TEST_CASE(analysis_should_detect_inconsistent_variable_bounds) { @@ -133,52 +180,17 @@ BOOST_AUTO_TEST_CASE(analysis_should_detect_inconsistent_variable_bounds) auto expected = VariableBounds("not-ok-var", 1, -1); BOOST_CHECK(variableEquals(incorrectVars[0], expected)); } +BOOST_AUTO_TEST_SUITE_END() -/*! - * Creates a problem with 2 variables linked by 1 constraint: - * - Variable 1 must be greater than 1 - * - Variable 2 must be lesser than -1 - * - but if feasible is false, constraint enforces that variable 2 is greater than variable 1 --> - * infeasible - */ -std::unique_ptr createProblem(const std::string& constraintName, bool feasible) -{ - std::unique_ptr problem(MPSolver::CreateSolver("GLOP")); - const double infinity = problem->infinity(); - auto var1 = problem->MakeNumVar(1, infinity, "var1"); - auto var2 = problem->MakeNumVar(-infinity, -1, "var2"); - auto constraint = problem->MakeRowConstraint(constraintName); - constraint->SetBounds(0, infinity); - if (feasible) - { - constraint->SetCoefficient(var1, 1); - constraint->SetCoefficient(var2, -1); - } - else - { - constraint->SetCoefficient(var1, -1); - constraint->SetCoefficient(var2, 1); - } - return problem; -} - -std::unique_ptr createFeasibleProblem(const std::string& constraintName) -{ - return createProblem(constraintName, true); -} - -std::unique_ptr createUnfeasibleProblem(const std::string& constraintName) -{ - return createProblem(constraintName, false); -} +BOOST_AUTO_TEST_SUITE(slack_variables_analyzer) -static const std::string validConstraintNames[] = { - "BC::hourly::hour<36>", - "BC::daily::day<67>", - "BC::weekly::week<12>", - "FictiveLoads::hour<25>", - "AreaHydroLevel::hour<8>", -}; +static const std::string validConstraintNames[] = {"BC-name-1::hourly::hour<36>", + "BC-name-2::daily::day<67>", + "BC-name-3::weekly::week<12>", + "FictiveLoads::area::hour<25>", + "AreaHydroLevel::area::hour<8>", + "Level::area::hour<28>", + "HydroPower::area::week<45>"}; BOOST_DATA_TEST_CASE(analysis_should_detect_unfeasible_constraint, bdata::make(validConstraintNames), @@ -202,16 +214,109 @@ BOOST_AUTO_TEST_CASE(analysis_should_ignore_ill_named_constraint) BOOST_CHECK(!analysis.hasDetectedInfeasibilityCause()); } -// TODO: this test should be improved by changing the API, the current interface does not allow -// to check that no constraint was identified... BOOST_AUTO_TEST_CASE(analysis_should_ignore_feasible_constraints) { - std::unique_ptr feasibleProblem = createFeasibleProblem("BC::hourly::hour<36>"); + std::unique_ptr feasibleProblem = createFeasibleProblem("BC-name::hourly::hour<36>"); BOOST_CHECK(feasibleProblem->Solve() == MPSolver::OPTIMAL); ConstraintSlackAnalysis analysis; analysis.run(feasibleProblem.get()); - BOOST_CHECK(analysis.hasDetectedInfeasibilityCause()); // Would expect false here instead? + BOOST_CHECK(!analysis.hasDetectedInfeasibilityCause()); +} + +BOOST_AUTO_TEST_CASE(analysis_slack_variables_are_ordered) +{ + std::unique_ptr problem = createProblemWith_n_violatedConstraints(3); + BOOST_CHECK(problem->Solve() == MPSolver::INFEASIBLE); + + ConstraintSlackAnalysis analysis; + analysis.run(problem.get()); + BOOST_CHECK(analysis.hasDetectedInfeasibilityCause()); + + auto& violatedConstraints = analysis.largestSlackVariables(); + BOOST_CHECK_EQUAL(violatedConstraints.size(), 3); + BOOST_CHECK_EQUAL(violatedConstraints[0]->name(), "BC-name-3::hourly::hour<15>::low"); + BOOST_CHECK_EQUAL(violatedConstraints[1]->name(), "BC-name-2::hourly::hour<10>::low"); + BOOST_CHECK_EQUAL(violatedConstraints[2]->name(), "BC-name-1::hourly::hour<5>::low"); +} + +BOOST_AUTO_TEST_CASE(analysis_slack_variables_are_ordered_and_limited_to_10) +{ + std::unique_ptr problem = createProblemWith_n_violatedConstraints(15); + BOOST_CHECK(problem->Solve() == MPSolver::INFEASIBLE); + + ConstraintSlackAnalysis analysis; + analysis.run(problem.get()); + BOOST_CHECK(analysis.hasDetectedInfeasibilityCause()); + + auto& violatedConstraints = analysis.largestSlackVariables(); + BOOST_CHECK_EQUAL(violatedConstraints.size(), 10); + BOOST_CHECK_EQUAL(violatedConstraints[0]->name(), "BC-name-15::hourly::hour<75>::low"); + BOOST_CHECK_EQUAL(violatedConstraints[9]->name(), "BC-name-6::hourly::hour<30>::low"); +} + +BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(slack_variables_report) + +BOOST_AUTO_TEST_CASE(constraints_associated_to_all_incoming_slack_vars_are_reported) +{ + // The problem is needed only to create variables, impossible otherwise. + std::unique_ptr problem(MPSolver::CreateSolver("GLOP")); + + std::vector slackVariables; + slackVariables.push_back(problem->MakeNumVar(0, 1, "BC-1::hourly::hour<36>::low")); + slackVariables.push_back(problem->MakeNumVar(0, 1, "BC-2::hourly::hour<65>::up")); + slackVariables.push_back( + problem->MakeNumVar(0, 1, "FictiveLoads::area::hour<25>::low")); + slackVariables.push_back( + problem->MakeNumVar(0, 1, "HydroPower::area::week<45>::up")); + + InfeasibleProblemReport report(slackVariables); + report.storeSuspiciousConstraints(); + auto reportLogs = report.getLogs(); + + BOOST_CHECK_EQUAL(reportLogs.size(), 5); // Expecting 5 lines in the report + BOOST_CHECK_EQUAL(reportLogs[1], "Hourly BC 'BC-1' at hour 36"); + BOOST_CHECK_EQUAL(reportLogs[2], "Hourly BC 'BC-2' at hour 65"); + BOOST_CHECK_EQUAL(reportLogs[3], "Last resort shedding status at area 'some-area' at hour 25"); + BOOST_CHECK_EQUAL(reportLogs[4], "Hydro weekly production at area 'some-area'"); +} + +BOOST_AUTO_TEST_CASE(Infeasibility_causes_are_unique_and_sorted_by_slack_value) +{ + // The problem is needed only to create variables, impossible otherwise. + std::unique_ptr problem(MPSolver::CreateSolver("GLOP")); + + addOneVarConstraintToProblem(problem.get(), "HydroPower::area::week<0>", 0., 1., 2.); + addOneVarConstraintToProblem(problem.get(), "BC-1::hourly::hour<36>", 0., 1., 3.); + addOneVarConstraintToProblem(problem.get(), + "FictiveLoads::area::hour<25>", + 0., + 1., + 4.); + addOneVarConstraintToProblem(problem.get(), "BC-2::hourly::hour<65>", 0., 1., 5.); + addOneVarConstraintToProblem(problem.get(), + "FictiveLoads::area::hour<56>", + 0., + 1., + 6.); + + BOOST_CHECK(problem->Solve() == MPSolver::INFEASIBLE); + + ConstraintSlackAnalysis analysis; + analysis.run(problem.get()); + BOOST_CHECK(analysis.hasDetectedInfeasibilityCause()); + + InfeasibleProblemReport report(analysis.largestSlackVariables()); + report.storeInfeasibilityCauses(); + auto reportLogs = report.getLogs(); + + BOOST_CHECK_EQUAL(reportLogs.size(), 4); // Expecting 4 lines in the report + BOOST_CHECK_EQUAL(reportLogs[0], "Possible causes of infeasibility:"); + BOOST_CHECK_EQUAL(reportLogs[1], "* Last resort shedding status."); + BOOST_CHECK_EQUAL(reportLogs[2], "* Hourly binding constraints."); + BOOST_CHECK_EQUAL(reportLogs[3], "* impossible to generate exactly the weekly hydro target"); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/lps/CMakeLists.txt b/src/tests/src/solver/lps/CMakeLists.txt new file mode 100644 index 0000000000..89121152ba --- /dev/null +++ b/src/tests/src/solver/lps/CMakeLists.txt @@ -0,0 +1,20 @@ +set(EXECUTABLE_NAME test-lps) +add_executable(${EXECUTABLE_NAME}) + +target_sources(${EXECUTABLE_NAME} + PRIVATE + test_lps.cpp +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + antares-solver-simulation +) + +# Storing tests-ts-numbers under the folder Unit-tests in the IDE +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) + +add_test(NAME test-lps COMMAND ${EXECUTABLE_NAME}) + +set_property(TEST test-lps PROPERTY LABELS unit) diff --git a/src/tests/src/solver/lps/test_lps.cpp b/src/tests/src/solver/lps/test_lps.cpp new file mode 100644 index 0000000000..3a0bf4aa34 --- /dev/null +++ b/src/tests/src/solver/lps/test_lps.cpp @@ -0,0 +1,77 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define BOOST_TEST_MODULE test_translator +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +using namespace Antares::Solver; + +BOOST_AUTO_TEST_CASE(new_lps_is_empty) +{ + LpsFromAntares lps; + BOOST_CHECK(lps.empty()); +} + +BOOST_AUTO_TEST_CASE(lps_with_only_constant_data_is_empty) +{ + LpsFromAntares lps; + lps.setConstantData(ConstantDataFromAntares()); + BOOST_CHECK(lps.empty()); +} + +BOOST_AUTO_TEST_CASE(lps_with_no_variabled_is_empty) +{ + LpsFromAntares lps; + lps.constantProblemData.VariablesCount = 0; + lps.addWeeklyData({0, 0}, WeeklyDataFromAntares()); + BOOST_CHECK(lps.empty()); +} + +BOOST_AUTO_TEST_CASE(lps_with_both_constant_and_weekly_data_is_not_empty) +{ + LpsFromAntares lps; + lps.constantProblemData.VariablesCount = 65; + lps.addWeeklyData({0, 0}, WeeklyDataFromAntares()); + BOOST_CHECK(!lps.empty()); +} + +BOOST_AUTO_TEST_CASE(replace_const_data) +{ + LpsFromAntares lps; + ConstantDataFromAntares var; + var.VariablesCount = 42; + lps.setConstantData(var); + BOOST_CHECK(lps.constantProblemData.VariablesCount == 42); +} + +// Add weekly data for week 1 year 1 +BOOST_AUTO_TEST_CASE(add_weekly_data_for_week_1_year_1) +{ + LpsFromAntares lps; + WeeklyDataFromAntares w; + w.RHS.push_back(43); + lps.addWeeklyData({1, 1}, w); + BOOST_CHECK(lps.weeklyData({1, 1}).RHS.size() != WeeklyDataFromAntares().RHS.size()); +} diff --git a/src/tests/src/solver/modeler/CMakeLists.txt b/src/tests/src/solver/modeler/CMakeLists.txt new file mode 100644 index 0000000000..53d257b04e --- /dev/null +++ b/src/tests/src/solver/modeler/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(api) diff --git a/src/tests/src/solver/modeler/api/CMakeLists.txt b/src/tests/src/solver/modeler/api/CMakeLists.txt new file mode 100644 index 0000000000..0299f3ec0b --- /dev/null +++ b/src/tests/src/solver/modeler/api/CMakeLists.txt @@ -0,0 +1,20 @@ +set(EXECUTABLE_NAME tests-modeler-api-ortools) +add_executable(${EXECUTABLE_NAME} testApiOrtoolsLinearProblem.cpp) + +target_include_directories(${EXECUTABLE_NAME} + PRIVATE + "${src_solver_optimisation}" +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + Antares::modeler-ortools-impl +) + +# Storing tests-ts-numbers under the folder Unit-tests in the IDE +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) + +add_test(NAME test-modeler-api-ortools COMMAND ${EXECUTABLE_NAME}) + +set_property(TEST test-modeler-api-ortools PROPERTY LABELS unit) diff --git a/src/tests/src/solver/modeler/api/testApiOrtoolsLinearProblem.cpp b/src/tests/src/solver/modeler/api/testApiOrtoolsLinearProblem.cpp new file mode 100644 index 0000000000..06bbcb6669 --- /dev/null +++ b/src/tests/src/solver/modeler/api/testApiOrtoolsLinearProblem.cpp @@ -0,0 +1,239 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ +#define BOOST_TEST_MODULE test modeler api ortools + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +using namespace Antares::Solver::Modeler; + +struct FixtureEmptyProblem +{ + FixtureEmptyProblem() + { + pb = std::make_unique(false, "sirius"); + } + + std::unique_ptr pb; +}; + +struct FixtureInfeasibleProblem: public FixtureEmptyProblem +{ + FixtureInfeasibleProblem() + { + auto* var = pb->addNumVariable(0, 1, "var"); + auto* constraint = pb->addConstraint(2, 2, "constraint"); + constraint->setCoefficient(var, 1); + } +}; + +struct FixtureFeasibleProblem: public FixtureEmptyProblem +{ + FixtureFeasibleProblem() + { + auto* var = pb->addNumVariable(0, 10, "var"); + auto* constraint = pb->addConstraint(1, 1, "constraint"); + constraint->setCoefficient(var, 1); + pb->setObjectiveCoefficient(var, 1); + } +}; + +BOOST_AUTO_TEST_SUITE(tests_on_OrtoolsLinearProblem) + +BOOST_FIXTURE_TEST_CASE(add_int_variable_to_problem___check_var_exists, FixtureEmptyProblem) +{ + pb->addIntVariable(5, 15, "var"); + auto* var = pb->getVariable("var"); + BOOST_CHECK(var); + BOOST_CHECK_EQUAL(var->getLb(), 5); + BOOST_CHECK_EQUAL(var->getUb(), 15); +} + +BOOST_FIXTURE_TEST_CASE(add_num_variable_to_problem___check_var_exists, FixtureEmptyProblem) +{ + pb->addNumVariable(2., 7., "var"); + auto* var = pb->getVariable("var"); + BOOST_CHECK(var); + BOOST_CHECK_EQUAL(var->getLb(), 2.); + BOOST_CHECK_EQUAL(var->getUb(), 7.); +} + +BOOST_FIXTURE_TEST_CASE(add_constraint_to_problem___check_constraint_exists, FixtureEmptyProblem) +{ + pb->addConstraint(3., 8., "constraint"); + auto* constraint = pb->getConstraint("constraint"); + BOOST_CHECK(constraint); + BOOST_CHECK_EQUAL(constraint->getLb(), 3.); + BOOST_CHECK_EQUAL(constraint->getUb(), 8.); +} + +BOOST_FIXTURE_TEST_CASE(give_coeff_to_var_in_constraint____check_coeff_exists, FixtureEmptyProblem) +{ + auto* var = pb->addNumVariable(0, 1, "var"); + auto* constraint = pb->addConstraint(0, 1, "constraint"); + constraint->setCoefficient(var, 3.2); + + BOOST_CHECK_EQUAL(constraint->getCoefficient(var), 3.2); +} + +BOOST_FIXTURE_TEST_CASE(give_coef_to_null_var_in_constaint_leads_to_bad_cast, FixtureEmptyProblem) +{ + auto* constraint = pb->addConstraint(0, 1, "constraint"); + BOOST_CHECK_THROW(constraint->setCoefficient(nullptr, 3.2), std::bad_cast); +} + +BOOST_FIXTURE_TEST_CASE(get_coef_of_null_var_in_constaint_leads_to_bad_cast, FixtureEmptyProblem) +{ + auto* constraint = pb->addConstraint(0, 1, "constraint"); + BOOST_CHECK_THROW(constraint->getCoefficient(nullptr), std::bad_cast); +} + +bool expectedMessage(const std::exception& ex) +{ + BOOST_CHECK_EQUAL(ex.what(), std::string("Element name already exists in linear problem")); + return true; +} + +BOOST_FIXTURE_TEST_CASE(add_already_existing_var_to_problem_leads_to_exception, FixtureEmptyProblem) +{ + pb->addNumVariable(0, 1, "var"); + BOOST_CHECK_EXCEPTION(pb->addNumVariable(0, 1, "var"), std::exception, expectedMessage); +} + +BOOST_FIXTURE_TEST_CASE(add_already_existing_constaint_to_problem_leads_to_exception, + FixtureEmptyProblem) +{ + pb->addConstraint(0, 1, "constraint"); + BOOST_CHECK_EXCEPTION(pb->addConstraint(0, 1, "constraint"), std::exception, expectedMessage); +} + +BOOST_FIXTURE_TEST_CASE(minimize_problem___check_minimize_status, FixtureEmptyProblem) +{ + pb->setMinimization(); + BOOST_CHECK(pb->isMinimization()); +} + +BOOST_FIXTURE_TEST_CASE(maximize_problem___check_maximize_status, FixtureEmptyProblem) +{ + pb->setMaximization(); + BOOST_CHECK(pb->isMaximization()); +} + +BOOST_FIXTURE_TEST_CASE(give_bounds_to_var___check_bounds_exist, FixtureEmptyProblem) +{ + auto* var = pb->addNumVariable(0, 1, "var"); + var->setLb(-4); + var->setUb(7); + + BOOST_CHECK_EQUAL(var->getLb(), -4); + BOOST_CHECK_EQUAL(var->getUb(), 7); + + var->setBounds(2, 13); + + BOOST_CHECK_EQUAL(var->getLb(), 2); + BOOST_CHECK_EQUAL(var->getUb(), 13); +} + +BOOST_FIXTURE_TEST_CASE(give_bounds_to_constraint___check_bounds_exist, FixtureEmptyProblem) +{ + auto* constraint = pb->addConstraint(0, 1, "var"); + + constraint->setLb(-4); + constraint->setUb(7); + BOOST_CHECK_EQUAL(constraint->getLb(), -4); + BOOST_CHECK_EQUAL(constraint->getUb(), 7); + + constraint->setBounds(2, 13); + BOOST_CHECK_EQUAL(constraint->getLb(), 2); + BOOST_CHECK_EQUAL(constraint->getUb(), 13); +} + +BOOST_FIXTURE_TEST_CASE(give_cost_to_variable___check_cost_exist, FixtureEmptyProblem) +{ + auto* var = pb->addIntVariable(0, 1, "var"); + pb->setObjectiveCoefficient(var, 1); + BOOST_CHECK_EQUAL(pb->getObjectiveCoefficient(var), 1); +} + +BOOST_FIXTURE_TEST_CASE(get_cost_from_null_variable_leads_to_bad_cast, FixtureEmptyProblem) +{ + BOOST_CHECK_THROW(pb->getObjectiveCoefficient(nullptr), std::bad_cast); +} + +BOOST_FIXTURE_TEST_CASE(give_cost_to_null_variable_leads_to_bad_cast, FixtureEmptyProblem) +{ + BOOST_CHECK_THROW(pb->setObjectiveCoefficient(nullptr, 0), std::bad_cast); +} + +BOOST_FIXTURE_TEST_CASE(solve_infeasible_problem_leads_to_error_status, FixtureInfeasibleProblem) +{ + auto* solution = pb->solve(true); + BOOST_CHECK(solution->getStatus() == Api::MipStatus::INFEASIBLE); +} + +BOOST_FIXTURE_TEST_CASE(solve_infeasible_problem_leads_to_null_objective_value, + FixtureInfeasibleProblem) +{ + auto* solution = pb->solve(true); + BOOST_CHECK_EQUAL(solution->getObjectiveValue(), 0); +} + +BOOST_FIXTURE_TEST_CASE(solve_infeasible_problem___check_any_var_is_zero, FixtureInfeasibleProblem) +{ + auto* solution = pb->solve(true); + + auto* var = pb->getVariable("var"); + BOOST_CHECK(var); // searched variable is known by problem + BOOST_CHECK_EQUAL(solution->getOptimalValue(var), 0); +} + +BOOST_FIXTURE_TEST_CASE(solve_feasible_problem___check_status_is_optimal, FixtureFeasibleProblem) +{ + auto* solution = pb->solve(false); + BOOST_CHECK(solution->getStatus() == Api::MipStatus::OPTIMAL); +} + +BOOST_FIXTURE_TEST_CASE(solve_feasible_problem___check_objective_has_expected_value, + FixtureFeasibleProblem) +{ + auto* solution = pb->solve(false); + BOOST_CHECK_EQUAL(solution->getObjectiveValue(), 1); +} + +BOOST_FIXTURE_TEST_CASE(solve_problem_then_add_new_var___new_var_optimal_value_is_zero, + FixtureFeasibleProblem) +{ + auto* solution = pb->solve(false); + auto* newVar = pb->addNumVariable(0, 1, "new var"); + BOOST_CHECK_EQUAL(solution->getOptimalValue(newVar), 0); +} + +BOOST_FIXTURE_TEST_CASE(solve_problem___check_optimal_value_of_null_var_is_zero, + FixtureFeasibleProblem) +{ + auto* solution = pb->solve(false); + BOOST_CHECK_EQUAL(solution->getOptimalValue(nullptr), 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/optimisation/CMakeLists.txt b/src/tests/src/solver/optimisation/CMakeLists.txt index 72d92448a3..90e70d52b7 100644 --- a/src/tests/src/solver/optimisation/CMakeLists.txt +++ b/src/tests/src/solver/optimisation/CMakeLists.txt @@ -1,24 +1,3 @@ -# Useful variables definitions -set(src_solver_optimisation "${CMAKE_SOURCE_DIR}/solver/optimisation") - -set(EXECUTABLE_NAME tests-adq-patch) -add_executable(${EXECUTABLE_NAME} adequacy_patch.cpp) - -target_include_directories(${EXECUTABLE_NAME} - PRIVATE - "${src_solver_optimisation}" -) - -target_link_libraries(${EXECUTABLE_NAME} - PRIVATE - Boost::unit_test_framework - model_antares - array -) - -# Storing tests-ts-numbers under the folder Unit-tests in the IDE -set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) - -add_test(NAME test-adq-patch COMMAND ${EXECUTABLE_NAME}) - -set_property(TEST test-adq-patch PROPERTY LABELS unit) +add_subdirectory(adequacy_patch) +add_subdirectory(translator) +add_subdirectory(name-translator) \ No newline at end of file diff --git a/src/tests/src/solver/optimisation/adequacy_patch/CMakeLists.txt b/src/tests/src/solver/optimisation/adequacy_patch/CMakeLists.txt new file mode 100644 index 0000000000..bb28a99864 --- /dev/null +++ b/src/tests/src/solver/optimisation/adequacy_patch/CMakeLists.txt @@ -0,0 +1,24 @@ +# Useful variables definitions +set(src_solver_optimisation "${CMAKE_SOURCE_DIR}/solver/optimisation") + +set(EXECUTABLE_NAME tests-adq-patch) +add_executable(${EXECUTABLE_NAME} adequacy_patch.cpp) + +target_include_directories(${EXECUTABLE_NAME} + PRIVATE + "${src_solver_optimisation}" +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + model_antares + array +) + +# Storing tests-ts-numbers under the folder Unit-tests in the IDE +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) + +add_test(NAME test-adq-patch COMMAND ${EXECUTABLE_NAME}) + +set_property(TEST test-adq-patch PROPERTY LABELS unit) diff --git a/src/tests/src/solver/optimisation/adequacy_patch.cpp b/src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp similarity index 65% rename from src/tests/src/solver/optimisation/adequacy_patch.cpp rename to src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp index 6234cc1c65..ea9762838b 100644 --- a/src/tests/src/solver/optimisation/adequacy_patch.cpp +++ b/src/tests/src/solver/optimisation/adequacy_patch/adequacy_patch.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test adequacy patch functions #define WIN32_LEAN_AND_MEAN @@ -31,50 +31,14 @@ #include #include #include "antares/solver/optimisation/adequacy_patch_csr/adq_patch_curtailment_sharing.h" -#include "antares/solver/optimisation/adequacy_patch_local_matching/adq_patch_local_matching.h" +#include "antares/solver/optimisation/adequacy_patch_csr/post_processing.h" #include "antares/study/parameters/adq-patch-params.h" static double origineExtremite = -1; static double extremiteOrigine = 5; using namespace Antares::Data::AdequacyPatch; - -// NOTE -// Xmax limits the flux origin -> extremity (direct) -// -Xmin limits the flux extremity -> origin (indirect) - -std::pair setNTCboundsForOneTimeStep(AdequacyPatchMode originType, - AdequacyPatchMode extremityType, - bool SetNTCOutsideToOutsideToZero, - bool SetNTCOutsideToInsideToZero) -{ - PROBLEME_HEBDO problem; - problem.adequacyPatchRuntimeData = std::make_shared(); - problem.adequacyPatchRuntimeData->originAreaMode.resize(1); - problem.adequacyPatchRuntimeData->extremityAreaMode.resize(1); - - problem.adequacyPatchRuntimeData->originAreaMode[0] = originType; - problem.adequacyPatchRuntimeData->extremityAreaMode[0] = extremityType; - problem.adequacyPatchRuntimeData->AdequacyFirstStep = true; - - AdqPatchParams adqPatchParams; - adqPatchParams.enabled = true; - adqPatchParams.localMatching.setToZeroOutsideOutsideLinks = SetNTCOutsideToOutsideToZero; - adqPatchParams.localMatching.setToZeroOutsideInsideLinks = SetNTCOutsideToInsideToZero; - - VALEURS_DE_NTC_ET_RESISTANCES ValeursDeNTC; - ValeursDeNTC.ValeurDeNTCOrigineVersExtremite.assign(1, 0.); - ValeursDeNTC.ValeurDeNTCExtremiteVersOrigine.assign(1, 0.); - ValeursDeNTC.ValeurDeNTCOrigineVersExtremite[0] = origineExtremite; - ValeursDeNTC.ValeurDeNTCExtremiteVersOrigine[0] = extremiteOrigine; - - double Xmin(0.); - double Xmax(0.); - - setNTCbounds(Xmax, Xmin, ValeursDeNTC, 0, &problem, adqPatchParams); - - return std::make_pair(Xmin, Xmax); -} +namespace tt = boost::test_tools; static const double flowArea0toArea1_positive = 10; static const double flowArea0toArea1_negative = -10; @@ -111,8 +75,7 @@ std::pair calculateAreaFlowBalanceForOneTimeStep( problem.IndexDebutIntercoExtremite = std::vector(1); // input values - adqPatchParams.localMatching.setToZeroOutsideInsideLinks - = !includeFlowsOutsideAdqPatchToDensNew; + adqPatchParams.setToZeroOutsideInsideLinks = !includeFlowsOutsideAdqPatchToDensNew; problem.ResultatsHoraires[Area].ValeursHorairesDeDefaillancePositive[hour] = ensInit; int Interco = 1; problem.IndexDebutIntercoOrigine[Area] = Interco; @@ -131,7 +94,7 @@ std::pair calculateAreaFlowBalanceForOneTimeStep( double densNew; std::tie(netPositionInit, densNew, std::ignore) = calculateAreaFlowBalance( &problem, - adqPatchParams.localMatching.setToZeroOutsideInsideLinks, + adqPatchParams.setToZeroOutsideInsideLinks, Area, hour); @@ -143,119 +106,11 @@ AdqPatchParams createParams() AdqPatchParams p; p.enabled = true; p.curtailmentSharing.includeHurdleCost = true; - p.localMatching.enabled = true; p.curtailmentSharing.priceTakingOrder = AdqPatchPTO::isDens; return p; } -// Virtual -> Virtual (0 -> 0) -// No change in bounds is expected -BOOST_AUTO_TEST_CASE(setNTCboundsForOneTimeStep_virtual_virtual_no_change_expected) -{ - double Xmin, Xmax; - std::tie(Xmin, Xmax) = setNTCboundsForOneTimeStep(virtualArea, - virtualArea, - true /*SetNTCOutsideToOutsideToZero*/, - false); - BOOST_CHECK_EQUAL(Xmax, origineExtremite); - BOOST_CHECK_EQUAL(Xmin, -extremiteOrigine); -} - -// Virtual -> physical area inside adq-patch (0 -> 2) -// No change in bounds is expected -BOOST_AUTO_TEST_CASE(setNTCboundsForOneTimeStep_virtual_inside_no_change_expected) -{ - double Xmin, Xmax; - std::tie(Xmin, Xmax) = setNTCboundsForOneTimeStep(virtualArea, - physicalAreaInsideAdqPatch, - true /*SetNTCOutsideToOutsideToZero*/, - false); - BOOST_CHECK_EQUAL(Xmax, origineExtremite); - BOOST_CHECK_EQUAL(Xmin, -extremiteOrigine); -} - -// Virtual -> physical area outside adq-patch (0 -> 1) -// No change in bounds is expected -BOOST_AUTO_TEST_CASE(setNTCboundsForOneTimeStep_virtual_outside_no_change_expected) -{ - double Xmin, Xmax; - std::tie(Xmin, Xmax) = setNTCboundsForOneTimeStep(virtualArea, - physicalAreaOutsideAdqPatch, - true /*SetNTCOutsideToOutsideToZero*/, - false); - BOOST_CHECK_EQUAL(Xmax, origineExtremite); - BOOST_CHECK_EQUAL(Xmin, -extremiteOrigine); -} - -// physical area outside adq-patch -> physical area outside adq-patch (1 -> 1) -// NTC should be set to 0 in both directions -BOOST_AUTO_TEST_CASE(setNTCboundsForOneTimeStep_outside_outside_zero_expected_both_directions) -{ - double Xmin, Xmax; - std::tie(Xmin, Xmax) = setNTCboundsForOneTimeStep(physicalAreaOutsideAdqPatch, - physicalAreaOutsideAdqPatch, - true /*SetNTCOutsideToOutsideToZero*/, - false); - BOOST_CHECK_EQUAL(Xmax, 0); - BOOST_CHECK_EQUAL(Xmin, 0); -} - -// physical area outside adq-patch -> physical area outside adq-patch (1 -> 1) -// SetNTCOutsideToOutsideToZero = true -// NTC should be set to 0 in both directions -BOOST_AUTO_TEST_CASE(setNTCboundsForOneTimeStep_outside_outside_no_change_expected) -{ - double Xmin, Xmax; - std::tie(Xmin, Xmax) = setNTCboundsForOneTimeStep(physicalAreaOutsideAdqPatch, - physicalAreaOutsideAdqPatch, - false, - false); - - BOOST_CHECK_EQUAL(Xmax, origineExtremite); - BOOST_CHECK_EQUAL(Xmin, -extremiteOrigine); -} - -// physical area inside adq-patch -> physical area outside adq-patch (2 -> 1) -// NTC should be set to 0 in both directions -BOOST_AUTO_TEST_CASE(setNTCboundsForOneTimeStep_inside_outside_zero_expected_both_directions) -{ - double Xmin, Xmax; - std::tie(Xmin, Xmax) = setNTCboundsForOneTimeStep(physicalAreaInsideAdqPatch, - physicalAreaOutsideAdqPatch, - false, - false); - BOOST_CHECK_EQUAL(Xmax, 0); - BOOST_CHECK_EQUAL(Xmin, 0); -} - -// physical area outside adq-patch -> physical area inside adq-patch (1 -> 2) -// NTC should be set to 0 in both directions -BOOST_AUTO_TEST_CASE(setNTCboundsForOneTimeStep_outside_inside_zero_expected_both_directions) -{ - double Xmin, Xmax; - std::tie(Xmin, Xmax) = setNTCboundsForOneTimeStep(physicalAreaOutsideAdqPatch, - physicalAreaInsideAdqPatch, - false, - true /*SetNTCOutsideToInsideToZero*/); - BOOST_CHECK_EQUAL(Xmax, 0); - BOOST_CHECK_EQUAL(Xmin, 0); -} - -// physical area outside adq-patch -> physical area inside adq-patch (1 -> 2) -// NTC should be unchanged in direction origin->extremity (direct) -// NTC should be set to 0 in direction extremity->origin (indirect) -BOOST_AUTO_TEST_CASE(setNTCboundsForOneTimeStep_outside_inside_change_expected_one_direction) -{ - double Xmin, Xmax; - std::tie(Xmin, Xmax) = setNTCboundsForOneTimeStep(physicalAreaOutsideAdqPatch, - physicalAreaInsideAdqPatch, - false, - false); - BOOST_CHECK_EQUAL(Xmax, origineExtremite); - BOOST_CHECK_EQUAL(Xmin, 0); -} - // Area 0 is physical area inside adq-patch connected to two areas: // Area1 virtual-area, and Area2-virtual area // flow from Area0 -> Area1 is positive @@ -547,3 +402,75 @@ BOOST_AUTO_TEST_CASE(check_adq_param_wrong_hurdle_cost) auto p = createParams(); BOOST_CHECK_THROW(p.checkAdqPatchIncludeHurdleCost(false), Error::IncompatibleHurdleCostCSR); } + +BOOST_AUTO_TEST_SUITE(adq_patch_post_processing) + +BOOST_AUTO_TEST_CASE(dtg_mrg_triggered_low_ens) +{ + const bool triggered = true; + const double dtgMrg = 32.; + const double ens = 21.; + + BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == 11., tt::tolerance(1.e-6)); + + BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens) + == std::abs(dtgMrg - ens), + tt::tolerance(1.e-6)); +} + +BOOST_AUTO_TEST_CASE(dtg_mrg_triggered_high_ens) +{ + const bool triggered = true; + const double dtgMrg = 32.; + const double ens = 42.; + + BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == 0., tt::tolerance(1.e-6)); + + BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens) + == std::abs(dtgMrg - ens), + tt::tolerance(1.e-6)); +} + +BOOST_AUTO_TEST_CASE(dtg_mrg_not_triggered_low_ens) +{ + const bool triggered = false; + const double dtgMrg = 32.; + const double ens = 21.; + + BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == dtgMrg, tt::tolerance(1.e-6)); + BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens) + == dtgMrg + ens, + tt::tolerance(1.e-6)); +} + +BOOST_AUTO_TEST_CASE(dtg_mrg_not_triggered_high_ens) +{ + const bool triggered = false; + const double dtgMrg = 32.; + const double ens = 42.; + + BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) == dtgMrg, tt::tolerance(1.e-6)); + BOOST_TEST(recomputeDTG_MRG(triggered, dtgMrg, ens) + recomputeENS_MRG(triggered, dtgMrg, ens) + == dtgMrg + ens, + tt::tolerance(1.e-6)); +} + +BOOST_AUTO_TEST_CASE(mrgprice_high_enscsr) +{ + const double ensCsr = 21.; + const double originalCost = 3.; + const double unsuppliedEnergyCost = 1000.; + BOOST_TEST(recomputeMRGPrice(ensCsr, originalCost, unsuppliedEnergyCost) + == -unsuppliedEnergyCost, + tt::tolerance(1.e-6)); +} + +BOOST_AUTO_TEST_CASE(mrgprice_low_enscsr) +{ + const double ensCsr = 0.; + const double originalCost = 3.; + const double unsuppliedEnergyCost = 1000.; + BOOST_TEST(recomputeMRGPrice(ensCsr, originalCost, unsuppliedEnergyCost) == originalCost, + tt::tolerance(1.e-6)); +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/optimisation/name-translator/CMakeLists.txt b/src/tests/src/solver/optimisation/name-translator/CMakeLists.txt new file mode 100644 index 0000000000..f5e1f0619d --- /dev/null +++ b/src/tests/src/solver/optimisation/name-translator/CMakeLists.txt @@ -0,0 +1,20 @@ +set(EXECUTABLE_NAME test-name-translator) +add_executable(${EXECUTABLE_NAME}) + +target_sources(${EXECUTABLE_NAME} + PRIVATE + test_name_translator.cpp +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + model_antares +) + +# Storing tests-ts-numbers under the folder Unit-tests in the IDE +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) + +add_test(NAME test-name-translator COMMAND ${EXECUTABLE_NAME}) + +set_property(TEST test-name-translator PROPERTY LABELS unit) diff --git a/src/tests/src/solver/optimisation/name-translator/test_name_translator.cpp b/src/tests/src/solver/optimisation/name-translator/test_name_translator.cpp new file mode 100644 index 0000000000..7819f7f3e1 --- /dev/null +++ b/src/tests/src/solver/optimisation/name-translator/test_name_translator.cpp @@ -0,0 +1,103 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define BOOST_TEST_MODULE test_name_translator +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include "antares/solver/utils/name_translator.h" + +BOOST_AUTO_TEST_SUITE(translations) + +BOOST_AUTO_TEST_CASE(ReturnedNullName) +{ + auto nul_names = NameTranslator::create(false); + auto* base_ptr = nul_names.get(); + const auto& expected_type_info = typeid(NullName); + BOOST_CHECK(expected_type_info == typeid(*base_ptr)); +} + +BOOST_AUTO_TEST_CASE(ReturnedRealName) +{ + auto real_names = NameTranslator::create(true); + auto* base_ptr = real_names.get(); + const auto& expected_type_info = typeid(RealName); + + BOOST_CHECK(expected_type_info == typeid(*base_ptr)); +} + +BOOST_AUTO_TEST_CASE(NullNameIsNotRealName) +{ + auto real_names = NameTranslator::create(true); + auto* base_ptr = real_names.get(); + const auto& expected_type_info = typeid(NullName); + + BOOST_CHECK(expected_type_info != typeid(*base_ptr)); +} + +BOOST_AUTO_TEST_CASE(NullNameWithEmptyInput) +{ + auto nul_names = NameTranslator::create(false); + std::vector names; + std::vector names_ptr; + BOOST_CHECK(nul_names->translate(names, names_ptr) == names_ptr.data()); + // size of names_ptr has not changed + BOOST_CHECK(0 == names_ptr.size()); +} + +BOOST_AUTO_TEST_CASE(NullNameWith2Names) +{ + auto nul_names = NameTranslator::create(false); + std::vector names{"name1", "name2"}; + std::vector names_ptr; + BOOST_CHECK(nul_names->translate(names, names_ptr) == names_ptr.data()); + // size of names_ptr should be updated to names.size() + BOOST_CHECK(names.size() == names_ptr.size()); + BOOST_CHECK(names_ptr[0] == nullptr); + BOOST_CHECK(names_ptr[1] == nullptr); +} + +BOOST_AUTO_TEST_CASE(RealNameWithEmptyInput) +{ + auto nul_names = NameTranslator::create(true); + std::vector names; + std::vector names_ptr; + BOOST_CHECK(nul_names->translate(names, names_ptr) == names_ptr.data()); + // size of names_ptr has not changed + BOOST_CHECK(0 == names_ptr.size()); +} + +BOOST_AUTO_TEST_CASE(RealNameWith2Names) +{ + auto nul_names = NameTranslator::create(true); + std::vector names{"name1", "name2"}; + std::vector names_ptr; + BOOST_CHECK(nul_names->translate(names, names_ptr) == names_ptr.data()); + // size of names_ptr should be updated to names.size() + BOOST_CHECK(names.size() == names_ptr.size()); + BOOST_CHECK(names_ptr[0] == names[0]); + BOOST_CHECK(names_ptr[1] == names[1]); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/optimisation/translator/CMakeLists.txt b/src/tests/src/solver/optimisation/translator/CMakeLists.txt new file mode 100644 index 0000000000..87f3d5a0cb --- /dev/null +++ b/src/tests/src/solver/optimisation/translator/CMakeLists.txt @@ -0,0 +1,20 @@ +set(EXECUTABLE_NAME test-translator) +add_executable(${EXECUTABLE_NAME}) + +target_sources(${EXECUTABLE_NAME} + PRIVATE + test_translator.cpp +) + +target_link_libraries(${EXECUTABLE_NAME} + PRIVATE + Boost::unit_test_framework + model_antares +) + +# Storing tests-ts-numbers under the folder Unit-tests in the IDE +set_target_properties(${EXECUTABLE_NAME} PROPERTIES FOLDER Unit-tests) + +add_test(NAME test-translator COMMAND ${EXECUTABLE_NAME}) + +set_property(TEST test-translator PROPERTY LABELS unit) diff --git a/src/tests/src/solver/optimisation/translator/test_translator.cpp b/src/tests/src/solver/optimisation/translator/test_translator.cpp new file mode 100644 index 0000000000..2430c74cb0 --- /dev/null +++ b/src/tests/src/solver/optimisation/translator/test_translator.cpp @@ -0,0 +1,191 @@ +/* + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ + +#define BOOST_TEST_MODULE test_translator +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +#include +#include "antares/solver/utils/opt_period_string_generator.h" + +using namespace Antares::Solver; + +class StubOptPeriodStringGenerator: public OptPeriodStringGenerator +{ +public: + std::string to_string() const override + { + return "Plop"; + } +}; + +BOOST_AUTO_TEST_CASE(null_hebdo_is_empty_lps) +{ + HebdoProblemToLpsTranslator translator; + auto ret = translator.translate(nullptr, std::string()); + BOOST_CHECK(ret == WeeklyDataFromAntares()); +} + +BOOST_AUTO_TEST_CASE(non_null_hebdo_returns_non_empty_lps) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + problemHebdo.CoutLineaire.push_back(45); + auto ret = translator.translate(&problemHebdo, std::string()); + BOOST_CHECK(ret != WeeklyDataFromAntares()); +} + +BOOST_AUTO_TEST_CASE(Data_properly_copied) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + problemHebdo.CoutLineaire = {0, 1, 2}; + problemHebdo.Xmax = {10, 11, 12}; + problemHebdo.Xmin = {20, 21, 22}; + problemHebdo.NomDesVariables = {"a", "b", "c"}; + problemHebdo.NomDesContraintes = {"d", "e", "f"}; + problemHebdo.SecondMembre = {30, 31, 32}; + + auto ret = translator.translate(&problemHebdo, std::string()); + BOOST_CHECK(ret.LinearCost == problemHebdo.CoutLineaire); + BOOST_CHECK(ret.Xmax == problemHebdo.Xmax); + BOOST_CHECK(ret.Xmin == problemHebdo.Xmin); + BOOST_CHECK(ret.RHS == problemHebdo.SecondMembre); + + BOOST_CHECK(ret.variables == problemHebdo.NomDesVariables); + BOOST_CHECK(ret.constraints == problemHebdo.NomDesContraintes); +} + +BOOST_AUTO_TEST_CASE(translate_sens) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + problemHebdo.Sens = "<=>"; + + auto ret = translator.translate(&problemHebdo, std::string()); + BOOST_CHECK(ret.Direction == std::vector({'<', '=', '>'})); +} + +BOOST_AUTO_TEST_CASE(translate_name_is_filled) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + + auto ret = translator.translate(&problemHebdo, "dummy"); + BOOST_CHECK(!ret.name.empty()); +} + +BOOST_AUTO_TEST_CASE(translate_name_is_properly_filled) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + + auto ret = translator.translate(&problemHebdo, "problem-Plop--optim-nb-1.mps"); + BOOST_CHECK_EQUAL(ret.name, "problem-Plop--optim-nb-1.mps"); +} + +BOOST_AUTO_TEST_CASE(empty_problem_empty_const_data) +{ + HebdoProblemToLpsTranslator translator; + auto ret = translator.commonProblemData(nullptr); + BOOST_CHECK(ret == ConstantDataFromAntares()); +} + +BOOST_AUTO_TEST_CASE(common_data_properly_copied) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + problemHebdo.NombreDeVariables = 1; + problemHebdo.NombreDeContraintes = 2; + problemHebdo.TypeDeVariable = {0, 1, 2}; + problemHebdo.IndicesDebutDeLigne = {0, 3}; + problemHebdo.NombreDeTermesDesLignes = {3, 3}; + problemHebdo.CoefficientsDeLaMatriceDesContraintes = {0, 1, 2, 3, 4, 5}; + problemHebdo.IndicesColonnes = {0, 1, 2, 3, 4, 5}; + + auto ret = translator.commonProblemData(&problemHebdo); + BOOST_CHECK_EQUAL(ret.VariablesCount, problemHebdo.NombreDeVariables); + BOOST_CHECK_EQUAL(ret.ConstraintesCount, problemHebdo.NombreDeContraintes); + BOOST_CHECK(std::ranges::equal(ret.VariablesType, problemHebdo.TypeDeVariable)); + BOOST_CHECK(ret.ConstraintsMatrixCoeff == problemHebdo.CoefficientsDeLaMatriceDesContraintes); + BOOST_CHECK(std::ranges::equal(ret.ColumnIndexes, problemHebdo.IndicesColonnes)); + auto expectedMdeb = problemHebdo.IndicesDebutDeLigne; + expectedMdeb.push_back(problemHebdo.CoefficientsDeLaMatriceDesContraintes.size()); + BOOST_CHECK(std::ranges::equal(ret.Mdeb, expectedMdeb)); +} + +// throw exception if NombreDeVariables is 0 +BOOST_AUTO_TEST_CASE(throw_exception_if_NombreDeVariables_is_0) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + problemHebdo.NombreDeVariables = 0; + BOOST_CHECK_THROW(translator.commonProblemData(&problemHebdo), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(throw_exception_if_NombreDeContraintes_is_0) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + problemHebdo.NombreDeContraintes = 0; + BOOST_CHECK_THROW(translator.commonProblemData(&problemHebdo), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(throw_exception_if_IndicesDebutDeLigne_out_of_bound) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + problemHebdo.NombreDeVariables = 1; + problemHebdo.NombreDeContraintes = 3; + problemHebdo.IndicesDebutDeLigne = {0, 3}; + problemHebdo.NombreDeTermesDesLignes = {0, 3, 6, 7, 8}; + BOOST_CHECK_THROW(translator.commonProblemData(&problemHebdo), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(throw_exception_if_NombreDeTermesDesLignes_out_of_bound) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + problemHebdo.NombreDeVariables = 1; + problemHebdo.NombreDeContraintes = 3; + problemHebdo.NombreDeTermesDesLignes = {0, 3}; + problemHebdo.IndicesDebutDeLigne = {0, 3, 6, 7, 8}; + BOOST_CHECK_THROW(translator.commonProblemData(&problemHebdo), std::runtime_error); +} + +// NombreDeCoefficients +BOOST_AUTO_TEST_CASE(NombreDeCoefficients_is_properly_computed) +{ + HebdoProblemToLpsTranslator translator; + PROBLEME_ANTARES_A_RESOUDRE problemHebdo; + problemHebdo.NombreDeVariables = 1; + problemHebdo.NombreDeContraintes = 3; + problemHebdo.IndicesDebutDeLigne = {0, 3, 6}; + problemHebdo.NombreDeTermesDesLignes = {3, 3, 3}; + problemHebdo.CoefficientsDeLaMatriceDesContraintes = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + problemHebdo.IndicesColonnes = {0, 1, 2, 3, 4, 5, 6, 7, 8}; + + auto ret = translator.commonProblemData(&problemHebdo); + BOOST_CHECK_EQUAL(ret.CoeffCount, 9); +} diff --git a/src/tests/src/solver/simulation/CMakeLists.txt b/src/tests/src/solver/simulation/CMakeLists.txt index e056ac388d..294005454b 100644 --- a/src/tests/src/solver/simulation/CMakeLists.txt +++ b/src/tests/src/solver/simulation/CMakeLists.txt @@ -1,5 +1,6 @@ # Useful variables definitions set(src_solver_simulation "${CMAKE_SOURCE_DIR}/solver/simulation") +set(src_solver_hydro "${CMAKE_SOURCE_DIR}/solver/hydro") set(src_libs_antares_study "${CMAKE_SOURCE_DIR}/libs/antares/study") set(SRC_TS_NUMBERS @@ -89,3 +90,33 @@ add_test(NAME time_series COMMAND test-time_series) set_property(TEST time_series PROPERTY LABELS unit) +# =================================== +# Tests on hydro final reservoir level functions +# =================================== + +add_executable(test-hydro_final test-hydro-final-reservoir-level-functions.cpp) + +target_include_directories(test-hydro_final + PRIVATE + "${src_solver_simulation}" + "${src_libs_antares_study}" + "${src_solver_hydro}" +) +target_link_libraries(test-hydro_final + PRIVATE + Boost::unit_test_framework + Antares::study + antares-solver-simulation + Antares::array +) + +# Linux +if(UNIX AND NOT APPLE) + target_link_libraries(test-hydro_final PRIVATE stdc++fs) +endif() + +set_target_properties(test-hydro_final PROPERTIES FOLDER Unit-tests) + +add_test(NAME hydro_final COMMAND test-hydro_final) + +set_property(TEST hydro_final PROPERTY LABELS unit) \ No newline at end of file diff --git a/src/tests/src/solver/simulation/test-hydro-final-reservoir-level-functions.cpp b/src/tests/src/solver/simulation/test-hydro-final-reservoir-level-functions.cpp new file mode 100644 index 0000000000..9eeeaf9618 --- /dev/null +++ b/src/tests/src/solver/simulation/test-hydro-final-reservoir-level-functions.cpp @@ -0,0 +1,294 @@ +// +// Created by Nikola Ilic on 23/06/23. +// + +#define BOOST_TEST_MODULE hydro - final - level +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include "antares/solver/hydro/management/HydroErrorsCollector.h" +#include "antares/solver/hydro/management/finalLevelValidator.h" + +#include "include/antares/solver/hydro/management/HydroInputsChecker.h" + +using namespace Antares::Solver; +using namespace Antares::Data; + +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() + { + // Simulation last day must be 365 so that final level checks succeeds + study->parameters.simulationDays.end = 365; + study->parameters.firstMonthInYear = january; + uint nbYears = study->parameters.nbYears = 2; + + area_1 = study->areaAdd("Area1"); + area_2 = study->areaAdd("Area2"); + + area_1->hydro.reservoirManagement = true; + area_2->hydro.reservoirManagement = true; + + area_1->hydro.useWaterValue = false; + area_2->hydro.useWaterValue = false; + + // Level date must be 0, see hydroAllocationStartMatchesSimulation function + area_1->hydro.initializeReservoirLevelDate = 0; + area_2->hydro.initializeReservoirLevelDate = 0; + + area_1->hydro.reservoirCapacity = 340.; + area_2->hydro.reservoirCapacity = 300.; + + // Set reservoir max and min daily levels, but just for the last day in year + area_1->hydro.reservoirLevel.resize(3, DAYS_PER_YEAR); + area_1->hydro.reservoirLevel[PartHydro::minimum][DAYS_PER_YEAR - 1] = 2.4; + area_1->hydro.reservoirLevel[PartHydro::maximum][DAYS_PER_YEAR - 1] = 6.5; + + area_2->hydro.reservoirLevel.resize(3, DAYS_PER_YEAR); + area_2->hydro.reservoirLevel[PartHydro::minimum][DAYS_PER_YEAR - 1] = 2.7; + area_2->hydro.reservoirLevel[PartHydro::maximum][DAYS_PER_YEAR - 1] = 6.4; + + // Resize vector final levels delta with initial levels + area_1->hydro.deltaBetweenFinalAndInitialLevels.resize(nbYears); + area_2->hydro.deltaBetweenFinalAndInitialLevels.resize(nbYears); + + // Scenario builder for initial and final reservoir levels + // ------------------------------------------------------- + uint areasCount = study->areas.size(); + + study->parameters.yearsFilter.assign(2, true); + + study->scenarioInitialHydroLevels.resize(nbYears, areasCount); + study->scenarioFinalHydroLevels.resize(nbYears, areasCount); + + study->scenarioInitialHydroLevels[0][0] = 2.3; + study->scenarioInitialHydroLevels[0][1] = 4.2; + study->scenarioInitialHydroLevels[1][0] = 1.5; + study->scenarioInitialHydroLevels[1][1] = 2.4; + + study->scenarioFinalHydroLevels[0][0] = 3.4; + study->scenarioFinalHydroLevels[0][1] = 5.1; + study->scenarioFinalHydroLevels[1][0] = 3.5; + study->scenarioFinalHydroLevels[1][1] = 4.3; + + // Inflows time series matrices + // ----------------------------- + uint nbInflowTS = 2; + // ... Area 1 : Inflows time series numbers for each year + area_1->hydro.series->timeseriesNumbers.reset(nbYears); + area_1->hydro.series->timeseriesNumbers[0] = 0; + area_1->hydro.series->timeseriesNumbers[1] = 1; + // ... Area 1 : Inflows time series + area_1->hydro.series->storage.resize(nbInflowTS, 365); + area_1->hydro.series->storage.timeSeries.fill(200.); + area_1->hydro.series->storage[0][0] = 200. + 1.; + area_1->hydro.series->storage[0][DAYS_PER_YEAR - 1] = 200. + 2.; + + // ... Area 2 : time series numbers for each year + area_2->hydro.series->timeseriesNumbers.reset(nbYears); + area_2->hydro.series->timeseriesNumbers[0] = 0; + area_2->hydro.series->timeseriesNumbers[1] = 1; + // ... Area 2 : Inflows time series + area_2->hydro.series->storage.resize(nbInflowTS, 365); + area_2->hydro.series->storage.timeSeries.fill(300.); + area_2->hydro.series->storage[0][0] = 300. + 1.; // DAYS_PER_YEAR + area_2->hydro.series->storage[0][DAYS_PER_YEAR - 1] = 300. + 2.; + } + + ~Fixture() = default; + + Study::Ptr study = std::make_shared(); + Area* area_1; + Area* area_2; + HydroErrorsCollector hydro_errors_collector; +}; + +BOOST_FIXTURE_TEST_SUITE(final_level_validator, Fixture) + +BOOST_AUTO_TEST_CASE(all_parameters_good___check_succeeds_and_final_level_is_usable) +{ + uint year = 0; + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear, + hydro_errors_collector); + + BOOST_CHECK_EQUAL(validator.check(), true); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), true); +} + +BOOST_AUTO_TEST_CASE(no_reservoir_management___check_succeeds_but_final_level_not_usable) +{ + uint year = 0; + area_1->hydro.reservoirManagement = false; + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear, + hydro_errors_collector); + + BOOST_CHECK_EQUAL(validator.check(), true); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(use_water_value_is_true___check_succeeds_but_final_level_not_usable) +{ + area_1->hydro.useWaterValue = true; + uint year = 0; + + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear, + hydro_errors_collector); + + BOOST_CHECK_EQUAL(validator.check(), true); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(final_level_not_set_by_user____check_succeeds_but_final_level_not_usable) +{ + uint year = 0; + study->scenarioFinalHydroLevels[area_1->index][year] = std::numeric_limits::quiet_NaN(); + + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear, + hydro_errors_collector); + + BOOST_CHECK_EQUAL(validator.check(), true); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE( + initial_level_month_and_simulation_first_month_different___check_fails_and_final_level_not_usable) +{ + uint year = 0; + area_1->hydro.initializeReservoirLevelDate = 3; // initialize reservoir level != January + + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear, + hydro_errors_collector); + + BOOST_CHECK_EQUAL(validator.check(), false); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(simulation_does_last_a_whole_year___check_fails_and_final_level_not_usable) +{ + uint year = 0; + study->parameters.simulationDays.end = 300; + + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear, + hydro_errors_collector); + + BOOST_CHECK_EQUAL(validator.check(), false); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(final_level_out_of_rule_curves___check_fails_and_final_level_not_usable) +{ + uint year = 0; + // Rule Curves on last simulation day = [2.4 - 6.5] + study->scenarioFinalHydroLevels[area_1->index][year] = 6.6; + + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear, + hydro_errors_collector); + + BOOST_CHECK_EQUAL(validator.check(), false); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE( + final_level_unreachable_because_of_too_few_inflows___check_fails_and_final_level_not_usable) +{ + area_1->hydro.reservoirCapacity = 185000; + uint year = 0; + study->scenarioInitialHydroLevels[area_1->index][year] = 10; + study->scenarioFinalHydroLevels[area_1->index][year] = 50; + + // Inflows = 200 MWh/day = 73 000 MWh/year + // (50 - 10) x Reservoir capacity == 74 000 > 73 000. + FinalLevelValidator validator(area_1->hydro, + area_1->index, + area_1->name, + study->scenarioInitialHydroLevels[area_1->index][year], + study->scenarioFinalHydroLevels[area_1->index][year], + year, + study->parameters.simulationDays.end, + study->parameters.firstMonthInYear, + hydro_errors_collector); + + BOOST_CHECK_EQUAL(validator.check(), false); + BOOST_CHECK_EQUAL(validator.finalLevelFineForUse(), false); +} + +BOOST_AUTO_TEST_CASE(check_all_areas_final_levels_when_config_is_ok___all_checks_succeed) +{ + HydroInputsChecker hydro_input_checker(*study); + + for (uint year: {0, 1}) + { + hydro_input_checker.CheckFinalReservoirLevelsConfiguration(year); + } + // CheckFinalReservoirLevelsConfiguration(*study, 0); + // CheckFinalReservoirLevelsConfiguration(*study, 1); + + // Checks on Area 1 modifier + BOOST_CHECK_EQUAL(area_1->hydro.deltaBetweenFinalAndInitialLevels[0].has_value(), true); + BOOST_CHECK_EQUAL(area_1->hydro.deltaBetweenFinalAndInitialLevels[1].has_value(), true); + BOOST_CHECK_EQUAL(area_1->hydro.deltaBetweenFinalAndInitialLevels[0].value(), 3.4 - 2.3); + BOOST_CHECK_EQUAL(area_1->hydro.deltaBetweenFinalAndInitialLevels[1].value(), 5.1 - 4.2); + + // Checks on Area 2 modifier + BOOST_CHECK_EQUAL(area_2->hydro.deltaBetweenFinalAndInitialLevels[0].has_value(), true); + BOOST_CHECK_EQUAL(area_2->hydro.deltaBetweenFinalAndInitialLevels[1].has_value(), true); + BOOST_CHECK_EQUAL(area_2->hydro.deltaBetweenFinalAndInitialLevels[0].value(), 3.5 - 1.5); + BOOST_CHECK_EQUAL(area_2->hydro.deltaBetweenFinalAndInitialLevels[1].value(), 4.3 - 2.4); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/tests/src/solver/simulation/test-store-timeseries-number.cpp b/src/tests/src/solver/simulation/test-store-timeseries-number.cpp index 1524b26627..1e68ef95be 100644 --- a/src/tests/src/solver/simulation/test-store-timeseries-number.cpp +++ b/src/tests/src/solver/simulation/test-store-timeseries-number.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ // // Created by marechaljas on 15/03/23. // @@ -44,10 +44,9 @@ void initializeStudy(Study& study) { study.parameters.derated = false; - study.runtime = new StudyRuntimeInfos(); - study.runtime->rangeLimits.year[rangeBegin] = 0; - study.runtime->rangeLimits.year[rangeEnd] = 0; - study.runtime->rangeLimits.year[rangeCount] = 1; + study.runtime.rangeLimits.year[rangeBegin] = 0; + study.runtime.rangeLimits.year[rangeEnd] = 0; + study.runtime.rangeLimits.year[rangeCount] = 1; study.parameters.renewableGeneration.toAggregated(); // Default diff --git a/src/tests/src/solver/simulation/test-time_series.cpp b/src/tests/src/solver/simulation/test-time_series.cpp index 5c9fdfa942..b999c17b48 100644 --- a/src/tests/src/solver/simulation/test-time_series.cpp +++ b/src/tests/src/solver/simulation/test-time_series.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ // // Created by marechaljas on 07/04/23. // @@ -40,10 +40,9 @@ void initializeStudy(Study& study) { study.parameters.derated = false; - study.runtime = new StudyRuntimeInfos(); - study.runtime->rangeLimits.year[rangeBegin] = 0; - study.runtime->rangeLimits.year[rangeEnd] = 0; - study.runtime->rangeLimits.year[rangeCount] = 1; + study.runtime.rangeLimits.year[rangeBegin] = 0; + study.runtime.rangeLimits.year[rangeEnd] = 0; + study.runtime.rangeLimits.year[rangeCount] = 1; study.parameters.renewableGeneration.toAggregated(); // Default diff --git a/src/tests/src/solver/simulation/tests-ts-numbers.cpp b/src/tests/src/solver/simulation/tests-ts-numbers.cpp index a6ecf820c1..8dbd450d53 100644 --- a/src/tests/src/solver/simulation/tests-ts-numbers.cpp +++ b/src/tests/src/solver/simulation/tests-ts-numbers.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test solver simulation things #define WIN32_LEAN_AND_MEAN @@ -38,9 +38,8 @@ void initializeStudy(Study::Ptr study, unsigned int nbYears = 1) { study->parameters.derated = false; - study->runtime = new StudyRuntimeInfos(); - study->runtime->rangeLimits.year[rangeBegin] = 0; - study->runtime->rangeLimits.year[rangeEnd] = nbYears - 1; + study->runtime.rangeLimits.year[rangeBegin] = 0; + study->runtime.rangeLimits.year[rangeEnd] = nbYears - 1; study->parameters.renewableGeneration.toAggregated(); // Default @@ -55,7 +54,7 @@ void initializeStudy(Study::Ptr study, unsigned int nbYears = 1) Area* addAreaToStudy(Study::Ptr study, const std::string& areaName) { Area* area = study->areaAdd(areaName); - BOOST_CHECK(area != NULL); + BOOST_CHECK(area); return area; } @@ -130,7 +129,7 @@ BOOST_AUTO_TEST_CASE(two_areas_with_5_ready_made_ts_on_load___check_intra_modal_ Area* area_1 = addAreaToStudy(study, "Area 1"); Area* area_2 = addAreaToStudy(study, "Area 2"); - study->areas.resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + study->areas.resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); area_1->load.series.timeSeries.resize(5, 1); area_2->load.series.timeSeries.resize(5, 1); @@ -157,7 +156,7 @@ static bool intramodal_load_two_areas(unsigned width_area_1, unsigned width_area Area* area_1 = addAreaToStudy(study, "Area 1"); Area* area_2 = addAreaToStudy(study, "Area 2"); - study->areas.resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + study->areas.resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); area_1->load.series.timeSeries.resize(width_area_1, 1); area_2->load.series.timeSeries.resize(width_area_2, 1); @@ -199,7 +198,7 @@ BOOST_AUTO_TEST_CASE( auto thCluster_21 = addClusterToArea(area_2, "th-cluster-21"); thCluster_21->series.timeSeries.resize(4, 1); - study->areas.resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + study->areas.resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); BOOST_CHECK(Generate(*study)); @@ -231,7 +230,7 @@ BOOST_AUTO_TEST_CASE( auto thCluster_21 = addClusterToArea(area_2, "th-cluster-21"); thCluster_21->series.timeSeries.resize(4, 1); - study->areas.resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + study->areas.resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); BOOST_CHECK(Generate(*study)); @@ -263,7 +262,7 @@ BOOST_AUTO_TEST_CASE( auto thCluster_21 = addClusterToArea(area_2, "th-cluster-21"); thCluster_21->series.timeSeries.resize(3, 1); - study->areas.resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + study->areas.resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); BOOST_CHECK(not Generate(*study)); } @@ -291,7 +290,7 @@ BOOST_AUTO_TEST_CASE( auto rnCluster_21 = addClusterToArea(area_2, "rn-cluster-21"); rnCluster_21->series.timeSeries.resize(4, 1); - study->areas.resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + study->areas.resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); BOOST_CHECK(Generate(*study)); @@ -323,7 +322,7 @@ BOOST_AUTO_TEST_CASE( auto rnCluster_21 = addClusterToArea(area_2, "rn-cluster-21"); rnCluster_21->series.timeSeries.resize(4, 1); - study->areas.resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + study->areas.resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); BOOST_CHECK(Generate(*study)); @@ -357,7 +356,7 @@ BOOST_AUTO_TEST_CASE( auto rnCluster_21 = addClusterToArea(area_2, "rn-cluster-21"); rnCluster_21->series.timeSeries.resize(4, 1); - study->areas.resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + study->areas.resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); BOOST_CHECK(not Generate(*study)); } @@ -389,7 +388,7 @@ BOOST_AUTO_TEST_CASE( auto thCluster_1 = addClusterToArea(area, "th-cluster-1"); auto thCluster_2 = addClusterToArea(area, "th-cluster-2"); - area->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + area->resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); TSGenerator::ResizeGeneratedTimeSeries(study->areas, study->parameters); BOOST_CHECK(Generate(*study)); @@ -425,7 +424,7 @@ BOOST_AUTO_TEST_CASE( auto thCluster_1 = addClusterToArea(area, "th-cluster-1"); auto thCluster_2 = addClusterToArea(area, "th-cluster-2"); - area->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + area->resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); TSGenerator::ResizeGeneratedTimeSeries(study->areas, study->parameters); BOOST_CHECK(Generate(*study)); @@ -461,7 +460,7 @@ BOOST_AUTO_TEST_CASE( auto thCluster_1 = addClusterToArea(area, "th-cluster-1"); auto thCluster_2 = addClusterToArea(area, "th-cluster-2"); - area->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + area->resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); TSGenerator::ResizeGeneratedTimeSeries(study->areas, study->parameters); BOOST_CHECK(not Generate(*study)); @@ -486,7 +485,7 @@ BOOST_AUTO_TEST_CASE( auto rnCluster_1 = addClusterToArea(area, "rn-cluster-1"); rnCluster_1->series.timeSeries.resize(5, 1); - area->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + area->resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); BOOST_CHECK(Generate(*study)); @@ -515,7 +514,7 @@ BOOST_AUTO_TEST_CASE( auto rnCluster_1 = addClusterToArea(area, "rn-cluster-1"); rnCluster_1->series.timeSeries.resize(4, 1); - area->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + area->resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); BOOST_CHECK(not Generate(*study)); } @@ -539,7 +538,7 @@ BOOST_AUTO_TEST_CASE( auto rnCluster_1 = addClusterToArea(area, "rn-cluster-1"); rnCluster_1->series.timeSeries.resize(1, 1); - area->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + area->resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); BOOST_CHECK(Generate(*study)); } @@ -581,7 +580,7 @@ BOOST_AUTO_TEST_CASE(load_wind_thermal_in_intra_and_inter_modal____check_all_ts_ area_2->wind.series.timeSeries.resize(5, 1); // Ready made TS for wind auto thCluster_area_2 = addClusterToArea(area_2, "th-cluster-area-2"); - study->areas.resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + study->areas.resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); TSGenerator::ResizeGeneratedTimeSeries(study->areas, study->parameters); BOOST_CHECK(Generate(*study)); @@ -629,14 +628,14 @@ BOOST_AUTO_TEST_CASE(check_all_drawn_ts_numbers_are_bounded_between_0_and_nb_of_ auto thCluster = addClusterToArea(area, "th-cluster"); - area->resizeAllTimeseriesNumbers(1 + study->runtime->rangeLimits.year[rangeEnd]); + area->resizeAllTimeseriesNumbers(1 + study->runtime.rangeLimits.year[rangeEnd]); auto bc = study->bindingConstraints.add("dummy"); bc->group("dummy"); study->bindingConstraintsGroups.add(bc->group()); bc->RHSTimeSeries().resize(42, 1); study->bindingConstraintsGroups.resizeAllTimeseriesNumbers( - 1 + study->runtime->rangeLimits.year[rangeEnd]); + 1 + study->runtime.rangeLimits.year[rangeEnd]); TSGenerator::ResizeGeneratedTimeSeries(study->areas, study->parameters); BOOST_CHECK(Generate(*study)); diff --git a/src/tests/src/solver/utils/basis_status.cpp b/src/tests/src/solver/utils/basis_status.cpp index b4994b28dc..292dc56c3c 100644 --- a/src/tests/src/solver/utils/basis_status.cpp +++ b/src/tests/src/solver/utils/basis_status.cpp @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #define BOOST_TEST_MODULE test adequacy patch functions #define WIN32_LEAN_AND_MEAN diff --git a/src/tools/batchrun/main.cpp b/src/tools/batchrun/main.cpp index 2ae0bc03e1..e2fb2e2278 100644 --- a/src/tools/batchrun/main.cpp +++ b/src/tools/batchrun/main.cpp @@ -74,7 +74,7 @@ String sendToNull() #endif } -int main(int argc, char* argv[]) +int main(int argc, const char* argv[]) { // locale InitializeDefaultLocale(); diff --git a/src/tools/config/main.cpp b/src/tools/config/main.cpp index 0cb15eac90..947b1f5a69 100644 --- a/src/tools/config/main.cpp +++ b/src/tools/config/main.cpp @@ -34,7 +34,7 @@ using namespace Yuni; using namespace Antares; -int main(int argc, char* argv[]) +int main(int argc, const char* argv[]) { // locale InitializeDefaultLocale(); diff --git a/src/tools/finder/main.cpp b/src/tools/finder/main.cpp index 02ea7fdb7f..0e04320741 100644 --- a/src/tools/finder/main.cpp +++ b/src/tools/finder/main.cpp @@ -68,7 +68,7 @@ class MyStudyFinder: public Data::StudyFinder bool csv; }; -int main(int argc, char* argv[]) +int main(int argc, const char* argv[]) { // locale InitializeDefaultLocale(); diff --git a/src/tools/kirchhoff-cbuilder/kirchhoff-cbuilder.h b/src/tools/kirchhoff-cbuilder/kirchhoff-cbuilder.h index e3afd8ab2b..1591840d1b 100644 --- a/src/tools/kirchhoff-cbuilder/kirchhoff-cbuilder.h +++ b/src/tools/kirchhoff-cbuilder/kirchhoff-cbuilder.h @@ -24,7 +24,7 @@ static void NotEnoughMemory(); -bool initResources(int argc, char* argv[]); +bool initResources(int argc, const char* argv[]); bool initComponents(std::shared_ptr study, const std::string& studyPath); bool runKirchhoffConstraints(std::shared_ptr study, const std::string& studyPath, diff --git a/src/tools/kirchhoff-cbuilder/main.cpp b/src/tools/kirchhoff-cbuilder/main.cpp index 7097917137..1f4abde58e 100644 --- a/src/tools/kirchhoff-cbuilder/main.cpp +++ b/src/tools/kirchhoff-cbuilder/main.cpp @@ -33,7 +33,7 @@ using namespace Yuni; using namespace Antares; -int main(int argc, char* argv[]) +int main(int argc, const char* argv[]) { logs.applicationName("k-cbuild"); if (argc < 2) @@ -121,7 +121,7 @@ static void NotEnoughMemory() logs.fatal() << "Not enough memory. aborting."; } -bool initResources(int argc, char* argv[]) +bool initResources(int argc, const char* argv[]) { std::set_new_handler(&NotEnoughMemory); diff --git a/src/tools/ts-generator/CMakeLists.txt b/src/tools/ts-generator/CMakeLists.txt index cea38ae0cd..f037e6f1dd 100644 --- a/src/tools/ts-generator/CMakeLists.txt +++ b/src/tools/ts-generator/CMakeLists.txt @@ -1,5 +1,9 @@ set(SRCS main.cpp + include/antares/tools/ts-generator/linksTSgenerator.h + include/antares/tools/ts-generator/tsGenerationOptions.h + tsGenerationOptions.cpp + linksTSgenerator.cpp ) set(execname "antares-ts-generator") @@ -13,15 +17,15 @@ INSTALL(EXPORT ${execname} target_link_libraries(${execname} PRIVATE - Antares::utils - antares-solver-ts-generator - Antares::study - Antares::checks + Antares::utils + antares-solver-ts-generator + Antares::study + Antares::checks ) target_include_directories(${execname} PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}/include" ) import_std_libs(${execname}) diff --git a/src/tools/ts-generator/include/antares/tools/ts-generator/linksTSgenerator.h b/src/tools/ts-generator/include/antares/tools/ts-generator/linksTSgenerator.h new file mode 100644 index 0000000000..1feaac5038 --- /dev/null +++ b/src/tools/ts-generator/include/antares/tools/ts-generator/linksTSgenerator.h @@ -0,0 +1,32 @@ + +#pragma once + +#include +#include "antares/tools/ts-generator/tsGenerationOptions.h" + +namespace fs = std::filesystem; + +namespace Antares::TSGenerator +{ + +class LinksTSgenerator +{ +public: + LinksTSgenerator(Settings&); + void extractData(); + bool generate(); + +private: + LinkPairs extractLinkNamesFromStudy(); + LinkPairs extractLinkNamesFromCmdLine(const LinkPairs&); + StudyParamsForLinkTS readGeneralParamsForLinksTS(); + void extractLinksSpecificTSparameters(); + + std::string linksFromCmdLineOptions_; + fs::path studyFolder_; + bool generateTSforAllLinks_ = false; + std::vector linkList_; + StudyParamsForLinkTS generalParams_; +}; + +} // namespace Antares::TSGenerator diff --git a/src/tools/ts-generator/include/antares/tools/ts-generator/tsGenerationOptions.h b/src/tools/ts-generator/include/antares/tools/ts-generator/tsGenerationOptions.h new file mode 100644 index 0000000000..e12ed09fd2 --- /dev/null +++ b/src/tools/ts-generator/include/antares/tools/ts-generator/tsGenerationOptions.h @@ -0,0 +1,31 @@ + +#pragma once + +#include + +#include + +namespace Antares::TSGenerator +{ +struct Settings +{ + std::string studyFolder; + + /// generate TS for all clusters if activated + bool allThermal = false; + /// generate TS for a list "area.cluster;area2.cluster2;" + std::string thermalListToGen = ""; + + /// generate TS for all links if activated + bool allLinks = false; + /// generate TS for a list "area.link;area2.link2;" + std::string linksListToGen; +}; + +bool parseOptions(int, const char*[], Settings&); +std::unique_ptr createTsGeneratorParser(Settings&); + +bool checkOptions(Settings& options); +bool linkTSrequired(Settings& options); +bool thermalTSrequired(Settings& options); +} // namespace Antares::TSGenerator diff --git a/src/tools/ts-generator/linksTSgenerator.cpp b/src/tools/ts-generator/linksTSgenerator.cpp new file mode 100644 index 0000000000..a200386a7e --- /dev/null +++ b/src/tools/ts-generator/linksTSgenerator.cpp @@ -0,0 +1,347 @@ + +#include "antares/tools/ts-generator/linksTSgenerator.h" + +#include "antares/utils/utils.h" + +namespace Antares::TSGenerator +{ +// ================== +// Free functions +// ================== +std::vector extractTargetAreas(const fs::path& sourceLinkDir) +{ + std::vector to_return; + fs::path pathToIni = sourceLinkDir / "properties.ini"; + IniFile ini; + ini.open(pathToIni); // gp : we should handle reading issues + for (auto s = ini.firstSection; s; s = s->next) + { + to_return.push_back(transformNameIntoID(s->name)); + } + return to_return; +} + +bool pairs_match(const LinkPair& p1, const LinkPair& p2) +{ + return (p1.first == p2.first && p1.second == p2.second) + || (p1.first == p2.second && p1.second == p2.first); +} + +const LinkPair* getMatchingPairInCollection(const LinkPair& pair, const LinkPairs& collection) +{ + for (const auto& p: collection) + { + if (pairs_match(pair, p)) + { + return &p; + } + } + return nullptr; +} + +bool readLinkGeneralProperty(StudyParamsForLinkTS& params, + const Yuni::String& key, + const Yuni::String& value) +{ + if (key == "derated") + { + return value.to(params.derated); + } + if (key == "nbtimeserieslinks") + { + return value.to(params.nbLinkTStoGenerate); + } + if (key == "seed-tsgen-links") + { + unsigned int seed{0}; + if (!value.to(seed)) + { + return false; + } + params.random.reset(seed); + return true; + } + return true; +} + +std::vector CreateLinkList(const LinkPairs& linksFromCmdLine) +{ + std::vector to_return; + std::for_each(linksFromCmdLine.begin(), + linksFromCmdLine.end(), + [&to_return](const auto& link_pair) + { + LinkTSgenerationParams link; + link.namesPair = link_pair; + to_return.push_back(std::move(link)); + }); + return to_return; +} + +LinkTSgenerationParams* findLinkInList(const LinkPair& link_to_find, + std::vector& linkList) +{ + for (auto& link: linkList) + { + if (link.namesPair == link_to_find) + { + return &link; + } + } + return nullptr; +} + +bool readLinkIniProperty(LinkTSgenerationParams* link, + const Yuni::String& key, + const Yuni::String& value) +{ + if (key == "unitcount") + { + return value.to(link->unitCount); + } + + if (key == "nominalcapacity") + { + return value.to(link->nominalCapacity); + } + + if (key == "law.planned") + { + return value.to(link->plannedLaw); + } + + if (key == "law.forced") + { + return value.to(link->forcedLaw); + } + + if (key == "volatility.planned") + { + return value.to(link->plannedVolatility); + } + + if (key == "volatility.forced") + { + return value.to(link->forcedVolatility); + } + + if (key == "force-no-generation") + { + return value.to(link->forceNoGeneration); + } + return true; +} + +void readLinkIniProperties(LinkTSgenerationParams* link, IniFile::Section* section) +{ + for (const IniFile::Property* p = section->firstProperty; p; p = p->next) + { + if (!readLinkIniProperty(link, p->key, p->value)) + { + std::string linkName = link->namesPair.first + "." + link->namesPair.second; + logs.warning() << "Link '" << linkName << "' : reading value of '" << p->key + << "' went wrong"; + link->hasValidData = false; + } + } +} + +void readSourceAreaIniFile(fs::path pathToIni, + std::string sourceAreaName, + std::vector& linkList) +{ + IniFile ini; + ini.open(pathToIni); // gp : we should handle reading problems here + for (auto* section = ini.firstSection; section; section = section->next) + { + std::string targetAreaName = transformNameIntoID(section->name); + const LinkPair processedLink = std::make_pair(sourceAreaName, targetAreaName); + if (auto* foundLink = findLinkInList(processedLink, linkList); foundLink) + { + readLinkIniProperties(foundLink, section); + } + } +} + +void readIniProperties(std::vector& linkList, fs::path toLinksDir) +{ + for (auto& link: linkList) + { + std::string sourceAreaName = link.namesPair.first; + fs::path pathToIni = toLinksDir / sourceAreaName / "properties.ini"; + readSourceAreaIniFile(pathToIni, sourceAreaName, linkList); + } +} + +fs::path makePreproFile(const fs::path& preproFilePath, const std::string& changingEnd) +{ + auto to_return = preproFilePath; + to_return += changingEnd + ".txt"; + return to_return; +} + +bool readLinkPreproTimeSeries(LinkTSgenerationParams& link, fs::path sourceAreaDir) +{ + bool to_return = true; + const auto preproId = link.namesPair.first + "/" + link.namesPair.second; + link.prepro = std::make_unique(preproId, link.unitCount); + + auto preproFileRoot = sourceAreaDir / "prepro" / link.namesPair.second; + + // Testing files existence + auto preproFile = makePreproFile(preproFileRoot, ""); + auto modulationDirectFile = makePreproFile(preproFileRoot, "_mod_direct"); + auto modulationIndirectFile = makePreproFile(preproFileRoot, "_mod_indirect"); + std::vector paths{preproFile, modulationDirectFile, modulationIndirectFile}; + if (std::any_of(paths.begin(), paths.end(), [](auto& path) { return !fs::exists(path); })) + { + link.hasValidData = false; + return false; + } + + // Files loading + to_return = link.prepro->data.loadFromCSVFile(preproFile.string(), + Data::PreproAvailability::preproAvailabilityMax, + DAYS_PER_YEAR) + && link.prepro->validate() && to_return; + + to_return = link.modulationCapacityDirect.loadFromCSVFile(modulationDirectFile.string(), + 1, + HOURS_PER_YEAR) + && to_return; + + to_return = link.modulationCapacityIndirect.loadFromCSVFile(modulationIndirectFile.string(), + 1, + HOURS_PER_YEAR) + && to_return; + + link.hasValidData = link.hasValidData && to_return; + return to_return; +} + +void readPreproTimeSeries(std::vector& linkList, fs::path toLinksDir) +{ + for (auto& link: linkList) + { + std::string sourceAreaName = link.namesPair.first; + fs::path sourceAreaDir = toLinksDir / sourceAreaName; + if (!readLinkPreproTimeSeries(link, sourceAreaDir)) + { + logs.warning() << "Could not load all prepro/modulation data for link '" + << link.namesPair.first << "." << link.namesPair.second << "'"; + } + } +} + +// ================== +// Class methods +// ================== +LinksTSgenerator::LinksTSgenerator(Settings& settings): + linksFromCmdLineOptions_(settings.linksListToGen), + studyFolder_(settings.studyFolder), + generateTSforAllLinks_(settings.allLinks) +{ +} + +void LinksTSgenerator::extractData() +{ + auto allLinksPairs = extractLinkNamesFromStudy(); + + LinkPairs namesLinksToGenerate; + if (generateTSforAllLinks_) + { + namesLinksToGenerate = allLinksPairs; + } + else + { + namesLinksToGenerate = extractLinkNamesFromCmdLine(allLinksPairs); + } + + linkList_ = CreateLinkList(namesLinksToGenerate); + extractLinksSpecificTSparameters(); + + generalParams_ = readGeneralParamsForLinksTS(); +} + +LinkPairs LinksTSgenerator::extractLinkNamesFromStudy() +{ + LinkPairs to_return; + fs::path linksDir = studyFolder_ / "input" / "links"; + for (const auto& item: fs::directory_iterator{linksDir}) + { + if (item.is_directory()) + { + std::string sourceAreaName = item.path().filename().generic_string(); + auto targetAreas = extractTargetAreas(item); + for (auto& targetAreaName: targetAreas) + { + auto linkPair = std::make_pair(sourceAreaName, targetAreaName); + to_return.push_back(linkPair); + } + } + } + return to_return; +} + +LinkPairs LinksTSgenerator::extractLinkNamesFromCmdLine(const LinkPairs& allLinks) +{ + LinkPairs to_return; + LinkPairs pairsFromCmdLine = splitStringIntoPairs(linksFromCmdLineOptions_, ';', '.'); + for (auto& p: pairsFromCmdLine) + { + if (const auto* found_pair = getMatchingPairInCollection(p, allLinks); found_pair) + { + to_return.push_back(*found_pair); + } + else + { + logs.error() << "Link '" << p.first << "." << p.second << "' not found"; + } + } + return to_return; +} + +StudyParamsForLinkTS LinksTSgenerator::readGeneralParamsForLinksTS() +{ + StudyParamsForLinkTS to_return; + fs::path pathToGeneraldata = studyFolder_ / "settings" / "generaldata.ini"; + IniFile ini; + ini.open(pathToGeneraldata); // gp : we should handle reading issues + for (auto* section = ini.firstSection; section; section = section->next) + { + // Skipping sections useless in the current context + Yuni::String sectionName = section->name; + if (sectionName != "general" && sectionName != "seeds - Mersenne Twister") + { + continue; + } + + for (const IniFile::Property* p = section->firstProperty; p; p = p->next) + { + if (!readLinkGeneralProperty(to_return, p->key, p->value)) + { + logs.warning() << ini.filename() << ": reading value of '" << p->key + << "' went wrong"; + } + } + } + return to_return; +} + +void LinksTSgenerator::extractLinksSpecificTSparameters() +{ + fs::path toLinksDir = studyFolder_ / "input" / "links"; + readIniProperties(linkList_, toLinksDir); + readPreproTimeSeries(linkList_, toLinksDir); +} + +bool LinksTSgenerator::generate() +{ + auto saveTSpath = fs::path(studyFolder_) / "output" / FormattedTime("%Y%m%d-%H%M"); + saveTSpath /= "ts-generator"; + saveTSpath /= "links"; + + return generateLinkTimeSeries(linkList_, generalParams_, saveTSpath); +} + +} // namespace Antares::TSGenerator diff --git a/src/tools/ts-generator/main.cpp b/src/tools/ts-generator/main.cpp index f59a5dc614..3c883a078b 100644 --- a/src/tools/ts-generator/main.cpp +++ b/src/tools/ts-generator/main.cpp @@ -22,56 +22,25 @@ #include #include -#include - -#include -#include -#include #include #include -#include #include #include -#include -#include +#include "antares/tools/ts-generator/linksTSgenerator.h" +#include "antares/tools/ts-generator/tsGenerationOptions.h" +using namespace Antares::TSGenerator; -struct Settings -{ - std::string studyFolder; +using namespace Antares::TSGenerator; - /// generate TS for all clusters if activated - bool allThermal = false; - /// generate TS for a list "area.cluster;area2.cluster2;" - std::string thermalListToGen = ""; -}; - -std::unique_ptr createTsGeneratorParser(Settings& settings) -{ - auto parser = std::make_unique(); - parser->addParagraph("Antares Time Series generator\n"); - - parser->addFlag(settings.allThermal, - ' ', - "all-thermal", - "Generate TS for all thermal clusters"); - parser->addFlag(settings.thermalListToGen, - ' ', - "thermal", - "Generate TS for a list of area IDs and thermal clusters IDs, " - "usage:\n\t--thermal=\"areaID.clusterID;area2ID.clusterID\""); - - parser->remainingArguments(settings.studyFolder); - - return parser; -} +namespace fs = std::filesystem; std::vector getClustersToGen(Data::AreaList& areas, const std::string& clustersToGen) { std::vector clusters; - const auto ids = splitStringIntoPairs(clustersToGen, ';', '.'); + const auto pairsAreaCluster = splitStringIntoPairs(clustersToGen, ';', '.'); - for (const auto& [areaID, clusterID]: ids) + for (const auto& [areaID, clusterID]: pairsAreaCluster) { logs.info() << "Searching for area: " << areaID << " and cluster: " << clusterID; @@ -95,82 +64,63 @@ std::vector getClustersToGen(Data::AreaList& areas, return clusters; } -int main(int argc, char* argv[]) +int main(int argc, const char* argv[]) { - Settings settings; - - auto parser = createTsGeneratorParser(settings); - switch (auto ret = parser->operator()(argc, argv); ret) - { - using namespace Yuni::GetOpt; - case ReturnCode::error: - logs.error() << "Unknown arguments, aborting"; - return parser->errors(); - case ReturnCode::help: - // End the program - return 0; - default: - break; - } + logs.applicationName("ts-generator"); - if (settings.allThermal && !settings.thermalListToGen.empty()) + Settings settings; + if (!parseOptions(argc, argv, settings)) { - logs.error() << "Conflicting options, either choose all thermal clusters or a list"; return 1; } - auto study = std::make_shared(true); - Data::StudyLoadOptions studyOptions; - studyOptions.prepareOutput = true; - - if (!study->loadFromFolder(settings.studyFolder, studyOptions)) + if (!checkOptions(settings)) { - logs.error() << "Invalid study given to the generator"; return 1; } - study->initializeRuntimeInfos(); - // Force the writing of generated TS into output/YYYYMMDD-HHSSeco/ts-generator/thermal[/mc-0] - study->parameters.timeSeriesToArchive |= Antares::Data::timeSeriesThermal; + bool return_code{true}; - try + if (thermalTSrequired(settings)) { - Antares::Check::checkMinStablePower(true, study->areas); - } - catch (Error::InvalidParametersForThermalClusters& ex) - { - Antares::logs.error() << ex.what(); - } - - Benchmarking::DurationCollector durationCollector; - - auto resultWriter = Solver::resultWriterFactory(Data::ResultFormat::legacyFilesDirectories, - study->folderOutput, - nullptr, - durationCollector); + // === Data for TS generation === + auto study = std::make_shared(true); + Data::StudyLoadOptions studyOptions; + if (!study->loadFromFolder(settings.studyFolder, studyOptions)) + { + logs.error() << "Invalid study given to the generator"; + return 1; + } - const auto thermalSavePath = std::filesystem::path("ts-generator") / "thermal"; + std::vector clusters; + if (settings.allThermal) + { + clusters = getAllClustersToGen(study->areas, true); + } + else if (!settings.thermalListToGen.empty()) + { + clusters = getClustersToGen(study->areas, settings.thermalListToGen); + } - // THERMAL - std::vector clusters; - if (settings.allThermal) - { - clusters = TSGenerator::getAllClustersToGen(study->areas, true); - } - else if (!settings.thermalListToGen.empty()) - { - clusters = getClustersToGen(study->areas, settings.thermalListToGen); + // === TS generation === + MersenneTwister thermalRandom; + thermalRandom.reset(study->parameters.seed[Data::seedTsGenThermal]); + return_code = TSGenerator::generateThermalTimeSeries(*study, clusters, thermalRandom); + + // === Writing generated TS on disk === + auto thermalSavePath = fs::path(settings.studyFolder) / "output" + / FormattedTime("%Y%m%d-%H%M"); + thermalSavePath /= "ts-generator"; + thermalSavePath /= "thermal"; + writeThermalTimeSeries(clusters, thermalSavePath); } - for (auto& c: clusters) + if (linkTSrequired(settings)) { - logs.debug() << c->id(); + LinksTSgenerator linksTSgenerator(settings); + linksTSgenerator.extractData(); + return_code = linksTSgenerator.generate() && return_code; } - bool ret = TSGenerator::generateThermalTimeSeries(*study, - clusters, - *resultWriter, - thermalSavePath.string()); - - return !ret; // return 0 for success + return !return_code; // return 0 for success } diff --git a/src/tools/ts-generator/tsGenerationOptions.cpp b/src/tools/ts-generator/tsGenerationOptions.cpp new file mode 100644 index 0000000000..468e3c941a --- /dev/null +++ b/src/tools/ts-generator/tsGenerationOptions.cpp @@ -0,0 +1,77 @@ +#include "antares/tools/ts-generator/tsGenerationOptions.h" + +#include + +namespace Antares::TSGenerator +{ + +std::unique_ptr createTsGeneratorParser(Settings& settings) +{ + auto parser = std::make_unique(); + parser->addParagraph("Antares Time Series generator\n"); + + parser->addFlag(settings.allThermal, + ' ', + "all-thermal", + "Generate TS for all thermal clusters"); + parser->addFlag(settings.thermalListToGen, + ' ', + "thermal", + "Generate TS for a list of area IDs and thermal clusters IDs, " + "\nusage: --thermal=\"areaID.clusterID;area2ID.clusterID\""); + + parser->addFlag(settings.allLinks, ' ', "all-links", "Generate TS capacities for all links"); + parser->addFlag(settings.linksListToGen, + ' ', + "links", + "Generate TS capacities for a list of 2 area IDs, " + "usage: --links=\"areaID.area2ID;area3ID.area1ID\""); + + parser->remainingArguments(settings.studyFolder); + + return parser; +} + +bool parseOptions(int argc, const char* argv[], Settings& options) +{ + auto parser = createTsGeneratorParser(options); + switch (auto ret = parser->operator()(argc, argv); ret) + { + using namespace Yuni::GetOpt; + case ReturnCode::error: + logs.error() << "Unknown arguments, aborting"; + return false; + case ReturnCode::help: + return false; + default: + break; + } + return true; +} + +bool checkOptions(Settings& options) +{ + if (options.allThermal && !options.thermalListToGen.empty()) + { + logs.error() << "Conflicting options, either choose all thermal clusters or a list"; + return false; + } + + if (options.allLinks && !options.linksListToGen.empty()) + { + logs.error() << "Conflicting options, either choose all links or a list"; + return false; + } + return true; +} + +bool linkTSrequired(Settings& options) +{ + return options.allLinks || !options.linksListToGen.empty(); +} + +bool thermalTSrequired(Settings& options) +{ + return options.allThermal || !options.thermalListToGen.empty(); +} +} // namespace Antares::TSGenerator diff --git a/src/tools/updater/main.cpp b/src/tools/updater/main.cpp index e1cc84944d..c32007cce3 100644 --- a/src/tools/updater/main.cpp +++ b/src/tools/updater/main.cpp @@ -166,7 +166,7 @@ std::string getMargin(int size) return margin; } -int main(int argc, char* argv[]) +int main(int argc, const char* argv[]) { // locale InitializeDefaultLocale(); diff --git a/src/tools/vacuum/main.cpp b/src/tools/vacuum/main.cpp index 8f78afd038..a89ac2532c 100644 --- a/src/tools/vacuum/main.cpp +++ b/src/tools/vacuum/main.cpp @@ -240,7 +240,7 @@ class DirectoryCleanerJob: public Job::IJob } // anonymous namespace -int main(int argc, char** argv) +int main(int argc, const char** argv) { // locale InitializeDefaultLocale(); diff --git a/src/tools/yby-aggregator/main.cpp b/src/tools/yby-aggregator/main.cpp index 31dd7c0cc3..3aa10b8788 100644 --- a/src/tools/yby-aggregator/main.cpp +++ b/src/tools/yby-aggregator/main.cpp @@ -295,7 +295,7 @@ static void PrepareTheWork(const String::Vector& outputs, Progress::Total = nbJobs; } -static void ReadCommandLineOptions(int argc, char** argv) +static void ReadCommandLineOptions(int argc, const char** argv) { String::Vector optOutputs; uint optJobs = FindNbProcessors(); @@ -642,7 +642,7 @@ static bool WriteAggregates() return true; } -int main(int argc, char* argv[]) +int main(int argc, const char* argv[]) { // locale InitializeDefaultLocale(); diff --git a/src/tools/yby-aggregator/result.cpp b/src/tools/yby-aggregator/result.cpp index d92dd1c246..fa0fea177a 100644 --- a/src/tools/yby-aggregator/result.cpp +++ b/src/tools/yby-aggregator/result.cpp @@ -61,7 +61,7 @@ ResultMatrix::ResultMatrix(): } ResultMatrix::ResultMatrix(const ResultMatrix&): - columns(NULL), + columns(nullptr), width(0), heightAfterAggregation(0) { diff --git a/src/triplets/x64-linux-antares.cmake b/src/triplets/x64-linux-antares.cmake new file mode 100644 index 0000000000..63954c80c5 --- /dev/null +++ b/src/triplets/x64-linux-antares.cmake @@ -0,0 +1,5 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CMAKE_SYSTEM_NAME Linux) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) + diff --git a/src/triplets/x64-linux-release.cmake b/src/triplets/x64-linux-release.cmake new file mode 100644 index 0000000000..d9eb98ddae --- /dev/null +++ b/src/triplets/x64-linux-release.cmake @@ -0,0 +1,7 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CMAKE_SYSTEM_NAME Linux) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE static) + +# Avoid building debug artifacts +set(VCPKG_BUILD_TYPE release) diff --git a/src/triplets/x64-windows-antares.cmake b/src/triplets/x64-windows-antares.cmake new file mode 100644 index 0000000000..f2480f7012 --- /dev/null +++ b/src/triplets/x64-windows-antares.cmake @@ -0,0 +1,11 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE dynamic) + +# Link zlib and minizip statically +list(APPEND STATIC_PORTS "zlib.*" "minizip.*") +foreach (STATIC_PORT IN LISTS STATIC_PORTS) + if(PORT MATCHES ${STATIC_PORT}) + set(VCPKG_LIBRARY_LINKAGE static) + endif() +endforeach () diff --git a/src/triplets/x64-windows-release.cmake b/src/triplets/x64-windows-release.cmake new file mode 100644 index 0000000000..7e4eb27f4d --- /dev/null +++ b/src/triplets/x64-windows-release.cmake @@ -0,0 +1,15 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) + +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE dynamic) + +# Avoid building debug artifacts +set(VCPKG_BUILD_TYPE release) + +# Link zlib and minizip statically +list(APPEND STATIC_PORTS "zlib.*" "minizip.*") +foreach (STATIC_PORT IN LISTS STATIC_PORTS) + if(PORT MATCHES ${STATIC_PORT}) + set(VCPKG_LIBRARY_LINKAGE static) + endif() +endforeach () diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 0c8f846f96..8bb000564a 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -1,9 +1,4 @@ - -if (USE_PRECOMPILED_EXT AND UNIX) - set (wxWidgets_CONFIG_EXECUTABLE ${DEPS_INSTALL_DIR}/bin/wx-config) -endif() - #wxWidget required find_package(wxWidgets REQUIRED COMPONENTS net core base richtext propgrid aui adv html xml) include(${wxWidgets_USE_FILE}) diff --git a/src/ui/action/handler/antares-study/area/create.cpp b/src/ui/action/handler/antares-study/area/create.cpp index cc671fec5d..4b9bd41a68 100644 --- a/src/ui/action/handler/antares-study/area/create.cpp +++ b/src/ui/action/handler/antares-study/area/create.cpp @@ -221,7 +221,7 @@ bool Create::performWL(Context& ctx) } } ctx.autoselectAreas.push_back(ctx.area); - return (ctx.area != NULL); + return (ctx.area); } void Create::createActionsForAStandardAreaCopy(Context& ctx, bool copyPosition) diff --git a/src/ui/action/handler/antares-study/constraint/create.cpp b/src/ui/action/handler/antares-study/constraint/create.cpp index 11425b2d51..fe223495e1 100644 --- a/src/ui/action/handler/antares-study/constraint/create.cpp +++ b/src/ui/action/handler/antares-study/constraint/create.cpp @@ -200,7 +200,7 @@ bool Create::performWL(Context& ctx) // ctx.constraint->type(pType); } ctx.autoselectConstraints.push_back(ctx.constraint); - return (ctx.constraint != NULL); + return (ctx.constraint != nullptr); } void Create::createActionsForAStandardConstraintCopy(Context&) diff --git a/src/ui/action/handler/antares-study/constraint/offsets.cpp b/src/ui/action/handler/antares-study/constraint/offsets.cpp index 5ecd0eb35e..8bf90571ec 100644 --- a/src/ui/action/handler/antares-study/constraint/offsets.cpp +++ b/src/ui/action/handler/antares-study/constraint/offsets.cpp @@ -33,7 +33,7 @@ namespace AntaresStudy namespace Constraint { Offsets::Offsets(const AnyString& name, Antares::Data::ConstraintName targetName) : - pOriginalConstraintName(name), targetName(targetName), pCurrentContext(NULL) + pOriginalConstraintName(name), targetName(targetName), pCurrentContext(nullptr) { pInfos.caption << "Offsets"; } diff --git a/src/ui/action/handler/antares-study/constraint/weights.cpp b/src/ui/action/handler/antares-study/constraint/weights.cpp index 865a57ec62..ad9691ace5 100644 --- a/src/ui/action/handler/antares-study/constraint/weights.cpp +++ b/src/ui/action/handler/antares-study/constraint/weights.cpp @@ -33,7 +33,7 @@ namespace AntaresStudy namespace Constraint { Weights::Weights(const AnyString& name, Antares::Data::ConstraintName targetName) : - pOriginalConstraintName(name), targetName(targetName), pCurrentContext(NULL) + pOriginalConstraintName(name), targetName(targetName), pCurrentContext(nullptr) { pInfos.caption << "Weights"; } diff --git a/src/ui/action/handler/antares-study/thermal-cluster/create.cpp b/src/ui/action/handler/antares-study/thermal-cluster/create.cpp index 495d434d5f..6a71b98626 100644 --- a/src/ui/action/handler/antares-study/thermal-cluster/create.cpp +++ b/src/ui/action/handler/antares-study/thermal-cluster/create.cpp @@ -182,7 +182,7 @@ bool Create::performWL(Context& ctx) if (pInfos.behavior == bhOverwrite) (ctx.cluster)->reset(); } - return (ctx.area != NULL); + return (ctx.area != nullptr); } return true; } diff --git a/src/ui/common/component/panel/panel.cpp b/src/ui/common/component/panel/panel.cpp index c2c20c5cf0..03ff527c59 100644 --- a/src/ui/common/component/panel/panel.cpp +++ b/src/ui/common/component/panel/panel.cpp @@ -40,9 +40,9 @@ Panel::Panel(wxWindow* parent) : { assert(parent && "invalid parent"); - Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(Panel::onInternalMotion), NULL, this); - Connect(GetId(), wxEVT_LEFT_DOWN, wxMouseEventHandler(Panel::onInternalMouseDown), NULL, this); - Connect(GetId(), wxEVT_LEFT_UP, wxMouseEventHandler(Panel::onInternalMouseUp), NULL, this); + Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(Panel::onInternalMotion), nullptr, this); + Connect(GetId(), wxEVT_LEFT_DOWN, wxMouseEventHandler(Panel::onInternalMouseDown), nullptr, this); + Connect(GetId(), wxEVT_LEFT_UP, wxMouseEventHandler(Panel::onInternalMouseUp), nullptr, this); } Panel::~Panel() diff --git a/src/ui/common/component/spotlight/spotlight.cpp b/src/ui/common/component/spotlight/spotlight.cpp index 661670dfac..09e381034e 100644 --- a/src/ui/common/component/spotlight/spotlight.cpp +++ b/src/ui/common/component/spotlight/spotlight.cpp @@ -122,7 +122,7 @@ void Spotlight::createComponents(Spotlight* parent, bool input, bool results) wxDefaultPosition, wxDefaultSize, 0, - NULL, + nullptr, wxCB_READONLY); pLayerFilter->SetFont(wxFont(wxFontInfo().Bold())); pLayerFilter->AppendString("All"); @@ -429,9 +429,9 @@ void Spotlight::resizeParentWindow() parent->SetSize(parent->GetSize().GetWidth(), idealH); } - assert(parent->GetSizer() != NULL); + assert(parent->GetSizer()); parent->GetSizer()->Layout(); - assert(GetSizer() != NULL); + assert(GetSizer()); GetSizer()->Layout(); Dispatcher::GUI::Refresh(parent); } diff --git a/src/ui/simulator/application/application.cpp b/src/ui/simulator/application/application.cpp index e05505fc49..932a5dc3b5 100644 --- a/src/ui/simulator/application/application.cpp +++ b/src/ui/simulator/application/application.cpp @@ -246,7 +246,7 @@ bool Application::OnInit() { String s; wxStringToString(wxString(argv[0]), s); - char* c_argv[] = {s.data(), nullptr}; + const char* c_argv[] = {s.data(), nullptr}; // Load the local policy settings LocalPolicy::Open(); diff --git a/src/ui/simulator/application/main/build/economic-optimization.cpp b/src/ui/simulator/application/main/build/economic-optimization.cpp index 7c1ddb66c3..f11c7865e2 100644 --- a/src/ui/simulator/application/main/build/economic-optimization.cpp +++ b/src/ui/simulator/application/main/build/economic-optimization.cpp @@ -34,7 +34,7 @@ namespace Forms { void ApplWnd::createNBNodalOptimization() { - assert(NULL != pNotebook); + assert(pNotebook); // Create a standard page with an input selector std::pair page diff --git a/src/ui/simulator/application/main/build/load.cpp b/src/ui/simulator/application/main/build/load.cpp index 98cdfb69e8..917279955b 100644 --- a/src/ui/simulator/application/main/build/load.cpp +++ b/src/ui/simulator/application/main/build/load.cpp @@ -35,7 +35,7 @@ namespace Forms { void ApplWnd::createNBLoad() { - assert(NULL != pNotebook); + assert(pNotebook); // Create a standard page with an input selector std::pair page diff --git a/src/ui/simulator/application/main/build/notes.cpp b/src/ui/simulator/application/main/build/notes.cpp index 9e9f6fb585..fcca4f545b 100644 --- a/src/ui/simulator/application/main/build/notes.cpp +++ b/src/ui/simulator/application/main/build/notes.cpp @@ -30,7 +30,7 @@ namespace Forms { void ApplWnd::createNBNotes() { - assert(NULL != pNotebook); + assert(pNotebook); pUserNotes = new Window::Notes(pNotebook); pNotebook->add(pUserNotes, wxT("notes"), wxT("User's Notes")); diff --git a/src/ui/simulator/application/main/build/scenario-builder.cpp b/src/ui/simulator/application/main/build/scenario-builder.cpp index 5d46aaf6c0..350c1633f7 100644 --- a/src/ui/simulator/application/main/build/scenario-builder.cpp +++ b/src/ui/simulator/application/main/build/scenario-builder.cpp @@ -35,6 +35,7 @@ #include "toolbox/components/datagrid/renderer/scenario-builder-wind-renderer.h" #include "toolbox/components/datagrid/renderer/scenario-builder-solar-renderer.h" #include "toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.h" +#include "toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h" #include "toolbox/components/datagrid/renderer/scenario-builder-ntc-renderer.h" using namespace Yuni; @@ -199,8 +200,8 @@ class solarScBuilderPageMaker final : public simpleScBuilderPageMaker } }; -// Hydro levels ... -class hydroLevelsScBuilderPageMaker final : public simpleScBuilderPageMaker +// Hydro Initial levels ... +class hydroInitialLevelsScBuilderPageMaker final : public simpleScBuilderPageMaker { using simpleScBuilderPageMaker::simpleScBuilderPageMaker; @@ -210,7 +211,22 @@ class hydroLevelsScBuilderPageMaker final : public simpleScBuilderPageMaker } Notebook::Page* addPageToNotebook() override { - return notebook()->add(grid(), wxT("hydro levels"), wxT("Hydro Levels")); + return notebook()->add(grid(), wxT("hydro initial levels"), wxT("Hydro Initial Levels")); + } +}; + +// Hydro Final levels ... +class hydroFinalLevelsScBuilderPageMaker final : public simpleScBuilderPageMaker +{ + using simpleScBuilderPageMaker::simpleScBuilderPageMaker; + + Renderer::ScBuilderRendererBase* getRenderer() override + { + return new_check_allocation(); + } + Notebook::Page* addPageToNotebook() override + { + return notebook()->add(grid(), wxT("hydro final levels"), wxT("Hydro Final Levels")); } }; @@ -366,9 +382,13 @@ void ApplWnd::createNBScenarioBuilder() pScenarioBuilderNotebook->addSeparator(); - hydroLevelsScBuilderPageMaker hydroLevelsSBpageMaker(scenarioBuilderPanel, + hydroInitialLevelsScBuilderPageMaker hydroInitialLevelsSBpageMaker(scenarioBuilderPanel, + pScenarioBuilderNotebook); + pageScBuilderHydroInitialLevels = hydroInitialLevelsSBpageMaker.createPage(); + + hydroFinalLevelsScBuilderPageMaker hydroFinalLevelsSBpageMaker(scenarioBuilderPanel, pScenarioBuilderNotebook); - pageScBuilderHydroLevels = hydroLevelsSBpageMaker.createPage(); + pageScBuilderHydroFinalLevels = hydroFinalLevelsSBpageMaker.createPage(); } void ApplWnd::createNBOutputViewer() diff --git a/src/ui/simulator/application/main/build/sets.cpp b/src/ui/simulator/application/main/build/sets.cpp index bbd139fba1..c6119f3d93 100644 --- a/src/ui/simulator/application/main/build/sets.cpp +++ b/src/ui/simulator/application/main/build/sets.cpp @@ -30,7 +30,7 @@ namespace Forms { void ApplWnd::createNBSets() { - assert(NULL != pNotebook); + assert(pNotebook); pSets = new Window::Sets(pNotebook); pNotebook->add(pSets, wxT("sets"), wxT("")); diff --git a/src/ui/simulator/application/main/build/solar.cpp b/src/ui/simulator/application/main/build/solar.cpp index a2d6d25657..6c9f29cea1 100644 --- a/src/ui/simulator/application/main/build/solar.cpp +++ b/src/ui/simulator/application/main/build/solar.cpp @@ -35,7 +35,7 @@ namespace Forms { void ApplWnd::createNBSolar() { - assert(NULL != pNotebook); + assert(pNotebook); // Create a standard page with an input selector std::pair page diff --git a/src/ui/simulator/application/main/build/wind.cpp b/src/ui/simulator/application/main/build/wind.cpp index c4f28409b6..73dce91d73 100644 --- a/src/ui/simulator/application/main/build/wind.cpp +++ b/src/ui/simulator/application/main/build/wind.cpp @@ -35,7 +35,7 @@ namespace Forms { void ApplWnd::createNBWind() { - assert(NULL != pNotebook); + assert(pNotebook); // Create a standard page with an input selector std::pair page diff --git a/src/ui/simulator/application/main/internal-data.cpp b/src/ui/simulator/application/main/internal-data.cpp index 36468656c6..07a9788001 100644 --- a/src/ui/simulator/application/main/internal-data.cpp +++ b/src/ui/simulator/application/main/internal-data.cpp @@ -32,7 +32,7 @@ MainFormData::MainFormData(ApplWnd& form) : wipEnabled(false), wipPanel(nullptr) void MainFormData::editCurrentLocation(const wxString& string) { - assert(pEditCurrentLocation != NULL); + assert(pEditCurrentLocation); pEditCurrentLocation->SetItemLabel(wxString(wxT("Current tab : ")) << string); } diff --git a/src/ui/simulator/application/main/logs.cpp b/src/ui/simulator/application/main/logs.cpp index 9be770b174..c2e47bd0a4 100644 --- a/src/ui/simulator/application/main/logs.cpp +++ b/src/ui/simulator/application/main/logs.cpp @@ -172,7 +172,7 @@ void ApplWnd::destroyLogs() if (pLogFlusherTimer) { wxTimer* timer = pLogFlusherTimer; - pLogFlusherTimer = NULL; + pLogFlusherTimer = nullptr; delete timer; } } @@ -196,7 +196,7 @@ void ApplWnd::destroyLogsViewer() if (pWndLogs) { pWndLogs->Destroy(); - pWndLogs = NULL; + pWndLogs = nullptr; } } diff --git a/src/ui/simulator/application/main/main.cpp b/src/ui/simulator/application/main/main.cpp index 3b321e6c12..31865edc53 100644 --- a/src/ui/simulator/application/main/main.cpp +++ b/src/ui/simulator/application/main/main.cpp @@ -702,7 +702,7 @@ void ApplWnd::onSectionNotebookPageChanging(Component::Notebook::Page& page) auto* job = new JobLoadScenarioBuilder(*study); wxTheApp->Yield(); job->run(); - study->scenarioRules = job->scenarioBuilder(); + study->scenarioRules.reset(job->scenarioBuilder()); job->Destroy(); } diff --git a/src/ui/simulator/application/main/main.h b/src/ui/simulator/application/main/main.h index aa16c92f33..0b1f9dd8bb 100644 --- a/src/ui/simulator/application/main/main.h +++ b/src/ui/simulator/application/main/main.h @@ -693,7 +693,8 @@ class ApplWnd final : public Component::Frame::WxLocalFrame, public Yuni::IEvent Component::Notebook::Page* pageScBuilderSolar; Component::Notebook::Page* pageScBuilderNTC; Component::Notebook::Page* pageScBuilderRenewable; - Component::Notebook::Page* pageScBuilderHydroLevels; + Component::Notebook::Page* pageScBuilderHydroInitialLevels; + Component::Notebook::Page* pageScBuilderHydroFinalLevels; //! A context menu for the map wxMenu* pMapContextMenu; diff --git a/src/ui/simulator/application/main/notes.cpp b/src/ui/simulator/application/main/notes.cpp index 4c0cbb62d5..60e2c17c08 100644 --- a/src/ui/simulator/application/main/notes.cpp +++ b/src/ui/simulator/application/main/notes.cpp @@ -31,25 +31,25 @@ namespace Forms { void ApplWnd::loadUserNotes() { - assert(NULL != pUserNotes); + assert(pUserNotes); pUserNotes->loadFromStudy(); } void ApplWnd::saveUserNotes() { - assert(NULL != pUserNotes); + assert(pUserNotes); pUserNotes->saveToStudy(); } void ApplWnd::loadSets() { - assert(NULL != pSets); + assert(pSets); pSets->loadFromStudy(); } void ApplWnd::saveSets() { - assert(NULL != pSets); + assert(pSets); pSets->saveToStudy(); } diff --git a/src/ui/simulator/application/main/options.cpp b/src/ui/simulator/application/main/options.cpp index eb8389a229..3b8fc01098 100644 --- a/src/ui/simulator/application/main/options.cpp +++ b/src/ui/simulator/application/main/options.cpp @@ -73,7 +73,7 @@ void ApplWnd::evtOnOptionsDistricts(wxCommandEvent&) Forms::Disabler disabler(*this); if (CurrentStudyIsValid()) { - assert(NULL != pNotebook); + assert(pNotebook); pNotebook->select("sets"); } } diff --git a/src/ui/simulator/application/main/refresh.cpp b/src/ui/simulator/application/main/refresh.cpp index 587c38bdbc..88c36a57cb 100644 --- a/src/ui/simulator/application/main/refresh.cpp +++ b/src/ui/simulator/application/main/refresh.cpp @@ -315,7 +315,7 @@ void ApplWnd::refreshMenuOutput() it->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(Forms::ApplWnd::evtOnOpenOutputInExplorer), - NULL, + nullptr, parentForm); } } diff --git a/src/ui/simulator/cmake/components.cmake b/src/ui/simulator/cmake/components.cmake index ad9dfba7a7..0586928a48 100644 --- a/src/ui/simulator/cmake/components.cmake +++ b/src/ui/simulator/cmake/components.cmake @@ -92,6 +92,8 @@ SET(SRC_TOOLBOX_COM_DBGRID_RENDERERS toolbox/components/datagrid/renderer/scenario-builder-solar-renderer.h toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.h toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.cpp + toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h + toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.cpp toolbox/components/datagrid/renderer/scenario-builder-ntc-renderer.h toolbox/components/datagrid/renderer/scenario-builder-ntc-renderer.cpp toolbox/components/datagrid/renderer/layers.cpp diff --git a/src/ui/simulator/main.cpp b/src/ui/simulator/main.cpp index 7fc62536dc..1a88811fee 100644 --- a/src/ui/simulator/main.cpp +++ b/src/ui/simulator/main.cpp @@ -1,33 +1,36 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ -#include -#include "application/application.h" #include "application/main.h" + +#include #include + #include +#include +#include #include #include -#include -#include + +#include "application/application.h" #ifdef YUNI_OS_MSVC // WxWidgets Stuff @@ -42,10 +45,12 @@ IMPLEMENT_APP_NO_MAIN(Antares::Application) using namespace Yuni; using namespace Antares; -int main(int argc, char* argv[]) +int main(int argc, const char* argv[]) { if (not memory.initializeTemporaryFolder()) + { return EXIT_FAILURE; + } // We have one or several arguments IntoUTF8ArgsTranslator toUTF8ArgsTranslator(argc, argv); @@ -94,7 +99,7 @@ int main(int argc, char* argv[]) Resources::Initialize(argc, argv, true); // Running the GUI - const int ret = wxEntry(argc, argv); + const int ret = wxEntry(argc, const_cast(argv)); LocalPolicy::Close(); return ret; diff --git a/src/ui/simulator/toolbox/components/button/button.cpp b/src/ui/simulator/toolbox/components/button/button.cpp index 3bdab39981..9fbb2b9118 100644 --- a/src/ui/simulator/toolbox/components/button/button.cpp +++ b/src/ui/simulator/toolbox/components/button/button.cpp @@ -158,7 +158,7 @@ void Button::loadIconFromResource(const char* filename) void Button::precalculateCoordinates() { // Assert - assert(this != NULL && "Button: this must not be null"); + assert(this != nullptr && "Button: this must not be null"); assert(iconMargin <= 128 && "Button: The margin seems suspicious"); if (pCaption.empty()) diff --git a/src/ui/simulator/toolbox/components/datagrid/component.cpp b/src/ui/simulator/toolbox/components/datagrid/component.cpp index e33bb0ea63..75f3196901 100644 --- a/src/ui/simulator/toolbox/components/datagrid/component.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/component.cpp @@ -517,7 +517,7 @@ void InternalState::createAllInternalControls(const CreateOptions& flags) wxDefaultPosition, wxSize(-1, 22), 0, - NULL, + nullptr, wxCB_READONLY); pLayerFilter->SetFont(wxFont(wxFontInfo().Bold())); pLayerFilter->AppendString("All"); diff --git a/src/ui/simulator/toolbox/components/datagrid/filter/operator.cpp b/src/ui/simulator/toolbox/components/datagrid/filter/operator.cpp index d54c277824..ef4d2e1997 100644 --- a/src/ui/simulator/toolbox/components/datagrid/filter/operator.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/filter/operator.cpp @@ -30,7 +30,7 @@ namespace Filter namespace Operator { AOperator::AOperator(AFilterBase* parent, const wxChar* name, const wxChar* caption) : - pParentFilter(parent), pName(name), pCaption(caption), pSizer(NULL) + pParentFilter(parent), pName(name), pCaption(caption), pSizer(nullptr) { parameters.push_back(Parameter(*this).presetInt()); } diff --git a/src/ui/simulator/toolbox/components/datagrid/filter/parameter/parameter.cpp b/src/ui/simulator/toolbox/components/datagrid/filter/parameter/parameter.cpp index 0235fd86fe..1e6711a8ee 100644 --- a/src/ui/simulator/toolbox/components/datagrid/filter/parameter/parameter.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/filter/parameter/parameter.cpp @@ -38,7 +38,7 @@ namespace Filter namespace Operator { Parameter::Parameter(AOperator& parent) : - pOperator(parent), dataType(DataType::dtNone), pSizer(NULL) + pOperator(parent), dataType(DataType::dtNone), pSizer(nullptr) { } @@ -50,7 +50,7 @@ Parameter::Parameter(const Parameter& copy) : dataType(copy.dataType), defaultValues(copy.defaultValues), value(copy.value), - pSizer(NULL) + pSizer(nullptr) { } @@ -70,7 +70,7 @@ Parameter& Parameter::operator=(const Parameter& copy) wxSizer* Parameter::sizer(wxWindow* parent) { - if (NULL == pSizer) + if (nullptr == pSizer) { pSizer = new wxBoxSizer(wxHORIZONTAL); @@ -95,7 +95,7 @@ wxSizer* Parameter::sizer(wxWindow* parent) ch->Connect(ch->GetId(), wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler(Parameter::onListChanged), - NULL, + nullptr, this); break; } @@ -125,7 +125,7 @@ wxSizer* Parameter::sizer(wxWindow* parent) edit->Connect(edit->GetId(), wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(Parameter::onChange), - NULL, + nullptr, this); } } diff --git a/src/ui/simulator/toolbox/components/datagrid/filter/static.cpp b/src/ui/simulator/toolbox/components/datagrid/filter/static.cpp index b7d29a319e..b5f055a1ca 100644 --- a/src/ui/simulator/toolbox/components/datagrid/filter/static.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/filter/static.cpp @@ -63,7 +63,7 @@ struct ResultNewInstance using Type = AFilterBase*; static AFilterBase* Default() { - return NULL; + return nullptr; } static T* Value(Input* parent) { diff --git a/src/ui/simulator/toolbox/components/datagrid/gridhelper.cpp b/src/ui/simulator/toolbox/components/datagrid/gridhelper.cpp index 62435e993b..9b6d962f95 100644 --- a/src/ui/simulator/toolbox/components/datagrid/gridhelper.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/gridhelper.cpp @@ -271,7 +271,7 @@ class GridCellAttrProvider final : public wxGridCellAttrProvider attr = pStyles[(uint)style]; } - assert(attr != NULL and "Invalid cell attribute"); + assert(attr &&"Invalid cell attribute"); attr->IncRef(); return attr; } diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/area/dsm.cpp b/src/ui/simulator/toolbox/components/datagrid/renderer/area/dsm.cpp index e249c43e93..8f7835a381 100644 --- a/src/ui/simulator/toolbox/components/datagrid/renderer/area/dsm.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/area/dsm.cpp @@ -58,7 +58,7 @@ wxString DSM::columnCaption(int colIndx) const void DSM::internalAreaChanged(Antares::Data::Area* area) { - this->matrix((area) ? &(area->reserves) : NULL); + this->matrix((area) ? &(area->reserves) : nullptr); Renderer::ARendererArea::internalAreaChanged(area); } diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/area/hydroprepro.cpp b/src/ui/simulator/toolbox/components/datagrid/renderer/area/hydroprepro.cpp index f2d0ebbabf..115bc0b0d4 100644 --- a/src/ui/simulator/toolbox/components/datagrid/renderer/area/hydroprepro.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/area/hydroprepro.cpp @@ -141,7 +141,7 @@ void HydroPrepro::internalAreaChanged(Antares::Data::Area* area) if (area && !study) study = GetCurrentStudy(); - auto* pPreproHydro = (area) ? area->hydro.prepro : nullptr; + auto* pPreproHydro = (area) ? area->hydro.prepro.get() : nullptr; Renderer::ARendererArea::internalAreaChanged(area); if (pPreproHydro) { diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/area/misc.cpp b/src/ui/simulator/toolbox/components/datagrid/renderer/area/misc.cpp index 180b0424bf..c1749b27ae 100644 --- a/src/ui/simulator/toolbox/components/datagrid/renderer/area/misc.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/area/misc.cpp @@ -100,7 +100,7 @@ double Misc::cellNumericValue(int x, int y) const void Misc::internalAreaChanged(Antares::Data::Area* area) { - this->matrix((area) ? &(area->miscGen) : NULL); + this->matrix((area) ? &(area->miscGen) : nullptr); Renderer::ARendererArea::internalAreaChanged(area); } diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/area/thermalprepro.cpp b/src/ui/simulator/toolbox/components/datagrid/renderer/area/thermalprepro.cpp index 4c39002613..d169a59f91 100644 --- a/src/ui/simulator/toolbox/components/datagrid/renderer/area/thermalprepro.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/area/thermalprepro.cpp @@ -183,7 +183,7 @@ bool ThermalClusterPrepro::cellValue(int x, int y, const String& value) void ThermalClusterPrepro::internalThermalClusterChanged(Antares::Data::ThermalCluster* cluster) { pCluster = cluster; - pPreproAvailability = (cluster) ? cluster->prepro : nullptr; + pPreproAvailability = (cluster) ? cluster->prepro.get() : nullptr; MatrixAncestorType::matrix((pPreproAvailability) ? &pPreproAvailability->data : nullptr); onRefresh(); } diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/area/timeseries.cpp b/src/ui/simulator/toolbox/components/datagrid/renderer/area/timeseries.cpp index df27cabc7c..a1060c1b70 100644 --- a/src/ui/simulator/toolbox/components/datagrid/renderer/area/timeseries.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/area/timeseries.cpp @@ -354,7 +354,7 @@ void TimeSeriesThermalClusterFuelCost::onStudyClosed() void TimeSeriesThermalClusterFuelCost::internalThermalClusterChanged( Antares::Data::ThermalCluster* cluster) { - matrix((CurrentStudyIsValid() && cluster) ? &(cluster->ecoInput.fuelcost) : NULL); + matrix((CurrentStudyIsValid() && cluster) ? &(cluster->ecoInput.fuelcost) : nullptr); } // ---------------------- @@ -384,7 +384,7 @@ void TimeSeriesThermalClusterCO2Cost::onStudyClosed() void TimeSeriesThermalClusterCO2Cost::internalThermalClusterChanged( Antares::Data::ThermalCluster* cluster) { - matrix((CurrentStudyIsValid() && cluster) ? &(cluster->ecoInput.co2cost) : NULL); + matrix((CurrentStudyIsValid() && cluster) ? &(cluster->ecoInput.co2cost) : nullptr); } // ---------------------- diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.cpp b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.cpp new file mode 100644 index 0000000000..809767e8e6 --- /dev/null +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.cpp @@ -0,0 +1,82 @@ +/* +** Copyright 2007-2023 RTE +** Authors: RTE-international / Redstork / 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 "scenario-builder-hydro-final-levels-renderer.h" +#include "antares/study/scenario-builder/scBuilderUtils.h" + +using namespace Antares::Data::ScenarioBuilder; + +namespace Antares +{ +namespace Component +{ +namespace Datagrid +{ +namespace Renderer +{ +wxString hydroFinalLevelsScBuilderRenderer::cellValue(int x, int y) const +{ + const double d = cellNumericValue(x, y); + return (std::isnan(d)) ? wxString() << wxT("init") : wxString() << fromHydroLevelToString(d); +} + +bool hydroFinalLevelsScBuilderRenderer::cellValue(int x, int y, const Yuni::String& value) +{ + if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears + && (uint)y < study->areas.size()) + { + assert((uint)y < pRules->hydroFinalLevels.width()); + assert((uint)x < pRules->hydroFinalLevels.height()); + double val = fromStringToHydroLevel(value, 100.) / 100.; + pRules->hydroFinalLevels.set_value(x, y, val); + return true; + } + return false; +} + +double hydroFinalLevelsScBuilderRenderer::cellNumericValue(int x, int y) const +{ + if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears + && (uint)y < study->areas.size()) + { + assert((uint)y < pRules->hydroFinalLevels.width()); + assert((uint)x < pRules->hydroFinalLevels.height()); + return pRules->hydroFinalLevels.get_value(x, y) * 100.; + } + return 0.; +} + +IRenderer::CellStyle hydroFinalLevelsScBuilderRenderer::cellStyle(int x, int y) const +{ + bool valid = (!(!study) && !(!pRules) && std::isnan(cellNumericValue(x, y))); + return valid ? cellStyleDefaultCenterDisabled : cellStyleDefaultCenter; +} + +} // namespace Renderer +} // namespace Datagrid +} // namespace Component +} // namespace Antares diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h new file mode 100644 index 0000000000..85a7c87e0f --- /dev/null +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-final-levels-renderer.h @@ -0,0 +1,56 @@ +/* +** Copyright 2007-2023 RTE +** Authors: RTE-international / Redstork / Antares_Simulator Team +** +** This file is part of Antares_Simulator. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** There are special exceptions to the terms and conditions of the +** license as they are applied to this software. View the full text of +** the exceptions in file COPYING.txt in the directory of this software +** distribution +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with Antares_Simulator. If not, see . +** +** SPDX-License-Identifier: licenceRef-GPL3_WITH_RTE-Exceptions +*/ +#ifndef __ANTARES_TOOLBOX_COMPONENT_DATAGRID_RENDERER_HYDRO_FINAL_LEVELS_SCENARIO_BUILDER_H__ +#define __ANTARES_TOOLBOX_COMPONENT_DATAGRID_RENDERER_HYDRO_FINAL_LEVELS_SCENARIO_BUILDER_H__ + +#include "scenario-builder-renderer-base.h" + +namespace Antares +{ +namespace Component +{ +namespace Datagrid +{ +namespace Renderer +{ +class hydroFinalLevelsScBuilderRenderer : public ScBuilderRendererAreasAsRows +{ +public: + hydroFinalLevelsScBuilderRenderer() = default; + + wxString cellValue(int x, int y) const; + bool cellValue(int x, int y, const Yuni::String& value); + double cellNumericValue(int x, int y) const; + IRenderer::CellStyle cellStyle(int x, int y) const; +}; // class hydroLevelsScBuilderRenderer + +} // namespace Renderer +} // namespace Datagrid +} // namespace Component +} // namespace Antares + +#endif // __ANTARES_TOOLBOX_COMPONENT_DATAGRID_RENDERER_HYDRO_FINAL_LEVELS_SCENARIO_BUILDER_H__ diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.cpp b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.cpp index ae8e43076f..4dce437a7d 100644 --- a/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.cpp +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-hydro-levels-renderer.cpp @@ -40,30 +40,26 @@ wxString hydroLevelsScBuilderRenderer::cellValue(int x, int y) const bool hydroLevelsScBuilderRenderer::cellValue(int x, int y, const Yuni::String& value) { - if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears) + if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears + && (uint)y < study->areas.size()) { - if ((uint)y < study->areas.size()) - { - assert((uint)y < pRules->hydroLevels.width()); - assert((uint)x < pRules->hydroLevels.height()); - double val = fromStringToHydroLevel(value, 100.) / 100.; - pRules->hydroLevels.set_value(x, y, val); - return true; - } + assert((uint)y < pRules->hydroInitialLevels.width()); + assert((uint)x < pRules->hydroInitialLevels.height()); + double val = fromStringToHydroLevel(value, 100.) / 100.; + pRules->hydroInitialLevels.set_value(x, y, val); + return true; } return false; } double hydroLevelsScBuilderRenderer::cellNumericValue(int x, int y) const { - if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears) + if (!(!study) && !(!pRules) && (uint)x < study->parameters.nbYears + && (uint)y < study->areas.size()) { - if ((uint)y < study->areas.size()) - { - assert((uint)y < pRules->hydroLevels.width()); - assert((uint)x < pRules->hydroLevels.height()); - return pRules->hydroLevels.get_value(x, y) * 100.; - } + assert((uint)y < pRules->hydroInitialLevels.width()); + assert((uint)x < pRules->hydroInitialLevels.height()); + return pRules->hydroInitialLevels.get_value(x, y) * 100.; } return 0.; } @@ -71,7 +67,7 @@ double hydroLevelsScBuilderRenderer::cellNumericValue(int x, int y) const IRenderer::CellStyle hydroLevelsScBuilderRenderer::cellStyle(int x, int y) const { bool valid = (!(!study) && !(!pRules) && std::isnan(cellNumericValue(x, y))); - return (valid) ? cellStyleDefaultCenterDisabled : cellStyleDefaultCenter; + return valid ? cellStyleDefaultCenterDisabled : cellStyleDefaultCenter; } } // namespace Renderer diff --git a/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-ntc-renderer.h b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-ntc-renderer.h index 9bb7cdfd1f..edc1c49580 100644 --- a/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-ntc-renderer.h +++ b/src/ui/simulator/toolbox/components/datagrid/renderer/scenario-builder-ntc-renderer.h @@ -1,23 +1,23 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #pragma once #include "scenario-builder-renderer-base.h" diff --git a/src/ui/simulator/toolbox/components/map/component.cpp b/src/ui/simulator/toolbox/components/map/component.cpp index 89daf4828a..93de041cb9 100644 --- a/src/ui/simulator/toolbox/components/map/component.cpp +++ b/src/ui/simulator/toolbox/components/map/component.cpp @@ -103,12 +103,12 @@ Component::Component(wxWindow* parent) : pSelectionPopUpMenu->Connect(Antares::Forms::MenusID::mnIDPopupSelectionHide, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(Component::evtOnSelectionHide), - NULL, + nullptr, this); pSelectionPopUpMenu->Connect(Antares::Forms::MenusID::mnIDPopupSelectionShow, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(Component::evtOnSelectionShow), - NULL, + nullptr, this); mainSizer->Layout(); diff --git a/src/ui/simulator/toolbox/components/map/nodes/item.cpp b/src/ui/simulator/toolbox/components/map/nodes/item.cpp index 4eac0ac92e..cb567af5af 100644 --- a/src/ui/simulator/toolbox/components/map/nodes/item.cpp +++ b/src/ui/simulator/toolbox/components/map/nodes/item.cpp @@ -112,7 +112,7 @@ void Item::internalClearAllLinks() if (pLinks && !pLinks->empty()) { Links* lnks = pLinks; - pLinks = NULL; + pLinks = nullptr; const Links::const_iterator end = lnks->end(); for (Links::const_iterator i = lnks->begin(); i != end; ++i) diff --git a/src/ui/simulator/toolbox/components/map/tools/tool.cpp b/src/ui/simulator/toolbox/components/map/tools/tool.cpp index ac957bb56b..3b244b5869 100644 --- a/src/ui/simulator/toolbox/components/map/tools/tool.cpp +++ b/src/ui/simulator/toolbox/components/map/tools/tool.cpp @@ -32,7 +32,7 @@ namespace Tool Tool::Tool(Manager& manager, const char* icon) : pManager(manager), pX(0), pY(0), pWidth(20), pHeight(20) { - pIcon = (icon && *icon != '\0') ? Resources::BitmapLoadFromFile(icon) : NULL; + pIcon = (icon && *icon != '\0') ? Resources::BitmapLoadFromFile(icon) : nullptr; } Tool::~Tool() @@ -43,7 +43,7 @@ Tool::~Tool() void Tool::icon(const char* filename) { delete pIcon; - pIcon = (filename && *filename != '\0') ? Resources::BitmapLoadFromFile(filename) : NULL; + pIcon = (filename && *filename != '\0') ? Resources::BitmapLoadFromFile(filename) : nullptr; } void Tool::draw(DrawingContext& dc, const bool mouseDown, const wxPoint&, const wxPoint&) const diff --git a/src/ui/simulator/toolbox/components/notebook/mapnotebook.cpp b/src/ui/simulator/toolbox/components/notebook/mapnotebook.cpp index 7b709afbe4..f4bee76ce3 100644 --- a/src/ui/simulator/toolbox/components/notebook/mapnotebook.cpp +++ b/src/ui/simulator/toolbox/components/notebook/mapnotebook.cpp @@ -98,8 +98,8 @@ bool MapNotebook::remove(Page* page) MapNotebook::MapTabs::MapTabs(wxWindow* parent, Notebook& notebook) : Tabs(parent, notebook), undrawnLeftTabs(0), remainingRightTabs(0), pTabNameCtrl(nullptr) { - Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(MapTabs::onMouseMove), NULL, this); - Connect(GetId(), wxEVT_LEAVE_WINDOW, wxMouseEventHandler(MapTabs::onMouseLeave), NULL, this); + Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(MapTabs::onMouseMove), nullptr, this); + Connect(GetId(), wxEVT_LEAVE_WINDOW, wxMouseEventHandler(MapTabs::onMouseLeave), nullptr, this); // add Page button addPageButton = new tabButton( "images/16x16/white_add_18.png", this, tabButton::btnNone, "images/16x16/grey_add_18.png"); diff --git a/src/ui/simulator/toolbox/create.cpp b/src/ui/simulator/toolbox/create.cpp index be3d23e13d..5687a5fc37 100644 --- a/src/ui/simulator/toolbox/create.cpp +++ b/src/ui/simulator/toolbox/create.cpp @@ -38,7 +38,7 @@ CustomWxButton::CustomWxButton(wxWindow* parent, const wxString& title) : wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent( wxCommandEventFunction, &CustomWxButton::evtOnUserClick), - NULL, + nullptr, this); } diff --git a/src/ui/simulator/toolbox/ext-source/apply.cpp b/src/ui/simulator/toolbox/ext-source/apply.cpp index 4e7f690151..13ea0c43a0 100644 --- a/src/ui/simulator/toolbox/ext-source/apply.cpp +++ b/src/ui/simulator/toolbox/ext-source/apply.cpp @@ -40,12 +40,12 @@ void Apply(Antares::Action::Context::Ptr context, if (windowRequired) { - auto* form = new Antares::Window::ApplyActionsDialog(NULL, context, root); + auto* form = new Antares::Window::ApplyActionsDialog(nullptr, context, root); Dispatcher::GUI::ShowModal(form); } else { - auto* form = new Antares::Window::PerformerDialog(NULL, context, root); + auto* form = new Antares::Window::PerformerDialog(nullptr, context, root); Dispatcher::GUI::ShowModal(form); } } diff --git a/src/ui/simulator/toolbox/input/connection.cpp b/src/ui/simulator/toolbox/input/connection.cpp index 7934b663f0..68e6f39f9f 100644 --- a/src/ui/simulator/toolbox/input/connection.cpp +++ b/src/ui/simulator/toolbox/input/connection.cpp @@ -112,7 +112,7 @@ void Connections::internalBuildSubControls() sizer->AddSpacer(1); // Layer filter pLayerFilter = new wxComboBox( - this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY); + this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY); pLayerFilter->SetFont(wxFont(wxFontInfo().Bold())); pLayerFilter->AppendString("All"); pLayerFilter->SetValue("All"); diff --git a/src/ui/simulator/toolbox/jobs/job.cpp b/src/ui/simulator/toolbox/jobs/job.cpp index 926764f484..f4c2f4e284 100644 --- a/src/ui/simulator/toolbox/jobs/job.cpp +++ b/src/ui/simulator/toolbox/jobs/job.cpp @@ -1,23 +1,23 @@ -/* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ +/* +** Copyright 2007-2024, RTE (https://www.rte-france.com) +** See AUTHORS.txt +** SPDX-License-Identifier: MPL-2.0 +** This file is part of Antares-Simulator, +** Adequacy and Performance assessment for interconnected energy networks. +** +** Antares_Simulator is free software: you can redistribute it and/or modify +** it under the terms of the Mozilla Public Licence 2.0 as published by +** the Mozilla Foundation, either version 2 of the License, or +** (at your option) any later version. +** +** Antares_Simulator is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** Mozilla Public Licence 2.0 for more details. +** +** You should have received a copy of the Mozilla Public Licence 2.0 +** along with Antares_Simulator. If not, see . +*/ #include #include @@ -478,7 +478,8 @@ class MessageFlusherTimer final : public wxTimer MessageFlusherTimer(const wxString& messageBuffer, wxStaticText* label, std::mutex& mutex) : wxTimer(), pMessageBuffer(messageBuffer), pLabel(label), pMutex(mutex) { - assert(pLabel != NULL); + assert(pLabel); + } virtual ~MessageFlusherTimer() @@ -513,7 +514,8 @@ class ReadWriteStatsFlusherTimer final : public wxTimer public: ReadWriteStatsFlusherTimer(wxStaticText* label) : wxTimer(), pLabel(label) { - assert(pLabel != NULL); + assert(pLabel); + } virtual ~ReadWriteStatsFlusherTimer() diff --git a/src/ui/simulator/toolbox/spotlight/area.cpp b/src/ui/simulator/toolbox/spotlight/area.cpp index 9d0147e104..64a7589a31 100644 --- a/src/ui/simulator/toolbox/spotlight/area.cpp +++ b/src/ui/simulator/toolbox/spotlight/area.cpp @@ -33,7 +33,7 @@ namespace Spotlight { ItemArea::ItemArea(Data::Area* a) : area(a) { - assert(a != NULL); + assert(a); caption(a->name); group("Area"); diff --git a/src/ui/simulator/toolbox/spotlight/constraint.cpp b/src/ui/simulator/toolbox/spotlight/constraint.cpp index 2917526b13..de73cb889d 100644 --- a/src/ui/simulator/toolbox/spotlight/constraint.cpp +++ b/src/ui/simulator/toolbox/spotlight/constraint.cpp @@ -33,7 +33,7 @@ namespace Spotlight { ItemConstraint::ItemConstraint(Data::BindingConstraint* a) : constraint(a) { - assert(a != NULL); + assert(a); caption(a->name()); group("Constraint"); diff --git a/src/ui/simulator/windows/correlation/correlation.cpp b/src/ui/simulator/windows/correlation/correlation.cpp index 6edf4e095c..110182bbde 100644 --- a/src/ui/simulator/windows/correlation/correlation.cpp +++ b/src/ui/simulator/windows/correlation/correlation.cpp @@ -1,36 +1,37 @@ /* -** Copyright 2007-2024, RTE (https://www.rte-france.com) -** See AUTHORS.txt -** SPDX-License-Identifier: MPL-2.0 -** This file is part of Antares-Simulator, -** Adequacy and Performance assessment for interconnected energy networks. -** -** Antares_Simulator is free software: you can redistribute it and/or modify -** it under the terms of the Mozilla Public Licence 2.0 as published by -** the Mozilla Foundation, either version 2 of the License, or -** (at your option) any later version. -** -** Antares_Simulator is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** Mozilla Public Licence 2.0 for more details. -** -** You should have received a copy of the Mozilla Public Licence 2.0 -** along with Antares_Simulator. If not, see . -*/ + * Copyright 2007-2024, RTE (https://www.rte-france.com) + * See AUTHORS.txt + * SPDX-License-Identifier: MPL-2.0 + * This file is part of Antares-Simulator, + * Adequacy and Performance assessment for interconnected energy networks. + * + * Antares_Simulator is free software: you can redistribute it and/or modify + * it under the terms of the Mozilla Public Licence 2.0 as published by + * the Mozilla Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Antares_Simulator is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Mozilla Public Licence 2.0 for more details. + * + * You should have received a copy of the Mozilla Public Licence 2.0 + * along with Antares_Simulator. If not, see . + */ #include "correlation.h" + +#include +#include + +#include + #include "../../application/study.h" -#include "../../toolbox/components/notebook/notebook.h" #include "../../toolbox/components/datagrid/component.h" #include "../../toolbox/components/datagrid/renderer/correlation.h" +#include "../../toolbox/components/notebook/notebook.h" #include "../../toolbox/components/refresh.h" -#include #include "../../toolbox/resources.h" - -#include -#include - #include "datasources.hxx" using namespace Yuni; @@ -45,12 +46,17 @@ class CorrelationPanelData final using CorrelationMatrixType = Component::Datagrid::Renderer::CorrelationMatrix; public: - CorrelationPanelData() : pCorrelation(nullptr) + CorrelationPanelData(): + pCorrelation(nullptr) { for (uint i = 0; i != 12; ++i) + { pGridMonthly[i] = nullptr; + } for (uint i = 0; i != 12 + 1; ++i) + { renderer[i] = nullptr; + } } public: @@ -62,7 +68,8 @@ class CorrelationPanelData final CorrelationMatrixType::IDatasource::Ptr datasource; }; -CorrelationPanel::CorrelationPanel(wxWindow* parent, int timeseries) : wxPanel(parent, wxID_ANY) +CorrelationPanel::CorrelationPanel(wxWindow* parent, int timeseries): + wxPanel(parent, wxID_ANY) { // Init pData = new CorrelationPanelData(); @@ -113,8 +120,9 @@ CorrelationPanel::CorrelationPanel(wxWindow* parent, int timeseries) : wxPanel(p }; #endif - btn - = Resources::BitmapButtonLoadFromFile(panel, wxID_ANY, "images/16x16/sort_alphabet.png"); + btn = Resources::BitmapButtonLoadFromFile(panel, + wxID_ANY, + "images/16x16/sort_alphabet.png"); btn->Connect(btn->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CorrelationPanel::onSortAlpha), @@ -123,8 +131,9 @@ CorrelationPanel::CorrelationPanel(wxWindow* parent, int timeseries) : wxPanel(p panel->GetSizer()->Add(btn, 0, wxALL | wxEXPAND, margin); // Sort - reverse - btn = Resources::BitmapButtonLoadFromFile( - panel, wxID_ANY, "images/16x16/sort_alphabet_descending.png"); + btn = Resources::BitmapButtonLoadFromFile(panel, + wxID_ANY, + "images/16x16/sort_alphabet_descending.png"); btn->Connect(btn->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(CorrelationPanel::onSortAlphaReverse), @@ -145,8 +154,8 @@ CorrelationPanel::CorrelationPanel(wxWindow* parent, int timeseries) : wxPanel(p { for (uint i = 0; i != 12; ++i) { - pData->pGridMonthly[i] - = new Component::Datagrid::Component(notebook, pData->renderer[i]); + pData->pGridMonthly[i] = new Component::Datagrid::Component(notebook, + pData->renderer[i]); pData->renderer[i]->control(pData->pGridMonthly[i]); notebook->add(pData->pGridMonthly[i], months[i]); } @@ -192,7 +201,9 @@ CorrelationPanel::~CorrelationPanel() // we should destroy all children as soon as possible. wxSizer* sizer = GetSizer(); if (sizer) + { sizer->Clear(true); + } } void CorrelationPanel::onStudyLoaded() @@ -226,7 +237,9 @@ void CorrelationPanel::reload() { assignMatrices(nullptr); if (not pData) + { return; + } pData->datasource->reload(); @@ -256,12 +269,16 @@ void CorrelationPanel::reload() // It is useless to reassign matrices since they are already // assigned to null if (pData->pCorrelation) + { assignMatrices(pData->pCorrelation); + } // Force refresh RefreshAllControls(pData->pGridAnnual); for (uint i = 0; i != 12; ++i) + { RefreshAllControls(pData->pGridMonthly[i]); + } } void CorrelationPanel::updateAllDatasources() @@ -270,13 +287,17 @@ void CorrelationPanel::updateAllDatasources() for (uint i = 0; i != 12 + 1; ++i) { if (pData->renderer[i]) + { pData->renderer[i]->datasource(pData->datasource); + } } for (uint i = 0; i != 12; ++i) { if (pData->pGridMonthly[i]) + { pData->pGridMonthly[i]->forceRefresh(); + } } pData->pGridAnnual->forceRefresh(); } @@ -303,12 +324,14 @@ void CorrelationPanel::assignMatrices(Data::Correlation* corr) { if (pData) { - if (corr == NULL) + if (!corr) { for (uint i = 0; i < 12 + 1; ++i) { if (pData->renderer) + { pData->renderer[i]->matrix(nullptr); + } } } else @@ -316,9 +339,11 @@ void CorrelationPanel::assignMatrices(Data::Correlation* corr) for (uint i = 0; i < 12; ++i) { if (pData->renderer[i]) + { pData->renderer[i]->matrix(&(corr->monthly[i])); + } } - pData->renderer[12]->matrix(corr->annual); + pData->renderer[12]->matrix(&corr->annual); } } } diff --git a/src/ui/simulator/windows/hydro/management.cpp b/src/ui/simulator/windows/hydro/management.cpp index 625a6e50a8..7822f58544 100644 --- a/src/ui/simulator/windows/hydro/management.cpp +++ b/src/ui/simulator/windows/hydro/management.cpp @@ -956,7 +956,7 @@ void Management::onToggleInitializeReservoirLevelDate(Component::Button&, wxMenu for (int i = 0; i < 12; i++) { - it = Menu::CreateItem(&menu, i, Antares::Date::MonthToString(i, 0), NULL, wxEmptyString); + it = Menu::CreateItem(&menu, i, Antares::Date::MonthToString(i, 0), nullptr, wxEmptyString); menu.Connect(it->GetId(), wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(Management::onChangingInitializeReservoirLevelDate), diff --git a/src/ui/simulator/windows/options/adequacy-patch/adequacy-patch-options.cpp b/src/ui/simulator/windows/options/adequacy-patch/adequacy-patch-options.cpp index 344a1acc7a..d65d6ddbeb 100644 --- a/src/ui/simulator/windows/options/adequacy-patch/adequacy-patch-options.cpp +++ b/src/ui/simulator/windows/options/adequacy-patch/adequacy-patch-options.cpp @@ -62,7 +62,7 @@ static void updateButton(Component::Button* button, bool value, std::string_view type = (buttonType == "pto") ? 'P' : 'S'; } - assert(button != NULL); + assert(button); if (value) { switch (type) @@ -165,29 +165,13 @@ AdequacyPatchOptions::AdequacyPatchOptions(wxWindow* parent) : button->menu(true); onPopup.bind(this, &AdequacyPatchOptions::onPopupMenuNTC, - PopupInfo(study.parameters.adqPatchParams.localMatching.setToZeroOutsideInsideLinks, + PopupInfo(study.parameters.adqPatchParams.setToZeroOutsideInsideLinks, wxT("NTC"))); button->onPopupMenu(onPopup); s->Add(label, 0, wxRIGHT | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); s->Add(button, 0, wxLEFT | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); pBtnNTCfromOutToInAdqPatch = button; } - // Transmission capacities (NTC) between physical areas outside adequacy patch (area type 1). - // Used in the first step of adequacy patch local matching rule. - { - label = Component::CreateLabel(this, wxT("NTC between physical areas outside adequacy patch")); - button = new Component::Button(this, wxT("Day"), "images/16x16/light_green.png"); - button->SetBackgroundColour(bgColor); - button->menu(true); - onPopup.bind(this, - &AdequacyPatchOptions::onPopupMenuNTC, - PopupInfo(study.parameters.adqPatchParams.localMatching.setToZeroOutsideOutsideLinks, - wxT("NTC"))); - button->onPopupMenu(onPopup); - s->Add(label, 0, wxRIGHT | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); - s->Add(button, 0, wxLEFT | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); - pBtnNTCfromOutToOutAdqPatch = button; - } // PTO (Price Taking Order). User can choose between DENS and Load { label = Component::CreateLabel(this, wxT("Price taking order")); @@ -360,12 +344,7 @@ void AdequacyPatchOptions::refresh() // adequacy patch (area type 2). Used in the first step of adequacy patch local matching rule. buttonType = "ntc"; updateButton(pBtnNTCfromOutToInAdqPatch, - study.parameters.adqPatchParams.localMatching.setToZeroOutsideInsideLinks, - buttonType); - // NTC between physical areas outside adequacy patch (area type 1). Used in the first step of - // adequacy patch local matching rule. - updateButton(pBtnNTCfromOutToOutAdqPatch, - study.parameters.adqPatchParams.localMatching.setToZeroOutsideOutsideLinks, + study.parameters.adqPatchParams.setToZeroOutsideInsideLinks, buttonType); // Price taking order (PTO) for adequacy patch buttonType = "pto"; diff --git a/src/ui/simulator/windows/options/advanced/advanced.cpp b/src/ui/simulator/windows/options/advanced/advanced.cpp index 97b0589bd4..fa21ca6895 100644 --- a/src/ui/simulator/windows/options/advanced/advanced.cpp +++ b/src/ui/simulator/windows/options/advanced/advanced.cpp @@ -156,14 +156,12 @@ AdvancedParameters::AdvancedParameters(wxWindow* parent) : // Initial reservoir levels { label = Component::CreateLabel(this, wxT("Initial reservoir levels")); - button = new Component::Button(this, wxT("cold start"), "images/16x16/tag.png"); + button = new Component::Button(this, wxT(""), "images/16x16/tag.png"); button->SetBackgroundColour(bgColor); - button->menu(true); - onPopup.bind(this, &AdvancedParameters::onInitialReservoirLevels); button->onPopupMenu(onPopup); + button->caption("hydro hot start deprecated"); s->Add(label, 0, wxRIGHT | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); s->Add(button, 0, wxLEFT | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); - pBtnInitialReservoirLevels = button; } // Hydro heuristic policy { @@ -285,7 +283,7 @@ AdvancedParameters::AdvancedParameters(wxWindow* parent) : // refresh Connect( - GetId(), wxEVT_MOTION, wxMouseEventHandler(AdvancedParameters::onInternalMotion), NULL, this); + GetId(), wxEVT_MOTION, wxMouseEventHandler(AdvancedParameters::onInternalMotion), nullptr, this); refresh(); SetSizer(sizer); @@ -327,7 +325,6 @@ void AdvancedParameters::onResetToDefault(void*) parameters.timeSeriesAccuracyOnCorrelation &= ~Data::timeSeriesWind; parameters.timeSeriesAccuracyOnCorrelation &= ~Data::timeSeriesSolar; - parameters.initialReservoirLevels.iniLevels = Data::irlColdStart; parameters.hydroHeuristicPolicy.hhPolicy = Data::hhpAccommodateRuleCurves; parameters.hydroPricing.hpMode = Data::hpHeuristic; parameters.power.fluctuations = Data::lssFreeModulations; @@ -375,10 +372,6 @@ void AdvancedParameters::refresh() wxString text; - text = wxStringFromUTF8( - InitialReservoirLevelsToCString(study.parameters.initialReservoirLevels.iniLevels)); - pBtnInitialReservoirLevels->caption(text); - text = wxStringFromUTF8( HydroHeuristicPolicyToCString(study.parameters.hydroHeuristicPolicy.hhPolicy)); pBtnHydroHeuristicPolicy->caption(text); @@ -508,58 +501,6 @@ void AdvancedParameters::onSelectNumericQualityHigh(wxCommandEvent&) } } -void AdvancedParameters::onInitialReservoirLevels(Component::Button&, wxMenu& menu, void*) -{ - wxMenuItem* it; - wxString text; - - text = wxStringFromUTF8(InitialReservoirLevelsToCString(Data::irlColdStart)); - text << wxT(" [default]"); - it = Menu::CreateItem(&menu, wxID_ANY, text, "images/16x16/tag.png"); - menu.Connect(it->GetId(), - wxEVT_COMMAND_MENU_SELECTED, - wxCommandEventHandler(AdvancedParameters::onSelectColdStart), - nullptr, - this); - - text.clear(); - text << wxStringFromUTF8(InitialReservoirLevelsToCString(Data::irlHotStart)); - it = Menu::CreateItem(&menu, wxID_ANY, text, "images/16x16/tag.png"); - menu.Connect(it->GetId(), - wxEVT_COMMAND_MENU_SELECTED, - wxCommandEventHandler(AdvancedParameters::onSelectHotStart), - nullptr, - this); -} - -void AdvancedParameters::onSelectColdStart(wxCommandEvent&) -{ - if (not CurrentStudyIsValid()) - return; - auto& study = *GetCurrentStudy(); - - if (study.parameters.initialReservoirLevels.iniLevels != Data::irlColdStart) - { - study.parameters.initialReservoirLevels.iniLevels = Data::irlColdStart; - MarkTheStudyAsModified(); - refresh(); - } -} - -void AdvancedParameters::onSelectHotStart(wxCommandEvent&) -{ - if (not CurrentStudyIsValid()) - return; - auto& study = *GetCurrentStudy(); - - if (study.parameters.initialReservoirLevels.iniLevels != Data::irlHotStart) - { - study.parameters.initialReservoirLevels.iniLevels = Data::irlHotStart; - MarkTheStudyAsModified(); - refresh(); - } -} - // ... Hydro heuristic policy void AdvancedParameters::onHydroHeuristicPolicy(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 a42d87c9c8..1410d05595 100644 --- a/src/ui/simulator/windows/options/advanced/advanced.h +++ b/src/ui/simulator/windows/options/advanced/advanced.h @@ -69,11 +69,7 @@ class AdvancedParameters final : public wxDialog void onNumericQuality(Component::Button&, wxMenu&, void*, Data::TimeSeriesType ts); void onSelectNumericQualityStandard(wxCommandEvent& evt); void onSelectNumericQualityHigh(wxCommandEvent& evt); - - void onInitialReservoirLevels(Component::Button&, wxMenu&, void*); - void onSelectHotStart(wxCommandEvent& evt); - void onSelectColdStart(wxCommandEvent& evt); - + void onHydroHeuristicPolicy(Component::Button&, wxMenu& menu, void*); void onSelectAccomodateRuleCurves(wxCommandEvent& evt); void onSelectMaximizeGeneration(wxCommandEvent& evt); @@ -115,7 +111,6 @@ class AdvancedParameters final : public wxDialog Component::Button* pBtnNumericQualityWind; Component::Button* pBtnNumericQualitySolar; Component::Button* pBtnPowerFluctuations; - Component::Button* pBtnInitialReservoirLevels; Component::Button* pBtnHydroHeuristicPolicy; Component::Button* pBtnHydroPricing; Component::Button* pBtnSheddingPolicy; diff --git a/src/ui/simulator/windows/options/optimization/optimization.cpp b/src/ui/simulator/windows/options/optimization/optimization.cpp index f6a6b5bf2a..7c0b01db29 100644 --- a/src/ui/simulator/windows/options/optimization/optimization.cpp +++ b/src/ui/simulator/windows/options/optimization/optimization.cpp @@ -41,7 +41,7 @@ namespace Options { static void ResetButton(Component::Button* button, bool value) { - assert(button != NULL); + assert(button); if (value) { button->image("images/16x16/light_green.png"); @@ -56,7 +56,7 @@ static void ResetButton(Component::Button* button, bool value) static void ResetButton(Component::Button* button, Data::GlobalTransmissionCapacities value) { - assert(button != NULL); + assert(button); button->image(transmissionCapacityIcon(value)); button->caption(GlobalTransmissionCapacitiesToString_Display(value)); } @@ -349,7 +349,7 @@ Optimization::Optimization(wxWindow* parent) : sizer->Add(panel, 0, wxALL | wxEXPAND); // refresh - Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(Optimization::onInternalMotion), NULL, this); + Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(Optimization::onInternalMotion), nullptr, this); refresh(); SetSizer(sizer); diff --git a/src/ui/simulator/windows/options/temp-folder/temp-folder.cpp b/src/ui/simulator/windows/options/temp-folder/temp-folder.cpp index 246809bc8f..bc82fd78e0 100644 --- a/src/ui/simulator/windows/options/temp-folder/temp-folder.cpp +++ b/src/ui/simulator/windows/options/temp-folder/temp-folder.cpp @@ -63,7 +63,7 @@ ConfigureTempFolder::ConfigureTempFolder(wxWindow* parent) : pDefaults(nullptr), pText(nullptr) { - assert(NULL != parent); + assert(parent); auto* config = new wxConfig(wxT(LOG_APPLICATION_NAME), wxT(LOG_APPLICATION_VENDOR)); // Title of the Form diff --git a/src/ui/simulator/windows/output/output.cpp b/src/ui/simulator/windows/output/output.cpp index 16ef15b100..28be461e76 100644 --- a/src/ui/simulator/windows/output/output.cpp +++ b/src/ui/simulator/windows/output/output.cpp @@ -502,7 +502,7 @@ void Component::createAllControlsIfNeeded() OnStudyClosed.connect(this, &Component::onStudyClosed); // Layout - assert(GetSizer() != NULL); + assert(GetSizer()); GetSizer()->Layout(); pControlsAlreadyCreated = true; diff --git a/src/ui/simulator/windows/output/panel/area-link-renderer.cpp b/src/ui/simulator/windows/output/panel/area-link-renderer.cpp index e9c675082a..0f6373334c 100644 --- a/src/ui/simulator/windows/output/panel/area-link-renderer.cpp +++ b/src/ui/simulator/windows/output/panel/area-link-renderer.cpp @@ -174,7 +174,7 @@ int AreaLinkRenderer::height() const bool AreaLinkRenderer::valid() const { - return (NULL != pMatrix); + return (nullptr != pMatrix); } wxString AreaLinkRenderer::columnCaption(int colIndx) const diff --git a/src/ui/simulator/windows/output/panel/area-link.cpp b/src/ui/simulator/windows/output/panel/area-link.cpp index eecbbc2bf9..d8830b5784 100644 --- a/src/ui/simulator/windows/output/panel/area-link.cpp +++ b/src/ui/simulator/windows/output/panel/area-link.cpp @@ -152,7 +152,7 @@ class JobMatrix : public Yuni::Job::IJob, public Yuni::IEventObserver } // The loading of the matrix had failed. - // The GUI will be updated with NULL + // The GUI will be updated with nullptr callback.bind(&pPanel, &Panel::loadDataFromMatrix, (MatrixType*)nullptr); if (not shouldAbort) Antares::Dispatcher::GUI::Post(callback, 50); @@ -393,7 +393,7 @@ class JobAggregator : public Yuni::Job::IJob, public Yuni::IEventObserverreset(ops.width, ops.height); @@ -464,7 +464,7 @@ class JobAggregator : public Yuni::Job::IJob, public Yuni::IEventObserverStart(150); // Event - Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(Run::onInternalMotion), NULL, this); + Connect(GetId(), wxEVT_MOTION, wxMouseEventHandler(Run::onInternalMotion), nullptr, this); } Run::~Run() diff --git a/src/vcpkg.json b/src/vcpkg.json new file mode 100644 index 0000000000..08acfb9e79 --- /dev/null +++ b/src/vcpkg.json @@ -0,0 +1,39 @@ +{ + "name": "antares-simulator", + "version-string": "9.1.0", + "builtin-baseline": "9484a57dd560b89f0a583be08af6753611c57fd5", + "vcpkg-configuration": { + "overlay-ports": [ + "./ports" + ], + "overlay-triplets": [ + "./triplets" + ] + }, + "dependencies": [ + { + "name": "sirius-solver", + "version>=": "1.5" + }, + { + "name": "wxwidgets", + "platform": "windows" + }, + { + "name": "boost-test", + "version>=": "1.81.0" + }, + { + "name": "boost-core", + "version>=": "1.81.0" + }, + { + "name": "minizip-ng", + "default-features": false, + "version>=": "4.0.0", + "features": [ + "zlib" + ] + } + ] +} diff --git a/vcpkg_manifest/vcpkg.json b/vcpkg_manifest/vcpkg.json deleted file mode 100644 index 15837160b1..0000000000 --- a/vcpkg_manifest/vcpkg.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "antares-simulator", - "version-string": "8.5.0", - "dependencies": [ - "wxwidgets", - "boost-test" - ] -} \ No newline at end of file