Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
ArcanePostProcessingModule.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* ArcanePostProcessingModule.cc (C) 2000-2025 */
9/* */
10/* Post-processing module. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/Ptr.h"
15#include "arcane/utils/List.h"
16
17#include "arcane/core/EntryPoint.h"
18#include "arcane/core/ISubDomain.h"
19#include "arcane/core/IVariableMng.h"
20#include "arcane/core/IParallelMng.h"
21#include "arcane/core/ItemGroup.h"
22#include "arcane/core/Directory.h"
23#include "arcane/core/ITimeHistoryMng.h"
24#include "arcane/core/ServiceUtils.h"
25#include "arcane/core/IPostProcessorWriter.h"
26#include "arcane/core/MeshAccessor.h"
27#include "arcane/core/IMesh.h"
28#include "arcane/core/VariableTypes.h"
29#include "arcane/core/CommonVariables.h"
31#include "arcane/core/ITimeLoopMng.h"
33#include "arcane/core/ModuleFactory.h"
34#include "arcane/core/Timer.h"
35#include "arcane/core/VariableCollection.h"
36#include "arcane/core/OutputChecker.h"
37#include "arcane/core/IExternalPlugin.h"
38
39#include "arcane/std/ArcanePostProcessing_axl.h"
40
41#include <set>
42
43/*---------------------------------------------------------------------------*/
44/*---------------------------------------------------------------------------*/
45
46namespace Arcane
47{
48
49/*---------------------------------------------------------------------------*/
50/*---------------------------------------------------------------------------*/
51
61class ArcanePostProcessingModule
62: public ArcaneArcanePostProcessingObject
63{
64 public:
65
66 explicit ArcanePostProcessingModule(const ModuleBuildInfo& mbi);
67 ~ArcanePostProcessingModule() override;
68
69 public:
70
71 VersionInfo versionInfo() const override { return VersionInfo(0, 1, 2); }
72
73 public:
74
75 void exportData() override;
76 void exportDataStart() override;
77
78 void postProcessingStartInit() override;
79 void postProcessingInit() override;
80 void postProcessingExit() override;
81
82 private:
83
84 OutputChecker m_output_checker;
85 OutputChecker m_history_output_checker;
87 bool m_is_output_active = true;
91 bool m_output_dir_created = false;
92 VariableList m_variables;
95 bool m_is_plugin_initialized = false;
96
97 private:
98
99 void _readConfig();
100 void _saveAtTime(Real);
101
102 void _checkCreateOutputDir();
105 void _checkExternalPlugin();
106};
107
108/*---------------------------------------------------------------------------*/
109/*---------------------------------------------------------------------------*/
110
111ARCANE_REGISTER_MODULE_ARCANEPOSTPROCESSING(ArcanePostProcessingModule);
112
113/*---------------------------------------------------------------------------*/
114/*---------------------------------------------------------------------------*/
115
116ArcanePostProcessingModule::
117ArcanePostProcessingModule(const ModuleBuildInfo& mbi)
119, m_output_checker(mbi.subDomain(), "PostProcessing")
120, m_history_output_checker(mbi.subDomain(), "PostProcessingHistory")
121, m_times(VariableBuilder(this, "ExportTimes"))
122{
123 m_output_checker.assignIteration(&m_next_iteration, &options()->outputPeriod);
124 m_output_checker.assignGlobalTime(&m_next_global_time, &options()->outputFrequency);
125
126 m_history_output_checker.assignIteration(&m_history_next_iteration, &options()->outputHistoryPeriod);
127 m_post_processor_timer = new Timer(mbi.subDomain(), "PostProcessorTimer", Timer::TimerReal);
128}
129
130/*---------------------------------------------------------------------------*/
131/*---------------------------------------------------------------------------*/
132
133ArcanePostProcessingModule::
134~ArcanePostProcessingModule()
135{
137}
138
139/*---------------------------------------------------------------------------*/
140/*---------------------------------------------------------------------------*/
141
144{
145 Integer nb_var = options()->output().variable.size();
146 Integer nb_group = options()->output().group.size();
147
148 IVariableMng* var_mng = subDomain()->variableMng();
150
151 if (nb_var != 0) {
152 std::set<String> used_variables; // List of variables already specified
153 m_variables.clear();
154 info() << " ";
155 info() << "-- List of output variables (" << nb_var << " variables):";
156 for (Integer i = 0; i < nb_var; ++i) {
157 String varname(options()->output().variable[i]);
158 IVariable* var = var_mng->findMeshVariable(defaultMesh(), varname);
159 if (!var)
160 ARCANE_FATAL("PostTreatment: no variable with name '{0}' exists", varname);
161 eItemKind ik = var->itemKind();
162 if (ik != IK_Node && ik != IK_Edge && ik != IK_Face && ik != IK_Cell)
163 ARCANE_FATAL("PostTreatment: variable ({0}) must"
164 " be a mesh variable (node, edge, face or cell)",
165 varname);
166
167 if (used_variables.find(varname) == used_variables.end()) {
168 info() << "Variable <" << varname << ">";
169 m_variables.add(var);
170 used_variables.insert(varname);
172 }
173 else {
174 warning() << "Variable <" << varname << "> required twice during post-processing analysis";
175 }
176 }
177 }
178 else
179 m_is_output_active = false;
180
181 if (nb_group != 0) {
182 std::set<String> used_groups; // List of groups already specified
183 //m_group_list.resize(nb_group);
184 info() << " ";
185 info() << "-- List of output groups (" << nb_group << " groups):";
186 for (Integer i = 0; i < nb_group; ++i) {
187 ItemGroup group = options()->output().group[i];
188 if (group.null())
189 continue;
190 String groupname = group.name();
191 if (used_groups.find(groupname) == used_groups.end()) {
192 info() << "Group <" << groupname << ">";
193 used_groups.insert(groupname);
194 m_groups.add(group);
195 }
196 else
197 warning() << "Group <" << groupname << "> required twice during post-processing analysis";
198 }
199 //m_group_list.resize(index);
200 }
201 else {
202 // If no group is specified, only save the entire cell.
203 //m_groups.resize(1);
204
206 if (mesh->isAmrActivated())
207 m_groups.add(mesh->allActiveCells());
208 else
209 m_groups.add(mesh->allCells());
210 }
211}
212
213/*---------------------------------------------------------------------------*/
214/*---------------------------------------------------------------------------*/
215
216void ArcanePostProcessingModule::
217_checkCreateOutputDir()
218{
220 return;
221 m_output_directory = Directory(subDomain()->exportDirectory(), "depouillement");
224}
225
226/*---------------------------------------------------------------------------*/
227/*---------------------------------------------------------------------------*/
228
229void ArcanePostProcessingModule::
230postProcessingInit()
231{
232 info() << " -------------------------------------------";
233 info() << "| POST PROCESSING |";
234 info() << " -------------------------------------------";
235 info() << " ";
236
237 bool is_continue = subDomain()->isContinue();
238
239 info() << "Variables output:";
240 m_output_checker.initialize(is_continue);
241
242 info() << "History output:";
243 m_history_output_checker.initialize(is_continue);
244
245 _readConfig();
246
247 // Positioning of the 'shrink' option of timeHistoryMng from the axl
248 if (options()->outputHistoryShrink)
249 subDomain()->timeHistoryMng()->setShrinkActive(options()->outputHistoryShrink);
250
251 // initialize parameter with a dry call to checker
253 const Real old_time = vc.globalOldTime();
254 const Real current_time = vc.globalTime();
255 m_output_checker.check(old_time, current_time, vc.globalIteration(), 0);
256 m_history_output_checker.check(old_time, current_time, vc.globalIteration(), 0);
257
258 if (options()->saveInit())
259 _saveAtTime(current_time);
260}
261
262/*---------------------------------------------------------------------------*/
263/*---------------------------------------------------------------------------*/
264
265void ArcanePostProcessingModule::
266postProcessingStartInit()
267{
268 m_next_global_time = 0.0;
270 m_curves_next_global_time = 0.0;
271 m_curves_next_iteration = 0;
272 m_history_next_iteration = 0;
273}
274
275/*---------------------------------------------------------------------------*/
276/*---------------------------------------------------------------------------*/
277
288{
289 const Real current_time = subDomain()->commonVariables().globalTime();
290 bool save_at_exit = false;
291 if (subDomain()->timeLoopMng()->finalTimeReached())
292 save_at_exit = options()->saveFinalTime();
293 if (!save_at_exit)
294 save_at_exit = options()->endExecutionOutput();
295 if (save_at_exit) {
296 _saveAtTime(current_time);
297 }
298
299 // Displays execution statistics
300 Real total_time = m_post_processor_timer->totalTime();
301 info() << "Total time for post-processing analysis output (second): " << total_time;
302 Integer nb_time = m_post_processor_timer->nbActivated();
303 if (nb_time != 0)
304 info() << "Average time per output (second): " << total_time / nb_time
305 << " (for " << nb_time << " outputs";
306 IPostProcessorWriter* post_processor = options()->format();
307 if (post_processor)
308 post_processor->close();
309}
310
311/*---------------------------------------------------------------------------*/
312/*---------------------------------------------------------------------------*/
313
319{
321 const Real current_time = subDomain()->commonVariables().globalTime();
322 _saveAtTime(current_time);
323 }
324}
325
326/*---------------------------------------------------------------------------*/
327/*---------------------------------------------------------------------------*/
328
334{
335 ISubDomain* sd = subDomain();
336 const CommonVariables& vc = sd->commonVariables();
337
338 const Int32 global_iteration = vc.globalIteration();
339 // Writes the post-processing values for initialization.
340 if (global_iteration == 0)
341 _saveAtTime(0.0);
342
344
345 // Checks if history should be activated for this iteration
346 const Real old_time = vc.globalOldTime();
347 const Real current_time = vc.globalTime();
348 bool do_history_output = m_history_output_checker.check(old_time, current_time, global_iteration, 0);
349 sd->timeHistoryMng()->setActive(do_history_output);
350
351 // Checks if post-processing outputs are planned for this iteration
352 if (m_is_output_active) {
353 bool do_at_current_iteration = m_output_checker.check(old_time, current_time, global_iteration, 0);
354 if (do_at_current_iteration)
356 }
357}
358
359/*---------------------------------------------------------------------------*/
360/*---------------------------------------------------------------------------*/
361
362void ArcanePostProcessingModule::
363_saveAtTime(Real saved_time)
364{
366
367 const Int32 size = m_times.size();
368
370
371 // Does not save if the current time is the same as the previous one
372 // (Otherwise, Ensight crashes...)
373 if (size != 0 && math::isEqual(m_times[size - 1], saved_time))
374 return;
375
376 m_times.resize(size + 1);
377 m_times[size] = saved_time;
378
379 _checkCreateOutputDir();
380
381 if (m_is_output_active) {
382 IPostProcessorWriter* post_processor = options()->format();
384 post_processor->setTimes(m_times);
385 post_processor->setVariables(m_variables);
386 post_processor->setGroups(m_groups);
387 info() << " ";
388 info() << "**** Output in progress at time " << saved_time << " ******";
389
390 {
392 _checkExternalPlugin();
393 vm->writePostProcessing(post_processor);
394 }
395 }
396}
397
398/*---------------------------------------------------------------------------*/
399/*---------------------------------------------------------------------------*/
400
406{
408 for (VariableList::Enumerator v_iter(m_variables); ++v_iter;) {
409 IVariable* v = *v_iter;
411 }
412}
413
414/*---------------------------------------------------------------------------*/
415/*---------------------------------------------------------------------------*/
416
422{
424 for (VariableList::Enumerator v_iter(m_variables); ++v_iter;) {
425 IVariable* v = *v_iter;
427 }
428}
429
430/*---------------------------------------------------------------------------*/
431/*---------------------------------------------------------------------------*/
432
433void ArcanePostProcessingModule::
434_checkExternalPlugin()
435{
436 // Experimental mode to use a python function.
437 // The C# wrapper must be active and the 'pythonnet' module must be installed.
438 auto& plugin_option = options()->experimentalPythonPlugin;
439 if (!plugin_option.isPresent())
440 return;
441 IExternalPlugin* p = plugin_option.externalPlugin();
442 String function = plugin_option.functionName();
443 info() << "Executing Python function '" << function << "'";
444 if (!m_is_plugin_initialized) {
445 info() << "Initializing Python environment";
446 p->loadFile(String{});
447 m_is_plugin_initialized = true;
448 }
449 p->executeContextFunction(function);
450}
451
452/*---------------------------------------------------------------------------*/
453/*---------------------------------------------------------------------------*/
454
455} // End namespace Arcane
456
457/*---------------------------------------------------------------------------*/
458/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Types and macros for iterating over mesh entities.
Various mathematical functions.
Generation de la classe de base du Module.
CaseOptionsArcanePostProcessing * options() const
Options du jeu de données du module.
Arcane::VariableScalarInteger m_next_iteration
Variables du module.
ISubDomain * subDomain() const override
Sub-domain associated with the module.
IMesh * defaultMesh() const override
Default mesh for this module.
Output module for post-processing.
Timer * m_post_processor_timer
Timer for time spent writing.
bool m_output_dir_created
true if directory created.
VariableArrayReal m_times
Time points of saves.
void _markCurrentIterationPostProcessing()
Marks variables as post-processed during this iteration.
VariableList m_variables
List of variables to export.
bool m_is_output_at_current_iteration
Indicates if outputs are performed during this iteration.
void _resetCurrentIterationPostProcessing()
Removes tags from variables post-processed during this iteration.
void exportData() override
Checks and writes the values for post-processing.
void postProcessingExit() override
Post-processing information at the end of the calculation loop.
ItemGroupList m_groups
List of groups to export.
void exportDataStart() override
Entry point at the beginning of an iteration.
VersionInfo versionInfo() const override
Module version.
constexpr Integer size() const noexcept
Returns the size of the array.
Common variables of a case.
Real globalTime() const
Current time.
Int32 globalIteration() const
Current iteration number.
CommonVariables(IModule *c)
Constructs the references of the common variables for the module c.
Real globalOldTime() const
Previous current time.
Class managing a directory.
Definition Directory.h:36
bool createDirectory() const override
Creates the directory.
Definition Directory.cc:102
String path() const override
Returns the path of the directory.
Definition Directory.cc:111
Interface for external service loading.
virtual void executeContextFunction(const String &function_name)=0
Executes the function function_name with a context.
virtual void loadFile(const String &filename)=0
Loads and executes a file containing an external script.
Interface for a writer for post-processing information.
virtual void setVariables(VariableCollection variables)=0
Positions the list of variables to output.
virtual void close()=0
Closes the writer. After closing, it can no longer be used.
virtual void setGroups(ItemGroupCollection groups)=0
Positions the list of groups to output.
virtual void setBaseDirectoryName(const String &dirname)=0
Positions the output directory name for files.
virtual void setTimes(ConstArrayView< Real > times)=0
Positions the list of times.
Interface of the subdomain manager.
Definition ISubDomain.h:75
virtual const CommonVariables & commonVariables() const =0
Information on standard variables.
virtual IMesh * defaultMesh()=0
Default mesh.
virtual bool isContinue() const =0
True if a restart is being performed, false otherwise.
virtual ITimeHistoryMng * timeHistoryMng()=0
Returns the history manager.
virtual IVariableMng * variableMng()=0
Returns the variable manager.
virtual void setShrinkActive(bool is_active)=0
Sets the boolean indicating if the history is compressed.
virtual void setActive(bool is_active)=0
Sets the activation status.
Variable manager interface.
virtual IVariable * findMeshVariable(IMesh *mesh, const String &name)=0
Returns the mesh variable named name or 0 if no such name exists.
virtual void writePostProcessing(IPostProcessorWriter *writer)=0
Writes variables for post-processing.
Interface of a variable.
Definition IVariable.h:40
virtual void addTag(const String &tagname, const String &tagvalue)=0
Adds the tag tagname with the value tagvalue.
virtual eItemKind itemKind() const =0
Kind of mesh entities on which the variable is based.
static const char * TAG_POST_PROCESSING
Tag used to indicate if a variable will be post-processed.
Definition IVariable.h:173
virtual void removeTag(const String &tagname)=0
Removes the tag tagname.
static const char * TAG_POST_PROCESSING_AT_THIS_ITERATION
Tag used to indicate if a variable will be post-processed at this iteration.
Definition IVariable.h:176
Mesh entity group.
Definition ItemGroup.h:51
const String & name() const
Group name.
Definition ItemGroup.h:81
bool null() const
true means the group is the null group
Definition ItemGroup.h:75
Information for building a module.
ISubDomain * subDomain() const
Access to the associated subdomain.
Manages outputs based on physical time, CPU time, or a number of iterations.
bool check(Real old_time, Real current_time, Integer current_iteration, Integer current_cpu_time, const String &from_function=String())
Checks whether an output should be performed.
Sentinel for the timer. The sentinel associated with a timer allows it to be triggered upon its const...
Definition Timer.h:90
Management of a timer.
Definition Timer.h:63
@ TimerReal
Timer using real time.
Definition Timer.h:77
TraceMessage info() const
Flow for an information message.
TraceMessage warning() const
Flow for a warning message.
virtual void resize(Integer new_size)
Resizes the array to contain new_size elements.
Information about a version.
Definition VersionInfo.h:47
constexpr Integer size() const noexcept
Returns the size of the array.
VariableRefArrayT< Real > VariableArrayReal
Array variable of real type.
constexpr __host__ __device__ bool isEqual(const _Type &a, const _Type &b)
Tests the bit-by-bit equality between two values.
Definition Numeric.h:260
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
Int32 Integer
Type representing an integer.
List< ItemGroup > ItemGroupList
Array of mesh item groups.
eItemKind
Mesh entity type.
@ IK_Node
Node mesh entity.
@ IK_Cell
Cell mesh entity.
@ IK_Face
Face mesh entity.
@ IK_Edge
Edge mesh entity.
double Real
Type representing a real number.
std::int32_t Int32
Signed integer type of 32 bits.