69 yearByYear(pYearByYear),
70 pDurationCollector(durationCollector),
71 pResultWriter(resultWriter),
72 simulationObserver_(simulationObserver),
73 hydroManagement(study.areas, study.parameters, study.calendar, resultWriter)
84 std::map<uint, bool>& yearFailed;
85 std::map<uint, bool>& isFirstPerformedYearOfASet;
86 bool firstSetParallelWithAPerformedYearWasRun;
87 unsigned int numSpace;
89 bool performCalculations;
91 std::vector<Variable::State>& states;
95 std::reference_wrapper<ISimulationObserver> simulationObserver_;
106 void logFailedWeek(
int y,
const Data::Study& study,
const std::list<uint>& failedWeekList)
108 if (!failedWeekList.empty())
110 std::stringstream failedWeekStr;
111 std::ranges::copy(failedWeekList, std::ostream_iterator<int>(failedWeekStr,
" "));
113 std::string s = failedWeekStr.str();
114 s = s.substr(0, s.length() - 1);
116 std::string failedStr = failedWeekList.size() != 1 ?
" failed at weeks "
117 :
" failed at week ";
121 if (Data::stopSimulation(study.parameters.include.unfeasibleProblemBehavior))
123 logs.fatal() <<
"Year " << y + 1 << failedStr << s <<
".";
127 logs.warning() <<
"Year " << y + 1 << failedStr << s <<
".";
137 if (performCalculations)
140 uint indexYear = randomForParallelYears.yearNumberToIndex[y];
143 yearRandomNumbers& randomForCurrentYear = randomForParallelYears.pYears[indexYear];
146 auto randomReservoirLevel = randomForCurrentYear.pReservoirLevels;
149 Antares::Data::Area::ScratchMap scratchmap = study.areas.buildScratchMap(numSpace);
152 simulation_->prepareClustersInMustRunMode(scratchmap, y);
155 pDurationCollector(
"hydro_ventilation") << [
this, &scratchmap, &randomReservoirLevel]
156 { hydroManagement.
makeVentilation(randomReservoirLevel.data(), y, scratchmap); };
159 auto& state = states[numSpace];
163 simulation_->variables.yearBegin(y, numSpace);
166 bool isFirstPerformedYearOfSimulation = isFirstPerformedYearOfASet[y]
167 && not firstSetParallelWithAPerformedYearWasRun;
168 std::list<uint> failedWeekList;
171 yearFailed[y] = !simulation_->year(progression,
174 randomForCurrentYear,
176 isFirstPerformedYearOfSimulation,
177 hydroManagement.ventilationResults(),
182 logFailedWeek(y, study, failedWeekList);
184 simulation_->variables.yearEndBuild(state, y, numSpace);
188 simulation_->variables.yearEnd(y, numSpace);
194 simulation_->variables.yearEndSpatialAggregates(simulation_->variables, y, numSpace);
199 pDurationCollector(
"yby_export") << [
this]
202 simulation_->variables.beforeYearByYearExport(y, numSpace);
210 simulation_->incrementProgression(progression);
212 logs.info() <<
" playlist: ignoring the year " << (y + 1);
214 yearFailed[y] =
false;
221template<
class ImplementationType>
224 const ::Settings& settings,
228 ImplementationType(study, resultWriter, simulationObserver),
231 pNbYearsReallyPerformed(0),
232 pNbMaxPerformedYearsInParallel(0),
233 pYearByYear(study.parameters.yearByYear),
234 pFirstSetParallelWithAPerformedYearWasRun(false),
235 pDurationCollector(duration_collector),
236 pQueueService(study.pQueueService),
237 pResultWriter(resultWriter),
238 simulationObserver_(simulationObserver)
242 logs.info() << LOG_UI_DISPLAY_MESSAGES_ON;
245 logs.checkpoint() <<
"Running the simulation (" << ImplementationType::Name() <<
')';
246 logs.info() <<
"Allocating resources...";
254template<
class ImplementationType>
258 if (!pQueueService && pResultWriter.needsTheJobQueue())
264template<
class ImplementationType>
269template<
class ImplementationType>
272 pNbMaxPerformedYearsInParallel = study.maxNbYearsInParallel;
275 ImplementationType::variables.initializeFromStudy(study);
277 study.parameters.variablesPrintInfo.computeMaxColumnsCountInReports();
279 logs.info() <<
"Allocating resources...";
284 ImplementationType::variables.template provideInformations<Variable::PrintInfosStdCout>(c);
289 pData.initialize(study.parameters);
291 ImplementationType::setNbPerformedYearsInParallel(pNbMaxPerformedYearsInParallel);
293 if (settings.tsGeneratorsOnly)
298 logs.info() <<
" Only the preprocessors are enabled.";
300 regenerateTimeSeries(0);
304 TSGenerator::DestroyAll(study);
309 TimeSeriesNumbers::StoreTimeSeriesNumbersIntoOuput(study, pResultWriter);
311 if (not ImplementationType::simulationBegin())
316 ImplementationType::variables.simulationBegin();
322 logs.info() <<
"MC-Years : [" << (study.runtime.rangeLimits.year[Data::rangeBegin] + 1)
323 <<
" .. " << (1 + study.runtime.rangeLimits.year[Data::rangeEnd])
324 <<
"], total: " << study.runtime.rangeLimits.year[Data::rangeCount];
327 std::vector<Variable::State> state(pNbMaxPerformedYearsInParallel,
Variable::State(study));
329 for (uint numSpace = 0; numSpace != pNbMaxPerformedYearsInParallel; ++numSpace)
331 ImplementationType::initializeState(state[numSpace], numSpace);
334 uint finalYear = 1 + study.runtime.rangeLimits.year[Data::rangeEnd];
336 pDurationCollector(
"mc_years")
337 << [finalYear, &state,
this] { loopThroughYears(0, finalYear, state); };
341 TSGenerator::DestroyAll(study);
344 pDurationCollector(
"post_processing") << [
this] { ImplementationType::simulationEnd(); };
346 ImplementationType::variables.simulationEnd();
352 ImplementationType::variables.simulationEndSpatialAggregates(ImplementationType::variables);
356template<
class ImplementationType>
359 using namespace Yuni;
365 assert(!settings.noOutput);
366 assert(!settings.tsGeneratorsOnly);
368 if (!pNbYearsReallyPerformed)
371 logs.info() <<
"The writing of the output results is disabled.";
378 const auto& parameters = study.parameters;
379 if (not parameters.synthesis)
381 logs.info() <<
"The simulation synthesis is disabled.";
388 newPath << ImplementationType::Name() << IO::Separator;
395 CString<10, false> tmp;
397 newPath <<
"mc-ind" << IO::Separator <<
"00000";
398 newPath.overwriteRight(tmp);
402 ImplementationType::variables.exportSurveyResults(synthesis,
409template<
class ImplementationType>
416 using namespace TSGenerator;
418 if (pData.haveToRefreshTSLoad && (year % pData.refreshIntervalLoad == 0))
420 pDurationCollector(
"tsgen_load")
421 << [year,
this] { GenerateTimeSeries<Data::timeSeriesLoad>(study, year, pResultWriter); };
424 if (pData.haveToRefreshTSSolar && (year % pData.refreshIntervalSolar == 0))
426 pDurationCollector(
"tsgen_solar") << [year,
this]
427 { GenerateTimeSeries<Data::timeSeriesSolar>(study, year, pResultWriter); };
430 if (pData.haveToRefreshTSWind && (year % pData.refreshIntervalWind == 0))
432 pDurationCollector(
"tsgen_wind")
433 << [year,
this] { GenerateTimeSeries<Data::timeSeriesWind>(study, year, pResultWriter); };
436 if (pData.haveToRefreshTSHydro && (year % pData.refreshIntervalHydro == 0))
438 pDurationCollector(
"tsgen_hydro") << [year,
this]
439 { GenerateTimeSeries<Data::timeSeriesHydro>(study, year, pResultWriter); };
443 const bool refreshTSonCurrentYear = (year % pData.refreshIntervalThermal == 0);
445 pDurationCollector(
"tsgen_thermal") << [refreshTSonCurrentYear, year,
this]
447 if (refreshTSonCurrentYear)
449 auto clusters = getAllClustersToGen(study.areas, pData.haveToRefreshTSThermal);
450 generateThermalTimeSeries(study,
452 study.runtime.random[Data::seedTsGenThermal]);
454 bool archive = study.parameters.timeSeriesToArchive & Data::timeSeriesThermal;
455 bool doWeWrite = archive && !study.parameters.noOutput;
458 fs::path savePath = study.folderOutput /
"ts-generator" /
"thermal" /
"mc-"
459 / std::to_string(year);
460 writeThermalTimeSeries(clusters, savePath);
464 for (
auto* cluster: clusters)
466 cluster->calculationOfSpinning();
472template<
class ImplementationType>
473uint ISimulation<ImplementationType>::buildSetsOfParallelYears(
476 std::vector<setOfParallelYears>& setsOfParallelYears)
479 const auto& yearsFilter = study.parameters.yearsFilter;
482 uint maxNbYearsPerformed = 0;
484 setOfParallelYears* set =
nullptr;
485 bool buildNewSet =
true;
486 bool foundFirstPerformedYearOfCurrentSet =
false;
489 for (uint y = firstYear; y < endYear; ++y)
491 unsigned int indexSpace = 999999;
492 bool performCalculations = yearsFilter[y];
496 bool refreshing =
false;
497 refreshing = pData.haveToRefreshTSLoad && (y % pData.refreshIntervalLoad == 0);
498 refreshing = refreshing
499 || (pData.haveToRefreshTSSolar && (y % pData.refreshIntervalSolar == 0));
500 refreshing = refreshing
501 || (pData.haveToRefreshTSWind && (y % pData.refreshIntervalWind == 0));
502 refreshing = refreshing
503 || (pData.haveToRefreshTSHydro && (y % pData.refreshIntervalHydro == 0));
507 bool haveToRefreshTSThermal = pData.haveToRefreshTSThermal
508 || study.runtime.thermalTSRefresh;
509 refreshing = refreshing
510 || (haveToRefreshTSThermal && (y % pData.refreshIntervalThermal == 0));
518 buildNewSet = buildNewSet || refreshing;
522 setOfParallelYears setToCreate;
523 setsOfParallelYears.push_back(setToCreate);
524 set = &(setsOfParallelYears.back());
527 set->nbPerformedYears = 0;
529 set->regenerateTS =
false;
530 set->yearForTSgeneration = 999999;
536 set->regenerateTS =
true;
537 set->yearForTSgeneration = y;
541 set->yearsIndices.push_back(y);
543 set->yearFailed[y] =
true;
544 set->isFirstPerformedYearOfASet[y] =
false;
546 if (performCalculations)
549 ++pNbYearsReallyPerformed;
552 set->nbPerformedYears++;
554 indexSpace = set->nbPerformedYears - 1;
556 set->isYearPerformed[y] =
true;
557 set->performedYearToSpace[y] = indexSpace;
558 set->spaceToPerformedYear[indexSpace] = y;
560 if (!foundFirstPerformedYearOfCurrentSet)
562 set->isFirstPerformedYearOfASet[y] =
true;
563 foundFirstPerformedYearOfCurrentSet =
true;
568 set->isYearPerformed[y] =
false;
572 if (indexSpace == pNbMaxPerformedYearsInParallel - 1 || y == endYear - 1)
575 foundFirstPerformedYearOfCurrentSet =
false;
576 if (set->nbPerformedYears > maxNbYearsPerformed)
578 maxNbYearsPerformed = set->nbPerformedYears;
588 return maxNbYearsPerformed;
591template<
class ImplementationType>
592void ISimulation<ImplementationType>::allocateMemoryForRandomNumbers(
593 randomNumbers& randomForParallelYears)
595 uint maxNbPerformedYears = randomForParallelYears.pMaxNbPerformedYears;
596 uint nbAreas = study.areas.size();
598 for (uint y = 0; y < maxNbPerformedYears; y++)
601 randomForParallelYears.pYears[y].setNbAreas(nbAreas);
602 randomForParallelYears.pYears[y].pNbClustersByArea.resize(nbAreas);
605 randomForParallelYears.pYears[y].pThermalNoisesByArea.resize(nbAreas);
607 for (uint a = 0; a != nbAreas; ++a)
610 auto& area = *(study.areas.byIndex[a]);
611 size_t nbClusters = area.thermal.list.allClustersCount();
612 randomForParallelYears.pYears[y].pThermalNoisesByArea[a].resize(nbClusters);
613 randomForParallelYears.pYears[y].pNbClustersByArea[a] = nbClusters;
617 randomForParallelYears.pYears[y].pReservoirLevels.resize(nbAreas);
620 randomForParallelYears.pYears[y].pUnsuppliedEnergy.resize(nbAreas);
621 randomForParallelYears.pYears[y].pSpilledEnergy.resize(nbAreas);
624 switch (study.parameters.power.fluctuations)
626 case Data::lssFreeModulations:
628 randomForParallelYears.pYears[y].pHydroCostsByArea_freeMod.resize(nbAreas);
629 for (uint a = 0; a != nbAreas; ++a)
631 randomForParallelYears.pYears[y].pHydroCostsByArea_freeMod[a].resize(8784);
635 case Data::lssMinimizeRamping:
636 case Data::lssMinimizeExcursions:
638 randomForParallelYears.pYears[y].pHydroCosts_rampingOrExcursion.resize(nbAreas);
641 case Data::lssUnknown:
643 logs.error() <<
"Power fluctuation unknown";
650template<
class ImplementationType>
651void ISimulation<ImplementationType>::computeRandomNumbers(
652 randomNumbers& randomForYears,
653 std::vector<uint>& years,
654 std::map<unsigned int, bool>& isYearPerformed,
658 std::vector<unsigned int>::iterator ity;
660 for (ity = years.begin(); ity != years.end(); ++ity)
663 bool isPerformed = isYearPerformed[y];
666 randomForYears.yearNumberToIndex[y] = indexYear;
670 const unsigned int nbAreas = study.areas.size();
673 for (
unsigned int a = 0; a != nbAreas; ++a)
676 const auto& area = *(study.areas.byIndex[a]);
678 for (
auto& cluster: area.thermal.list.all())
680 uint clusterIndex = cluster->areaWideIndex;
681 double thermalNoise = study.runtime.random[Data::seedThermalCosts].next();
684 randomForYears.pYears[indexYear].pThermalNoisesByArea[a][clusterIndex]
693 [&areaIndex, &indexYear, &randomForYears, &randomHydroGenerator, &y, &isPerformed,
this](
704 int initResLevelOnMonth = area.hydro.initializeReservoirLevelDate;
707 int initResLevelOnSimMonth = study.calendar.mapping.months[initResLevelOnMonth];
710 int firstDayOfMonth = study.calendar.months[initResLevelOnSimMonth].daysYear.first;
712 double randomLevel = randomReservoirLevel(min[firstDayOfMonth],
713 avg[firstDayOfMonth],
714 max[firstDayOfMonth],
715 randomHydroGenerator);
718 if (study.parameters.useCustomScenario)
720 double levelFromScenarioBuilder = study.scenarioInitialHydroLevels[areaIndex][y];
721 if (levelFromScenarioBuilder >= 0.)
723 randomLevel = levelFromScenarioBuilder;
732 randomForYears.pYears[indexYear].pReservoirLevels[areaIndex] = randomLevel;
740 auto& randomUnsupplied = study.runtime.random[Data::seedUnsuppliedEnergyCosts];
741 auto& randomSpilled = study.runtime.random[Data::seedSpilledEnergyCosts];
743 int currentSpilledEnergySeed = study.parameters.seed[Data::seedSpilledEnergyCosts];
744 int defaultSpilledEnergySeed = Data::antaresSeedDefaultValue
745 + Data::seedSpilledEnergyCosts * Data::antaresSeedIncrement;
746 bool SpilledEnergySeedIsDefault = (currentSpilledEnergySeed == defaultSpilledEnergySeed);
755 &SpilledEnergySeedIsDefault](
Data::Area& area)
760 double randomNumber = randomUnsupplied();
761 randomForYears.pYears[indexYear].pUnsuppliedEnergy[areaIndex] = randomNumber;
762 randomForYears.pYears[indexYear].pSpilledEnergy[areaIndex] = randomNumber;
763 if (!SpilledEnergySeedIsDefault)
765 randomForYears.pYears[indexYear].pSpilledEnergy[areaIndex] = randomSpilled();
771 if (!SpilledEnergySeedIsDefault)
781 auto& randomHydro = study.runtime.random[Data::seedHydroCosts];
783 Data::PowerFluctuations powerFluctuations = study.parameters.power.fluctuations;
784 switch (powerFluctuations)
786 case Data::lssFreeModulations:
789 auto end = study.areas.end();
795 for (
auto i = study.areas.begin(); i != end; ++i)
797 auto& noise = randomForYears.pYears[indexYear]
798 .pHydroCostsByArea_freeMod[areaIndex];
799 std::set<hydroCostNoise, compareHydroCostsNoises> setHydroCostsNoises;
800 for (uint j = 0; j != 8784; ++j)
802 noise[j] = randomHydro();
807 setHydroCostsNoises.insert(hydroCostNoise(noise[j], j));
811 std::set<hydroCostNoise, compareHydroCostsNoises>::iterator it;
812 for (it = setHydroCostsNoises.begin(); it != setHydroCostsNoises.end(); it++)
814 uint index = it->getIndex();
815 double value = it->getValue();
819 noise[index] = -5 * 1.e-4 * (1 + rank / 8784.);
823 noise[index] = 5 * 1.e-4 * (1 + rank / 8784.);
834 for (
auto i = study.areas.begin(); i != end; ++i)
836 for (uint j = 0; j != 8784; ++j)
846 case Data::lssMinimizeRamping:
847 case Data::lssMinimizeExcursions:
850 auto end = study.areas.end();
851 for (
auto i = study.areas.begin(); i != end; ++i)
855 randomForYears.pYears[indexYear].pHydroCosts_rampingOrExcursion[areaIndex]
868 case Data::lssUnknown:
870 logs.error() <<
"Power fluctuation unknown";
884template<
class ImplementationType>
885void ISimulation<ImplementationType>::computeAnnualCostsStatistics(
886 std::vector<Variable::State>& state,
887 setOfParallelYears& batch)
890 for (
auto y: batch.yearsIndices)
892 if (batch.isYearPerformed[y])
895 uint numSpace = batch.performedYearToSpace[y];
896 const Variable::State& s = state[numSpace];
897 pAnnualStatistics.systemCost.addCost(s.annualSystemCost);
898 pAnnualStatistics.criterionCost1.addCost(s.optimalSolutionCost1);
899 pAnnualStatistics.criterionCost2.addCost(s.optimalSolutionCost2);
900 pAnnualStatistics.optimizationTime1.addCost(s.averageOptimizationTime1);
901 pAnnualStatistics.optimizationTime2.addCost(s.averageOptimizationTime2);
902 pAnnualStatistics.updateTime.addCost(s.averageUpdateTime);
907static inline void logPerformedYearsInAset(setOfParallelYears& set)
909 logs.info() <<
"parallel batch size : " << set.nbYears <<
" (" << set.nbPerformedYears
912 std::string performedYearsToLog =
"";
914 std::ranges::for_each(set.yearsIndices,
915 [&set, &performedYearsToLog](
const uint& y)
917 if (set.isYearPerformed[y])
919 performedYearsToLog += std::to_string(y + 1) +
" ";
923 logs.info() <<
"Year(s) " << performedYearsToLog;
926template<
class ImplementationType>
927void ISimulation<ImplementationType>::loopThroughYears(uint firstYear,
929 std::vector<Variable::State>& state)
931 assert(endYear <= study.parameters.nbYears);
935 randomHydroGenerator.
reset(study.parameters.seed[Data::seedHydroManagement]);
938 std::vector<setOfParallelYears> setsOfParallelYears;
944 uint maxNbYearsPerformedInAset = buildSetsOfParallelYears(firstYear,
946 setsOfParallelYears);
948 pAnnualStatistics.setNbPerformedYears(pNbYearsReallyPerformed);
951 randomNumbers randomForParallelYears(maxNbYearsPerformedInAset,
952 study.parameters.power.fluctuations);
955 allocateMemoryForRandomNumbers(randomForParallelYears);
958 pQueueService->maximumThreadCount(pNbMaxPerformedYearsInParallel);
961 logs.info() <<
" Doing hydro validation";
964 for (
const auto& batch: setsOfParallelYears)
966 if (batch.regenerateTS)
970 for (
auto year: batch.yearsIndices)
972 hydroInputsChecker.Execute(year);
975 hydroInputsChecker.CheckForErrors();
977 logs.info() <<
" Starting the simulation";
980 for (
auto& batch: setsOfParallelYears)
985 if (batch.regenerateTS)
987 regenerateTimeSeries(batch.yearForTSgeneration);
989 computeRandomNumbers(randomForParallelYears,
991 batch.isYearPerformed,
992 randomHydroGenerator);
994 bool yearPerformed =
false;
996 for (
auto y: batch.yearsIndices)
999 hydroInputsChecker.Execute(y);
1000 hydroInputsChecker.CheckForErrors();
1002 bool performCalculations = batch.isYearPerformed[y];
1003 unsigned int numSpace = 999999;
1004 if (performCalculations)
1006 yearPerformed =
true;
1007 numSpace = batch.performedYearToSpace[y];
1015 auto task = std::make_shared<yearJob<ImplementationType>>(
1019 batch.isFirstPerformedYearOfASet,
1020 pFirstSetParallelWithAPerformedYearWasRun,
1022 randomForParallelYears,
1023 performCalculations,
1029 simulationObserver_.get());
1030 results.
add(Concurrency::AddTask(*pQueueService, task));
1033 logPerformedYearsInAset(batch);
1035 pQueueService->start();
1037 pQueueService->wait(Yuni::qseIdle);
1038 pQueueService->stop();
1040 pResultWriter.flush();
1044 if (!pFirstSetParallelWithAPerformedYearWasRun && yearPerformed)
1046 pFirstSetParallelWithAPerformedYearWasRun =
true;
1050 for (
auto& [year, failed]: batch.yearFailed)
1055 std::ostringstream msg;
1056 msg <<
"Year " << year + 1 <<
" has failed in the previous set of parallel year.";
1062 ImplementationType::variables.computeSummary(batch.spaceToPerformedYear,
1063 batch.nbPerformedYears);
1066 ImplementationType::variables.computeSpatialAggregatesSummary(ImplementationType::variables,
1067 batch.spaceToPerformedYear,
1068 batch.nbPerformedYears);
1072 computeAnnualCostsStatistics(state, batch);
1075 randomForParallelYears.reset();
1080 pAnnualStatistics.endStandardDeviations();
1081 pAnnualStatistics.writeToOutput(pResultWriter);