1 /*============================================================================
2  * Lagrangian module postprocessing
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  * Standard C library headers
31  *----------------------------------------------------------------------------*/
32 
33 #include <stddef.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <math.h>
38 #include <assert.h>
39 
40 /*----------------------------------------------------------------------------
41  *  Local headers
42  *----------------------------------------------------------------------------*/
43 
44 #include "bft_mem.h"
45 #include "bft_printf.h"
46 
47 #include "cs_base.h"
48 #include "cs_mesh_location.h"
49 
50 #include "cs_parameters.h"
51 #include "cs_time_step.h"
52 #include "cs_parall.h"
53 #include "cs_post.h"
54 
55 #include "cs_lagr.h"
56 #include "cs_lagr_particle.h"
57 #include "cs_lagr_stat.h"
58 
59 /*----------------------------------------------------------------------------
60  *  Header for the current file
61  *----------------------------------------------------------------------------*/
62 
63 #include "cs_lagr_post.h"
64 
65 /*----------------------------------------------------------------------------*/
66 
67 BEGIN_C_DECLS
68 
69 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
70 
71 /*============================================================================
72  * Local types and structures
73  *============================================================================*/
74 
75 /* Structure associated with postprocessing options */
76 /*--------------------------------------------------*/
77 
78 typedef struct {
79 
80   /*! \anchor particle_attr
81     flag for activation of output for each possible particle attribute:
82     0:   not active
83     1:   active
84     > 1: for atributes with multiple components, number of components
85     postprocessed as separate scalars */
86   int  attr_output[CS_LAGR_N_ATTRIBUTES];
87 
88 } cs_lagr_post_options_t;
89 
90 /*============================================================================
91  * Static global variables
92  *============================================================================*/
93 
94 static bool                    _lagr_post_options_is_set = false;
95 
96 /* Postprocessing options structure and associated pointer */
97 
98 static cs_lagr_post_options_t  _lagr_post_options
99 = {.attr_output[0] = -1};
100 
101 const cs_lagr_post_options_t *cs_glob_lagr_post_options = &_lagr_post_options;
102 
103 /*=============================================================================
104  * Private function definitions
105  *============================================================================*/
106 
107 /*----------------------------------------------------------------------------
108  * Define which Lagragian variables should be postprocessed
109  *----------------------------------------------------------------------------*/
110 
111 static void
_activate_particle_output(void)112 _activate_particle_output(void)
113 {
114   /* No output if nothing initialized by now */
115 
116   if (_lagr_post_options.attr_output[0] == -1) {
117     for (cs_lagr_attribute_t i = 0; i < CS_LAGR_N_ATTRIBUTES; i++) {
118       _lagr_post_options.attr_output[i] = 0;
119     }
120   }
121 
122   else {
123     for (cs_lagr_attribute_t i = 0; i < CS_LAGR_N_ATTRIBUTES; i++) {
124       if (_lagr_post_options.attr_output[i]) {
125         int count = 0;
126         cs_lagr_get_attr_info(cs_glob_lagr_particle_set,
127                               0,
128                               i,
129                               NULL,
130                               NULL,
131                               NULL,
132                               NULL,
133                               &count);
134 
135         if (count == 3) {
136           switch(i) {
137           case CS_LAGR_COORDS:
138           case CS_LAGR_VELOCITY:
139           case CS_LAGR_VELOCITY_SEEN:
140           case CS_LAGR_PRED_VELOCITY:
141           case CS_LAGR_PRED_VELOCITY_SEEN:
142           case CS_LAGR_ORIENTATION:
143           case CS_LAGR_RADII:
144           case CS_LAGR_ANGULAR_VEL:
145             count = 1;
146             break;
147           default:
148             break;
149           }
150         }
151 
152         _lagr_post_options.attr_output[i] = count;
153       }
154     }
155   }
156 }
157 
158 /*----------------------------------------------------------------------------
159  * Default additional particle output of mesh and time-dependent variables
160  * for the call to pstvar / cs_post_write_vars.
161  *
162  * Note: if the input pointer is non-NULL, it must point to valid data
163  * when the output function is called, so either:
164  * - that value or structure should not be temporary (i.e. local);
165  * - post-processing output must be ensured using cs_post_write_var()
166  *   or similar before the data pointed to goes out of scope.
167  *
168  * parameters:
169  *   input       <-> pointer to optional (untyped) value or structure;
170  *                   here, we should point to _lagr_post_options.
171  *   mesh_id     <-- id of the output mesh for the current call
172  *   cat_id      <-- category id of the output mesh for the current call
173  *   ts          <-- time step status structure
174  *----------------------------------------------------------------------------*/
175 
176 static void
_write_particle_vars(cs_lagr_post_options_t * options,int mesh_id,const cs_time_step_t * ts)177 _write_particle_vars(cs_lagr_post_options_t  *options,
178                      int                      mesh_id,
179                      const cs_time_step_t    *ts)
180 {
181   cs_lagr_attribute_t attr_id;
182 
183   char var_name[64];
184   int  component_id;
185   char var_name_component[96];
186 
187   for (attr_id = 0; attr_id < CS_LAGR_N_ATTRIBUTES; attr_id++) {
188 
189     if (options->attr_output[attr_id] > 0) {
190 
191       /* build name */
192 
193       snprintf(var_name,
194                63,
195                "particle_%s",
196                cs_lagr_attribute_name[attr_id]);
197       var_name[63] = '\0';
198 
199       /* Output values */
200 
201       if (options->attr_output[attr_id] == 1)
202         cs_post_write_particle_values(mesh_id,
203                                       CS_POST_WRITER_ALL_ASSOCIATED,
204                                       attr_id,
205                                       var_name,
206                                       -1,
207                                       ts);
208       else {
209         /* Create one output per component */
210         for (component_id = 0;
211              component_id < options->attr_output[attr_id];
212              component_id++) {
213           snprintf(var_name_component,
214                    95,
215                    "%s_layer_%2.2i",
216                    var_name,
217                    component_id+1);
218           var_name_component[95] = '\0';
219           cs_post_write_particle_values(mesh_id,
220                                         CS_POST_WRITER_ALL_ASSOCIATED,
221                                         attr_id,
222                                         var_name_component,
223                                         component_id,
224                                         ts);
225         }
226       }
227     }
228 
229   }
230 }
231 
232 /*----------------------------------------------------------------------------
233  * Function for additional postprocessing of Lagrangian data.
234  *
235  * This function should match the prototype of a
236  * (cs_post_time_mesh_dep_output_t) function, and be registered using
237  * cs_post_add_time_mesh_dep_output().
238  *
239  * parameters:
240  *   input       <-> pointer to optional (untyped) value or structure.
241  *   mesh_id     <-- id of the output mesh for the current call
242  *   cat_id      <-- category id of the output mesh for the current call
243  *   ent_flag    <-- indicate global presence of cells (ent_flag[0]), interior
244  *                   faces (ent_flag[1]), boundary faces (ent_flag[2]),
245  *                   particles (ent_flag[3]) or probes (ent_flag[4])
246  *   n_cells     <-- local number of cells of post_mesh
247  *   n_i_faces   <-- local number of interior faces of post_mesh
248  *   n_b_faces   <-- local number of boundary faces of post_mesh
249  *   cell_ids    <-- list of cells (0 to n-1) of post-processing mesh
250  *   i_face_ids  <-- list of interior faces (0 to n-1) of post-processing mesh
251  *   b_face_ids  <-- list of boundary faces (0 to n-1) of post-processing mesh
252  *   ts          <-- time step status structure, or NULL
253  *----------------------------------------------------------------------------*/
254 
255 static void
_cs_lagr_post(void * input,int mesh_id,int cat_id,int ent_flag[5],cs_lnum_t n_cells,cs_lnum_t n_i_faces,cs_lnum_t n_b_faces,const cs_lnum_t cell_ids[],const cs_lnum_t i_face_ids[],const cs_lnum_t b_face_ids[],const cs_time_step_t * ts)256 _cs_lagr_post(void                  *input,
257               int                    mesh_id,
258               int                    cat_id,
259               int                    ent_flag[5],
260               cs_lnum_t              n_cells,
261               cs_lnum_t              n_i_faces,
262               cs_lnum_t              n_b_faces,
263               const cs_lnum_t        cell_ids[],
264               const cs_lnum_t        i_face_ids[],
265               const cs_lnum_t        b_face_ids[],
266               const cs_time_step_t  *ts)
267 {
268   CS_UNUSED(ent_flag);
269   CS_UNUSED(n_cells);
270   CS_UNUSED(n_i_faces);
271   CS_UNUSED(cell_ids);
272   CS_UNUSED(i_face_ids);
273 
274   /* Specific handling for particle meshes */
275 
276   if (cat_id == -3) {
277     _write_particle_vars(input, mesh_id, ts);
278     return;
279   }
280 
281   /* Boundary statistics */
282   /*---------------------*/
283 
284   else if (cat_id == -2 && cs_glob_lagr_time_scheme->iilagr > 0) {
285 
286     cs_lnum_t nfabor = cs_glob_mesh->n_b_faces;
287 
288     const cs_lagr_boundary_interactions_t
289       *lagr_b = cs_glob_lagr_boundary_interactions;
290 
291     cs_real_t  threshold = cs_glob_lagr_stat_options->threshold;
292 
293     cs_real_t *val;
294     BFT_MALLOC(val, nfabor, cs_real_t);
295 
296     for (int irf = 0; irf < cs_glob_lagr_dim->n_boundary_stats; irf++) {
297 
298       const char *var_name = lagr_b->nombrd[irf];
299 
300       const cs_real_t *_b_stats = bound_stat + nfabor*irf;
301 
302       const cs_real_t *_f_count = bound_stat + nfabor*lagr_b->inbr;
303 
304       for (cs_lnum_t i = 0; i < n_b_faces; i++) {
305         cs_lnum_t f_id = b_face_ids[i];
306         if (_f_count[f_id] > threshold)
307           val[i] = _b_stats[f_id];
308         else
309           val[i] = 0.;
310       }
311 
312       cs_post_write_var(mesh_id,
313                         CS_POST_WRITER_ALL_ASSOCIATED,
314                         var_name,
315                         1,       /* var_dim */
316                         true,    /* interlace */
317                         false,   /* use_parent */
318                         CS_POST_TYPE_cs_real_t,
319                         NULL,
320                         NULL,
321                         val,
322                         cs_glob_time_step);
323 
324     }
325 
326     BFT_FREE(val);
327 
328   }
329 }
330 
331 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
332 
333 /*============================================================================
334  * Public function definitions
335  *============================================================================*/
336 
337 /*----------------------------------------------------------------------------*/
338 /*!
339  * \brief Initialize Lagrangian postprocessing.
340  */
341 /*----------------------------------------------------------------------------*/
342 
343 void
cs_lagr_post_init(void)344 cs_lagr_post_init(void)
345 {
346   _activate_particle_output();
347 
348   cs_post_add_time_mesh_dep_output(_cs_lagr_post, &_lagr_post_options);
349   _lagr_post_options_is_set = true;
350 }
351 
352 /*----------------------------------------------------------------------------*/
353 /*!
354  * \brief Activate or deactive postprocessing for a given particle attribute.
355  *
356  * \param[in]  attr_id  associated attribute id
357  *
358  * \return     true if output of given attribute is active, false otherwise
359  */
360 /*----------------------------------------------------------------------------*/
361 
362 bool
cs_lagr_post_get_attr(cs_lagr_attribute_t attr_id)363 cs_lagr_post_get_attr(cs_lagr_attribute_t  attr_id)
364 {
365   /* Initialize if not done yet */
366 
367   if (_lagr_post_options.attr_output[0] == -1) {
368     for (cs_lagr_attribute_t i = 0; i < CS_LAGR_N_ATTRIBUTES; i++) {
369       _lagr_post_options.attr_output[i] = 0;
370     }
371   }
372 
373   bool retval = false;
374   if (_lagr_post_options.attr_output[attr_id] > 0)
375     retval = true;
376 
377   return retval;
378 }
379 
380 /*----------------------------------------------------------------------------*/
381 /*!
382  * \brief Activate or deactive postprocessing for a given particle attribute.
383  *
384  * \param[in]  attr_id  associated attribute id
385  * \param[in]  active   true if postprocessing is required, false otherwise
386  */
387 /*----------------------------------------------------------------------------*/
388 
389 void
cs_lagr_post_set_attr(cs_lagr_attribute_t attr_id,bool active)390 cs_lagr_post_set_attr(cs_lagr_attribute_t  attr_id,
391                       bool                 active)
392 {
393   if (_lagr_post_options_is_set)
394     bft_error(__FILE__, __LINE__, 0,
395               _("%s should not be called after %s."),
396               __func__, "cs_lagr_post_init");
397 
398   /* Initialize if not done yet */
399 
400   if (_lagr_post_options.attr_output[0] == -1) {
401     for (cs_lagr_attribute_t i = 0; i < CS_LAGR_N_ATTRIBUTES; i++) {
402       _lagr_post_options.attr_output[i] = 0;
403     }
404   }
405 
406   cs_lagr_particle_attr_in_range(attr_id);
407 
408   if (active == false)
409     _lagr_post_options.attr_output[attr_id] = 0;
410   else
411     _lagr_post_options.attr_output[attr_id] = 1;
412 }
413 
414 /*----------------------------------------------------------------------------*/
415 
416 END_C_DECLS
417