Arcane  4.1.12.0
User documentation
Loading...
Searching...
No Matches
OutputChecker.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/* OutputChecker.cc (C) 2000-2016 */
9/* */
10/* Outputs based on time (physical or CPU) or number of iterations. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ArcanePrecomp.h"
15
16#include "arcane/utils/CheckedConvert.h"
17#include "arcane/utils/ITraceMng.h"
18
19#include "arcane/core/ISubDomain.h"
20#include "arcane/core/ICaseFunction.h"
21#include "arcane/core/CommonVariables.h"
22
23#include "arcane/core/OutputChecker.h"
24
25/*---------------------------------------------------------------------------*/
26/*---------------------------------------------------------------------------*/
27
28namespace Arcane
29{
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
34OutputChecker::
35OutputChecker(ISubDomain* sd, const String& name)
36: m_sub_domain(sd)
37, m_name(name)
38, m_out_type(OutTypeNone)
39, m_next_iteration(0)
40, m_next_global_time(0)
41, m_next_cpu_time(0)
42, m_step_iteration(0)
43, m_step_global_time(0)
44, m_step_cpu_time(0)
45{}
46
47void OutputChecker::
48assignGlobalTime(VariableScalarReal* variable, const CaseOptionReal* option)
49{
50 m_next_global_time = variable;
51 m_step_global_time = option;
52}
53
54void OutputChecker::
55assignCPUTime(VariableScalarInteger* variable, const CaseOptionInteger* option)
56{
57 m_next_cpu_time = variable;
58 m_step_cpu_time = option;
59}
60
61void OutputChecker::
62assignIteration(VariableScalarInteger* variable, const CaseOptionInteger* option)
63{
64 m_next_iteration = variable;
65 m_step_iteration = option;
66}
67
68/*---------------------------------------------------------------------------*/
69/*---------------------------------------------------------------------------*/
70
71/*!
72 * \brief Checks whether an output should be performed.
73 *
74 * \arg \a old_time and \a current_time are used for physical time outputs.
75 * \arg \a current_iteration is used for iteration count outputs.
76 * \arg \a cpu_time_used is used for CPU time outputs.
77
78 When an output type is not available, the associated value(s)
79 are not used and may be arbitrary.
80
81 * \param old_time physical time of the previous iteration.
82 * \param current_time current physical time.
83 * \param current_iteration current iteration.
84 * \param cpu_time_used CPU time used
85 */
86bool OutputChecker::
87check(Real old_time, Real current_time,
88 Integer current_iteration, Integer cpu_time_used,
89 const String& from_function)
90{
91 String function_id = "OutputChecker::check >>> ";
92
93 if (m_out_type == OutTypeNone)
94 return false;
95
96 ITraceMng* trace = m_sub_domain->traceMng();
97
98 // \a true if we are going to perform an output
99 bool do_output = false;
100 switch (m_out_type) {
101 case OutTypeGlobalTime: {
102 Real next_time = (*m_next_global_time)();
103 trace->debug() << from_function << function_id << "Next out: " << next_time << " Saved Time: " << old_time
104 << " Current time: " << current_time << " step=" << m_step_global_time;
105 //if (math::isEqual(m_next_time(),old_time))
106 if (math::isEqual(next_time, current_time))
107 do_output = true;
108 // To perform an output, we must have exceeded
109 // the previous time and the current time must be #strictly# greater
110 // than the output time.
111 else if (next_time > old_time && next_time < current_time) {
112 do_output = true;
113 }
114 // TODO: divide by the number of output steps
115 if (do_output || next_time < old_time) {
116 //Real to_add = m_step_time(); //old_time);
117 // If the time is given by a step table, its value must be taken
118 // at the current instant.
119 // We must take the value
120 Real to_add = m_step_global_time->valueAtParameter(current_time); //old_time);
121 if (!math::isZero(to_add)) {
122 //m_next_time += to_add;
123 Real diff = (current_time - next_time) / to_add;
124 if (diff < 0.)
125 *m_next_global_time = next_time + to_add;
126 else {
127 double i_diff = math::floor(diff);
128 *m_next_global_time = next_time + (to_add * (i_diff + 1));
129 }
130 trace->debug() << from_function << function_id
131 << "Next output at time " << next_time
132 << " (" << to_add << ' ' << old_time
133 << ' ' << current_iteration << ")";
134 }
135 }
136 } break;
137 case OutTypeIteration: {
138 Integer next_iteration = (*m_next_iteration)();
139 Integer to_add = m_step_iteration->valueAtParameter(current_time);
140
141 if (next_iteration > current_iteration + to_add) {
142 // TH: In case of resumption with decrease in output period in days
143 // TH: we resume outputs immediately
144 next_iteration = current_iteration;
145 }
146
147 if (next_iteration == current_iteration)
148 do_output = true;
149
150 // Calculate the next save iteration if necessary
151 if (next_iteration <= current_iteration) {
152 if (to_add != 0) {
153 Integer diff = (current_iteration - next_iteration) / to_add;
154 (*m_next_iteration) = next_iteration + ((diff + 1) * to_add);
155 trace->debug() << from_function << function_id
156 << "Next output at iteration " << (*m_next_iteration)()
157 << " (" << to_add << ' ' << old_time
158 << ' ' << current_iteration << " diff=" << diff << ")";
159 }
160 }
161 } break;
162 case OutTypeCPUTime: {
163 Integer next_cpu_time = (*m_next_cpu_time)();
164 Integer cpu_time = cpu_time_used;
165 // Convert CPU time to minutes (to remain consistent with the conversion
166 // in _recomputeTypeCPUTime())
167
168 Integer current_cpu_time = cpu_time / 60;
169
170 if (next_cpu_time <= current_cpu_time)
171 do_output = true;
172
173 // Calculate the next save CPU time if necessary
174 if (next_cpu_time <= current_cpu_time) {
175 Integer to_add = m_step_cpu_time->valueAtParameter(current_time);
176 if (to_add != 0) {
177 Integer diff = (current_cpu_time - next_cpu_time) / to_add;
178 (*m_next_cpu_time) = next_cpu_time + ((diff + 1) * to_add);
179 trace->debug() << from_function << function_id
180 << "Next output at cpu time " << (*m_next_cpu_time)()
181 << " (" << to_add << ' ' << current_cpu_time << " diff=" << diff << ")";
182 }
183 }
184
185 // Does nothing for the first minute.
186 if (current_cpu_time == 0)
187 do_output = false;
188
189 //if (do_output)
190 //cerr << "** ** OUTPUT AT CPU TIME " << cpu_time
191 //<< ' ' << current_cpu_time << ' ' << (*m_next_cpu_time)()
192 // << ' ' << (*m_step_cpu_time)() << '\n';
193
194 }
195 //msg->warning() << "Not implemented";
196 break;
197 case OutTypeNone:
198 break;
199 }
200
201 return do_output;
202}
203
204/*---------------------------------------------------------------------------*/
205/*---------------------------------------------------------------------------*/
206
207/*---------------------------------------------------------------------------*/
208/*---------------------------------------------------------------------------*/
209
210void OutputChecker::
211_recomputeTypeGlobalTime()
212{
213 Real current_time = m_sub_domain->commonVariables().globalTime();
214 Real step = m_step_global_time->valueAtParameter(current_time);
215
216 Real old_next = (*m_next_global_time)();
217 Real next = old_next;
218 Real current_value = current_time;
219 if (!math::isZero(step)) {
220 Real index = ::floor(current_value / step);
221 next = step * (index + 1.0);
222 *m_next_global_time = next;
223 }
224
225 ITraceMng* tm = m_sub_domain->traceMng();
226 tm->info(4) << "Recompute OutputChecker for Global Time: old=" << old_next
227 << " new=" << next;
228}
229
230/*---------------------------------------------------------------------------*/
231/*---------------------------------------------------------------------------*/
232
233void OutputChecker::
234_recomputeTypeCPUTime()
235{
236 Real current_time = m_sub_domain->commonVariables().globalTime();
237 Integer step = m_step_cpu_time->valueAtParameter(current_time);
238
239 Integer old_next = (*m_next_cpu_time)();
240 Integer next = old_next;
241 double current_value = math::floor(m_sub_domain->commonVariables().globalCPUTime());
242
243 // Convert to minutes (to remain consistent with the conversion in check())
244 current_value /= 60.0;
245
246 if (step != 0) {
247 Integer index = CheckedConvert::toInteger(current_value / step);
248 next = step * (index + 1);
249 *m_next_cpu_time = next;
250 }
251
252 ITraceMng* tm = m_sub_domain->traceMng();
253 tm->info(4) << "Recompute OutputChecker for CPU Time: old=" << old_next << " new=" << next;
254}
255
256/*---------------------------------------------------------------------------*/
257/*---------------------------------------------------------------------------*/
258
259void OutputChecker::
260_recomputeTypeIteration()
261{
262 Real current_time = m_sub_domain->commonVariables().globalTime();
263 Integer step = m_step_iteration->valueAtParameter(current_time);
264
265 Integer old_next = (*m_next_iteration)();
266 Integer next = old_next;
267 Integer current_value = m_sub_domain->commonVariables().globalIteration();
268 if (step != 0) {
269 if (old_next <= current_value) {
270 *m_next_iteration = current_value;
271 }
272 else {
273 Integer index = current_value / step;
274 next = step * (index + 1);
275 *m_next_iteration = next;
276 }
277 }
278
279 ITraceMng* tm = m_sub_domain->traceMng();
280 tm->info(4) << "Recompute OutputChecker for CPU Time: old=" << old_next << " new=" << next;
281}
282
283/*---------------------------------------------------------------------------*/
284/*---------------------------------------------------------------------------*/
285
286void OutputChecker::
287initialize()
288{
289 initialize(false);
290}
291
292/*---------------------------------------------------------------------------*/
293/*---------------------------------------------------------------------------*/
294
295void OutputChecker::
296initialize(bool recompute_next_value)
297{
298 ITraceMng* trace = m_sub_domain->traceMng();
299 m_out_type = OutTypeNone;
300
301 ICaseFunction* func = 0;
302 // Prioritizes physical time outputs, then
303 // iteration count, then CPU time.
304 if (m_step_global_time && m_next_global_time && m_step_global_time->isPresent()) {
305 m_out_type = OutTypeGlobalTime;
306 func = m_step_global_time->function();
307 if (func)
308 trace->info() << "Output in real time controlled by function '" << func->name() << "'.";
309 else
310 trace->info() << "Output in real time every " << (*m_step_global_time)() << " seconds.";
311 if (recompute_next_value)
312 _recomputeTypeGlobalTime();
313 }
314 else if (m_step_iteration && m_next_iteration && m_step_iteration->value() != 0) {
315 m_out_type = OutTypeIteration;
316 func = m_step_iteration->function();
317 if (func)
318 trace->info() << "Output in iterations controlled by function '" << func->name() << "'.";
319 else
320 trace->info() << "Output every " << (*m_step_iteration)() << " iterations.";
321 if (recompute_next_value)
322 _recomputeTypeIteration();
323 }
324 else if (m_step_cpu_time && m_next_cpu_time && m_step_cpu_time->isPresent()) {
325 m_out_type = OutTypeCPUTime;
326 func = m_step_cpu_time->function();
327 if (func)
328 trace->info() << "Output in CPU time controlled by function '" << func->name() << "'.";
329 else
330 trace->info() << "Output in CPU time every " << (*m_step_cpu_time)() << " minutes.";
331 if (recompute_next_value)
332 _recomputeTypeCPUTime();
333 }
334 else
335 trace->info() << "No output required.";
336}
337
338/*---------------------------------------------------------------------------*/
339/*---------------------------------------------------------------------------*/
340
341Real OutputChecker::
342nextGlobalTime() const
343{
344 Real v = 0.0;
345 if (m_next_global_time)
346 v = (*m_next_global_time)();
347 return v;
348}
349
350/*---------------------------------------------------------------------------*/
351/*---------------------------------------------------------------------------*/
352
353Integer OutputChecker::
354nextIteration() const
355{
356 Integer v = 0;
357 if (m_next_iteration)
358 v = (*m_next_iteration)();
359 return v;
360}
361
362/*---------------------------------------------------------------------------*/
363/*---------------------------------------------------------------------------*/
364
365Integer OutputChecker::
366nextCPUTime() const
367{
368 Integer v = 0;
369 if (m_next_cpu_time)
370 v = (*m_next_cpu_time)();
371 return v;
372}
373
374/*---------------------------------------------------------------------------*/
375/*---------------------------------------------------------------------------*/
376
377} // namespace Arcane
378
379/*---------------------------------------------------------------------------*/
380/*---------------------------------------------------------------------------*/
Interface of the subdomain manager.
Definition ISubDomain.h:75
virtual TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium)=0
Stream for a debug message.
@ OutTypeCPUTime
Output based on consumed CPU time.
@ OutTypeIteration
Output based on number of iterations.
@ OutTypeNone
No outputs.
@ OutTypeGlobalTime
Output based on physical time.
__host__ __device__ double floor(double v)
Round v down to the immediately lower integer.
Definition Math.h:100
bool isZero(const BuiltInProxy< _Type > &a)
Tests if a value is exactly equal to zero.
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.
double Real
Type representing a real number.