Skip to content

Commit

Permalink
Expose API [ANT-1158] (#1993)
Browse files Browse the repository at this point in the history
Expose Antares Solver in a library. the library and target are called
AntaresAPI. This API expose one entry point to run a simulation on a
study. The return value of this is a data structure with the path to the
simulation and the weekly problems.

- New component API
- Create a new project "api_client" and corresponding tests to detect
API lib install regressions
- rename "utils" project in tests as "in-memory-study"
- promote this project at top level in tests. This allow in-memory-study
to be used for any tests
- create SimulationObserver. Object passed throughout all "frames" of
the simulation.

---------

Co-authored-by: Florian Omnès <[email protected]>
Co-authored-by: Florian OMNES <[email protected]>
  • Loading branch information
3 people authored Jun 27, 2024
1 parent ea815a1 commit 60977f6
Show file tree
Hide file tree
Showing 91 changed files with 2,427 additions and 729 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/install-cmake-328/action.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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
Expand Down
19 changes: 18 additions & 1 deletion .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -115,6 +114,24 @@ jobs:
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 \
-DCMAKE_C_COMPILER=/usr/bin/gcc-10 \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER=/usr/bin/g++-10 \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=ON \
-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
# simtest
- name: Read simtest version
id: simtest-version
Expand Down
10 changes: 5 additions & 5 deletions docs/Architecture_Decision_Records/Expose_cpp_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
25 changes: 25 additions & 0 deletions docs/Architecture_Decision_Records/separate_install_exe_api.md
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ message(STATUS "OR-Tools tag ${ORTOOLS_TAG}")
FetchContent_MakeAvailable(ortools)
endif()

find_package(minizip-ng)
find_package(minizip-ng QUIET)
if (minizip-ng_FOUND)
add_library(MINIZIP::minizip ALIAS MINIZIP::minizip-ng)
else ()
Expand Down Expand Up @@ -267,6 +267,7 @@ add_subdirectory("ext/yuni/src")
OMESSAGE("") # empty line

# Sub Directories
add_subdirectory(api)
add_subdirectory(libs) #antares-core fswalker

if(BUILD_UI)
Expand Down
116 changes: 116 additions & 0 deletions src/api/API.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* 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 <https://opensource.org/license/mpl-2-0/>.
*/

#include "API.h"
#include "antares/solver/simulation/economy_mode.h"
#include "antares/solver/simulation/adequacy_mode.h"
#include "antares/solver/misc/options.h"
#include "antares/infoCollection/StudyInfoCollector.h"
#include "antares/benchmarking/DurationCollector.h"
#include "antares/exception/LoadingError.hpp"
#include <antares/writer/writer_factory.h>
#include <SimulationObserver.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};
}

study_->computePThetaInfForThermalClusters();

// 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<Yuni::Job::QueueService>();
ioQueueService->maximumThreadCount(1);
ioQueueService->start();
auto resultWriter = Solver::resultWriterFactory(
study_->parameters.resultFormat, study_->folderOutput, ioQueueService, durationCollector);
SimulationObserver simulationObserver;
// Run the simulation
switch (study_->runtime->mode)
{
case Data::SimulationMode::Economy:
case Data::SimulationMode::Expansion:
Solver::runSimulationInEconomicMode(*study_,
settings,
durationCollector,
*resultWriter,
optimizationInfo,
simulationObserver);
break;
case Data::SimulationMode::Adequacy:
Solver::runSimulationInAdequacyMode(*study_,
settings,
durationCollector,
*resultWriter,
optimizationInfo,
simulationObserver);
break;
default:
break;
}

// Importing Time-Series if asked
study_->importTimeseriesIntoInput();

// Stop the display of the progression
study_->progression.stop();
return
{
.simulationPath = study_->folderOutput.c_str(),
.antares_problems = simulationObserver.acquireLps(),
.error{}
};
}
} // namespace Antares::API
42 changes: 42 additions & 0 deletions src/api/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/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"
)
73 changes: 73 additions & 0 deletions src/api/SimulationObserver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

/*
* 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 <https://opensource.org/license/mpl-2-0/>.
*/

#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,
const unsigned int year,
const unsigned int week)
{
auto weekly_data = translator.translate(problemeHebdo.ProblemeAResoudre.get(), name);
Solver::ConstantDataFromAntares common_data;
if (year == 1 && week == 1)
{
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, year, week);
std::lock_guard lock(mutex_);
if (year == 1 && week == 1)
{
lps_.setConstantData(common_data);
}
lps_.addWeeklyData({year, week}, weekly_data);
}

Solver::LpsFromAntares&& SimulationObserver::acquireLps() noexcept
{
std::lock_guard lock(mutex_);
return std::move(lps_);
}
} // namespace Antares::API
22 changes: 22 additions & 0 deletions src/api/SimulationResults.cpp
Original file line number Diff line number Diff line change
@@ -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 <https://opensource.org/license/mpl-2-0/>.
*/

#include "antares/api/SimulationResults.h"
Loading

0 comments on commit 60977f6

Please sign in to comment.