1 /*============================================================================
2  * Time dependency control for variables or properties.
3  *============================================================================*/
4 
5 /*
6   This file is part of Code_Saturne, a general-purpose CFD tool.
7 
8   Copyright (C) 1998-2021 EDF S.A.
9 
10   This program is free software; you can redistribute it and/or modify it under
11   the terms of the GNU General Public License as published by the Free Software
12   Foundation; either version 2 of the License, or (at your option) any later
13   version.
14 
15   This program is distributed in the hope that it will be useful, but WITHOUT
16   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18   details.
19 
20   You should have received a copy of the GNU General Public License along with
21   this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22   Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24 
25 /*----------------------------------------------------------------------------*/
26 
27 #include "cs_defs.h"
28 
29 /*----------------------------------------------------------------------------*/
30 
31 /*----------------------------------------------------------------------------
32  * Standard C library headers
33  *----------------------------------------------------------------------------*/
34 
35 #include <assert.h>
36 #include <math.h>
37 #include <stdio.h>
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <string.h>
41 
42 /*----------------------------------------------------------------------------
43  * Local headers
44  *----------------------------------------------------------------------------*/
45 
46 #include "bft_mem.h"
47 #include "bft_error.h"
48 #include "bft_printf.h"
49 
50 #include "cs_log.h"
51 #include "cs_map.h"
52 
53 /*----------------------------------------------------------------------------
54  * Header for the current file
55  *----------------------------------------------------------------------------*/
56 
57 #include "cs_time_control.h"
58 
59 /*----------------------------------------------------------------------------*/
60 
61 BEGIN_C_DECLS
62 
63 /*=============================================================================
64  * Additional doxygen documentation
65  *============================================================================*/
66 
67 /*!
68   \file cs_time_control.c
69         Time dependency control for variables or properties.
70 */
71 
72 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
73 
74 /*=============================================================================
75  * Macro definitions
76  *============================================================================*/
77 
78 /*============================================================================
79  * Type definitions
80  *============================================================================*/
81 
82 /*============================================================================
83  * Static global variables
84  *============================================================================*/
85 
86 /*============================================================================
87  * Global variables
88  *============================================================================*/
89 
90 static const cs_time_control_t  cs_time_control_default
91 = {
92   .type = CS_TIME_CONTROL_TIME_STEP,
93   .at_start = false,
94   .at_end = false,
95   .start_nt = -1,
96   .end_nt = -1,
97   .interval_nt = 1,
98   .control_func = NULL,
99   .control_input = NULL,
100   .current_state = false,
101   .current_time_step = -1,
102   .last_nt = -2,
103   .last_t = -HUGE_VAL
104 };
105 
106 /*============================================================================
107  * Private function definitions
108  *============================================================================*/
109 
110 /*----------------------------------------------------------------------------
111  *!
112  * \brief Base initialization for time control.
113  *
114  * \param[in]  tc        pointer to time control structure.
115  * \param[in]  at_start  always active at start ?
116  * \param[in]  at_start  always active at end ?
117  */
118 /*----------------------------------------------------------------------------*/
119 
120 static void
_time_control_init_base(cs_time_control_t * tc,bool at_start,bool at_end)121 _time_control_init_base(cs_time_control_t  *tc,
122                         bool                at_start,
123                         bool                at_end)
124 {
125   memset(tc, 0, sizeof(cs_time_control_t));
126 
127   *tc = cs_time_control_default;
128 
129   tc->at_start = at_start;
130   tc->at_end = at_end;
131 }
132 
133 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
134 
135 /*=============================================================================
136  * Public function definitions
137  *============================================================================*/
138 
139 /*----------------------------------------------------------------------------
140  *!
141  * \brief Indicate if a time control is active or not at the given time.
142  *
143  * If the time control or time step argument is NULL, true is returned.
144  *
145  * \param[in]  tc  time control structure
146  * \param[in]  ts  time step structure
147  *
148  * \return  true if active, false if inactive
149  */
150 /*----------------------------------------------------------------------------*/
151 
152 bool
cs_time_control_is_active(cs_time_control_t * tc,const cs_time_step_t * ts)153 cs_time_control_is_active(cs_time_control_t     *tc,
154                           const cs_time_step_t  *ts)
155 {
156   bool retval = false;
157 
158   if (tc == NULL || ts == NULL)
159     retval = true;
160 
161   else {
162     if (tc->current_time_step == ts->nt_cur)
163       retval = tc->current_state;
164 
165     else {
166       switch (tc->type) {
167       case CS_TIME_CONTROL_TIME_STEP:
168         if (   tc->interval_nt > 0
169             && ts->nt_cur > ts->nt_prev
170             && ts->nt_cur % (tc->interval_nt) == 0)
171           retval = true;
172         if (tc->start_nt > ts->nt_cur)
173           retval = false;
174         if (tc->end_nt >= 0 && tc->end_nt < ts->nt_cur)
175           retval = false;
176         break;
177 
178       case CS_TIME_CONTROL_TIME:
179         {
180           double  delta_t = ts->t_cur - tc->last_t;
181           if (   delta_t >= tc->interval_t*(1-1e-6)
182               && tc->interval_t > 0)
183             retval = true;
184           if (tc->start_t > ts->t_cur)
185             retval = false;
186           if (tc->end_t >= 0 && tc->end_t < ts->nt_cur)
187             retval = false;
188         }
189         break;
190 
191       case CS_TIME_CONTROL_FUNCTION:
192         retval = tc->control_func(ts, tc->control_input);
193       }
194 
195     }
196 
197     if (ts->nt_cur == ts->nt_prev && tc->at_start)
198       retval = true;
199     if (ts->nt_cur == ts->nt_max && tc->at_end)
200       retval = true;
201 
202   }
203 
204   if (tc->current_time_step < ts->nt_cur) {
205     tc->current_time_step = ts->nt_cur;
206     tc->current_state = retval;
207     if (retval) {
208       tc->last_nt = ts->nt_cur;
209       tc->last_t = ts->t_cur;
210     }
211   }
212 
213   return retval;
214 }
215 
216 /*----------------------------------------------------------------------------
217  *!
218  * \brief Simple time control initialization based on time step options.
219  *
220  * \param[in]  tc        pointer to time control structure.
221  * \param[in]  nt_start  start time step (or < 0 for unlimited)
222  * \param[in]  nt_end    end time step (or < 0 for unlimited)
223  * \param[in]  at_start  always active at start ?
224  * \param[in]  at_start  always active at end ?
225  */
226 /*----------------------------------------------------------------------------*/
227 
228 void
cs_time_control_init_by_time_step(cs_time_control_t * tc,int nt_start,int nt_end,int nt_interval,bool at_start,bool at_end)229 cs_time_control_init_by_time_step(cs_time_control_t  *tc,
230                                   int                 nt_start,
231                                   int                 nt_end,
232                                   int                 nt_interval,
233                                   bool                at_start,
234                                   bool                at_end)
235 {
236   _time_control_init_base(tc, at_start, at_end);
237 
238   tc->type = CS_TIME_CONTROL_TIME_STEP;
239 
240   if (nt_start < 0)
241     nt_start = -1;
242   if (nt_end < 0)
243     nt_end = -1;
244   if (nt_interval < 1)
245     nt_interval = -1;
246 
247   tc->start_nt = nt_start;
248   tc->end_nt = nt_end;
249   tc->interval_nt = nt_interval;
250 }
251 
252 /*----------------------------------------------------------------------------
253  *!
254  * \brief Simple time control initialization based on physical time options.
255  *
256  * \param[in]  tc        pointer to time control structure.
257  * \param[in]  t_start   start time (or < 0 for unlimited)
258  * \param[in]  t_end     end time (or < 0 for unlimited)
259  * \param[in]  at_start  always active at start ?
260  * \param[in]  at_start  always active at end ?
261  */
262 /*----------------------------------------------------------------------------*/
263 
264 void
cs_time_control_init_by_time(cs_time_control_t * tc,double t_start,double t_end,double t_interval,bool at_start,bool at_end)265 cs_time_control_init_by_time(cs_time_control_t  *tc,
266                              double              t_start,
267                              double              t_end,
268                              double              t_interval,
269                              bool                at_start,
270                              bool                at_end)
271 {
272   _time_control_init_base(tc, at_start, at_end);
273 
274   tc->type = CS_TIME_CONTROL_TIME;
275 
276   if (t_start < 0)
277     t_start = -1;
278   if (t_end < 0)
279     t_end = -1;
280   if (t_interval <= 0)
281     t_interval = 0;
282 
283   tc->start_t = t_start;
284   tc->end_t = t_end;
285   tc->interval_t = t_interval;
286 }
287 
288 /*----------------------------------------------------------------------------
289  *!
290  * \brief Simple time control initialization based on external function.
291  *
292  * \remark: if the input pointer is non-NULL, it must point to valid data
293  *          when the control function is called, so that value or structure
294  *          should not be temporary (i.e. local);
295  *
296  * \param[in]  tc             pointer to time control structure.
297  * \param[in]  control_func   pointer to time control funcction.
298  * \param[in]  control_input  pointer to optional (untyped) value or structure,
299  *                            or NULL.
300  * \param[in]  at_start       always active at start ?
301  * \param[in]  at_start       always active at end ?
302  */
303 /*----------------------------------------------------------------------------*/
304 
305 void
cs_time_control_init_by_func(cs_time_control_t * tc,cs_time_control_func_t * control_func,void * control_input,bool at_start,bool at_end)306 cs_time_control_init_by_func(cs_time_control_t       *tc,
307                              cs_time_control_func_t  *control_func,
308                              void                    *control_input,
309                              bool                     at_start,
310                              bool                     at_end)
311 {
312   _time_control_init_base(tc, at_start, at_end);
313 
314   tc->type = CS_TIME_CONTROL_FUNCTION;
315 
316   tc->control_func = control_func;
317   tc->control_input = control_input;
318 }
319 
320 /*----------------------------------------------------------------------------
321  *!
322  * \brief Get text description of time control configuration.
323  *
324  * If the time control or time step argument is NULL, true is returned.
325  *
326  * \param[in]   tc         time control structure
327  * \param[out]  desc       description string
328  * \param[in]   desc_size  description string maximum size
329  *
330  * \return  true if active, false if inactive
331  */
332 /*----------------------------------------------------------------------------*/
333 
334 void
cs_time_control_get_description(const cs_time_control_t * tc,char * desc,size_t desc_size)335 cs_time_control_get_description(const cs_time_control_t  *tc,
336                                 char                     *desc,
337                                 size_t                    desc_size)
338 {
339   char b[256] = "";  /* should be more than enough */
340   char *s = b;
341 
342   if (tc == NULL) {
343     snprintf(s, 256, "always active");
344   }
345 
346   else {
347 
348     switch (tc->type) {
349     case CS_TIME_CONTROL_TIME_STEP:
350       if (tc->interval_nt == 1)
351         s += sprintf(s, _(", every time step"));
352       else if (tc->interval_nt > 1)
353         s += sprintf(s, _(", every %d time steps"), tc->interval_nt);
354       if (tc->start_nt > 0)
355         s += sprintf(s, _(", start %d"), tc->start_nt);
356       if (tc->end_nt > 0)
357         s += sprintf(s, _(", end %d"), tc->end_nt);
358       break;
359 
360       case CS_TIME_CONTROL_TIME:
361         if (tc->interval_t >= 0) {
362           if (tc->interval_t <= 0)
363             s += sprintf(s, _(", every time step"));
364           else
365             s += sprintf(s, _(", every %g s"), tc->interval_t);
366         }
367         if (tc->start_t > 0)
368           s += sprintf(s, _(", start %g s"), tc->start_t);
369         if (tc->end_nt > 0)
370           s += sprintf(s, _(", end %g s"), tc->end_t);
371         break;
372 
373       case CS_TIME_CONTROL_FUNCTION:
374         s += sprintf(s, _(", function-based"));
375     }
376 
377     if (tc->at_start)
378       s += sprintf(s, _(", at start"));
379     if (tc->at_end)
380       s += sprintf(s, _(", at end"));
381   }
382 
383   int shift = 0;
384   while (b[shift] == ' ' || b[shift] == ',')
385     shift++;
386 
387   strncpy(desc, b+shift, desc_size);
388   if (desc_size > 0)
389     desc[desc_size-1] = '\0';
390 }
391 
392 /*----------------------------------------------------------------------------*/
393 
394 END_C_DECLS
395