1 /*============================================================================
2  * Management of post-processing for joining operation
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 <assert.h>
34 #include <stdio.h>
35 #include <string.h>
36 
37 /*----------------------------------------------------------------------------
38  *  Local headers
39  *---------------------------------------------------------------------------*/
40 
41 #include "bft_error.h"
42 #include "bft_mem.h"
43 
44 #include "fvm_nodal.h"
45 #include "fvm_nodal_order.h"
46 #include "fvm_nodal_from_desc.h"
47 #include "fvm_writer.h"
48 
49 #include "cs_file.h"
50 #include "cs_mesh_connect.h"
51 #include "cs_post.h"
52 #include "cs_timer_stats.h"
53 
54 /*----------------------------------------------------------------------------
55  *  Header for the current file
56  *---------------------------------------------------------------------------*/
57 
58 #include "cs_join_post.h"
59 
60 /*---------------------------------------------------------------------------*/
61 
62 BEGIN_C_DECLS
63 
64 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
65 
66 /*============================================================================
67  * Macro and type definitions
68  *===========================================================================*/
69 
70 typedef struct {
71 
72   int            writer_num;    /* identifier for the related writer */
73   fvm_writer_t  *writer;        /* writer used for post-processing */
74 
75 } cs_join_post_t;
76 
77 /* Directory name separator
78    (historically, '/' for Unix/Linux, '\' for Windows, ':' for Mac
79    but '/' should work for all on modern systems) */
80 
81 #define DIR_SEPARATOR '/'
82 
83 /*============================================================================
84  * Static global variables
85  *===========================================================================*/
86 
87 static  cs_join_post_t  _cs_join_post_param;
88 
89 static  bool            _cs_join_post_initialized = false;
90 static  int             _post_stage_stat_id = -1;
91 
92 /*============================================================================
93  * Private function definitions
94  *===========================================================================*/
95 
96 /*----------------------------------------------------------------------------
97  * Initialize post-processing writer with same format and associated
98  * options as default writer, but no time dependency, intended to
99  * post elements implied in the joining operations.
100  *
101  * returns:
102  *   id of associated writer (< 0, or 0 in case of failure)
103  *----------------------------------------------------------------------------*/
104 
105 static int
_init_join_writer(void)106 _init_join_writer(void)
107 {
108   int  writer_id = cs_post_get_free_writer_id();
109 
110   /* Special case for Catalyst: if matching co-processing script is
111      not available, revert to EnSight Gold format */
112 
113   int default_format_id
114     = fvm_writer_get_format_id(cs_post_get_default_format());
115 
116   if (default_format_id == fvm_writer_get_format_id("Catalyst")) {
117     if (! cs_file_isreg("error.py"))
118       return 0;
119   }
120 
121   cs_post_define_writer(writer_id,
122                         "joining",
123                         "postprocessing",
124                         fvm_writer_format_name(default_format_id),
125                         cs_post_get_default_format_options(),
126                         FVM_WRITER_FIXED_MESH,
127                         false,
128                         false,
129                         -1,
130                         -1.0);
131 
132   return  writer_id;
133 }
134 
135 /*----------------------------------------------------------------------------
136  * Write a field of "double" on the vertices of the selected mesh.
137  * Variable is interlaced.
138  *
139  * parameters:
140  *  mesh      <--  mesh on which we want to write the current field.
141  *  varname   <--  name of the field.
142  *  dim       <--  dimension of the field to export.
143  *  field     <--  variable to write.
144  *---------------------------------------------------------------------------*/
145 
146 static void
_post_vtx_dfield(fvm_nodal_t * mesh,const char * varname,int dim,const double * field)147 _post_vtx_dfield(fvm_nodal_t   *mesh,
148                  const char    *varname,
149                  int            dim,
150                  const double  *field)
151 {
152   fvm_writer_t  *writer = _cs_join_post_param.writer;
153 
154   cs_lnum_t  parent_num_shift[2]  = {0, 0};
155 
156   const double  *var_ptr[9] = {NULL, NULL, NULL,
157                                NULL, NULL, NULL,
158                                NULL, NULL, NULL};
159 
160   assert(writer != NULL);
161   assert(sizeof(double) == 8);
162 
163   var_ptr[0] = field;
164 
165   fvm_writer_export_field(writer,
166                           mesh,
167                           varname,
168                           FVM_WRITER_PER_NODE,
169                           dim,
170                           CS_INTERLACE,
171                           0,
172                           parent_num_shift,
173                           CS_DOUBLE,
174                           -1,
175                           0.,
176                           (const void **)var_ptr);
177 }
178 
179 /*----------------------------------------------------------------------------
180  * Write an integer field on the elements of the selected mesh.
181  * Variable is interlaced.
182  *
183  * parameters:
184  *  mesh      <--  mesh on which we want to write the current field.
185  *  varname   <--  name of the field.
186  *  dim       <--  dimension of the field to export.
187  *  field     <--  variable to write.
188  *---------------------------------------------------------------------------*/
189 
190 static void
_post_elt_ifield(fvm_nodal_t * mesh,const char * varname,int dim,const int * field)191 _post_elt_ifield(fvm_nodal_t  *mesh,
192                  const char   *varname,
193                  int           dim,
194                  const int    *field)
195 {
196   fvm_writer_t  *writer = _cs_join_post_param.writer;
197 
198   cs_lnum_t  parent_num_shift[2]  = {0, 0};
199   cs_datatype_t  datatype = CS_DATATYPE_NULL;
200 
201   const int  *var_ptr[9] = {NULL, NULL, NULL,
202                             NULL, NULL, NULL,
203                             NULL, NULL, NULL};
204 
205   assert(writer != NULL);
206   assert(sizeof(cs_lnum_t) == sizeof(int));
207 
208   if (sizeof(int) == 4)
209     datatype = CS_INT32;
210   else if (sizeof(int) == 8)
211     datatype = CS_INT64;
212   else
213     bft_error(__FILE__, __LINE__, 0,
214               _(" Size of \"int\" is not 4 or 8 bytes.\n"
215                 " Check the datatype of the field to export.\n"));
216 
217   var_ptr[0] = field;
218 
219   fvm_writer_export_field(writer,
220                           mesh,
221                           varname,
222                           FVM_WRITER_PER_ELEMENT,
223                           dim,
224                           CS_INTERLACE,
225                           0,
226                           parent_num_shift,
227                           datatype,
228                           -1,
229                           0.,
230                           (const void **)var_ptr);
231 }
232 
233 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
234 
235 /*============================================================================
236  * Public function definitions
237  *===========================================================================*/
238 
239 /*----------------------------------------------------------------------------
240  * Create a writer to output post-processing files for a joining operation.
241  *---------------------------------------------------------------------------*/
242 
243 void
cs_join_post_init(void)244 cs_join_post_init(void)
245 {
246   if (_cs_join_post_initialized == true)
247     return;
248 
249   _post_stage_stat_id = cs_timer_stats_id_by_name("postprocessing_stage");
250 
251   int  writer_num = _init_join_writer();
252 
253   if (writer_num != 0) {
254 
255     _cs_join_post_initialized = true;
256 
257     cs_post_activate_writer(writer_num, 1);
258 
259     _cs_join_post_param.writer = cs_post_get_writer(writer_num);
260     _cs_join_post_param.writer_num = writer_num;
261 
262   }
263 }
264 
265 /*----------------------------------------------------------------------------
266  * Post-treatment of a cs_join_mesh_t structure.
267  *
268  * parameters:
269  *   mesh_name <-- name of the mesh for the post-processing
270  *   mesh      <-- pointer to a cs_join_mesh_t structure to post-process
271  *---------------------------------------------------------------------------*/
272 
273 void
cs_join_post_mesh(const char * mesh_name,const cs_join_mesh_t * join_mesh)274 cs_join_post_mesh(const char            *mesh_name,
275                   const cs_join_mesh_t  *join_mesh)
276 {
277   if (_cs_join_post_initialized == true)
278     return;
279 
280   int t_top_id = cs_timer_stats_switch(_post_stage_stat_id);
281 
282   int  i, j;
283   cs_lnum_t  n_vertices;
284 
285   const char *name = NULL;
286   int  *ifield = NULL;
287   double  *dfield = NULL;
288   cs_gnum_t  *vertex_gnum = NULL;
289   cs_real_t  *vertex_coord = NULL;
290   cs_lnum_t  *parent_vtx_num = NULL;
291   fvm_nodal_t  *post_mesh = NULL;
292   fvm_writer_t  *writer = _cs_join_post_param.writer;
293 
294   const int  local_rank = CS_MAX(cs_glob_rank_id, 0);
295   const cs_lnum_t  face_list_shift[2] = {0, join_mesh->n_faces};
296   const cs_lnum_t  *face_vertex_idx[1] = {join_mesh->face_vtx_idx};
297   const cs_lnum_t  *face_vertex_lst[1] = {join_mesh->face_vtx_lst};
298 
299   /* Define an fvm_nodal_mesh_t structure from a cs_join_mesh_t structure */
300 
301   /* Create an empty fvm_nodal_t structure. */
302 
303   if (mesh_name == NULL)
304     name = join_mesh->name;
305   else
306     name = mesh_name;
307 
308   post_mesh = fvm_nodal_create(name, 3);
309 
310   /* Define fvm_nodal_t structure */
311 
312   fvm_nodal_from_desc_add_faces(post_mesh,
313                                 -1,
314                                 join_mesh->n_faces,
315                                 NULL,
316                                 1,
317                                 face_list_shift,
318                                 face_vertex_idx,
319                                 face_vertex_lst,
320                                 NULL,
321                                 NULL);
322 
323   /* Define vertex_coord for fvm_nodal_set_shared_vertices() */
324 
325   BFT_MALLOC(vertex_coord, 3*join_mesh->n_vertices, cs_real_t);
326 
327   for (i = 0; i < join_mesh->n_vertices; i++)
328     for (j = 0; j < 3; j++)
329       vertex_coord[3*i+j] = (join_mesh->vertices[i]).coord[j];
330 
331   fvm_nodal_set_shared_vertices(post_mesh, vertex_coord);
332 
333   /* Order faces by increasing global number */
334 
335   fvm_nodal_order_faces(post_mesh, join_mesh->face_gnum);
336   fvm_nodal_init_io_num(post_mesh, join_mesh->face_gnum, 2);
337 
338   /* Order vertices by increasing global number */
339 
340   BFT_MALLOC(vertex_gnum, join_mesh->n_vertices, cs_gnum_t);
341 
342   for (i = 0; i < join_mesh->n_vertices; i++)
343     vertex_gnum[i] = (join_mesh->vertices[i]).gnum;
344 
345   fvm_nodal_order_vertices(post_mesh, vertex_gnum);
346   fvm_nodal_init_io_num(post_mesh, vertex_gnum, 0);
347 
348   /* Write current mesh */
349 
350   fvm_writer_export_nodal(writer, post_mesh);
351 
352   BFT_FREE(vertex_gnum);
353   BFT_FREE(vertex_coord);
354 
355   /* Write rank associated to each face */
356 
357   BFT_MALLOC(ifield, join_mesh->n_faces, int);
358 
359   for (i = 0; i < join_mesh->n_faces; i++)
360     ifield[i] = local_rank;
361 
362   _post_elt_ifield(post_mesh, _("Rank"), 1, ifield);
363 
364   BFT_FREE(ifield);
365 
366   /* Write vertex tolerance */
367 
368   n_vertices = fvm_nodal_get_n_entities(post_mesh, 0);
369 
370   BFT_MALLOC(parent_vtx_num, n_vertices, cs_lnum_t);
371   BFT_MALLOC(dfield, n_vertices, double);
372 
373   fvm_nodal_get_parent_num(post_mesh, 0, parent_vtx_num);
374 
375   for (i = 0; i < n_vertices; i++) {
376 
377     cs_join_vertex_t  data = join_mesh->vertices[parent_vtx_num[i]-1];
378 
379     dfield[i] = data.tolerance;
380   }
381 
382   _post_vtx_dfield(post_mesh, _("VtxTolerance"), 1, dfield);
383 
384   BFT_FREE(parent_vtx_num);
385   BFT_FREE(dfield);
386 
387   post_mesh = fvm_nodal_destroy(post_mesh);
388 
389   cs_timer_stats_switch(t_top_id);
390 }
391 
392 /*----------------------------------------------------------------------------
393  * Post-process a subset of faces of a cs_join_mesh_t structure.
394  *
395  * parameters:
396  *   mesh_name        <-- name of the sub-set mesh
397  *   mesh             <-- pointer to the parent cs_join_mesh_t structure
398  *   n_selected_faces <-- number of selected faces (size of the sub-set)
399  *   selected_faces   <-- list of local number in parent mesh
400  *---------------------------------------------------------------------------*/
401 
402 void
cs_join_post_faces_subset(const char * mesh_name,const cs_join_mesh_t * parent_mesh,cs_lnum_t n_select_faces,const cs_lnum_t selected_faces[])403 cs_join_post_faces_subset(const char            *mesh_name,
404                           const cs_join_mesh_t  *parent_mesh,
405                           cs_lnum_t              n_select_faces,
406                           const cs_lnum_t        selected_faces[])
407 {
408   if (_cs_join_post_initialized == true)
409     return;
410 
411   int t_top_id = cs_timer_stats_switch(_post_stage_stat_id);
412 
413   cs_join_mesh_t  *subset_mesh = NULL;
414 
415   assert(parent_mesh != NULL);
416 
417   subset_mesh = cs_join_mesh_create_from_subset(mesh_name,
418                                                 n_select_faces,
419                                                 selected_faces,
420                                                 parent_mesh);
421 
422   cs_join_post_mesh(subset_mesh->name, subset_mesh);
423 
424   cs_join_mesh_destroy(&subset_mesh);
425 
426   cs_timer_stats_switch(t_top_id);
427 }
428 
429 /*----------------------------------------------------------------------------
430  * Post-process mesh after the update following the merge operation.
431  *
432  * parameters:
433  *   join_param  <-- set of parameters for the joining operation
434  *   join_select <-- list of participating entities in the joining operation
435  *---------------------------------------------------------------------------*/
436 
437 void
cs_join_post_after_merge(cs_join_param_t join_param,const cs_join_select_t * join_select)438 cs_join_post_after_merge(cs_join_param_t          join_param,
439                          const cs_join_select_t  *join_select)
440 {
441   if (_cs_join_post_initialized == true)
442     return;
443 
444   int t_top_id = cs_timer_stats_switch(_post_stage_stat_id);
445 
446   int  adj_mesh_id, sel_mesh_id;
447 
448   int  writer_ids[] = {_cs_join_post_param.writer_num};
449   char  *mesh_name = NULL;
450   fvm_nodal_t *adj_mesh = NULL, *sel_mesh = NULL;
451 
452   adj_mesh_id = cs_post_get_free_mesh_id();
453 
454   BFT_MALLOC(mesh_name, strlen("AdjacentJoinFaces_j") + 2 + 1, char);
455   sprintf(mesh_name,"%s%02d", "AdjacentJoinFaces_j", join_param.num);
456 
457   adj_mesh = cs_mesh_connect_faces_to_nodal(cs_glob_mesh,
458                                             mesh_name,
459                                             false, /* include families */
460                                             join_select->n_i_adj_faces,
461                                             join_select->n_b_adj_faces,
462                                             join_select->i_adj_faces,
463                                             join_select->b_adj_faces);
464 
465   cs_post_define_existing_mesh(adj_mesh_id,
466                                adj_mesh,
467                                0,    /* dim_shift */
468                                true, /* transfer ownership */
469                                false,
470                                1,
471                                writer_ids);
472 
473   sel_mesh_id = cs_post_get_free_mesh_id();
474 
475   BFT_REALLOC(mesh_name, strlen("JoinFacesAfterMerge_j") + 2 + 1, char);
476   sprintf(mesh_name,"%s%02d", "JoinFacesAfterMerge_j", join_param.num);
477 
478   sel_mesh = cs_mesh_connect_faces_to_nodal(cs_glob_mesh,
479                                             mesh_name,
480                                             false, /* include families */
481                                             0,
482                                             join_select->n_faces,
483                                             NULL,
484                                             join_select->faces);
485 
486   cs_post_define_existing_mesh(sel_mesh_id,
487                                sel_mesh,
488                                0,    /* dim_shift */
489                                true, /* transfer ownership */
490                                false,
491                                1,
492                                writer_ids);
493 
494   /* Post */
495 
496   cs_post_activate_writer(_cs_join_post_param.writer_num, 1);
497   cs_post_write_meshes(NULL);
498 
499   cs_post_free_mesh(sel_mesh_id);
500   cs_post_free_mesh(adj_mesh_id);
501 
502   BFT_FREE(mesh_name);
503 
504   cs_timer_stats_switch(t_top_id);
505 }
506 
507 /*----------------------------------------------------------------------------
508  * Post-process mesh after the update following the split operation.
509  *
510  * parameters:
511  *   n_old_i_faces   <-- initial number of interior faces
512  *   n_old_b_faces   <-- initial number of border faces
513  *   n_g_new_b_faces <-- global number of new border faces
514  *   n_select_faces  <-- number of selected faces
515  *   mesh            <-- pointer to a cs_mesh_t structure
516  *   join_param      <-- set of parameters for the joining operation
517  *---------------------------------------------------------------------------*/
518 
519 void
cs_join_post_after_split(cs_lnum_t n_old_i_faces,cs_lnum_t n_old_b_faces,cs_gnum_t n_g_new_b_faces,cs_lnum_t n_select_faces,const cs_mesh_t * mesh,cs_join_param_t join_param)520 cs_join_post_after_split(cs_lnum_t         n_old_i_faces,
521                          cs_lnum_t         n_old_b_faces,
522                          cs_gnum_t         n_g_new_b_faces,
523                          cs_lnum_t         n_select_faces,
524                          const cs_mesh_t  *mesh,
525                          cs_join_param_t   join_param)
526 {
527   if (join_param.visualization < 1 || _cs_join_post_initialized == false)
528     return;
529 
530   int t_top_id = cs_timer_stats_switch(_post_stage_stat_id);
531 
532   cs_lnum_t  i, j;
533 
534   int  writer_ids[] = {_cs_join_post_param.writer_num};
535   char  *mesh_name = NULL;
536   cs_lnum_t  *post_i_faces = NULL, *post_b_faces = NULL;
537   fvm_nodal_t  *post_i_mesh = NULL;
538   int  post_i_mesh_id = cs_post_get_free_mesh_id();
539   int  post_b_mesh_id = 0;
540 
541   const int  n_new_i_faces = mesh->n_i_faces - n_old_i_faces;
542   const int  n_new_b_faces = mesh->n_b_faces - n_old_b_faces + n_select_faces;
543 
544   /* Define list of faces to post-treat */
545 
546   BFT_MALLOC(post_i_faces, n_new_i_faces, cs_lnum_t);
547   BFT_MALLOC(post_b_faces, n_new_b_faces, cs_lnum_t);
548 
549   for (i = n_old_i_faces, j = 0; i < mesh->n_i_faces; i++, j++)
550     post_i_faces[j] = i + 1;
551 
552   for (i = n_old_b_faces-n_select_faces, j = 0; i < mesh->n_b_faces; i++, j++)
553     post_b_faces[j] = i + 1;
554 
555   BFT_MALLOC(mesh_name, strlen("InteriorJoinedFaces_j") + 2 + 1, char);
556   sprintf(mesh_name,"%s%02d", "InteriorJoinedFaces_j", join_param.num);
557 
558   post_i_mesh = cs_mesh_connect_faces_to_nodal(cs_glob_mesh,
559                                                mesh_name,
560                                                false, /* include families */
561                                                n_new_i_faces,
562                                                0,
563                                                post_i_faces,
564                                                NULL);
565 
566   cs_post_define_existing_mesh(post_i_mesh_id,
567                                post_i_mesh,
568                                0,    /* dim_shift */
569                                true, /* transfer ownership */
570                                false,
571                                1,
572                                writer_ids);
573 
574   if (join_param.visualization > 1 && n_g_new_b_faces > 0) {
575 
576     fvm_nodal_t  *post_b_mesh = NULL;
577     post_b_mesh_id = cs_post_get_free_mesh_id();
578 
579     BFT_REALLOC(mesh_name, strlen("BoundaryJoinedFaces_j") + 2 + 1, char);
580     sprintf(mesh_name,"%s%02d", "BoundaryJoinedFaces_j", join_param.num);
581 
582     post_b_mesh = cs_mesh_connect_faces_to_nodal(cs_glob_mesh,
583                                                  mesh_name,
584                                                  false, /* include families */
585                                                  0,
586                                                  n_new_b_faces,
587                                                  NULL,
588                                                  post_b_faces);
589 
590     cs_post_define_existing_mesh(post_b_mesh_id,
591                                  post_b_mesh,
592                                  0,    /* dim_shift */
593                                  true, /* transfer ownership */
594                                  false,
595                                  1,
596                                  writer_ids);
597 
598   }
599 
600   /* Post */
601 
602   cs_post_activate_writer(_cs_join_post_param.writer_num, 1);
603   cs_post_write_meshes(NULL);
604 
605   if (post_b_mesh_id != 0)
606     cs_post_free_mesh(post_b_mesh_id);
607   cs_post_free_mesh(post_i_mesh_id);
608 
609   BFT_FREE(post_i_faces);
610   BFT_FREE(post_b_faces);
611   BFT_FREE(mesh_name);
612 
613   cs_timer_stats_switch(t_top_id);
614 }
615 
616 /*----------------------------------------------------------------------------
617  * Post-process mesh after the update following the split operation.
618  *
619  * parameters:
620  *   n_i_clean_faces <-- number of interior faces cleaned
621  *   i_clean_faces   <-> list of interior face numbers (ordered on exit)
622  *   n_b_clean_faces <-- number of border faces cleaned
623  *   b_clean_faces   <-> list of border face numbers (ordered on exit)
624  *   param           <-- set of parameters for the joining operation
625  *---------------------------------------------------------------------------*/
626 
627 void
cs_join_post_cleaned_faces(cs_lnum_t n_i_clean_faces,cs_lnum_t i_clean_faces[],cs_lnum_t n_b_clean_faces,cs_lnum_t b_clean_faces[],cs_join_param_t param)628 cs_join_post_cleaned_faces(cs_lnum_t        n_i_clean_faces,
629                            cs_lnum_t        i_clean_faces[],
630                            cs_lnum_t        n_b_clean_faces,
631                            cs_lnum_t        b_clean_faces[],
632                            cs_join_param_t  param)
633 {
634   if (_cs_join_post_initialized == false)
635     return;
636 
637   int t_top_id = cs_timer_stats_switch(_post_stage_stat_id);
638 
639   int  writer_ids[] = {_cs_join_post_param.writer_num};
640   int  post_mesh_id = cs_post_get_free_mesh_id();
641   char  *name = NULL;
642   fvm_nodal_t *export_mesh = NULL;
643 
644   BFT_MALLOC(name, strlen("CleanFaces_j") + 2 + 1, char);
645   sprintf(name,"%s%02d", "CleanFaces_j", param.num);
646 
647   export_mesh = cs_mesh_connect_faces_to_nodal(cs_glob_mesh,
648                                                name,
649                                                false, /* include families */
650                                                n_i_clean_faces,
651                                                n_b_clean_faces,
652                                                i_clean_faces,
653                                                b_clean_faces);
654 
655   cs_post_define_existing_mesh(post_mesh_id,
656                                export_mesh,
657                                0,    /* dim_shift */
658                                true, /* transfer ownership */
659                                false,
660                                1,
661                                writer_ids);
662 
663   /* Output post-processing data */
664 
665   cs_post_activate_writer(_cs_join_post_param.writer_num, 1);
666   cs_post_write_meshes(NULL);
667 
668   cs_post_free_mesh(post_mesh_id);
669 
670   BFT_FREE(name);
671 
672   cs_timer_stats_switch(t_top_id);
673 }
674 
675 /*----------------------------------------------------------------------------
676  * Output processor-specific post-processing data for a cs_join_mesh_t
677  * structure according to the visualization level.
678  *
679  * parameters:
680  *   basename <-- generic name for the mesh to post
681  *   mesh     <-- fvm_join_mesh_t structure to post-process
682  *   param    <-- fvm_join_param_t structure
683  *---------------------------------------------------------------------------*/
684 
685 void
cs_join_post_dump_mesh(const char * basename,const cs_join_mesh_t * mesh,cs_join_param_t param)686 cs_join_post_dump_mesh(const char            *basename,
687                        const cs_join_mesh_t  *mesh,
688                        cs_join_param_t        param)
689 {
690   int  rank, len;
691 
692   cs_join_mesh_t  *tmp = NULL;
693   char  *fullname = NULL;
694 
695   const  int  n_ranks = cs_glob_n_ranks;
696   const  int  rank_id = CS_MAX(cs_glob_rank_id, 0);
697 
698   /* Define a specific name for the output */
699 
700   len = strlen("log/JoinDBG_.dat") + strlen(basename) + 4 + 2 + 1;
701   BFT_MALLOC(fullname, len, char);
702   sprintf(fullname, "log%cJoin%02dDBG_%s%04d.dat", DIR_SEPARATOR,
703           param.num, basename, rank_id);
704 
705 #if 0 && defined(DEBUG) && !defined(NDEBUG) /* Dump mesh structure */
706   if (param.verbosity > 3) {
707     FILE  *dbg_file = NULL;
708     dbg_file = fopen(fullname, "w");
709     cs_join_mesh_dump_file(dbg_file, mesh);
710     fflush(dbg_file);
711     fclose(dbg_file);
712   }
713 #endif
714 
715   if (_cs_join_post_initialized == true && param.visualization > 3) {
716 
717     if (n_ranks == 1)
718       cs_join_post_mesh(fullname, mesh);
719 
720     else { /* Parallel */
721 
722       for (rank = 0; rank < n_ranks; rank++) {
723 
724         char *mesh_name = NULL;
725 
726         BFT_MALLOC(mesh_name, strlen(basename) + 2 + 2 + 5 + 1, char);
727         sprintf(mesh_name,"%s%02d%s%05d", basename, param.num, "_n", rank);
728 
729         if (rank_id == rank)
730           cs_join_post_mesh(mesh_name, mesh);
731 
732         else { /* Pieces empty on other ranks */
733           tmp = cs_join_mesh_create(mesh_name);
734           cs_join_post_mesh(mesh_name, tmp);
735           cs_join_mesh_destroy(&tmp);
736         }
737 
738         BFT_FREE(mesh_name);
739 
740       } /* End of loop on ranks */
741     } /* End of parallel treatment */
742   }
743 
744   BFT_FREE(fullname);
745 
746 #if defined(HAVE_MPI)
747   if (n_ranks > 1)
748     MPI_Barrier(cs_glob_mpi_comm);
749 #endif
750 }
751 
752 /*---------------------------------------------------------------------------*/
753 
754 END_C_DECLS
755