21 #ifndef __SOLVER_SIMULATION_SOLVER_HXX__
22 #define __SOLVER_SIMULATION_SOLVER_HXX__
24 #include <antares/antares/fatal-error.h>
25 #include <antares/date/date.h>
26 #include <antares/exception/InitializationError.hpp>
27 #include <antares/logs/logs.h>
28 #include "antares/concurrency/concurrency.h"
29 #include "antares/io/outputs/SimulationTableCsv.h"
30 #include "antares/solver/hydro/management/HydroInputsChecker.h"
31 #include "antares/solver/hydro/management/management.h"
32 #include "antares/solver/simulation/common-eco-adq.h"
33 #include "antares/solver/simulation/numspace_manager.h"
34 #include "antares/solver/simulation/opt_time_writer.h"
35 #include "antares/solver/simulation/random.h"
36 #include "antares/solver/simulation/regenerate_timeseries.h"
37 #include "antares/solver/simulation/timeseries-numbers.h"
38 #include "antares/solver/ts-generator/generator.h"
39 #include "antares/solver/variable/print.h"
41 namespace Antares::Solver::Simulation
50 std::map<uint, bool>& pYearsFailed,
54 std::vector<Variable::State>& pStates,
59 std::mutex& aggregationMutex):
60 simulation_(simulation),
62 yearsFailed(pYearsFailed),
63 numspaceManager(numspaceManager),
64 randomForParallelYears(pRandomForParallelYears),
67 yearByYear(pYearByYear),
68 pDurationCollector(durationCollector),
69 pResultWriter(resultWriter),
70 simulationObserver_(simulationObserver),
71 hydroManagement(study.areas, study.parameters, study.calendar, resultWriter),
72 aggregationMutex(aggregationMutex)
83 std::map<uint, bool>& yearsFailed;
87 std::vector<Variable::State>& states;
93 std::mutex& aggregationMutex;
103 void logFailedWeek(
int y,
const Data::Study& study,
const std::list<uint>& failedWeekList)
105 if (!failedWeekList.empty())
107 std::stringstream failedWeekStr;
108 std::ranges::copy(failedWeekList, std::ostream_iterator<int>(failedWeekStr,
" "));
110 std::string s = failedWeekStr.str();
111 s = s.substr(0, s.length() - 1);
113 std::string failedStr = failedWeekList.size() != 1 ?
" failed at weeks "
114 :
" failed at week ";
118 if (Data::stopSimulation(study.parameters.include.unfeasibleProblemBehavior))
120 logs.fatal() <<
"Year " << y + 1 << failedStr << s <<
".";
124 logs.warning() <<
"Year " << y + 1 << failedStr << s <<
".";
135 uint indexYear = randomForParallelYears.yearNumberToIndex[y];
138 yearRandomNumbers& randomForCurrentYear = randomForParallelYears.pYears[indexYear];
141 auto randomReservoirLevel = randomForCurrentYear.pReservoirLevels;
144 unsigned numSpace = numspaceManager.getAvailableNumSpace();
145 Yuni::Logs::threadNumber() = numSpace;
146 logs.info() <<
"Year " << y + 1 <<
" started";
148 Antares::Data::Area::ScratchMap scratchmap = study.areas.buildScratchMap(numSpace);
151 prepareClustersInMustRunMode(study, scratchmap, y, Impl::mode);
154 pDurationCollector(
"hydro_ventilation") << [
this, &scratchmap, &randomReservoirLevel]
155 { hydroManagement.
makeVentilation(randomReservoirLevel, y, scratchmap); };
158 auto& state = states[numSpace];
162 simulation_->variables.yearBegin(y, numSpace);
165 std::list<uint> failedWeekList;
168 bool yearFailed = !simulation_->year(progression,
171 randomForCurrentYear,
173 hydroManagement.ventilationResults(),
176 if (!study.parameters.noOutput)
178 auto& simTable = simulation_->getSimulationTable(numSpace);
180 auto buffers = simTable.moveBuffers();
182 simulation_->storeYearBuffers(y, std::move(buffers.first), std::move(buffers.second));
186 logFailedWeek(y, study, failedWeekList);
188 simulation_->variables.yearEndBuild(state, y, numSpace);
192 simulation_->variables.yearEnd(y, numSpace);
198 simulation_->variables.yearEndSpatialAggregates(simulation_->variables, y, numSpace);
203 pDurationCollector(
"yby_export") << [
this, &numSpace]
206 simulation_->variables.beforeYearByYearExport(y, numSpace);
215 aggregationMutex.lock();
216 yearsFailed[y] = yearFailed;
218 simulation_->variables.computeSummary(y, numSpace);
221 simulation_->variables.computeSpatialAggregatesSummary(simulation_->variables, y, numSpace);
225 simulation_->computeAnnualCostsStatistics(state);
227 logs.debug() <<
"year " << y + 1 <<
" ended and returned numSpace " << numSpace;
228 numspaceManager.freeNumSpace(numSpace);
229 simulation_->incrementProgression(progression);
231 aggregationMutex.unlock();
236 template<
class ImplementationType>
239 const ::Settings& settings,
243 ImplementationType(study, resultWriter, simulationObserver),
246 pNbMaxPerformedYearsInParallel(0),
247 pYearByYear(study.parameters.yearByYear),
248 pDurationCollector(duration_collector),
249 pQueueService(study.pQueueService),
250 pResultWriter(resultWriter),
251 simulationObserver_(simulationObserver)
255 logs.info() << LOG_UI_DISPLAY_MESSAGES_ON;
258 logs.checkpoint() <<
"Running the simulation (" << ImplementationType::Name() <<
')';
259 logs.info() <<
"Allocating resources...";
267 template<
class ImplementationType>
271 if (!pQueueService && pResultWriter.needsTheJobQueue())
277 template<
class ImplementationType>
282 template<
class ImplementationType>
285 pNbMaxPerformedYearsInParallel = study.maxNbYearsInParallel;
288 ImplementationType::variables.initializeFromStudy(study);
290 study.parameters.variablesPrintInfo.computeMaxColumnsCountInReports();
292 logs.info() <<
"Allocating resources...";
297 ImplementationType::variables.template provideInformations<Variable::PrintInfosStdCout>(c);
300 ImplementationType::setNbPerformedYearsInParallel(pNbMaxPerformedYearsInParallel);
302 if (settings.tsGeneratorsOnly)
307 logs.info() <<
" Only the preprocessors are enabled.";
309 regenerateTimeSeries(study, pResultWriter, pDurationCollector);
313 TSGenerator::DestroyAll(study);
318 TimeSeriesNumbers::StoreTimeSeriesNumbersIntoOuput(study, pResultWriter);
320 if (not ImplementationType::simulationBegin())
325 ImplementationType::variables.simulationBegin();
331 logs.info() <<
"MC-Years : [" << (study.runtime.rangeLimits.year[Data::rangeBegin] + 1)
332 <<
" .. " << (1 + study.runtime.rangeLimits.year[Data::rangeEnd])
333 <<
"], total: " << study.runtime.rangeLimits.year[Data::rangeCount];
336 std::vector<Variable::State> state(pNbMaxPerformedYearsInParallel,
Variable::State(study));
338 for (uint numSpace = 0; numSpace != pNbMaxPerformedYearsInParallel; ++numSpace)
340 ImplementationType::initializeState(state[numSpace], numSpace);
343 uint finalYear = 1 + study.runtime.rangeLimits.year[Data::rangeEnd];
345 pDurationCollector(
"mc_years")
346 << [finalYear, &state,
this] { loopThroughYears(0, finalYear, state); };
350 TSGenerator::DestroyAll(study);
353 pDurationCollector(
"post_processing") << [
this] { ImplementationType::simulationEnd(); };
355 ImplementationType::variables.simulationEnd();
361 ImplementationType::variables.simulationEndSpatialAggregates(ImplementationType::variables);
365 template<
class ImplementationType>
368 using namespace Yuni;
374 assert(!settings.noOutput);
375 assert(!settings.tsGeneratorsOnly);
377 if (!pNbYearsReallyPerformed)
380 logs.info() <<
"The writing of the output results is disabled.";
387 const auto& parameters = study.parameters;
388 if (not parameters.synthesis)
390 logs.info() <<
"The simulation synthesis is disabled.";
397 newPath << ImplementationType::Name() << IO::Separator;
404 CString<10, false> tmp;
406 newPath <<
"mc-ind" << IO::Separator <<
"00000";
407 newPath.overwriteRight(tmp);
411 ImplementationType::variables.exportSurveyResults(synthesis,
418 template<
class ImplementationType>
421 pAnnualStatistics.systemCost.addCost(s.annualSystemCost);
429 template<
class ImplementationType>
430 void ISimulation<ImplementationType>::loopThroughYears(uint firstYear,
432 std::vector<Variable::State>& state)
434 assert(endYear <= study.parameters.nbYears);
438 randomHydroGenerator.
reset(study.parameters.seed[Data::seedHydroManagement]);
441 std::vector<setOfParallelYears> setsOfParallelYears;
444 pQueueService->maximumThreadCount(pNbMaxPerformedYearsInParallel);
446 regenerateTimeSeries(study, pResultWriter, pDurationCollector);
448 logs.info() <<
" Doing hydro validation";
451 std::map<unsigned, bool> yearsFailed;
452 std::map<unsigned, bool> isYearPerformed;
453 pNbYearsReallyPerformed = 0;
454 for (uint year = firstYear; year < endYear; ++year)
456 isYearPerformed[year] = study.parameters.yearsFilter[year];
457 if (study.parameters.yearsFilter[year])
459 ++pNbYearsReallyPerformed;
463 logs.debug() <<
"Ignoring year " << year + 1 <<
": not in the playlist";
464 yearsFailed[year] =
false;
468 if (pNbYearsReallyPerformed != endYear)
470 logs.info() <<
"Playlist detected, " << pNbYearsReallyPerformed
471 <<
" years to be performed out of " << endYear <<
" years.";
474 logs.info() <<
" Starting the simulation";
477 pAnnualStatistics.setNbPerformedYears(pNbYearsReallyPerformed);
480 randomNumbers randomForParallelYears(pNbYearsReallyPerformed,
481 study.parameters.power.fluctuations);
483 randomForParallelYears.allocate(study);
484 randomForParallelYears.compute(study, endYear, isYearPerformed, randomHydroGenerator);
487 for (uint year = firstYear; year < endYear; ++year)
489 if (study.parameters.yearsFilter[year])
491 hydroInputsChecker.Execute(year);
494 hydroInputsChecker.CheckForErrors();
496 NumSpaceManager numspaceManager(pNbMaxPerformedYearsInParallel);
499 std::mutex aggregationMutex;
500 for (uint year = firstYear; year < endYear; ++year)
502 if (study.parameters.yearsFilter[year])
509 auto task = std::make_shared<yearJob<ImplementationType>>(
this,
513 randomForParallelYears,
519 simulationObserver_.get(),
521 results.
add(Concurrency::AddTask(*pQueueService, task));
525 pQueueService->start();
527 pQueueService->wait(Yuni::qseIdle);
528 pQueueService->stop();
529 if (!study.parameters.noOutput)
531 aggregateAndWriteSimulationTables();
534 pResultWriter.flush();
536 for (
auto& [year, failed]: yearsFailed)
541 std::ostringstream msg;
542 msg <<
"Year " << year + 1 <<
" has failed in the previous set of parallel year.";
548 randomForParallelYears.reset();
551 pAnnualStatistics.endStandardDeviations();
552 pAnnualStatistics.writeToOutput(pResultWriter);
555 template<
class ImplementationType>
556 void ISimulation<ImplementationType>::storeYearBuffers(uint year,
557 std::string&& firstBuffer,
558 std::string&& secondBuffer)
560 std::lock_guard lock(buffersMutex_);
561 yearSimulationBuffers_.emplace(year,
562 std::pair{std::move(firstBuffer), std::move(secondBuffer)});
565 template<
class ImplementationType>
566 void ISimulation<ImplementationType>::aggregateAndWriteSimulationTables()
568 std::lock_guard lock(buffersMutex_);
569 std::string globalFirstBuffer;
570 std::string globalSecondBuffer;
572 for (uint year = 0; year < study.parameters.nbYears; ++year)
574 auto it = yearSimulationBuffers_.find(year);
575 if (it != yearSimulationBuffers_.end())
577 globalFirstBuffer += it->second.first;
578 globalSecondBuffer += it->second.second;
581 const auto header = ImplementationType::getSimulationTableHeader() +
"\n";
582 if (!globalFirstBuffer.empty())
584 std::string writerEntry = header + std::move(globalFirstBuffer);
585 pResultWriter.addEntryFromBuffer(
"simulation_table--optim-nb-1.csv", writerEntry);
587 if (!globalSecondBuffer.empty())
589 std::string writerEntry = header + std::move(globalSecondBuffer);
590 pResultWriter.addEntryFromBuffer(
"simulation_table--optim-nb-2.csv", writerEntry);
593 yearSimulationBuffers_.clear();
596 template<
class ImplementationType>
601 return ImplementationType::getSimulationTable(numSpace);
Utility class to gather futures to wait for.
Definition: concurrency.h:61
void add(TaskFuture &&f)
Adds one future to be monitored by this set.
Definition: concurrency.cpp:71
void join()
Waits for completion of all added futures.
Definition: concurrency.cpp:77
A generic exception for errors that should end the program.
Definition: fatal-error.h:32
Definition: management.h:62
void makeVentilation(const std::vector< double > &randomReservoirLevel, uint y, Antares::Data::Area::ScratchMap &scratchmap)
Perform the hydro ventilation.
Definition: management.cpp:269
MersenneTwister Pseudo random number generator.
Definition: mersenne-twister.h:41
void reset()
Reset the generator.
Definition: mersenne-twister.cpp:126
Definition: i_writer.h:32
Definition: InitializationError.hpp:29
Definition: progression.h:89
The ISimulationObserver class is an interface for observing the simulation.
Definition: ISimulationObserver.h:36
const ::Settings & settings
The global settings.
Definition: solver.h:85
void writeResults(bool synthesis, uint year=0, uint numSpace=9999)
Export the results to disk.
Definition: solver.hxx:366
ISimulation(Data::Study &study, const ::Settings &settings, Benchmarking::DurationCollector &duration_collector, IResultWriter &resultWriter, Simulation::ISimulationObserver &simulationObserver)
Constructor (with a given study)
Definition: solver.hxx:237
void run()
Run the simulation.
Definition: solver.hxx:283
~ISimulation()
Destructor.
Definition: solver.hxx:278
Definition: numspace_manager.h:30
Definition: solver.hxx:46
double optimalSolutionCost1
Sum of the weekly optimal costs over the year (first optimisation step)
Definition: state.h:227
double averageOptimizationTime2
Average time spent in second optimization over the year (ms)
Definition: state.h:233
double averageUpdateTime
Average time spent updating the problem over the year (ms)
Definition: state.h:235
double optimalSolutionCost2
Sum of the weekly optimal costs over the year (second optimisation step)
Definition: state.h:229
double averageOptimizationTime1
Average time spent in first optimization over the year (ms)
Definition: state.h:231
Definition: DurationCollector.h:36
Definition: OptimisationsSimulationTable.h:31
Definition: opt_time_writer.h:30
bool tsGeneratorsOnly
Run the TS generator only.
Definition: options.h:56
bool noOutput
True to disable the writing in the output folder.
Definition: options.h:59