Skip to content

Commit

Permalink
High-level API: provide output path instead of returning it [ANT-2561] (
Browse files Browse the repository at this point in the history
#2548)

TODO
- [x] Fix build for api_client_test (missing argument)
- [x] Fix extra output directory created by Simulator, for example
20241204-1554eco and 20241204-1554eco-2
  • Loading branch information
flomnes authored Jan 3, 2025
1 parent 832e89b commit 9a9715e
Show file tree
Hide file tree
Showing 12 changed files with 46 additions and 42 deletions.
21 changes: 15 additions & 6 deletions src/api/API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ namespace Antares::API
{
SimulationResults APIInternal::run(
const IStudyLoader& study_loader,
const std::filesystem::path& output,
const Antares::Solver::Optimization::OptimizationOptions& optOptions)
{
try
Expand All @@ -43,9 +44,9 @@ SimulationResults APIInternal::run(
catch (const ::Antares::Error::StudyFolderDoesNotExist& e)
{
Antares::API::Error err{.reason = e.what()};
return {.simulationPath = "", .antares_problems = {}, .error = err};
return {.antares_problems = {}, .error = err};
}
return execute(optOptions);
return execute(output, optOptions);
}

/**
Expand All @@ -56,14 +57,15 @@ SimulationResults APIInternal::run(
* dupllication
*/
SimulationResults APIInternal::execute(
const std::filesystem::path& output,
const Antares::Solver::Optimization::OptimizationOptions& optOptions) 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};
return {.antares_problems{}, .error = err};
}

Settings settings;
Expand All @@ -75,10 +77,19 @@ SimulationResults APIInternal::execute(
auto ioQueueService = std::make_shared<Yuni::Job::QueueService>();
ioQueueService->maximumThreadCount(1);
ioQueueService->start();

study_->folderOutput = output;
auto resultWriter = Solver::resultWriterFactory(parameters.resultFormat,
study_->folderOutput,
ioQueueService,
durationCollector);

// In some cases (e.g tests) we don't want to write anything
if (!output.empty())
{
study_->saveAboutTheStudy(*resultWriter);
}

SimulationObserver simulationObserver;

optimizationInfo = simulationRun(*study_,
Expand All @@ -90,8 +101,6 @@ SimulationResults APIInternal::execute(
// Importing Time-Series if asked
study_->importTimeseriesIntoInput();

return {.simulationPath = study_->folderOutput,
.antares_problems = simulationObserver.acquireLps(),
.error{}};
return {.antares_problems = simulationObserver.acquireLps(), .error{}};
}
} // namespace Antares::API
10 changes: 4 additions & 6 deletions src/api/include/antares/api/SimulationResults.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <filesystem>
#include <optional>
#include <string>

#include "antares/solver/lps/LpsFromAntares.h"

namespace Antares::API
Expand All @@ -31,7 +32,8 @@ namespace Antares::API
* @struct Error
* @brief The Error structure is used to represent an error that occurred during the simulation.
*/
struct Error {
struct Error
{
/**
* @brief The reason for the error.
*/
Expand All @@ -45,10 +47,6 @@ struct Error {
*/
struct [[nodiscard("Contains results and potential error")]] SimulationResults
{
/**
* @brief The path to the simulation (output).
*/
std::filesystem::path simulationPath;
/**
* @brief weekly problems
*/
Expand All @@ -59,4 +57,4 @@ struct [[nodiscard("Contains results and potential error")]] SimulationResults
std::optional<Error> error;
};

}
} // namespace Antares::API
1 change: 1 addition & 0 deletions src/api/include/antares/api/solver.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ namespace Antares::API
*/
SimulationResults PerformSimulation(
const std::filesystem::path& study_path,
const std::filesystem::path& output,
const Antares::Solver::Optimization::OptimizationOptions& optOptions) noexcept;
} // namespace Antares::API
2 changes: 2 additions & 0 deletions src/api/private/API.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ class APIInternal
* @return SimulationResults object which contains the results of the simulation.
*/
SimulationResults run(const IStudyLoader& study_loader,
const std::filesystem::path& output,
const Antares::Solver::Optimization::OptimizationOptions& optOptions);

private:
std::shared_ptr<Antares::Data::Study> study_;
SimulationResults execute(
const std::filesystem::path& output,
const Antares::Solver::Optimization::OptimizationOptions& optOptions) const;
};

Expand Down
5 changes: 3 additions & 2 deletions src/api/solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,19 @@ namespace Antares::API

SimulationResults PerformSimulation(
const std::filesystem::path& study_path,
const std::filesystem::path& output,
const Antares::Solver::Optimization::OptimizationOptions& optOptions) noexcept
{
try
{
APIInternal api;
FileTreeStudyLoader study_loader(study_path);
return api.run(study_loader, optOptions);
return api.run(study_loader, output, optOptions);
}
catch (const std::exception& e)
{
Antares::API::Error err{.reason = e.what()};
return SimulationResults{.simulationPath = study_path, .antares_problems{}, .error = err};
return SimulationResults{.antares_problems{}, .error = err};
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/api_client_example/src/API_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@

#include <utility>

Antares::API::SimulationResults solve(std::filesystem::path study_path)
Antares::API::SimulationResults solve(std::filesystem::path study_path,
std::filesystem::path output)
{
return Antares::API::PerformSimulation(std::move(study_path), {});
return Antares::API::PerformSimulation(std::move(study_path), std::move(output), {});
}
5 changes: 3 additions & 2 deletions src/api_client_example/src/API_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@

#pragma once

#include <antares/api/solver.h>
#include <antares/api/SimulationResults.h>
#include <antares/api/solver.h>

Antares::API::SimulationResults solve(std::filesystem::path study_path);
Antares::API::SimulationResults solve(std::filesystem::path study_path,
std::filesystem::path output);
8 changes: 5 additions & 3 deletions src/api_client_example/tests/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
#define BOOST_TEST_MODULE test_client_api

#include <boost/test/unit_test.hpp>

#include "API_client.h"

BOOST_AUTO_TEST_CASE(test_run) {
auto results = solve("dummy_study_test_client_api");
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;
Expand All @@ -34,4 +36,4 @@ BOOST_AUTO_TEST_CASE(test_run) {
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);
}
}
2 changes: 1 addition & 1 deletion src/format-code.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
if [ $# -eq 0 ]
then
# No arguments: format all
SOURCE_DIRS="analyzer/ libs/ solver/ tools/ config/ tests/ packaging/"
SOURCE_DIRS="analyzer/ libs/ solver/ tools/ config/ tests/ packaging/ api/"
SOURCE_FILES=$(find $SOURCE_DIRS -regextype egrep -regex ".*/*\.(c|cxx|cpp|cc|h|hxx|hpp)$" ! -path '*/antlr-interface/*')
else
# Format files provided as arguments
Expand Down
6 changes: 3 additions & 3 deletions src/solver/application/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,6 @@ void Application::readDataForTheStudy(Data::StudyLoadOptions& options)

Antares::Solver::initializeSignalHandlers(resultWriter);

// Save about-the-study files (comments, notes, etc.)
study.saveAboutTheStudy(*resultWriter);

// Name of the simulation (again, if the value has been overwritten)
if (!pSettings.simulationName.empty())
{
Expand Down Expand Up @@ -375,6 +372,9 @@ void Application::execute()
return;
}

// Save about-the-study files (comments, notes, etc.)
pStudy->saveAboutTheStudy(*resultWriter);

SystemMemoryLogger memoryReport;
memoryReport.interval(1000 * 60 * 5); // 5 minutes
memoryReport.start();
Expand Down
21 changes: 5 additions & 16 deletions src/tests/src/api_internal/test_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,28 +52,17 @@ class InMemoryStudyLoader: public Antares::IStudyLoader
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<InMemoryStudyLoader>();
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<InMemoryStudyLoader>();
auto results = api.run(*study_loader.get(), {});
auto results = api.run(*study_loader, {}, {});

BOOST_CHECK(!results.antares_problems.empty());
BOOST_CHECK(!results.error);
Expand All @@ -83,7 +72,7 @@ BOOST_AUTO_TEST_CASE(result_failure_when_study_is_null)
{
Antares::API::APIInternal api;
auto study_loader = std::make_unique<InMemoryStudyLoader>(false);
auto results = api.run(*study_loader.get(), {});
auto results = api.run(*study_loader, {}, {});

BOOST_CHECK(results.error);
}
Expand All @@ -93,7 +82,7 @@ BOOST_AUTO_TEST_CASE(result_contains_problems)
{
Antares::API::APIInternal api;
auto study_loader = std::make_unique<InMemoryStudyLoader>();
auto results = api.run(*study_loader.get(), {});
auto results = api.run(*study_loader, {}, {});

BOOST_CHECK(!results.antares_problems.empty());
BOOST_CHECK(!results.error);
Expand All @@ -109,7 +98,7 @@ BOOST_AUTO_TEST_CASE(result_with_ortools_coin)
.solverLogs = false,
.solverParameters = ""};

auto results = api.run(*study_loader.get(), opt);
auto results = api.run(*study_loader, {}, opt);

BOOST_CHECK(!results.antares_problems.empty());
BOOST_CHECK(!results.error);
Expand All @@ -126,7 +115,7 @@ BOOST_AUTO_TEST_CASE(invalid_ortools_solver)
.solverLogs = true,
.solverParameters = ""};

auto shouldThrow = [&api, &study_loader, &opt] { return api.run(*study_loader.get(), opt); };
auto shouldThrow = [&api, &study_loader, &opt] { return api.run(*study_loader, {}, opt); };
BOOST_CHECK_EXCEPTION(shouldThrow(),
std::invalid_argument,
checkMessage("Solver this-solver-does-not-exist not found"));
Expand Down
2 changes: 1 addition & 1 deletion src/tests/src/api_lib/test_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
BOOST_AUTO_TEST_CASE(result_failure_when_study_path_invalid)
{
using namespace std::string_literals;
auto results = Antares::API::PerformSimulation("dummy"s, {});
auto results = Antares::API::PerformSimulation("dummy"s, {}, {});
BOOST_CHECK(results.error);
BOOST_CHECK(!results.error->reason.empty());
}

0 comments on commit 9a9715e

Please sign in to comment.