Antares Simulator
Power System Simulator
reportbuilder.hxx
1 /*
2  * Copyright 2007-2025, RTE (https://www.rte-france.com)
3  * See AUTHORS.txt
4  * SPDX-License-Identifier: MPL-2.0
5  * This file is part of Antares-Simulator,
6  * Adequacy and Performance assessment for interconnected energy networks.
7  *
8  * Antares_Simulator is free software: you can redistribute it and/or modify
9  * it under the terms of the Mozilla Public Licence 2.0 as published by
10  * the Mozilla Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * Antares_Simulator is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * Mozilla Public Licence 2.0 for more details.
17  *
18  * You should have received a copy of the Mozilla Public Licence 2.0
19  * along with Antares_Simulator. If not, see <https://opensource.org/license/mpl-2-0/>.
20  */
21 #ifndef __SOLVER_VARIABLE_SURVEYRESULTS_REPORT_BUILDER_HXX__
22 #define __SOLVER_VARIABLE_SURVEYRESULTS_REPORT_BUILDER_HXX__
23 
24 #include <limits>
25 
26 #include <yuni/yuni.h>
27 #include <yuni/core/static/types.h>
28 #include <yuni/core/string.h>
29 #include <yuni/io/directory.h>
30 
31 #include <antares/logs/logs.h>
32 #include <antares/study/filter.h>
33 
34 #include "../categories.h"
35 #include "../endoflist.h"
36 #include "../info.h"
37 #include "../surveyresults.h"
38 
39 namespace Antares::Solver::Variable::Container
40 {
41 namespace // anonymous
42 {
43 template<class NextT, int CDataLevel, int CFile = 1>
44 struct VariablesStatsByDataLevel
45 {
46  enum
47  {
48  nextFileLevel = (CFile * 2 > (int)Category::FileLevel::maxFileLevel) ? 1 : CFile * 2,
49  currentVariableCount = NextT::template Statistics < CDataLevel,
50  CFile > ::count,
51  nextVariableCount = VariablesStatsByDataLevel < NextT,
52  CDataLevel,
53  nextFileLevel > ::count,
54 
56  count = (int)currentVariableCount + (int)nextVariableCount,
57  };
58 };
59 
60 template<class NextT, int CDataLevel>
61 struct VariablesStatsByDataLevel<NextT, CDataLevel, Category::FileLevel::maxFileLevel>
62 {
63  enum
64  {
65  count = 0,
66  };
67 };
68 
69 template<class NextT, int CDataLevel = 1, int CFile = 1>
70 struct BrowseAllVariables
71 {
72  enum
73  {
74  nextFileLevel = (CFile * 2 > (int)Category::FileLevel::maxFileLevel) ? 1 : CFile * 2,
75  nextDataLevel = (CDataLevel * 2 > (int)Category::DataLevel::maxDataLevel) ? 1
76  : CDataLevel * 2,
77  currentValue = NextT::template Statistics < CDataLevel,
78  CFile > ::count,
79  nextValue = BrowseAllVariables < NextT,
80  nextDataLevel,
81  nextFileLevel > ::maxValue,
82 
83  maxValue = (currentValue > (int)nextValue) ? currentValue : (int)nextValue,
84  };
85 
86  template<class L, class S>
87  static void buildSurveyResults(const L& list, S& results)
88  {
89  // Exporting data for the current state
90  list.template buildSurveyResults<S, CDataLevel, CFile>(results);
91  // Go to the next status
92  BrowseAllVariables<NextT, nextDataLevel, nextFileLevel>::template buildSurveyResults<L, S>(
93  list,
94  results);
95  }
96 };
97 
98 template<class NextT>
99 struct BrowseAllVariables<NextT,
100  Category::DataLevel::maxDataLevel,
101  Category::FileLevel::maxFileLevel>
102 {
103  enum
104  {
105  maxValue = NextT::template Statistics < Category::DataLevel::maxDataLevel,
106  Category::FileLevel::maxFileLevel > ::count
107  };
108 
109  template<class L, class S>
110  static void buildSurveyResults(const L& list, S& results)
111  {
112  // Exporting data for the current state
113  list.template buildSurveyResults<S,
114  Category::DataLevel::maxDataLevel,
115  Category::FileLevel::maxFileLevel>(results);
116  // This is the final available state
117  }
118 };
119 
120 template<bool GlobalT, class NextT, int CDataLevel, int CFile = 1>
121 class SurveyReportBuilderFile
122 {
123 public:
124  using ListType = NextT;
125 
126  enum
127  {
129  globalResults = (GlobalT) ? 1 : 0,
131  nextFileLevel = CFile * 2,
132  };
133 
134  static void Run(const ListType& list, SurveyResults& results, unsigned int numSpace)
135  {
136  if (globalResults)
137  {
138  RunGlobalResults(list, results);
139  }
140  else
141  {
142  RunAnnual(list, results, numSpace);
143  }
144 
145  // The survey type
146  using SurveyRBFileType = SurveyReportBuilderFile<GlobalT, NextT, CDataLevel, nextFileLevel>;
147  // Go to the next data level
148  SurveyRBFileType::Run(list, results, numSpace);
149  }
150 
151 private:
152  static void RunGlobalResults(const ListType& list, SurveyResults& results)
153  {
154  // All hours
155  list.buildSurveyReport(results, CDataLevel, CFile, Category::hourly);
156  // All days
157  list.buildSurveyReport(results, CDataLevel, CFile, Category::daily);
158  // All weeks
159  list.buildSurveyReport(results, CDataLevel, CFile, Category::weekly);
160  // All months
161  list.buildSurveyReport(results, CDataLevel, CFile, Category::monthly);
162  // All years
163  list.buildSurveyReport(results, CDataLevel, CFile, Category::annual);
164  }
165 
166  static void RunAnnual(const ListType& list, SurveyResults& results, unsigned int numSpace)
167  {
168  // All hours
169  list.buildAnnualSurveyReport(results, CDataLevel, CFile, Category::hourly, numSpace);
170  // All days
171  list.buildAnnualSurveyReport(results, CDataLevel, CFile, Category::daily, numSpace);
172  // All weeks
173  list.buildAnnualSurveyReport(results, CDataLevel, CFile, Category::weekly, numSpace);
174  // All months
175  list.buildAnnualSurveyReport(results, CDataLevel, CFile, Category::monthly, numSpace);
176  // All years
177  list.buildAnnualSurveyReport(results, CDataLevel, CFile, Category::annual, numSpace);
178  }
179 
180 }; // class SurveyReportBuilderFile
181 
182 // Specialization for the final state (dummy)
183 template<bool GlobalT, class NextT, int N>
184 class SurveyReportBuilderFile<GlobalT, NextT, N, 2 * Category::FileLevel::maxFileLevel>
185 {
186 public:
187  using ListType = NextT;
188 
189  // dead end
190  static inline void Run(const ListType&, SurveyResults&, unsigned int)
191  {
192  }
193 };
194 
195 template<bool GlobalT, class NextT, int CDataLevel = 1>
196 class SurveyReportBuilder
197 {
198 public:
200  using ListType = NextT;
201 
202  enum
203  {
204  nextDataLevel = CDataLevel * 2,
205  };
206 
207  static void Run(const ListType& list, SurveyResults& results, unsigned int numSpace = 9999)
208  {
209  // Area - Thermal clusters - Links
210  if (CDataLevel & Category::DataLevel::area || CDataLevel & Category::DataLevel::link
211  || CDataLevel & Category::DataLevel::thermalAggregate)
212  {
213  RunForEachArea(list, results, numSpace);
214  }
215 
216  // Set of Areas
217  if (CDataLevel & Category::DataLevel::setOfAreas)
218  {
219  RunForEachSetOfAreas(list, results, numSpace);
220  }
221 
222  // Binding constraints level
223  if (CDataLevel & Category::DataLevel::bindingConstraint)
224  {
225  RunForEachBindingConstraint(list, results, numSpace);
226  }
227 
228  // Go to the next data level
229  SurveyReportBuilder<GlobalT, NextT, nextDataLevel>::Run(list, results, numSpace);
230  }
231 
232  static void RunDigest(const ListType& list, SurveyResults& results, IResultWriter& writer)
233  {
234  logs.info() << "Exporting digest...";
235  logs.debug() << " . Digest, truncating file";
236  // Digest: Summary for All years
237  logs.debug() << " . Digest, annual";
238 
239  // Digest file : areas part
240  std::string digestBuffer;
241  list.buildDigest(results, Category::digestAllYears, Category::DataLevel::area);
242  results.exportDigestAllYears(digestBuffer);
243 
244  // Degest file : districts part
245  list.buildDigest(results, Category::digestAllYears, Category::DataLevel::setOfAreas);
246  results.exportDigestAllYears(digestBuffer);
247 
248  // Digest: Flow linear (only if selected by user)
249  if (results.data.study.parameters.variablesPrintInfo.isPrinted("FLOW LIN."))
250  {
251  logs.debug() << " . Digest, flow linear";
252  results.data.matrix.fill(std::numeric_limits<double>::quiet_NaN());
253  list.buildDigest(results, Category::digestFlowLinear, Category::DataLevel::area);
254  results.exportDigestMatrix("Links (FLOW LIN.)", digestBuffer);
255  }
256 
257  // Digest: Flow Quad (only if selected by user)
258  if (results.data.study.parameters.variablesPrintInfo.isPrinted("FLOW QUAD."))
259  {
260  logs.debug() << " . Digest, flow quad";
261  results.data.matrix.fill(std::numeric_limits<double>::quiet_NaN());
262  list.buildDigest(results, Category::digestFlowQuad, Category::DataLevel::area);
263  results.exportDigestMatrix("Links (FLOW QUAD.)", digestBuffer);
264  }
265  // THIS FILE IS DEPRECATED !!!
266  YString digestFileName;
267  std::filesystem::path path = static_cast<std::string>(results.data.originalOutput);
268  path /= "grid";
269  path /= "digest.txt";
270  writer.addEntryFromBuffer(path, digestBuffer);
271  }
272 
273 private:
274  static void RunForEachArea(const ListType& list, SurveyResults& results, unsigned int numSpace)
275  {
276  using namespace Yuni;
277 
278  // No need to do anything for any area here if no zonal variables were selected.
279  uint selectedZonalVarsCount = results.data.study.parameters.variablesPrintInfo
280  .getNbSelectedZonalVars();
281 
282  // All values related to an area
283  // Note: A thermal cluster is attached to an area
284  auto end = results.data.study.areas.end();
285  for (auto i = results.data.study.areas.begin(); i != end; ++i)
286  {
287  auto& area = *(i->second);
288  // Alias to the current area
289  results.data.area = &area;
290  // No thermal cluster for now
291  results.data.thermalCluster = nullptr;
292  // No link for now
293  results.data.link = nullptr;
294 
295  // Skipping the creation of a result directory if it is meant to be empty.
296  // ... Getting few indicators value before deciding if we skip the results directory
297  // creation.
298  bool printingSynthesis = GlobalT; // Are we printing synthesis or year-by-year results ?
299  bool filterAllYearByYear = !(area.filterYearByYear & Data::filterAll);
300  bool filterAllSynthesis = !(area.filterSynthesis & Data::filterAll);
301 
302  // ... Do we skip the current area's result directory creation because no results were
303  // asked
304  // in the inspector for the current area ?
305  bool skipDirectory = (!printingSynthesis && filterAllYearByYear)
306  || (printingSynthesis && filterAllSynthesis);
307 
308  // ... Or do we skip the current area's result directory creation because no zonal
309  // variables were selected ?
310  skipDirectory = skipDirectory || !selectedZonalVarsCount;
311 
312  // Generating the report for each area
313  if (CDataLevel & Category::DataLevel::area && !skipDirectory)
314  {
315  logs.info() << "Exporting results : " << area.name;
316  // The new output
317  std::filesystem::path path = static_cast<std::string>(results.data.originalOutput);
318  path /= "areas";
319  path /= area.id.to<std::string>();
320 
321  results.data.output = path.string();
322  SurveyReportBuilderFile<GlobalT, NextT, CDataLevel>::Run(list, results, numSpace);
323  }
324 
325  // Thermal clusters for the current area
326  if (CDataLevel & Category::DataLevel::thermalAggregate)
327  {
328  RunForEachThermalCluster(list, results, numSpace);
329  }
330  // Links
331  if (CDataLevel & Category::DataLevel::link && !area.links.empty())
332  {
333  RunForEachLink(list, results, numSpace);
334  }
335  }
336  }
337 
338  static void RunForEachThermalCluster(const ListType& list,
339  SurveyResults& results,
340  unsigned int numSpace)
341  {
342  // Only do something if there is at least one column to write somewhere
343  // See below: if (CDataLevel & Category::DataLevel::thermalAggregate)
344  if (VariablesStatsByDataLevel<NextT, Category::DataLevel::thermalAggregate>::count)
345  {
346  auto& area = *results.data.area;
347  for (auto& cluster: area.thermal.list.each_enabled_and_not_mustrun())
348  {
349  results.data.thermalCluster = cluster.get();
350 
351  logs.info() << "Exporting results : " << area.name << " :: " << cluster->name();
352  // The new output
353  std::filesystem::path path = static_cast<std::string>(results.data.originalOutput);
354  path /= std::filesystem::path("areas") / area.id.to<std::string>() / "thermal"
355  / cluster->id();
356 
357  results.data.output = path.string();
358 
359  SurveyReportBuilderFile<GlobalT, NextT, CDataLevel>::Run(list, results, numSpace);
360  }
361  }
362  }
363 
364  static void RunForEachLink(const ListType& list, SurveyResults& results, unsigned int numSpace)
365  {
366  using namespace Yuni;
367 
368  // No need to do anything for any link here if no link variables were selected.
369  uint selectedLinkVarsCount = results.data.study.parameters.variablesPrintInfo
370  .getNbSelectedLinkVars();
371  if (!selectedLinkVarsCount)
372  {
373  return;
374  }
375 
376  int count_int = VariablesStatsByDataLevel<NextT, Category::DataLevel::link>::count;
377  if (count_int)
378  {
379  auto& area = *results.data.area;
380  auto end = area.links.end();
381  for (auto i = area.links.begin(); i != end; ++i)
382  {
383  // The link
384  auto& link = *(i->second);
385  results.data.link = &link;
386 
387  // Skipping the creation of a result directory if it is meant to be empty.
388  // ... Getting few indicators value before deciding if we skip the results directory
389  // creation.
390  bool printingSynthesis = GlobalT; // Are we printing synthesis or year-by-year
391  // results ?
392  bool filterAllYearByYear = !(link.filterYearByYear & Data::filterAll);
393  bool filterAllSynthesis = !(link.filterSynthesis & Data::filterAll);
394 
395  // ... Do we skip the current link's result directory creation because no results
396  // were asked
397  // in the inspector for the current link ?
398  bool skipDirectory = (!printingSynthesis && filterAllYearByYear)
399  || (printingSynthesis && filterAllSynthesis);
400 
401  if (!skipDirectory)
402  {
403  Antares::logs.info() << "Exporting results : " << area.name << " - "
404  << results.data.link->with->name;
405  // The new output
406  std::filesystem::path path = static_cast<std::string>(
407  results.data.originalOutput);
408  std::string areaId = static_cast<std::string>(area.id) + " - "
409  + results.data.link->with->id;
410  path /= std::filesystem::path("links") / areaId;
411 
412  results.data.output = path.string();
413 
414  SurveyReportBuilderFile<GlobalT, NextT, CDataLevel>::Run(list,
415  results,
416  numSpace);
417  }
418  }
419  }
420  }
421 
422  static void RunForEachSetOfAreas(const ListType& list,
423  SurveyResults& results,
424  unsigned int numSpace)
425  {
426  using namespace ::Antares;
427  using namespace ::Yuni;
428 
429  // No need to do anything for any district (set of areas) here if no zonal variables were
430  // selected.
431  uint selectedZonalVarsCount = results.data.study.parameters.variablesPrintInfo
432  .getNbSelectedZonalVars();
433  if (!selectedZonalVarsCount)
434  {
435  return;
436  }
437 
438  results.data.area = nullptr;
439  results.data.thermalCluster = nullptr;
440  results.data.link = nullptr;
441 
442  // alias to the set of sets of areas
443  const Data::Study::SetsOfAreas& sets = results.data.study.setsOfAreas;
444 
445  unsigned int indx = 0;
446  for (unsigned int i = 0; i != sets.size(); ++i)
447  {
448  if (!sets.hasOutput(i) || !sets.resultSize(i))
449  {
450  continue;
451  }
452 
453  logs.info() << "Exporting results : " << sets.caption(i);
454  // The new output
455  std::filesystem::path path = static_cast<std::string>(results.data.originalOutput);
456  std::string setId = "@ " + sets.nameByIndex(i);
457  path /= std::filesystem::path("areas") / setId;
458 
459  results.data.output = path.string();
460  results.data.setOfAreasIndex = indx++;
461 
462  SurveyReportBuilderFile<GlobalT, NextT, CDataLevel>::Run(list, results, numSpace);
463  }
464  }
465 
466  static void RunForEachBindingConstraint(const ListType& list,
467  SurveyResults& results,
468  unsigned int numSpace)
469  {
470  using namespace Yuni;
471 
472  // Generating the report for each binding constraint
473  if (CDataLevel & Category::DataLevel::bindingConstraint)
474  {
475  logs.info() << "Exporting results : binding constraints";
476  // The new output
477  std::filesystem::path path = static_cast<std::string>(results.data.originalOutput);
478  path /= "binding_constraints";
479 
480  results.data.output = path.string();
481  SurveyReportBuilderFile<GlobalT, NextT, CDataLevel>::Run(list, results, numSpace);
482  }
483  }
484 
485 }; // class SurveyReportBuilder
486 
487 template<bool GlobalT, class NextT>
488 class SurveyReportBuilder<GlobalT, NextT, 2 * Category::DataLevel::maxDataLevel>
489 {
490 public:
491  using ListType = NextT;
492 
493  // Dead end
494  static void Run(const ListType&, SurveyResults&, unsigned int)
495  {
496  }
497 };
498 
499 } // Anonymous namespace
500 
501 } // namespace Antares::Solver::Variable::Container
502 
503 #endif // __SOLVER_VARIABLE_SURVEYRESULTS_REPORT_BUILDER_HXX__
Definition: sets.h:40
bool hasOutput(const Yuni::ShortString128 &s) const
Get if the results for a given group should be written to the output.
Definition: sets.cpp:360
uint resultSize(const Yuni::ShortString128 &s) const
Get the size of a result set.
Definition: sets.cpp:371