1 /*============================================================================
2  * Define postprocessing output.
3  *============================================================================*/
4 
5 /* VERS */
6 
7 /*
8   This file is part of Code_Saturne, a general-purpose CFD tool.
9 
10   Copyright (C) 1998-2021 EDF S.A.
11 
12   This program is free software; you can redistribute it and/or modify it under
13   the terms of the GNU General Public License as published by the Free Software
14   Foundation; either version 2 of the License, or (at your option) any later
15   version.
16 
17   This program is distributed in the hope that it will be useful, but WITHOUT
18   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
20   details.
21 
22   You should have received a copy of the GNU General Public License along with
23   this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
24   Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 */
26 
27 /*----------------------------------------------------------------------------*/
28 
29 #include "cs_defs.h"
30 
31 /*----------------------------------------------------------------------------
32  * Standard C library headers
33  *----------------------------------------------------------------------------*/
34 
35 #include "stdlib.h"
36 #include "string.h"
37 
38 /*----------------------------------------------------------------------------
39  * Local headers
40  *----------------------------------------------------------------------------*/
41 
42 #include "cs_headers.h"
43 
44 /*----------------------------------------------------------------------------*/
45 
46 BEGIN_C_DECLS
47 
48 /*============================================================================
49  * Local (user defined) function definitions
50  *============================================================================*/
51 
52 /*----------------------------------------------------------------------------
53  * Example function for advanced selection of interior faces.
54  *
55  * Selects interior faces separating cells of group "2" from those
56  * of group "3", (assuming no cell has both colors).
57  *
58  * parameters:
59  *   input    <-> pointer to input (unused here)
60  *   n_faces  --> number of selected faces
61  *   face_ids --> array of selected face ids (0 to n-1 numbering)
62  *----------------------------------------------------------------------------*/
63 
64 /*! [post_select_func_1] */
65 static void
_i_faces_select_example(void * input,cs_lnum_t * n_faces,cs_lnum_t ** face_ids)66 _i_faces_select_example(void         *input,
67                         cs_lnum_t    *n_faces,
68                         cs_lnum_t   **face_ids)
69 {
70   CS_UNUSED(input);
71 
72   cs_lnum_t i, face_id;
73   int n_families = 0;
74   int *family_list = NULL;
75   int *family_mask = NULL;
76 
77   cs_lnum_t n_i_faces = 0;
78   cs_lnum_t *i_face_ids = NULL;
79 
80   const cs_mesh_t *m = cs_glob_mesh;
81 
82   /* Allocate selection list */
83 
84   BFT_MALLOC(i_face_ids, m->n_i_faces, cs_lnum_t);
85 
86   /* Build mask on families matching groups "2" (1), "3" (2) */
87 
88   BFT_MALLOC(family_list, m->n_families, int);
89   BFT_MALLOC(family_mask, m->n_families, int);
90 
91   for (i = 0; i < m->n_families; i++)
92     family_mask[i] = 0;
93 
94   cs_selector_get_family_list("2",  &n_families, family_list);
95 
96   for (i = 0; i < n_families; i++)
97     family_mask[family_list[i] - 1] += 1;
98 
99   cs_selector_get_family_list("3",  &n_families, family_list);
100 
101   for (i = 0; i < n_families; i++)
102     family_mask[family_list[i] - 1] += 2;
103 
104   BFT_FREE(family_list);
105 
106   /* Now that mask is built, test for adjacency */
107 
108   for (face_id = 0; face_id < m->n_i_faces; face_id++) {
109 
110     /* Adjacent cells  and flags */
111 
112     cs_lnum_t c1 = m->i_face_cells[face_id][0];
113     cs_lnum_t c2 = m->i_face_cells[face_id][1];
114 
115     int iflag1 = family_mask[m->cell_family[c1]];
116     int iflag2 = family_mask[m->cell_family[c2]];
117 
118     /* Should the face belong to the extracted mesh ? */
119 
120     if ((iflag1 == 1 && iflag2 == 2) || (iflag1 == 2 && iflag2 == 1)) {
121       i_face_ids[n_i_faces] = face_id;
122       n_i_faces += 1;
123     }
124 
125   }
126 
127   /* Free memory */
128 
129   BFT_FREE(family_mask);
130   BFT_REALLOC(i_face_ids, n_i_faces, cs_lnum_t);
131 
132   /* Set return values */
133 
134   *n_faces = n_i_faces;
135   *face_ids = i_face_ids;
136 }
137 /*! [post_select_func_1] */
138 
139 /*----------------------------------------------------------------------------
140  * Example function for selection of boundary faces.
141  *
142  * selects boundary faces of group "4".
143  *
144  * parameters:
145  *   input    <-> pointer to input (unused here)
146  *   n_faces  --> number of selected faces
147  *   face_ids --> array of selected face ids (0 to n-1 numbering)
148  *----------------------------------------------------------------------------*/
149 
150 /*! [post_select_func_2] */
151 static void
_b_faces_select_example(void * input,cs_lnum_t * n_faces,cs_lnum_t ** face_ids)152 _b_faces_select_example(void         *input,
153                         cs_lnum_t    *n_faces,
154                         cs_lnum_t   **face_ids)
155 {
156   CS_UNUSED(input);
157 
158   cs_lnum_t n_b_faces = 0;
159   cs_lnum_t *b_face_ids = NULL;
160 
161   const cs_mesh_t *m = cs_glob_mesh;
162 
163   /* Allocate selection list */
164 
165   BFT_MALLOC(b_face_ids, m->n_b_faces, cs_lnum_t);
166 
167   /* Use simple selection function */
168 
169   cs_selector_get_b_face_list("4", &n_b_faces, b_face_ids);
170 
171   /* Adjust array to final size (cleaner, but not required) */
172 
173   BFT_REALLOC(b_face_ids, n_b_faces, cs_lnum_t);
174 
175   /* Set return values */
176 
177   *n_faces = n_b_faces;
178   *face_ids = b_face_ids;
179 }
180 /*! [post_select_func_2] */
181 
182 /*----------------------------------------------------------------------------
183  * Example function for selection of cells with scalar field values above
184  * a certain threshold.
185  *
186  * In this example, the selection is base on the value of a scalar field
187  * named "he_fraction" being above above 0.05.
188  *
189  * parameters:
190  *   input    <-> pointer to input (unused here)
191  *   n_cells  --> number of selected cells
192  *   cell_ids --> array of selected cell ids (0 to n-1 numbering)
193  *----------------------------------------------------------------------------*/
194 
195 /*! [post_select_func_3] */
196 static void
_he_fraction_05_select(void * input,cs_lnum_t * n_cells,cs_lnum_t ** cell_ids)197 _he_fraction_05_select(void        *input,
198                        cs_lnum_t   *n_cells,
199                        cs_lnum_t  **cell_ids)
200 {
201   CS_UNUSED(input);
202 
203   cs_lnum_t _n_cells = 0;
204   cs_lnum_t *_cell_ids = NULL;
205 
206   const cs_mesh_t *m = cs_glob_mesh;
207 
208   cs_field_t *f = cs_field_by_name_try("He_fraction"); /* Get access to field */
209 
210   if (f == NULL)
211     bft_error(__FILE__, __LINE__, 0,
212               "No field with name \"He_fraction\" defined");
213 
214   /* Before time loop, field is defined, but has no values yet,
215      so ignore that case (postprocessing mesh will be initially empty) */
216 
217   if (f->val != NULL) {
218 
219     BFT_MALLOC(_cell_ids, m->n_cells, cs_lnum_t); /* Allocate selection list */
220 
221     for (cs_lnum_t i = 0; i < m->n_cells; i++) {
222       if (f->val[i] > 5.e-2) {
223         _cell_ids[_n_cells] = i;
224         _n_cells += 1;
225       }
226     }
227 
228     BFT_REALLOC(_cell_ids, _n_cells, cs_lnum_t); /* Adjust size (good practice,
229                                                     but not required) */
230 
231   }
232 
233   /* Set return values */
234 
235   *n_cells = _n_cells;
236   *cell_ids = _cell_ids;
237 }
238 /*! [post_select_func_3] */
239 
240 /*============================================================================
241  * User function definitions
242  *============================================================================*/
243 
244 /*----------------------------------------------------------------------------*/
245 /*!
246  * \brief Define post-processing writers.
247  *
248  * The default output format and frequency may be configured, and additional
249  * post-processing writers allowing outputs in different formats or with
250  * different format options and output frequency than the main writer may
251  * be defined.
252  */
253 /*----------------------------------------------------------------------------*/
254 
255 void
cs_user_postprocess_writers(void)256 cs_user_postprocess_writers(void)
257 {
258   /* Set time plot file writer flush behavior defaults. */
259 
260   /*! [post_set_tp_flush] */
261   cs_time_plot_set_flush_default(1800, /* flush_wtime */
262                                  -1);  /* n_buffer_steps */
263   /*! [post_set_tp_flush] */
264 
265   /* Default output format and options */
266 
267   /* Redefine default writer */
268   /* ----------------------- */
269 
270   /*! [post_define_writer_m1] */
271   cs_post_define_writer(CS_POST_WRITER_DEFAULT,       /* writer_id */
272                         "results",                    /* writer name */
273                         "postprocessing",             /* directory name */
274                         "EnSight Gold",               /* format_name */
275                         "",                           /* format_options */
276                         FVM_WRITER_FIXED_MESH,
277                         false,                        /* output_at_start */
278                         true,                         /* output_at_end */
279                         -1,                           /* frequency_n */
280                         -1.0);                        /* frequency_t */
281   /*! [post_define_writer_m1] */
282 
283   /* Define additional writers */
284   /* ------------------------- */
285 
286   /* Common parameters for all writers */
287 
288   /*! [post_define_writer_freq] */
289   double frequency_n = -1.0;
290   double frequency_t = -1.0;
291   /*! [post_define_writer_freq] */
292 
293   /*! [post_define_writer_1] */
294   cs_post_define_writer(1,                            /* writer_id */
295                         "user_txt",                   /* writer name */
296                         "postprocessing",             /* directory name */
297                         "MED",                        /* format name */
298                         "divide_polyhedra",
299                         FVM_WRITER_FIXED_MESH,
300                         false,                        /* output_at_start */
301                         true,                         /* output_at_end */
302                         -1,                           /* frequency_n */
303                         -1.0);                        /* frequency_t */
304   /*! [post_define_writer_1] */
305 
306   /*! [post_define_writer_2] */
307   cs_post_define_writer(2,                            /* writer_id */
308                         "modif",                      /* writer name */
309                         "postprocessing",             /* directory name */
310                         "ensight",                    /* format name */
311                         "text",
312                         FVM_WRITER_TRANSIENT_CONNECT,
313                         false,                        /* output_at_start */
314                         false,                        /* output_at_end */
315                         3,
316                         frequency_t);
317   /*! [post_define_writer_2] */
318 
319   /*! [post_define_writer_3] */
320   cs_post_define_writer(3,                /* writer_id */
321                         "profile",        /* writer name */
322                         "postprocessing", /* directory name */
323                         "plot",           /* format name */
324                         "",               /* format options */
325                         FVM_WRITER_FIXED_MESH,
326                         false,            /* output_at_start */
327                         false,            /* output_at_end */
328                         100,              /* nt_freq */
329                         -1.0);            /* dt_freq */
330   /*! [post_define_writer_3] */
331 
332   /*! [post_define_writer_4] */
333   cs_post_define_writer(6,                        /* writer_id */
334                         "Histogram",              /* writer name */
335                         "histograms",             /* directory name */
336                         "histogram",              /* format name */
337                         "10 tex",                 /* format options */
338                         FVM_WRITER_FIXED_MESH,
339                         false,                    /* output_at_start */
340                         true,                     /* output at end */
341                         -1,                       /* time step frequency */
342                         -1.0);                    /* time value frequency */
343   /*! [post_define_writer_4] */
344 }
345 
346 /*----------------------------------------------------------------------------*/
347 /*!
348  * \brief Define post-processing meshes.
349  *
350  * The main post-processing meshes may be configured, and additional
351  * post-processing meshes may be defined as a subset of the main mesh's
352  * cells or faces (both interior and boundary).
353  */
354 /*----------------------------------------------------------------------------*/
355 
356 void
cs_user_postprocess_meshes(void)357 cs_user_postprocess_meshes(void)
358 {
359   /* Reconfigure predefined meshes (mesh_id -1 for volume, -2 for boundary */
360 
361   /* De-activate boundary mesh output by redefining it with no writer
362      association (default is:
363      int n_writers = 1;
364      const int writer_ids[] = {CS_POST_WRITER_DEFAULT});
365   */
366 
367   /*! [post_define_mesh_m2] */
368   {
369     int n_writers = 0;
370     const int *writer_ids = NULL;
371 
372     cs_post_define_surface_mesh(CS_POST_MESH_BOUNDARY,  /* mesh_id */
373                                 "Boundary",  /* mesh name */
374                                 NULL,        /* interior face selection criteria */
375                                 "all[]",     /* boundary face selection criteria */
376                                 true,        /* add_groups */
377                                 true,        /* automatic variables output */
378                                 n_writers,
379                                 writer_ids);
380   }
381   /*! [post_define_mesh_m2] */
382 
383   /*--------------------------------------------------------------------------*/
384 
385   /* Example: select interior faces with y = 0.5 */
386 
387   /*! [post_define_mesh_1] */
388   {
389     const int n_writers = 2;
390     const int writer_ids[] = {1, 4};  /* Associate to writers 1 and 4 */
391 
392     const char *interior_criteria = "plane[0, -1, 0, 0.5, "
393                                     "epsilon = 0.0001]";
394     const char *boundary_criteria = NULL;
395 
396     cs_post_define_surface_mesh(1,               /* mesh id */
397                                 "Median plane",
398                                 interior_criteria,
399                                 boundary_criteria,
400                                 false, /* add_groups */
401                                 false, /* auto_variables */
402                                 n_writers,
403                                 writer_ids);
404 
405   }
406   /*! [post_define_mesh_1] */
407 
408   /*--------------------------------------------------------------------------*/
409 
410   /* Advanced example:
411      Build a surface mesh containing interior faces separating cells of group "2"
412      from those of group "3", (assuming no cell has both colors), as well as
413      boundary faces of group "4". */
414 
415   /*! [post_define_mesh_3] */
416   {
417     const int n_writers = 1;
418     const int writer_ids[] = {1};  /* Associate to writer 1 */
419 
420     /* Define postprocessing mesh */
421 
422     cs_post_define_surface_mesh_by_func(3,               /* mesh id */
423                                         "Mixed surface",
424                                         _i_faces_select_example,
425                                         _b_faces_select_example,
426                                         NULL,            /* i_faces_sel_input */
427                                         NULL,            /* b_faces_sel_input */
428                                         false,           /* time varying */
429                                         false,           /* add_groups */
430                                         false,           /* auto_variables */
431                                         n_writers,
432                                         writer_ids);
433   }
434   /*! [post_define_mesh_3] */
435 
436   /* Advanced example:
437      Build a (time varying) volume mesh containing cells
438      with values of field named "He_fraction" > 0.05 */
439 
440   /*! [post_define_mesh_4] */
441   {
442     const int n_writers = 1;
443     const int writer_ids[] = {2};  /* Associate to writer 2 */
444 
445     /* Define postprocessing mesh */
446 
447     cs_post_define_volume_mesh_by_func(4,               /* mesh id */
448                                        "He_fraction_05",
449                                        _he_fraction_05_select,
450                                        NULL,            /* _c_05_select_input */
451                                        true,            /* time varying */
452                                        false,           /* add_groups */
453                                        false,           /* auto_variables */
454                                        n_writers,
455                                        writer_ids);
456   }
457   /*! [post_define_mesh_4] */
458 
459   /*--------------------------------------------------------------------------*/
460 
461   /* Example: extract face edges of another mesh */
462 
463   /*! [post_define_mesh_5] */
464   {
465     const int n_writers = 1;
466     const int writer_ids[] = {4};  /* Associate to writer 4 */
467 
468     cs_post_define_edges_mesh(5, /* mesh_id */
469                               1, /* base_mesh_id */
470                               n_writers,
471                               writer_ids);
472   }
473   /*! [post_define_mesh_5] */
474 
475   /*--------------------------------------------------------------------------*/
476 
477   /* Example: attach default txt histogram writer on boundary mesh */
478 
479   /*! [post_attach_mesh_1] */
480   cs_post_mesh_attach_writer(CS_POST_MESH_BOUNDARY, CS_POST_WRITER_HISTOGRAMS);
481   /*! [post_attach_mesh_1] */
482 
483   /*--------------------------------------------------------------------------*/
484 
485   /* Example: attach user tex histogram writer of id 6 on volume mesh */
486 
487   /*! [post_attach_mesh_2] */
488   cs_post_mesh_attach_writer(CS_POST_MESH_VOLUME, 6);
489   /*! [post_attach_mesh_2] */
490 
491   /*--------------------------------------------------------------------------*/
492 
493   /* Example: output specific field on mesh with all associated writers */
494 
495   /*! [post_attach_field_1] */
496   cs_post_mesh_attach_field(4,
497                             CS_POST_WRITER_ALL_ASSOCIATED,
498                             cs_field_id_by_name("pressure"),
499                             -1);
500   /*! [post_attach_field_1] */
501   /*--------------------------------------------------------------------------*/
502 
503   /* Example: output z-component of velocity field on mesh with
504      a given writer */
505 
506   /*! [post_attach_field_2] */
507   cs_post_mesh_attach_field(4,
508                             1,
509                             CS_F_(vel)->id,
510                             2);
511   /*! [post_attach_field_2] */
512 }
513 
514 /*----------------------------------------------------------------------------*/
515 /*!
516  * \brief Define monitoring probes and profiles.
517  *
518  * Profiles are defined as sets of probes.
519  */
520 /*----------------------------------------------------------------------------*/
521 
522 void
cs_user_postprocess_probes(void)523 cs_user_postprocess_probes(void)
524 {
525   /* Define monitoring probes */
526 
527   /* A writer (id = CS_POST_WRITER_PROBES) using the format "time_plot" is
528      associated by default to a set of monitoring probes.
529      This is not the case for a profile. */
530 
531   /*! [post_define_probes_1] */
532   {
533     cs_probe_set_t  *pset = cs_probe_set_create("Monitoring");
534 
535     cs_probe_set_add_probe(pset, 0.25, 0.025, 0.025, "M1");
536     cs_probe_set_add_probe(pset, 0.50, 0.025, 0.025, "M2");
537     cs_probe_set_add_probe(pset, 0.75, 0.025, 0.025, "M3");
538   }
539   /*! [post_define_probes_1] */
540 
541   /*! [post_define_probes_2] */
542   {
543     const cs_real_t coords[][3] = {{0.25, 0.025, 0.025},
544                                    {0.50, 0.025, 0.025},
545                                    {0.75, 0.025, 0.025}};
546     const char *labels[] = {"M1", "M2", "M3"};
547 
548     cs_probe_set_t  *pset = cs_probe_set_create_from_array("Monitoring",
549                                                            3,
550                                                            coords,
551                                                            labels);
552   }
553   /*! [post_define_probes_2] */
554 
555   /*! [post_set_probes_interpolate] */
556   {
557     cs_probe_set_t  *pset = cs_probe_set_get("probes");
558 
559     cs_probe_set_option(pset, "interpolation", "1");
560   }
561   /*! [post_set_probes_interpolate] */
562 
563   /* Add a first profile */
564 
565   /*! [post_define_profile_1] */
566   {
567     cs_coord_3_t  start = {0., 0.025, 0.025};
568     cs_coord_3_t  end = {1., 0.025, 0.025};
569     int  writer_ids[] = {2};
570 
571     cs_probe_set_t  *pset =
572       cs_probe_set_create_from_segment("Prof1", // name
573                                        11,      // n_probes
574                                        start,   // start coordinates
575                                        end);    // end coordinates
576 
577     cs_probe_set_associate_writers(pset, 1, writer_ids);
578   }
579   /*! [post_define_profile_1] */
580 
581   /* Add a second profile attached to boundary vertices */
582 
583   /*! [post_define_profile_2] */
584   {
585     cs_coord_3_t  start = {0., 0., 0.};
586     cs_coord_3_t  end = {1., 0., 0.};
587 
588     cs_probe_set_t  *pset =
589       cs_probe_set_create_from_segment("P2",    // name
590                                        11,      // n_probes
591                                        start,   // start coordinates
592                                        end);    // end coordinates
593 
594     int  writer_ids[] = {2};
595     cs_probe_set_associate_writers(pset, 1, writer_ids);
596 
597     cs_probe_set_option(pset, "boundary", "true");
598     cs_probe_set_snap_mode(pset, CS_PROBE_SNAP_VERTEX);
599   }
600   /*! [post_define_profile_2] */
601 
602   /* Define output on a profile */
603 
604   /*! [post_define_profile_3] */
605   {
606     cs_coord_3_t  start = {0., 0.025, 0.025};
607     cs_coord_3_t  end = {1., 0.025, 0.025};
608     int  writer_ids[] = {2};
609 
610     cs_probe_set_t  *pset =
611       cs_probe_set_create_from_segment("Prof4", // name
612                                        11,      // n_probes
613                                        start,   // start coordinates
614                                        end);    // end coordinates
615 
616     cs_probe_set_associate_writers(pset, 1, writer_ids);
617 
618     cs_probe_set_auto_curvilinear_coords(pset, true);
619     cs_probe_set_auto_var(pset, false);
620 
621     cs_probe_set_associate_field(pset,
622                                  CS_POST_WRITER_ALL_ASSOCIATED,
623                                  CS_F_(p)->id,
624                                  -1);
625     cs_probe_set_associate_field(pset,
626                                  CS_POST_WRITER_ALL_ASSOCIATED,
627                                  CS_F_(vel)->id,
628                                  0);
629   }
630   /*! [post_define_profile_3] */
631 }
632 
633 /*----------------------------------------------------------------------------*/
634 /*!
635  * \brief User function for output of values on a post-processing mesh.
636  *
637  * \param[in]       mesh_name    name of the output mesh for the current call
638  * \param[in]       mesh_id      id of the output mesh for the current call
639  * \param[in]       cat_id       category id of the output mesh for the
640  *                               current call
641  * \param[in]       probes       pointer to associated probe set structure if
642  *                               the mesh is a probe set, NULL otherwise
643  * \param[in]       n_cells      local number of cells of post_mesh
644  * \param[in]       n_i_faces    local number of interior faces of post_mesh
645  * \param[in]       n_b_faces    local number of boundary faces of post_mesh
646  * \param[in]       n_vertices   local number of vertices faces of post_mesh
647  * \param[in]       cell_list    list of cells (0 to n-1) of post-processing
648  *                               mesh
649  * \param[in]       i_face_list  list of interior faces (0 to n-1) of
650  *                               post-processing mesh
651  * \param[in]       b_face_list  list of boundary faces (0 to n-1) of
652  *                               post-processing mesh
653  * \param[in]       vertex_list  list of vertices (0 to n-1) of
654  *                               post-processing mesh
655  * \param[in]       ts           time step status structure, or NULL
656  */
657 /*----------------------------------------------------------------------------*/
658 
659 void
cs_user_postprocess_values(const char * mesh_name,int mesh_id,int cat_id,cs_probe_set_t * probes,cs_lnum_t n_cells,cs_lnum_t n_i_faces,cs_lnum_t n_b_faces,cs_lnum_t n_vertices,const cs_lnum_t cell_list[],const cs_lnum_t i_face_list[],const cs_lnum_t b_face_list[],const cs_lnum_t vertex_list[],const cs_time_step_t * ts)660 cs_user_postprocess_values(const char            *mesh_name,
661                            int                    mesh_id,
662                            int                    cat_id,
663                            cs_probe_set_t        *probes,
664                            cs_lnum_t              n_cells,
665                            cs_lnum_t              n_i_faces,
666                            cs_lnum_t              n_b_faces,
667                            cs_lnum_t              n_vertices,
668                            const cs_lnum_t        cell_list[],
669                            const cs_lnum_t        i_face_list[],
670                            const cs_lnum_t        b_face_list[],
671                            const cs_lnum_t        vertex_list[],
672                            const cs_time_step_t  *ts)
673 {
674   CS_NO_WARN_IF_UNUSED(probes);
675   CS_NO_WARN_IF_UNUSED(n_vertices);
676   CS_NO_WARN_IF_UNUSED(vertex_list);
677 
678   /* Output of k = 1/2 (R11+R22+R33) for the Rij-epsilon model
679      ------------------------------------------------------ */
680 
681   /*< [postprocess_values_ex_1] */
682   if (cat_id == CS_POST_MESH_VOLUME) { /* filter: only for volume
683                                           postprocessing mesh */
684 
685     if (cs_glob_turb_model->itytur == 3) {
686 
687       cs_real_t *s_cell;
688       BFT_MALLOC(s_cell, n_cells, cs_real_t);
689 
690       const cs_real_6_t *cvar_r = (const cs_real_6_t *)(CS_F_(rij)->val);
691       for (cs_lnum_t i = 0; i < n_cells; i++) {
692         cs_lnum_t cell_id = cell_list[i];
693         s_cell[i] = 0.5* (  cvar_r[cell_id][0]
694                           + cvar_r[cell_id][1]
695                           + cvar_r[cell_id][2]);
696       }
697 
698       cs_post_write_var(mesh_id,
699                         CS_POST_WRITER_ALL_ASSOCIATED,  /* writer id filter */
700                         "Turb energy",                  /* var_name */
701                         1,                              /* var_dim */
702                         true,                           /* interlace, */
703                         false,                          /* use_parent */
704                         CS_POST_TYPE_cs_real_t,         /* var_type */
705                         s_cell,                         /* cel_vals */
706                         NULL,                           /* i_face_vals */
707                         NULL,                           /* b_face_vals */
708                         ts);
709 
710       BFT_FREE(s_cell);
711 
712     }
713 
714   }
715   /*< [postprocess_values_ex_1] */
716 
717   /* Output pressure on surface mesh
718      ------------------------------- */
719 
720   /*< [postprocess_values_ex_2] */
721   if (strcmp(mesh_name, "pressure_surface") == 0) { /* Restrict to this mesh */
722 
723     cs_real_t *cvar_p = CS_F_(p)->val; /* pressure */
724 
725     /* Ensure variable is synchronized in parallel or periodic cases;
726        should already have been done before, repeated for safety */
727     cs_mesh_sync_var_scal(cvar_p);
728 
729     const cs_mesh_t *m = cs_glob_mesh;
730 
731     cs_real_t *s_i_faces = NULL, *s_b_faces = NULL;
732 
733     /* Interior faces  */
734 
735     if (n_i_faces > 0) {
736       BFT_MALLOC(s_i_faces, n_i_faces, cs_real_t);
737 
738       for (cs_lnum_t i = 0; i < n_i_faces; i++) {
739         cs_lnum_t face_id = i_face_list[i];
740         /* Use unweighted mean of adjacent cell values here */
741         cs_lnum_t c1 = m->i_face_cells[face_id][0];
742         cs_lnum_t c2 = m->i_face_cells[face_id][1];
743         s_i_faces[i] = 0.5 * (cvar_p[c1] + cvar_p[c2]);
744       }
745     }
746 
747     /* Boundary faces  */
748 
749     if (n_b_faces > 0) {
750       BFT_MALLOC(s_b_faces, n_b_faces, cs_real_t);
751 
752       for (cs_lnum_t i = 0; i < n_b_faces; i++) {
753         cs_lnum_t face_id = b_face_list[i];
754         /* Use adjacent cell value here */
755         cs_lnum_t cell_id = m->b_face_cells[face_id];
756         s_b_faces[i] = cvar_p[cell_id];
757       }
758     }
759 
760     cs_post_write_var(mesh_id,
761                       CS_POST_WRITER_ALL_ASSOCIATED,  /* writer id filter */
762                       "Pressure",                     /* var_name */
763                       1,                              /* var_dim */
764                       true,                           /* interlace, */
765                       false,                          /* use_parent */
766                       CS_POST_TYPE_cs_real_t,         /* var_type */
767                       NULL,                           /* cel_vals */
768                       s_i_faces,                      /* i_face_vals */
769                       s_b_faces,                      /* b_face_vals */
770                       ts);
771 
772     BFT_FREE(s_i_faces);
773     BFT_FREE(s_b_faces);
774   }
775   /*< [postprocess_values_ex_2] */
776 
777   /* Output cell-based scalar user field values on volume and meshes
778      ---------------------------------------------------------------- */
779 
780   /*< [postprocess_values_ex_3] */
781   if (   cat_id == CS_POST_MESH_VOLUME
782       || cat_id == CS_POST_MESH_PROBES) {
783 
784     const cs_field_t *f = cs_field_by_name_try("my_field");
785 
786     if (f != NULL)
787       cs_post_write_var(mesh_id,
788                         CS_POST_WRITER_ALL_ASSOCIATED,  /* writer id filter */
789                         f->name,                        /* var_name */
790                         1,                              /* var_dim */
791                         true,                           /* interlace, */
792                         true,                           /* use_parent */
793                         CS_POST_TYPE_cs_real_t,         /* var_type */
794                         f->val,                         /* cel_vals */
795                         NULL,                           /* i_face_vals */
796                         NULL,                           /* b_face_vals */
797                         ts);
798   }
799   /*< [postprocess_values_ex_3] */
800 
801   /* Output constant cell-based scalar user field values on volume mesh
802      ------------------------------------------------------------------ */
803 
804   /*< [postprocess_values_ex_4] */
805   if (cat_id == CS_POST_MESH_VOLUME) {
806 
807     const cs_field_t *f = cs_field_by_name_try("my_const_field");
808 
809     if (f != NULL) {
810       if (ts->nt_cur == ts->nt_prev + 1) { /* before time loop */
811 
812         cs_time_step_t ts0 = *ts;
813         ts0.nt_cur = 1; /* Negative time step value implies time-independent */
814 
815         cs_post_write_var(mesh_id,
816                           CS_POST_WRITER_ALL_ASSOCIATED,  /* writer id filter */
817                           f->name,                        /* var_name */
818                           1,                              /* var_dim */
819                           true,                           /* interlace, */
820                           true,                           /* use_parent */
821                           CS_POST_TYPE_cs_real_t,         /* var_type */
822                           f->val,                         /* cel_vals */
823                           NULL,                           /* i_face_vals */
824                           NULL,                           /* b_face_vals */
825                           &ts0);
826 
827       }
828     }
829 
830   }
831   /*< [postprocess_values_ex_4] */
832 }
833 
834 /*----------------------------------------------------------------------------*/
835 /*!
836  * Override default frequency or calculation end based output.
837  *
838  * This allows fine-grained control of activation or deactivation,
839  *
840  * \param[in]  nt_max_abs  maximum time step number
841  * \param[in]  nt_cur_abs  current time step number
842  * \param[in]  t_cur_abs   absolute time at the current time step
843  */
844 /*----------------------------------------------------------------------------*/
845 
846 void
cs_user_postprocess_activate(int nt_max_abs,int nt_cur_abs,double t_cur_abs)847 cs_user_postprocess_activate(int     nt_max_abs,
848                              int     nt_cur_abs,
849                              double  t_cur_abs)
850 {
851   CS_NO_WARN_IF_UNUSED(nt_cur_abs);
852   CS_NO_WARN_IF_UNUSED(t_cur_abs);
853 
854   /* Use the cs_post_activate_writer() function to force the
855    * "active" or "inactive" flag for a specific writer or for all
856    * writers for the current time step.
857 
858    * the parameters for cs_post_activate_writer() are:
859    *   writer_id <-- writer id, or 0 for all writers
860    *   activate  <-- false to deactivate, true to activate */
861 
862   /* Example: deactivate all output before time step 1000 */
863 
864   /*! [post_activate] */
865   if (nt_max_abs < 1000) {
866     int writer_id = 0; /* 0: all writers */
867     cs_post_activate_writer(writer_id, false);
868   }
869   /*! [post_activate] */
870 }
871 
872 /*----------------------------------------------------------------------------*/
873 
874 END_C_DECLS
875