~ubuntu-branches/ubuntu/precise/code-saturne/precise

« back to all changes in this revision

Viewing changes to src/fvm/fvm_to_ensight.c

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2011-11-01 17:43:32 UTC
  • mto: (6.1.7 sid)
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: package-import@ubuntu.com-20111101174332-tl4vk45no0x3emc3
Tags: upstream-2.1.0
ImportĀ upstreamĀ versionĀ 2.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*============================================================================
 
2
 * Write a nodal representation associated with a mesh and associated
 
3
 * variables to EnSight Gold files
 
4
 *============================================================================*/
 
5
 
 
6
/*
 
7
  This file is part of Code_Saturne, a general-purpose CFD tool.
 
8
 
 
9
  Copyright (C) 1998-2011 EDF S.A.
 
10
 
 
11
  This program is free software; you can redistribute it and/or modify it under
 
12
  the terms of the GNU General Public License as published by the Free Software
 
13
  Foundation; either version 2 of the License, or (at your option) any later
 
14
  version.
 
15
 
 
16
  This program is distributed in the hope that it will be useful, but WITHOUT
 
17
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
18
  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
19
  details.
 
20
 
 
21
  You should have received a copy of the GNU General Public License along with
 
22
  this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 
23
  Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
24
*/
 
25
 
 
26
/*----------------------------------------------------------------------------*/
 
27
 
 
28
#if defined(HAVE_CONFIG_H)
 
29
#include "cs_config.h"
 
30
#endif
 
31
 
 
32
/*----------------------------------------------------------------------------
 
33
 * Standard C library headers
 
34
 *----------------------------------------------------------------------------*/
 
35
 
 
36
#include <assert.h>
 
37
#include <stdio.h>
 
38
#include <stdlib.h>
 
39
#include <string.h>
 
40
#include <errno.h>
 
41
 
 
42
/*----------------------------------------------------------------------------
 
43
 * BFT library headers
 
44
 *----------------------------------------------------------------------------*/
 
45
 
 
46
#include <bft_error.h>
 
47
#include <bft_mem.h>
 
48
#include <bft_file.h>
 
49
#include <bft_printf.h>
 
50
 
 
51
/*----------------------------------------------------------------------------
 
52
 *  Local headers
 
53
 *----------------------------------------------------------------------------*/
 
54
 
 
55
#include "fvm_config_defs.h"
 
56
#include "fvm_defs.h"
 
57
#include "fvm_convert_array.h"
 
58
#include "fvm_part_to_block.h"
 
59
#include "fvm_block_to_part.h"
 
60
#include "fvm_gather.h"
 
61
#include "fvm_io_num.h"
 
62
#include "fvm_nodal.h"
 
63
#include "fvm_nodal_priv.h"
 
64
#include "fvm_parall.h"
 
65
#include "fvm_to_ensight_case.h"
 
66
#include "fvm_writer_helper.h"
 
67
#include "fvm_writer_priv.h"
 
68
#include "fvm_file.h"
 
69
 
 
70
/*----------------------------------------------------------------------------
 
71
 *  Header for the current file
 
72
 *----------------------------------------------------------------------------*/
 
73
 
 
74
#include "fvm_to_ensight.h"
 
75
 
 
76
/*----------------------------------------------------------------------------*/
 
77
 
 
78
#ifdef __cplusplus
 
79
extern "C" {
 
80
#if 0
 
81
} /* Fake brace to force back Emacs auto-indentation back to column 0 */
 
82
#endif
 
83
#endif /* __cplusplus */
 
84
 
 
85
/*============================================================================
 
86
 * Local Type Definitions
 
87
 *============================================================================*/
 
88
 
 
89
/*----------------------------------------------------------------------------
 
90
 * EnSight Gold writer structure
 
91
 *----------------------------------------------------------------------------*/
 
92
 
 
93
typedef struct {
 
94
 
 
95
  char        *name;               /* Writer name */
 
96
 
 
97
  int          rank;               /* Rank of current process in communicator */
 
98
  int          n_ranks;            /* Number of processes in communicator */
 
99
 
 
100
  _Bool        text_mode;          /* true if using text output */
 
101
  _Bool        swap_endian;        /* true if binary file endianness must
 
102
                                      be changed */
 
103
 
 
104
  _Bool        discard_polygons;   /* Option to discard polygonal elements */
 
105
  _Bool        discard_polyhedra;  /* Option to discard polyhedral elements */
 
106
 
 
107
  _Bool        divide_polygons;    /* Option to tesselate polygonal elements */
 
108
  _Bool        divide_polyhedra;   /* Option to tesselate polyhedral elements */
 
109
 
 
110
  fvm_to_ensight_case_t  *case_info;  /* Associated case structure */
 
111
 
 
112
#if defined(HAVE_MPI)
 
113
  MPI_Comm     comm;               /* Associated MPI communicator */
 
114
#endif
 
115
 
 
116
} fvm_to_ensight_writer_t;
 
117
 
 
118
/*----------------------------------------------------------------------------
 
119
 * Indirect file structure to handle both text and binary files
 
120
 *----------------------------------------------------------------------------*/
 
121
 
 
122
typedef struct {
 
123
 
 
124
  bft_file_t  *tf;                 /* Text file handing structure */
 
125
  fvm_file_t  *bf;                 /* Binary file handling structure */
 
126
 
 
127
} _ensight_file_t;
 
128
 
 
129
/*============================================================================
 
130
 * Static global variables
 
131
 *============================================================================*/
 
132
 
 
133
static const char  *_ensight_type_name[FVM_N_ELEMENT_TYPES] = {"bar2",
 
134
                                                               "tria3",
 
135
                                                               "quad4",
 
136
                                                               "nsided",
 
137
                                                               "tetra4",
 
138
                                                               "pyramid5",
 
139
                                                               "penta6",
 
140
                                                               "hexa8",
 
141
                                                               "nfaced"};
 
142
 
 
143
/*============================================================================
 
144
 * Private function definitions
 
145
 *============================================================================*/
 
146
 
 
147
/*----------------------------------------------------------------------------
 
148
 * Open an EnSight Gold geometry or variable file
 
149
 *
 
150
 * parameters:
 
151
 *   this_writer <-- pointer to Ensight Gold writer structure.
 
152
 *   filename    <-- name of file to open.
 
153
 *   apend       <-- if true, append to file instead of overwriting
 
154
 *----------------------------------------------------------------------------*/
 
155
 
 
156
static _ensight_file_t
 
157
_open_ensight_file(const fvm_to_ensight_writer_t  *this_writer,
 
158
                   const char                     *filename,
 
159
                   _Bool                           append)
 
160
{
 
161
  _ensight_file_t f = {NULL, NULL};
 
162
 
 
163
  if (this_writer->text_mode == true) {
 
164
    bft_file_mode_t mode = append ? BFT_FILE_MODE_APPEND : BFT_FILE_MODE_WRITE;
 
165
    if (this_writer->rank == 0)
 
166
      f.tf = bft_file_open(filename, mode, BFT_FILE_TYPE_TEXT);
 
167
  }
 
168
  else {
 
169
    fvm_file_mode_t mode = append ? FVM_FILE_MODE_APPEND : FVM_FILE_MODE_WRITE;
 
170
    const int hints = 0;
 
171
#if defined(HAVE_MPI)
 
172
    f.bf = fvm_file_open(filename, mode, hints, this_writer->comm);
 
173
#else
 
174
    f.bf = fvm_file_open(filename, mode, hints);
 
175
#endif
 
176
    if (this_writer->swap_endian == true)
 
177
      fvm_file_set_swap_endian(f.bf, 1);
 
178
  }
 
179
 
 
180
  return f;
 
181
}
 
182
 
 
183
/*----------------------------------------------------------------------------
 
184
 * close an EnSight Gold geometry or variable file
 
185
 *
 
186
 * parameters:
 
187
 *   f <-- pointer to file handler structure.
 
188
 *----------------------------------------------------------------------------*/
 
189
 
 
190
static void
 
191
_free_ensight_file(_ensight_file_t  *f)
 
192
{
 
193
  if (f->tf != NULL)
 
194
    f->tf = bft_file_free(f->tf);
 
195
 
 
196
  else if (f->bf != NULL)
 
197
    f->bf = fvm_file_free(f->bf);
 
198
}
 
199
 
 
200
/*----------------------------------------------------------------------------
 
201
 * Count number of extra vertices when tesselations are present
 
202
 *
 
203
 * parameters:
 
204
 *   mesh               <-- pointer to nodal mesh structure
 
205
 *   divide_polyhedra   <-- true if polyhedra are tesselated
 
206
 *   n_extra_vertices_g --> global number of extra vertices (optional)
 
207
 *   n_extra_vertices   --> local number of extra vertices (optional)
 
208
 *----------------------------------------------------------------------------*/
 
209
 
 
210
static void
 
211
_count_extra_vertices(const fvm_nodal_t  *mesh,
 
212
                      _Bool               divide_polyhedra,
 
213
                      fvm_gnum_t         *n_extra_vertices_g,
 
214
                      fvm_lnum_t         *n_extra_vertices)
 
215
{
 
216
  int  i;
 
217
 
 
218
  const int  export_dim = fvm_nodal_get_max_entity_dim(mesh);
 
219
 
 
220
  /* Initial count and allocation */
 
221
 
 
222
  if (n_extra_vertices_g != NULL)
 
223
    *n_extra_vertices_g = 0;
 
224
  if (n_extra_vertices != NULL)
 
225
    *n_extra_vertices   = 0;
 
226
 
 
227
  if (divide_polyhedra) {
 
228
 
 
229
    for (i = 0; i < mesh->n_sections; i++) {
 
230
 
 
231
      const fvm_nodal_section_t  *section = mesh->sections[i];
 
232
 
 
233
      /* Output if entity dimension equal to highest in mesh
 
234
         (i.e. no output of faces if cells present, or edges
 
235
         if cells or faces) */
 
236
 
 
237
      if (   section->entity_dim == export_dim
 
238
          && section->type == FVM_CELL_POLY
 
239
          && section->tesselation != NULL) {
 
240
 
 
241
        if (n_extra_vertices_g != NULL)
 
242
          *n_extra_vertices_g
 
243
            += fvm_tesselation_n_g_vertices_add(section->tesselation);
 
244
 
 
245
        if (n_extra_vertices != NULL)
 
246
          *n_extra_vertices
 
247
            += fvm_tesselation_n_vertices_add(section->tesselation);
 
248
 
 
249
      }
 
250
    }
 
251
  }
 
252
}
 
253
 
 
254
/*----------------------------------------------------------------------------
 
255
 * Write string to a text or C binary EnSight Gold file
 
256
 *
 
257
 * parameters:
 
258
 *   f <-- file to write to
 
259
 *   s <-- string to write
 
260
 *----------------------------------------------------------------------------*/
 
261
 
 
262
static void
 
263
_write_string(_ensight_file_t   f,
 
264
              const char       *s)
 
265
{
 
266
  size_t  i;
 
267
  char  buf[82];
 
268
 
 
269
  if (f.tf != NULL) {
 
270
    strncpy(buf, s, 80);
 
271
    buf[80] = '\0';
 
272
    bft_file_printf(f.tf, "%s\n", buf);
 
273
  }
 
274
 
 
275
  else if (f.bf != NULL) {
 
276
    strncpy(buf, s, 80);
 
277
    buf[80] = '\0';
 
278
    for (i = strlen(buf); i < 80; i++)
 
279
      buf[i] = ' ';
 
280
    fvm_file_write_global(f.bf, buf, 1, 80);
 
281
  }
 
282
}
 
283
 
 
284
/*----------------------------------------------------------------------------
 
285
 * Write integer to a text or C binary EnSight Gold file
 
286
 *
 
287
 * parameters:
 
288
 *   f <-- file to write to
 
289
 *   n <-- integer value to write
 
290
 *----------------------------------------------------------------------------*/
 
291
 
 
292
inline static void
 
293
_write_int(_ensight_file_t  f,
 
294
           int32_t          n)
 
295
{
 
296
  if (f.tf != NULL)
 
297
    bft_file_printf(f.tf, "%10d\n", (int)n);
 
298
 
 
299
  else if (f.bf != NULL) {
 
300
    int _n = n;
 
301
    fvm_file_write_global(f.bf, &_n, sizeof(int32_t), 1);
 
302
  }
 
303
}
 
304
 
 
305
/*----------------------------------------------------------------------------
 
306
 * Write headers to an EnSight Gold geometry file.
 
307
 *
 
308
 * parameters:
 
309
 *   this_writer <-- pointer to Ensight Gold writer structure.
 
310
 *   f           <-- pointer to file to initialize.
 
311
 *----------------------------------------------------------------------------*/
 
312
 
 
313
static void
 
314
_write_geom_headers(fvm_to_ensight_writer_t  *this_writer,
 
315
                    _ensight_file_t           f)
 
316
{
 
317
  if (f.bf != NULL)
 
318
    _write_string(f, "C Binary");
 
319
 
 
320
  /* 1st description line */
 
321
  {
 
322
    char buf[81] = "";
 
323
    if (this_writer->name != NULL)
 
324
      strncpy(buf, this_writer->name, 80);
 
325
    buf[80] = '\0';
 
326
    _write_string(f, buf);
 
327
  }
 
328
  /* 2nd description line */
 
329
  _write_string(f, "Output by Code_Saturne version "VERSION);
 
330
  _write_string(f, "node id assign");
 
331
  _write_string(f, "element id assign");
 
332
}
 
333
 
 
334
#if defined(HAVE_MPI)
 
335
 
 
336
/*----------------------------------------------------------------------------
 
337
 * Write block of a vector of floats to an EnSight Gold file.
 
338
 *
 
339
 * This variant is called in parallel mode, where the values are already
 
340
 * in a temporary block buffer and may be discarded.
 
341
 *
 
342
 * parameters:
 
343
 *   num_start <-- global number of first element for this block
 
344
 *   num_end   <-- global number of past the last element for this block
 
345
 *   values    <-- pointer to values block array
 
346
 *   comm      <-- associated MPI communicator
 
347
 *   f         <-- file to write to
 
348
 *----------------------------------------------------------------------------*/
 
349
 
 
350
static void
 
351
_write_block_floats_g(fvm_gnum_t        num_start,
 
352
                      fvm_gnum_t        num_end,
 
353
                      float             values[],
 
354
                      MPI_Comm          comm,
 
355
                      _ensight_file_t   f)
 
356
{
 
357
  size_t  i;
 
358
  fvm_gnum_t  j;
 
359
 
 
360
  /* In Binary mode, all ranks have a file structure,
 
361
     we may use use a collective call */
 
362
 
 
363
  if (f.bf != NULL)
 
364
    fvm_file_write_block_buffer(f.bf,
 
365
                                values,
 
366
                                sizeof(float),
 
367
                                1,
 
368
                                num_start,
 
369
                                num_end);
 
370
 
 
371
  /* If all ranks do not have a binary file structure pointer, then
 
372
     we are using a text file, open only on rank 0 */
 
373
 
 
374
  else {
 
375
 
 
376
    float *_values = NULL;
 
377
    fvm_file_serializer_t *s
 
378
      = fvm_file_serializer_create(sizeof(float),
 
379
                                   1,
 
380
                                   num_start,
 
381
                                   num_end,
 
382
                                   0,
 
383
                                   values,
 
384
                                   comm);
 
385
 
 
386
    do {
 
387
 
 
388
      fvm_gnum_t range[2] = {num_start, num_end};
 
389
 
 
390
      _values = fvm_file_serializer_advance(s, range);
 
391
 
 
392
      if (_values != NULL) { /* only possible on rank 0 */
 
393
        assert(f.tf != NULL);
 
394
        for (i = 0, j = range[0]; j < range[1]; i++, j++)
 
395
          bft_file_printf(f.tf, "%12.5e\n", _values[i]);
 
396
      }
 
397
 
 
398
    } while (_values != NULL);
 
399
 
 
400
    fvm_file_serializer_destroy(&s);
 
401
  }
 
402
 
 
403
}
 
404
 
 
405
#endif /* defined(HAVE_MPI) */
 
406
 
 
407
/*----------------------------------------------------------------------------
 
408
 * Write block of a vector of floats to an EnSight Gold file
 
409
 *
 
410
 * parameters:
 
411
 *   n_values <-- number of values to write
 
412
 *   num_end  <-- global number of past the last element for this block
 
413
 *   values   <-- pointer to values block array
 
414
 *   f        <-- file to write to
 
415
 *----------------------------------------------------------------------------*/
 
416
 
 
417
static void
 
418
_write_block_floats_l(size_t           n_values,
 
419
                      const float      values[],
 
420
                      _ensight_file_t  f)
 
421
{
 
422
  size_t  i;
 
423
 
 
424
  if (f.tf != NULL) {
 
425
    for (i = 0; i < n_values; i++)
 
426
      bft_file_printf(f.tf, "%12.5e\n", values[i]);
 
427
  }
 
428
  else if (f.bf != NULL)
 
429
    fvm_file_write_global(f.bf, values, sizeof(float), n_values);
 
430
}
 
431
 
 
432
/*----------------------------------------------------------------------------
 
433
 * Return extra vertex coordinates when tesselations are present
 
434
 *
 
435
 * parameters:
 
436
 *   mesh             <-- pointer to nodal mesh structure
 
437
 *   n_extra_vertices <-- number of extra vertices
 
438
 *
 
439
 * returns:
 
440
 *   array containing all extra vertex coordinates
 
441
 *----------------------------------------------------------------------------*/
 
442
 
 
443
static fvm_coord_t *
 
444
_extra_vertex_coords(const fvm_nodal_t  *mesh,
 
445
                     fvm_lnum_t          n_extra_vertices)
 
446
{
 
447
  int  i;
 
448
  fvm_lnum_t  n_extra_vertices_section;
 
449
 
 
450
  size_t  coord_shift = 0;
 
451
  fvm_coord_t  *coords = NULL;
 
452
 
 
453
  if (n_extra_vertices > 0) { /* This implies divide_polyhedra = true */
 
454
 
 
455
    BFT_MALLOC(coords, n_extra_vertices * 3, fvm_coord_t);
 
456
 
 
457
    for (i = 0; i < mesh->n_sections; i++) {
 
458
 
 
459
      const fvm_nodal_section_t  *const  section = mesh->sections[i];
 
460
 
 
461
      if (   section->type == FVM_CELL_POLY
 
462
          && section->tesselation != NULL) {
 
463
 
 
464
        n_extra_vertices_section
 
465
          = fvm_tesselation_n_vertices_add(section->tesselation);
 
466
 
 
467
        if (n_extra_vertices_section > 0) {
 
468
 
 
469
          fvm_tesselation_vertex_coords(section->tesselation,
 
470
                                        coords + coord_shift);
 
471
 
 
472
          coord_shift += n_extra_vertices_section * 3;
 
473
 
 
474
        }
 
475
 
 
476
      }
 
477
    }
 
478
  }
 
479
 
 
480
  return coords;
 
481
}
 
482
 
 
483
#if defined(HAVE_MPI)
 
484
 
 
485
/*----------------------------------------------------------------------------
 
486
 * Get extra vertex global numbers when tesselations are present
 
487
 *
 
488
 * parameters:
 
489
 *   mesh             <-- pointer to nodal mesh structure
 
490
 *   n_extra_vertices <-- number of extra vertices
 
491
 *   vtx_gnum         --> extra vertex global numbers (size: n_extra_vertices)
 
492
 *----------------------------------------------------------------------------*/
 
493
 
 
494
static void
 
495
_extra_vertex_get_gnum(const fvm_nodal_t  *mesh,
 
496
                       fvm_lnum_t          n_extra_vertices,
 
497
                       fvm_gnum_t          vtx_gnum[])
 
498
{
 
499
  int  i;
 
500
  fvm_lnum_t  j = 0;
 
501
  fvm_lnum_t  start_id = 0;
 
502
  fvm_gnum_t  gnum_shift
 
503
    = fvm_io_num_get_global_count(mesh->global_vertex_num);
 
504
 
 
505
  if (n_extra_vertices > 0) { /* Implies divide_polyhedra */
 
506
 
 
507
    for (i = 0; i < mesh->n_sections; i++) {
 
508
 
 
509
      const fvm_nodal_section_t  *const  section = mesh->sections[i];
 
510
 
 
511
      if (   section->type == FVM_CELL_POLY
 
512
          && section->tesselation != NULL) {
 
513
 
 
514
        fvm_lnum_t n_extra_vertices_section
 
515
          = fvm_tesselation_n_vertices_add(section->tesselation);
 
516
 
 
517
        if (n_extra_vertices_section > 0) {
 
518
 
 
519
          const fvm_io_num_t *extra_vertex_num
 
520
            = fvm_tesselation_global_vertex_num(section->tesselation);
 
521
          const fvm_gnum_t *extra_gnum
 
522
            = fvm_io_num_get_global_num(extra_vertex_num);
 
523
 
 
524
          for (j = 0; j < n_extra_vertices_section; j++)
 
525
            vtx_gnum[start_id + j] = extra_gnum[j] + gnum_shift;
 
526
 
 
527
          start_id += n_extra_vertices_section;
 
528
 
 
529
        }
 
530
 
 
531
        gnum_shift
 
532
          = fvm_tesselation_n_g_vertices_add(section->tesselation);
 
533
 
 
534
      }
 
535
    }
 
536
  }
 
537
}
 
538
 
 
539
/*----------------------------------------------------------------------------
 
540
 * Build block info and part to block distribution helper for vertices.
 
541
 *
 
542
 * parameters:
 
543
 *   mesh             <-- pointer to nodal mesh structure
 
544
 *   divide_polyhedra <-- true if polyhedra are tesselated
 
545
 *   comm             <-- associated MPI communicator
 
546
 *   bi               --> block information structure
 
547
 *   d                --> part to bloc distributor
 
548
 *----------------------------------------------------------------------------*/
 
549
 
 
550
static void
 
551
_vertex_part_to_block_create(const fvm_nodal_t          *mesh,
 
552
                             _Bool                       divide_polyhedra,
 
553
                             MPI_Comm                    comm,
 
554
                             fvm_part_to_block_info_t   *bi,
 
555
                             fvm_part_to_block_t       **d)
 
556
{
 
557
  int  rank, n_ranks;
 
558
 
 
559
  fvm_gnum_t   n_g_extra_vertices = 0, n_g_vertices_tot = 0;
 
560
  fvm_lnum_t   n_extra_vertices = 0, n_vertices_tot = 0;
 
561
 
 
562
  fvm_gnum_t  *_g_num = NULL;
 
563
 
 
564
  fvm_part_to_block_info_t  _bi;
 
565
  fvm_part_to_block_t       *_d;
 
566
 
 
567
  size_t min_block_size
 
568
    = fvm_parall_get_min_coll_buf_size() / sizeof(float);
 
569
 
 
570
  const fvm_lnum_t  n_vertices
 
571
    = fvm_io_num_get_local_count(mesh->global_vertex_num);
 
572
  fvm_gnum_t  n_g_vertices
 
573
    = fvm_io_num_get_global_count(mesh->global_vertex_num);
 
574
  const fvm_gnum_t  *g_num
 
575
    = fvm_io_num_get_global_num(mesh->global_vertex_num);
 
576
 
 
577
  /* Get info on the current MPI communicator */
 
578
 
 
579
  MPI_Comm_rank(comm, &rank);
 
580
  MPI_Comm_size(comm, &n_ranks);
 
581
 
 
582
  /* Compute extra vertex coordinates if present */
 
583
 
 
584
  _count_extra_vertices(mesh,
 
585
                        divide_polyhedra,
 
586
                        &n_g_extra_vertices,
 
587
                        &n_extra_vertices);
 
588
 
 
589
  n_vertices_tot = n_vertices + n_extra_vertices;
 
590
  n_g_vertices_tot = n_g_vertices + n_g_extra_vertices;
 
591
 
 
592
  _bi = fvm_part_to_block_compute_sizes(rank,
 
593
                                        n_ranks,
 
594
                                        0,
 
595
                                        min_block_size,
 
596
                                        n_g_vertices_tot);
 
597
 
 
598
  /* Global vertex numbers */
 
599
 
 
600
 
 
601
  if (n_extra_vertices > 0) {
 
602
 
 
603
    BFT_MALLOC(_g_num, n_vertices_tot, fvm_gnum_t);
 
604
 
 
605
    memcpy(_g_num, g_num, n_vertices*sizeof(fvm_gnum_t));
 
606
    _extra_vertex_get_gnum(mesh, n_extra_vertices, _g_num + n_vertices);
 
607
 
 
608
    g_num = _g_num;
 
609
 
 
610
  }
 
611
 
 
612
  /* Build distribution structures */
 
613
 
 
614
  _d = fvm_part_to_block_create_by_gnum(comm, _bi, n_vertices_tot, g_num);
 
615
 
 
616
  if (n_extra_vertices > 0)
 
617
    fvm_part_to_block_transfer_gnum(_d, _g_num);
 
618
 
 
619
  /* Return initialized structures */
 
620
 
 
621
  if (bi != NULL)
 
622
    *bi = _bi;
 
623
 
 
624
  if (d != NULL)
 
625
    *d = _d;
 
626
}
 
627
 
 
628
/*----------------------------------------------------------------------------
 
629
 * Write vertex coordinates to an EnSight Gold file in parallel mode
 
630
 *
 
631
 * parameters:
 
632
 *   this_writer <-- pointer to associated writer
 
633
 *   mesh        <-- pointer to nodal mesh structure
 
634
 *   f           <-- associated file handle
 
635
 *----------------------------------------------------------------------------*/
 
636
 
 
637
static void
 
638
_export_vertex_coords_g(const fvm_to_ensight_writer_t  *this_writer,
 
639
                        const fvm_nodal_t              *mesh,
 
640
                        _ensight_file_t                 f)
 
641
{
 
642
  fvm_lnum_t  i, j;
 
643
  size_t stride;
 
644
  fvm_part_to_block_info_t  bi;
 
645
 
 
646
  fvm_gnum_t   n_g_extra_vertices = 0, n_g_vertices_tot = 0;
 
647
  fvm_lnum_t   n_extra_vertices = 0, n_vertices_tot = 0;
 
648
  fvm_coord_t  *extra_vertex_coords = NULL;
 
649
  float        *part_coords = NULL, *block_coords = NULL;
 
650
 
 
651
  fvm_part_to_block_t   *d = NULL;
 
652
  size_t                 block_buf_size = 0;
 
653
 
 
654
  const double      *vertex_coords = mesh->vertex_coords;
 
655
  const fvm_lnum_t  *parent_vertex_num = mesh->parent_vertex_num;
 
656
  const fvm_lnum_t  n_vertices
 
657
      = fvm_io_num_get_local_count(mesh->global_vertex_num);
 
658
  fvm_gnum_t  n_g_vertices
 
659
      = fvm_io_num_get_global_count(mesh->global_vertex_num);
 
660
 
 
661
  /* Initialize distribution info */
 
662
 
 
663
  _vertex_part_to_block_create(mesh,
 
664
                               this_writer->divide_polyhedra,
 
665
                               this_writer->comm,
 
666
                               &bi,
 
667
                               &d);
 
668
 
 
669
  /* Compute extra vertex coordinates if present */
 
670
 
 
671
  _count_extra_vertices(mesh,
 
672
                        this_writer->divide_polyhedra,
 
673
                        &n_g_extra_vertices,
 
674
                        &n_extra_vertices);
 
675
 
 
676
  n_vertices_tot = n_vertices + n_extra_vertices;
 
677
  n_g_vertices_tot = n_g_vertices + n_g_extra_vertices;
 
678
 
 
679
  extra_vertex_coords = _extra_vertex_coords(mesh,
 
680
                                             n_extra_vertices);
 
681
 
 
682
  /* Build arrays */
 
683
 
 
684
  block_buf_size = (bi.gnum_range[1] - bi.gnum_range[0]);
 
685
  BFT_MALLOC(block_coords, block_buf_size, float);
 
686
  BFT_MALLOC(part_coords, n_vertices_tot, float);
 
687
 
 
688
  /* Vertex coordinates */
 
689
  /*--------------------*/
 
690
 
 
691
  stride = (size_t)(mesh->dim);
 
692
 
 
693
  _write_string(f, "coordinates");
 
694
  _write_int(f, (int)(n_g_vertices_tot));
 
695
 
 
696
  /* Loop on dimension (de-interlace coordinates, always 3D for EnSight) */
 
697
 
 
698
  for (j = 0; j < 3; j++) {
 
699
 
 
700
    if (j < mesh->dim) {
 
701
 
 
702
      if (parent_vertex_num != NULL) {
 
703
        for (i = 0; i < n_vertices; i++)
 
704
          part_coords[i] = vertex_coords[(parent_vertex_num[i]-1)*stride + j];
 
705
      }
 
706
      else {
 
707
        for (i = 0; i < n_vertices; i++)
 
708
          part_coords[i] = vertex_coords[i*stride + j];
 
709
      }
 
710
 
 
711
      for (i = 0; i < n_extra_vertices; i++)
 
712
        part_coords[n_vertices + i] = extra_vertex_coords[(i*stride) + j];
 
713
    }
 
714
    else {
 
715
      for (i = 0; i < n_vertices_tot; i++)
 
716
        part_coords[i] = 0.0;
 
717
    }
 
718
 
 
719
    fvm_part_to_block_copy_array(d,
 
720
                                 sizeof(float),
 
721
                                 1,
 
722
                                 part_coords,
 
723
                                 block_coords);
 
724
 
 
725
    _write_block_floats_g(bi.gnum_range[0],
 
726
                          bi.gnum_range[1],
 
727
                          block_coords,
 
728
                          this_writer->comm,
 
729
                          f);
 
730
 
 
731
  } /* end of loop on spatial dimension */
 
732
 
 
733
  fvm_part_to_block_destroy(&d);
 
734
 
 
735
  BFT_FREE(block_coords);
 
736
  BFT_FREE(part_coords);
 
737
  if (extra_vertex_coords != NULL)
 
738
    BFT_FREE(extra_vertex_coords);
 
739
}
 
740
 
 
741
#endif /* defined(HAVE_MPI) */
 
742
 
 
743
/*----------------------------------------------------------------------------
 
744
 * Write vertex coordinates to an EnSight Gold file in serial mode
 
745
 *
 
746
 * parameters:
 
747
 *   this_writer <-- pointer to associated writer
 
748
 *   mesh        <-- pointer to nodal mesh structure
 
749
 *   f           <-- associated file handle
 
750
 *----------------------------------------------------------------------------*/
 
751
 
 
752
static void
 
753
_export_vertex_coords_l(const fvm_to_ensight_writer_t  *this_writer,
 
754
                        const fvm_nodal_t              *mesh,
 
755
                        _ensight_file_t                 f)
 
756
{
 
757
  fvm_lnum_t   i, j;
 
758
  fvm_lnum_t   n_extra_vertices = 0;
 
759
  fvm_coord_t  *extra_vertex_coords = NULL;
 
760
  float        *coords_tmp = NULL;
 
761
 
 
762
  const fvm_lnum_t   n_vertices = mesh->n_vertices;
 
763
  const double      *vertex_coords = mesh->vertex_coords;
 
764
  const fvm_lnum_t  *parent_vertex_num = mesh->parent_vertex_num;
 
765
 
 
766
  const size_t  stride = (size_t)(mesh->dim);
 
767
 
 
768
  /* Compute extra vertex coordinates if present */
 
769
 
 
770
  _count_extra_vertices(mesh,
 
771
                        this_writer->divide_polyhedra,
 
772
                        NULL,
 
773
                        &n_extra_vertices);
 
774
 
 
775
  extra_vertex_coords = _extra_vertex_coords(mesh,
 
776
                                             n_extra_vertices);
 
777
 
 
778
  /* Vertex coordinates */
 
779
  /*--------------------*/
 
780
 
 
781
  BFT_MALLOC(coords_tmp, FVM_MAX(n_vertices, n_extra_vertices), float);
 
782
 
 
783
  _write_string(f, "coordinates");
 
784
  _write_int(f, n_vertices + n_extra_vertices);
 
785
 
 
786
  /* Loop on dimension (de-interlace coordinates, always 3D for EnSight) */
 
787
 
 
788
  for (j = 0; j < 3; j++) {
 
789
 
 
790
    /* First, handle regular vertices */
 
791
 
 
792
    if (j < mesh->dim) {
 
793
      if (parent_vertex_num != NULL) {
 
794
        for (i = 0; i < n_vertices; i++)
 
795
          coords_tmp[i]
 
796
            = (float)(vertex_coords[(parent_vertex_num[i]-1)*stride + j]);
 
797
      }
 
798
      else {
 
799
        for (i = 0; i < n_vertices; i++)
 
800
          coords_tmp[i] = (float)(vertex_coords[i*stride + j]);
 
801
      }
 
802
    }
 
803
    else {
 
804
      for (i = 0; i < (n_vertices); i++)
 
805
        coords_tmp[i] = 0.0;
 
806
    }
 
807
 
 
808
    _write_block_floats_l(n_vertices,
 
809
                          coords_tmp,
 
810
                          f);
 
811
 
 
812
    /* Handle extra vertices (only occur with polyhedra tesselations in 3d) */
 
813
 
 
814
    for (i = 0; i < n_extra_vertices; i++)
 
815
      coords_tmp[i] = (float)(extra_vertex_coords[i*stride + j]);
 
816
 
 
817
    if (n_extra_vertices > 0)
 
818
      _write_block_floats_l(n_extra_vertices,
 
819
                            coords_tmp,
 
820
                            f);
 
821
 
 
822
  } /* end of loop on mesh dimension */
 
823
 
 
824
  BFT_FREE(coords_tmp);
 
825
 
 
826
  if (extra_vertex_coords != NULL)
 
827
    BFT_FREE(extra_vertex_coords);
 
828
}
 
829
 
 
830
#if defined(HAVE_MPI)
 
831
 
 
832
/*----------------------------------------------------------------------------
 
833
 * Write strided connectivity block to an EnSight Gold file in text mode
 
834
 *
 
835
 * parameters:
 
836
 *   stride  <-- number of vertices per element type
 
837
 *   n_elems <-- number of elements
 
838
 *   connect <-- connectivity array
 
839
 *   tf      <-- file to write to
 
840
 *----------------------------------------------------------------------------*/
 
841
 
 
842
static void
 
843
_write_connect_block_gt(int             stride,
 
844
                        fvm_lnum_t      n_elems,
 
845
                        const int32_t   connect[],
 
846
                        bft_file_t     *tf)
 
847
{
 
848
  fvm_lnum_t  i;
 
849
 
 
850
  assert(tf != NULL);
 
851
  assert(bft_file_get_type(tf) == BFT_FILE_TYPE_TEXT);
 
852
 
 
853
  switch(stride) {
 
854
 
 
855
  case 1: /* length */
 
856
    for (i = 0; i < n_elems; i++)
 
857
      bft_file_printf(tf, "%10d\n",
 
858
                      (int)connect[i]);
 
859
    break;
 
860
 
 
861
  case 2: /* edge */
 
862
    for (i = 0; i < n_elems; i++)
 
863
      bft_file_printf(tf, "%10d%10d\n",
 
864
                      (int)connect[i*2],
 
865
                      (int)connect[i*2+1]);
 
866
    break;
 
867
 
 
868
  case 3: /* FVM_FACE_TRIA */
 
869
    for (i = 0; i < n_elems; i++)
 
870
      bft_file_printf(tf, "%10d%10d%10d\n",
 
871
                      (int)connect[i*3],
 
872
                      (int)connect[i*3+1],
 
873
                      (int)connect[i*3+2]);
 
874
    break;
 
875
 
 
876
  case 4: /* FVM_FACE_QUAD or FVM_CELL_TETRA */
 
877
    for (i = 0; i < n_elems; i++)
 
878
      bft_file_printf(tf, "%10d%10d%10d%10d\n",
 
879
                      (int)connect[i*4],
 
880
                      (int)connect[i*4+1],
 
881
                      (int)connect[i*4+2],
 
882
                      (int)connect[i*4+3]);
 
883
    break;
 
884
 
 
885
  case 5: /* FVM_CELL_PYRAM */
 
886
    for (i = 0; i < n_elems; i++)
 
887
      bft_file_printf(tf, "%10d%10d%10d%10d%10d\n",
 
888
                      (int)connect[i*5],
 
889
                      (int)connect[i*5+1],
 
890
                      (int)connect[i*5+2],
 
891
                      (int)connect[i*5+3],
 
892
                      (int)connect[i*5+4]);
 
893
    break;
 
894
 
 
895
  case 6: /* FVM_CELL_PRISM */
 
896
    for (i = 0; i < n_elems; i++)
 
897
      bft_file_printf(tf, "%10d%10d%10d%10d%10d%10d\n",
 
898
                      (int)connect[i*6],
 
899
                      (int)connect[i*6+1],
 
900
                      (int)connect[i*6+2],
 
901
                      (int)connect[i*6+3],
 
902
                      (int)connect[i*6+4],
 
903
                      (int)connect[i*6+5]);
 
904
    break;
 
905
 
 
906
  case 8: /* FVM_CELL_HEXA */
 
907
    for (i = 0; i < n_elems; i++)
 
908
      bft_file_printf(tf,
 
909
                      "%10d%10d%10d%10d%10d%10d%10d%10d\n",
 
910
                      (int)connect[i*8],
 
911
                      (int)connect[i*8+1],
 
912
                      (int)connect[i*8+2],
 
913
                      (int)connect[i*8+3],
 
914
                      (int)connect[i*8+4],
 
915
                      (int)connect[i*8+5],
 
916
                      (int)connect[i*8+6],
 
917
                      (int)connect[i*8+7]);
 
918
    break;
 
919
 
 
920
  default:
 
921
    assert(0);
 
922
  }
 
923
}
 
924
 
 
925
/*----------------------------------------------------------------------------
 
926
 * Write strided global connectivity block to an EnSight Gold file
 
927
 *
 
928
 * parameters:
 
929
 *   stride        <-- number of vertices per element type
 
930
 *   num_start     <-- global number of first element for this block
 
931
 *   num_end       <-- global number of past last element for this block
 
932
 *   block_connect <-> global connectivity block array
 
933
 *   comm          <-- associated MPI communicator
 
934
 *   f             <-- associated file handle
 
935
 *----------------------------------------------------------------------------*/
 
936
 
 
937
static void
 
938
_write_block_connect_g(int              stride,
 
939
                       fvm_gnum_t       num_start,
 
940
                       fvm_gnum_t       num_end,
 
941
                       int32_t          block_connect[],
 
942
                       MPI_Comm         comm,
 
943
                       _ensight_file_t  f)
 
944
{
 
945
  /* In Binary mode, all ranks have a file structure,
 
946
     we may use use a collective call */
 
947
 
 
948
  if (f.bf != NULL)
 
949
    fvm_file_write_block(f.bf,
 
950
                         block_connect,
 
951
                         sizeof(int32_t),
 
952
                         stride,
 
953
                         num_start,
 
954
                         num_end);
 
955
 
 
956
  /* If all ranks do not have a binary file structure pointer, then
 
957
     we are using a text file, open only on rank 0 */
 
958
 
 
959
  else {
 
960
 
 
961
    int32_t *_block_connect = NULL;
 
962
 
 
963
    fvm_file_serializer_t *s = fvm_file_serializer_create(sizeof(int32_t),
 
964
                                                          stride,
 
965
                                                          num_start,
 
966
                                                          num_end,
 
967
                                                          0,
 
968
                                                          block_connect,
 
969
                                                          comm);
 
970
 
 
971
    do {
 
972
      fvm_gnum_t range[2] = {num_start, num_end};
 
973
 
 
974
      _block_connect = fvm_file_serializer_advance(s, range);
 
975
 
 
976
      if (_block_connect != NULL) /* only possible on rank 0 */
 
977
        _write_connect_block_gt(stride,
 
978
                                (range[1] - range[0]),
 
979
                                _block_connect,
 
980
                                f.tf);
 
981
 
 
982
    } while (_block_connect != NULL);
 
983
 
 
984
    fvm_file_serializer_destroy(&s);
 
985
  }
 
986
}
 
987
 
 
988
#endif /* defined(HAVE_MPI) */
 
989
 
 
990
/*----------------------------------------------------------------------------
 
991
 * Write strided local connectivity to an EnSight Gold file
 
992
 *
 
993
 * parameters:
 
994
 *   stride      <-- number of vertices per element type
 
995
 *   n_elems     <-- number of elements
 
996
 *   connect     <-- connectivity array
 
997
 *   f           <-- file to write to
 
998
 *----------------------------------------------------------------------------*/
 
999
 
 
1000
static void
 
1001
_write_connect_l(int                stride,
 
1002
                 fvm_lnum_t         n_elems,
 
1003
                 const fvm_lnum_t   connect[],
 
1004
                 _ensight_file_t    f)
 
1005
{
 
1006
  fvm_lnum_t  i;
 
1007
 
 
1008
  if (f.tf != NULL) { /* Text mode */
 
1009
 
 
1010
    switch(stride) {
 
1011
 
 
1012
    case 2: /* edge */
 
1013
      for (i = 0; i < n_elems; i++)
 
1014
        bft_file_printf(f.tf, "%10d%10d\n",
 
1015
                        (int)connect[i*2],
 
1016
                        (int)connect[i*2+1]);
 
1017
      break;
 
1018
 
 
1019
    case 3: /* FVM_FACE_TRIA */
 
1020
      for (i = 0; i < n_elems; i++)
 
1021
        bft_file_printf(f.tf, "%10d%10d%10d\n",
 
1022
                        (int)connect[i*3],
 
1023
                        (int)connect[i*3+1],
 
1024
                        (int)connect[i*3+2]);
 
1025
      break;
 
1026
 
 
1027
    case 4: /* FVM_FACE_QUAD or FVM_CELL_TETRA */
 
1028
      for (i = 0; i < n_elems; i++)
 
1029
        bft_file_printf(f.tf, "%10d%10d%10d%10d\n",
 
1030
                        (int)connect[i*4],
 
1031
                        (int)connect[i*4+1],
 
1032
                        (int)connect[i*4+2],
 
1033
                        (int)connect[i*4+3]);
 
1034
      break;
 
1035
 
 
1036
    case 5: /* FVM_CELL_PYRAM */
 
1037
      for (i = 0; i < n_elems; i++)
 
1038
        bft_file_printf(f.tf, "%10d%10d%10d%10d%10d\n",
 
1039
                        (int)connect[i*5],
 
1040
                        (int)connect[i*5+1],
 
1041
                        (int)connect[i*5+2],
 
1042
                        (int)connect[i*5+3],
 
1043
                        (int)connect[i*5+4]);
 
1044
      break;
 
1045
 
 
1046
    case 6: /* FVM_CELL_PRISM */
 
1047
      for (i = 0; i < n_elems; i++)
 
1048
        bft_file_printf(f.tf, "%10d%10d%10d%10d%10d%10d\n",
 
1049
                        (int)connect[i*6],
 
1050
                        (int)connect[i*6+1],
 
1051
                        (int)connect[i*6+2],
 
1052
                        (int)connect[i*6+3],
 
1053
                        (int)connect[i*6+4],
 
1054
                        (int)connect[i*6+5]);
 
1055
      break;
 
1056
 
 
1057
    case 8: /* FVM_CELL_HEXA */
 
1058
      for (i = 0; i < n_elems; i++)
 
1059
        bft_file_printf(f.tf,
 
1060
                        "%10d%10d%10d%10d%10d%10d%10d%10d\n",
 
1061
                        (int)connect[i*8],
 
1062
                        (int)connect[i*8+1],
 
1063
                        (int)connect[i*8+2],
 
1064
                        (int)connect[i*8+3],
 
1065
                        (int)connect[i*8+4],
 
1066
                        (int)connect[i*8+5],
 
1067
                        (int)connect[i*8+6],
 
1068
                        (int)connect[i*8+7]);
 
1069
      break;
 
1070
 
 
1071
    default:
 
1072
      assert(0);
 
1073
    }
 
1074
 
 
1075
  }
 
1076
  else if (f.bf != NULL) { /* Binary mode */
 
1077
 
 
1078
    size_t  j;
 
1079
    size_t  k = 0;
 
1080
    int32_t  *buffer = NULL;
 
1081
    const size_t  n_values = n_elems*stride;
 
1082
    const size_t  buffer_size = n_values >  64 ? (n_values / 8) : n_values;
 
1083
 
 
1084
    BFT_MALLOC(buffer, buffer_size, int32_t);
 
1085
 
 
1086
    while (k < n_values) {
 
1087
      for (j = 0; j < buffer_size && k < n_values; j++)
 
1088
        buffer[j] = (int)(connect[k++]);
 
1089
      fvm_file_write_global(f.bf, buffer, sizeof(int32_t), j);
 
1090
    }
 
1091
 
 
1092
    BFT_FREE(buffer);
 
1093
  }
 
1094
 
 
1095
}
 
1096
 
 
1097
#if defined(HAVE_MPI)
 
1098
 
 
1099
/*----------------------------------------------------------------------------
 
1100
 * Write "trivial" point elements to an EnSight Gold file in parallel mode
 
1101
 *
 
1102
 * parameters:
 
1103
 *   mesh <-- pointer to nodal mesh structure
 
1104
 *   comm <-- associated MPI communicator
 
1105
 *   f    <-- file to write to
 
1106
 *----------------------------------------------------------------------------*/
 
1107
 
 
1108
static void
 
1109
_export_point_elements_g(const fvm_nodal_t  *mesh,
 
1110
                         MPI_Comm            comm,
 
1111
                         _ensight_file_t     f)
 
1112
{
 
1113
  const fvm_gnum_t  n_g_vertices
 
1114
    = fvm_io_num_get_global_count(mesh->global_vertex_num);
 
1115
 
 
1116
  _write_string(f, "point");
 
1117
  _write_int(f, (int)n_g_vertices);
 
1118
 
 
1119
  if (f.tf != NULL) { /* Text mode, rank 0 only */
 
1120
 
 
1121
    fvm_gnum_t  i;
 
1122
    int32_t  j = 1;
 
1123
 
 
1124
    for (i = 0; i < n_g_vertices; i++)
 
1125
      bft_file_printf(f.tf, "%10d\n", j++);
 
1126
 
 
1127
  }
 
1128
  else if (f.bf != NULL) { /* Binary mode */
 
1129
 
 
1130
    int  rank, n_ranks;
 
1131
    fvm_lnum_t  i;
 
1132
    fvm_gnum_t j;
 
1133
    fvm_part_to_block_info_t  bi;
 
1134
 
 
1135
    size_t min_block_size
 
1136
      = fvm_parall_get_min_coll_buf_size() / sizeof(float);
 
1137
    int32_t  *connect = NULL;
 
1138
 
 
1139
    /* Get info on the current MPI communicator */
 
1140
 
 
1141
    MPI_Comm_rank(comm, &rank);
 
1142
    MPI_Comm_size(comm, &n_ranks);
 
1143
 
 
1144
    bi = fvm_part_to_block_compute_sizes(rank,
 
1145
                                         n_ranks,
 
1146
                                         0,
 
1147
                                         min_block_size,
 
1148
                                         n_g_vertices);
 
1149
 
 
1150
    BFT_MALLOC(connect, bi.gnum_range[1] - bi.gnum_range[0], int32_t);
 
1151
 
 
1152
    for (i = 0, j = bi.gnum_range[0]; j < bi.gnum_range[1]; i++, j++)
 
1153
      connect[i] = j;
 
1154
 
 
1155
    _write_block_connect_g(1,
 
1156
                           bi.gnum_range[0],
 
1157
                           bi.gnum_range[1],
 
1158
                           connect,
 
1159
                           comm,
 
1160
                           f);
 
1161
 
 
1162
    BFT_FREE(connect);
 
1163
  }
 
1164
}
 
1165
 
 
1166
#endif /* defined(HAVE_MPI) */
 
1167
 
 
1168
/*----------------------------------------------------------------------------
 
1169
 * Write "trivial" point elements to an EnSight Gold file in serial mode
 
1170
 *
 
1171
 * parameters:
 
1172
 *   mesh <-- pointer to nodal mesh structure
 
1173
 *   f    <-- file to write to
 
1174
 *----------------------------------------------------------------------------*/
 
1175
 
 
1176
static void
 
1177
_export_point_elements_l(const fvm_nodal_t  *mesh,
 
1178
                         _ensight_file_t     f)
 
1179
{
 
1180
  const fvm_lnum_t  n_vertices = mesh->n_vertices;
 
1181
 
 
1182
  _write_string(f, "point");
 
1183
  _write_int(f, (int)n_vertices);
 
1184
 
 
1185
  if (n_vertices == 0)
 
1186
    return;
 
1187
 
 
1188
  if (f.tf != NULL) { /* Text mode */
 
1189
    int i;
 
1190
    for (i = 0; i < n_vertices; i++)
 
1191
      bft_file_printf(f.tf, "%10d\n", i+1);
 
1192
  }
 
1193
 
 
1194
  else if (f.bf != NULL) { /* Binary mode */
 
1195
 
 
1196
    int32_t  k, j_end;
 
1197
    int32_t  j = 0;
 
1198
    int32_t  *buf = NULL;
 
1199
    const int32_t  bufsize = n_vertices >  64 ? (n_vertices / 8) : n_vertices;
 
1200
 
 
1201
    BFT_MALLOC(buf, bufsize, int32_t);
 
1202
 
 
1203
    j_end = n_vertices + 1;
 
1204
    while (j < j_end) {
 
1205
      for (k = 0;  j < j_end  && k < bufsize; k++)
 
1206
        buf[k] = j++;
 
1207
      fvm_file_write_global(f.bf, buf, sizeof(int32_t), k);
 
1208
    }
 
1209
 
 
1210
    BFT_FREE(buf);
 
1211
  }
 
1212
}
 
1213
 
 
1214
#if defined(HAVE_MPI)
 
1215
 
 
1216
/*----------------------------------------------------------------------------
 
1217
 * Write indexed element lengths from a nodal mesh to an EnSight Gold
 
1218
 * file in parallel mode
 
1219
 *
 
1220
 * parameters:
 
1221
 *   global_element_num <-- global element numbering
 
1222
 *   vertex_index       <-- pointer to element -> vertex index
 
1223
 *   comm               <-- associated MPI communicator
 
1224
 *   n_ranks            <-- number of processes in communicator
 
1225
 *   f                  <-- associated file handle
 
1226
 *----------------------------------------------------------------------------*/
 
1227
 
 
1228
static void
 
1229
_write_lengths_g(const fvm_io_num_t  *global_element_num,
 
1230
                 const fvm_lnum_t     vertex_index[],
 
1231
                 MPI_Comm             comm,
 
1232
                 _ensight_file_t      f)
 
1233
{
 
1234
  int  rank, n_ranks;
 
1235
  fvm_lnum_t  i;
 
1236
  fvm_part_to_block_info_t   bi;
 
1237
 
 
1238
  int32_t  *part_lengths = NULL;
 
1239
  int32_t  *block_lengths = NULL;
 
1240
 
 
1241
  fvm_part_to_block_t  *d = NULL;
 
1242
 
 
1243
  const size_t min_block_size
 
1244
    = fvm_parall_get_min_coll_buf_size() / sizeof(int32_t);
 
1245
  const fvm_lnum_t  n_elements
 
1246
    = fvm_io_num_get_local_count(global_element_num);
 
1247
  const fvm_lnum_t  n_g_elements
 
1248
    = fvm_io_num_get_global_count(global_element_num);
 
1249
  const fvm_gnum_t  *g_num
 
1250
    = fvm_io_num_get_global_num(global_element_num);
 
1251
 
 
1252
  /* Get info on the current MPI communicator */
 
1253
 
 
1254
  MPI_Comm_rank(comm, &rank);
 
1255
  MPI_Comm_size(comm, &n_ranks);
 
1256
 
 
1257
  /* Allocate block buffer */
 
1258
 
 
1259
  bi = fvm_part_to_block_compute_sizes(rank,
 
1260
                                       n_ranks,
 
1261
                                       0,
 
1262
                                       min_block_size,
 
1263
                                       n_g_elements);
 
1264
 
 
1265
  /* Build distribution structures */
 
1266
 
 
1267
  BFT_MALLOC(block_lengths, bi.gnum_range[1] - bi.gnum_range[0], int);
 
1268
  BFT_MALLOC(part_lengths, n_elements, int32_t);
 
1269
 
 
1270
  for (i = 0; i < n_elements; i++)
 
1271
    part_lengths[i] = vertex_index[i+1] - vertex_index[i];
 
1272
 
 
1273
  d = fvm_part_to_block_create_by_gnum(comm, bi, n_elements, g_num);
 
1274
 
 
1275
  fvm_part_to_block_copy_array(d,
 
1276
                               sizeof(int32_t),
 
1277
                               1,
 
1278
                               part_lengths,
 
1279
                               block_lengths);
 
1280
 
 
1281
  fvm_part_to_block_destroy(&d);
 
1282
  BFT_FREE(part_lengths);
 
1283
 
 
1284
  /* Write to file */
 
1285
 
 
1286
  _write_block_connect_g(1,
 
1287
                         bi.gnum_range[0],
 
1288
                         bi.gnum_range[1],
 
1289
                         block_lengths,
 
1290
                         comm,
 
1291
                         f);
 
1292
 
 
1293
  BFT_FREE(block_lengths);
 
1294
}
 
1295
 
 
1296
/*----------------------------------------------------------------------------
 
1297
 * Write block-distributed indexed element (polygons or polyhedra)
 
1298
 * cell -> vertex connectivity to an EnSight Gold file in parallel mode.
 
1299
 *
 
1300
 * In text mode, zeroes may be used in place of extra vertex numbers
 
1301
 * to indicate extra newlines between face -> vertex definitions.
 
1302
 *
 
1303
 * parameters:
 
1304
 *   num_start     <-- global number of first element for this block
 
1305
 *   num_end       <-- global number of past last element for this block
 
1306
 *   block_index   <-- global connectivity block array
 
1307
 *   block_connect <-> global connectivity block array
 
1308
 *   comm          <-- associated MPI communicator
 
1309
 *   f             <-- associated file handle
 
1310
 *----------------------------------------------------------------------------*/
 
1311
 
 
1312
static void
 
1313
_write_block_indexed(fvm_gnum_t        num_start,
 
1314
                     fvm_gnum_t        num_end,
 
1315
                     const fvm_lnum_t  block_index[],
 
1316
                     int32_t           block_connect[],
 
1317
                     MPI_Comm          comm,
 
1318
                     _ensight_file_t   f)
 
1319
{
 
1320
  fvm_gnum_t block_size = 0, block_start = 0, block_end = 0;
 
1321
 
 
1322
  /* Prepare write to file */
 
1323
 
 
1324
  block_size = block_index[num_end - num_start];
 
1325
 
 
1326
  MPI_Scan(&block_size, &block_end, 1, FVM_MPI_GNUM, MPI_SUM, comm);
 
1327
  block_end += 1;
 
1328
  block_start = block_end - block_size;
 
1329
 
 
1330
  /* In Binary mode, all ranks have a file structure,
 
1331
     we may use use a collective call */
 
1332
 
 
1333
  if (f.bf != NULL)
 
1334
    fvm_file_write_block(f.bf,
 
1335
                         block_connect,
 
1336
                         sizeof(int32_t),
 
1337
                         1,
 
1338
                         block_start,
 
1339
                         block_end);
 
1340
 
 
1341
  /* If all ranks do not have a binary file structure pointer, then
 
1342
     we are using a text file, open only on rank 0 */
 
1343
 
 
1344
  else {
 
1345
    fvm_lnum_t  i;
 
1346
    int32_t *_block_vtx_num = NULL;
 
1347
    fvm_file_serializer_t *s = fvm_file_serializer_create(sizeof(int32_t),
 
1348
                                                          1,
 
1349
                                                          block_start,
 
1350
                                                          block_end,
 
1351
                                                          0,
 
1352
                                                          block_connect,
 
1353
                                                          comm);
 
1354
 
 
1355
    do {
 
1356
      fvm_gnum_t j;
 
1357
      fvm_gnum_t range[2] = {block_start, block_end};
 
1358
      _block_vtx_num = fvm_file_serializer_advance(s, range);
 
1359
      if (_block_vtx_num != NULL) { /* only possible on rank 0 */
 
1360
        assert(f.tf != NULL);
 
1361
        for (i = 0, j = range[0]; j < range[1]; i++, j++) {
 
1362
          if (_block_vtx_num[i] != 0)
 
1363
            bft_file_printf(f.tf, "%10d", _block_vtx_num[i]);
 
1364
          else
 
1365
            bft_file_printf(f.tf, "\n");
 
1366
        }
 
1367
      }
 
1368
    } while (_block_vtx_num != NULL);
 
1369
 
 
1370
    fvm_file_serializer_destroy(&s);
 
1371
  }
 
1372
}
 
1373
 
 
1374
/*----------------------------------------------------------------------------
 
1375
 * Write indexed element (polygons or polyhedra) cell -> vertex connectivity
 
1376
 * to an EnSight Gold file in parallel mode.
 
1377
 *
 
1378
 * In text mode, zeroes may be used in place of extra vertex numbers
 
1379
 * to indicate extra newlines between face -> vertex definitions.
 
1380
 *
 
1381
 * parameters:
 
1382
 *   global_vertex_num  <-- vertex global numbering
 
1383
 *   global_element_num <-- global element numbering
 
1384
 *   vertex_index       <-- element -> vertex index
 
1385
 *   vertex_num         <-- element -> vertex number
 
1386
 *   comm               <-- associated MPI communicator
 
1387
 *   f                  <-- associated file handle
 
1388
 *----------------------------------------------------------------------------*/
 
1389
 
 
1390
static void
 
1391
_write_indexed_connect_g(const fvm_io_num_t  *global_element_num,
 
1392
                         const fvm_lnum_t     vertex_index[],
 
1393
                         const int32_t        vertex_num[],
 
1394
                         MPI_Comm             comm,
 
1395
                         _ensight_file_t      f)
 
1396
{
 
1397
  int  rank, n_ranks;
 
1398
  fvm_part_to_block_info_t bi;
 
1399
 
 
1400
  fvm_gnum_t loc_size = 0, tot_size = 0, block_size = 0;
 
1401
  fvm_part_to_block_t  *d = NULL;
 
1402
  fvm_lnum_t  *block_index = NULL;
 
1403
  int32_t  *block_vtx_num = NULL;
 
1404
  size_t  min_block_size
 
1405
    = fvm_parall_get_min_coll_buf_size() / sizeof(int32_t);
 
1406
 
 
1407
  const fvm_gnum_t  n_g_elements
 
1408
    = fvm_io_num_get_global_count(global_element_num);
 
1409
  const fvm_lnum_t  n_elements
 
1410
    = fvm_io_num_get_local_count(global_element_num);
 
1411
  const fvm_gnum_t  *g_elt_num
 
1412
    = fvm_io_num_get_global_num(global_element_num);
 
1413
 
 
1414
  /* Get info on the current MPI communicator */
 
1415
 
 
1416
  MPI_Comm_rank(comm, &rank);
 
1417
  MPI_Comm_size(comm, &n_ranks);
 
1418
 
 
1419
  /* Adjust min block size based on minimum element size */
 
1420
 
 
1421
  loc_size = vertex_index[n_elements];
 
1422
  MPI_Allreduce(&loc_size, &tot_size, 1, FVM_MPI_GNUM, MPI_SUM, comm);
 
1423
 
 
1424
  min_block_size /= (tot_size / n_g_elements);
 
1425
 
 
1426
  /* Allocate memory for additionnal indexes */
 
1427
 
 
1428
  bi = fvm_part_to_block_compute_sizes(rank,
 
1429
                                       n_ranks,
 
1430
                                       0,
 
1431
                                       min_block_size,
 
1432
                                       n_g_elements);
 
1433
 
 
1434
  BFT_MALLOC(block_index, bi.gnum_range[1] - bi.gnum_range[0] + 1, fvm_lnum_t);
 
1435
 
 
1436
  d = fvm_part_to_block_create_by_gnum(comm, bi, n_elements, g_elt_num);
 
1437
 
 
1438
  fvm_part_to_block_copy_index(d,
 
1439
                               vertex_index,
 
1440
                               block_index);
 
1441
 
 
1442
  block_size = block_index[bi.gnum_range[1] - bi.gnum_range[0]];
 
1443
 
 
1444
  BFT_MALLOC(block_vtx_num, block_size, int32_t);
 
1445
 
 
1446
  fvm_part_to_block_copy_indexed(d,
 
1447
                                 sizeof(int32_t),
 
1448
                                 vertex_index,
 
1449
                                 vertex_num,
 
1450
                                 block_index,
 
1451
                                 block_vtx_num);
 
1452
 
 
1453
  /* Write to file */
 
1454
 
 
1455
  _write_block_indexed(bi.gnum_range[0],
 
1456
                       bi.gnum_range[1],
 
1457
                       block_index,
 
1458
                       block_vtx_num,
 
1459
                       comm,
 
1460
                       f);
 
1461
 
 
1462
  /* Free memory */
 
1463
 
 
1464
  BFT_FREE(block_vtx_num);
 
1465
  fvm_part_to_block_destroy(&d);
 
1466
  BFT_FREE(block_index);
 
1467
}
 
1468
 
 
1469
/*----------------------------------------------------------------------------
 
1470
 * Write polyhedra from a nodal mesh to an EnSight Gold file in parallel mode
 
1471
 *
 
1472
 * parameters:
 
1473
 *   export_section    <-- pointer to EnSight section helper structure
 
1474
 *   global_vertex_num <-- pointer to vertex global numbering
 
1475
 *   comm              <-- associated MPI communicator
 
1476
 *   f                 <-- associated file handle
 
1477
 *
 
1478
 * returns:
 
1479
 *  pointer to next EnSight section helper structure in list
 
1480
 *----------------------------------------------------------------------------*/
 
1481
 
 
1482
static const fvm_writer_section_t *
 
1483
_export_nodal_polyhedra_g(const fvm_writer_section_t  *export_section,
 
1484
                          const fvm_io_num_t          *global_vertex_num,
 
1485
                          MPI_Comm                     comm,
 
1486
                          _ensight_file_t              f)
 
1487
{
 
1488
  int  rank, n_ranks;
 
1489
  fvm_lnum_t  i, j, k, l, face_id;
 
1490
 
 
1491
  fvm_lnum_t  face_length, cell_length;
 
1492
  fvm_part_to_block_info_t  bi;
 
1493
 
 
1494
  fvm_part_to_block_t  *d = NULL;
 
1495
  const fvm_writer_section_t  *current_section;
 
1496
 
 
1497
  /* Get info on the current MPI communicator */
 
1498
 
 
1499
  MPI_Comm_rank(comm, &rank);
 
1500
  MPI_Comm_size(comm, &n_ranks);
 
1501
 
 
1502
  /* Export number of faces per polyhedron */
 
1503
  /*---------------------------------------*/
 
1504
 
 
1505
  current_section = export_section;
 
1506
 
 
1507
  do { /* loop on sections which should be appended */
 
1508
 
 
1509
    const fvm_nodal_section_t  *section = current_section->section;
 
1510
 
 
1511
    _write_lengths_g(section->global_element_num,
 
1512
                     section->face_index,
 
1513
                     comm,
 
1514
                     f);
 
1515
 
 
1516
    current_section = current_section->next;
 
1517
 
 
1518
  } while (   current_section != NULL
 
1519
           && current_section->continues_previous == true);
 
1520
 
 
1521
  /* Export number of vertices per face per polyhedron */
 
1522
  /*---------------------------------------------------*/
 
1523
 
 
1524
  current_section = export_section;
 
1525
 
 
1526
  do { /* loop on sections which should be appended */
 
1527
 
 
1528
    fvm_gnum_t  block_size = 0, block_start = 0, block_end = 0;
 
1529
    fvm_lnum_t *block_index = NULL;
 
1530
 
 
1531
    size_t  min_block_size
 
1532
      = fvm_parall_get_min_coll_buf_size() / sizeof(int32_t);
 
1533
    int32_t  *part_face_len = NULL, *block_face_len = NULL;
 
1534
 
 
1535
    const fvm_nodal_section_t  *section = current_section->section;
 
1536
    const fvm_lnum_t  n_elements
 
1537
      = fvm_io_num_get_local_count(section->global_element_num);
 
1538
    const fvm_gnum_t n_g_elements
 
1539
      = fvm_io_num_get_global_count(section->global_element_num);
 
1540
    const fvm_gnum_t  *g_elt_num
 
1541
      = fvm_io_num_get_global_num(section->global_element_num);
 
1542
 
 
1543
    /* Build local polyhedron face lengths information */
 
1544
 
 
1545
    BFT_MALLOC(part_face_len,
 
1546
               section->face_index[section->n_elements],
 
1547
               int32_t);
 
1548
 
 
1549
    k = 0;
 
1550
    for (i = 0; i < section->n_elements; i++) {
 
1551
      for (j = section->face_index[i]; j < section->face_index[i+1]; j++) {
 
1552
        face_id = FVM_ABS(section->face_num[j]) - 1;
 
1553
        face_length = (  section->vertex_index[face_id+1]
 
1554
                       - section->vertex_index[face_id]);
 
1555
        part_face_len[k++] = face_length;
 
1556
      }
 
1557
    }
 
1558
    assert(k == section->face_index[section->n_elements]);
 
1559
 
 
1560
    /* Prepare distribution structures */
 
1561
 
 
1562
    bi = fvm_part_to_block_compute_sizes(rank,
 
1563
                                         n_ranks,
 
1564
                                         0,
 
1565
                                         min_block_size,
 
1566
                                         n_g_elements);
 
1567
 
 
1568
    d = fvm_part_to_block_create_by_gnum(comm,
 
1569
                                         bi,
 
1570
                                         n_elements,
 
1571
                                         g_elt_num);
 
1572
 
 
1573
    BFT_MALLOC(block_index, bi.gnum_range[1] - bi.gnum_range[0] + 1, fvm_lnum_t);
 
1574
 
 
1575
    fvm_part_to_block_copy_index(d,
 
1576
                                 section->face_index,
 
1577
                                 block_index);
 
1578
 
 
1579
    block_size = block_index[bi.gnum_range[1] - bi.gnum_range[0]];
 
1580
 
 
1581
    BFT_MALLOC(block_face_len, block_size, int32_t);
 
1582
 
 
1583
    fvm_part_to_block_copy_indexed(d,
 
1584
                                   sizeof(int32_t),
 
1585
                                   section->face_index,
 
1586
                                   part_face_len,
 
1587
                                   block_index,
 
1588
                                   block_face_len);
 
1589
 
 
1590
    MPI_Scan(&block_size, &block_end, 1, FVM_MPI_GNUM, MPI_SUM, comm);
 
1591
    block_end += 1;
 
1592
    block_start = block_end - block_size;
 
1593
 
 
1594
    _write_block_connect_g(1,
 
1595
                           block_start,
 
1596
                           block_end,
 
1597
                           block_face_len,
 
1598
                           comm,
 
1599
                           f);
 
1600
 
 
1601
    BFT_FREE(block_face_len);
 
1602
 
 
1603
    fvm_part_to_block_destroy(&d);
 
1604
 
 
1605
    BFT_FREE(block_index);
 
1606
    BFT_FREE(part_face_len);
 
1607
 
 
1608
    current_section = current_section->next;
 
1609
 
 
1610
  } while (   current_section != NULL
 
1611
           && current_section->continues_previous == true);
 
1612
 
 
1613
  /* Export cell->vertex connectivity by blocks */
 
1614
  /*--------------------------------------------*/
 
1615
 
 
1616
  current_section = export_section;
 
1617
 
 
1618
  do { /* loop on sections which should be appended */
 
1619
 
 
1620
    fvm_lnum_t  *part_vtx_idx = NULL;
 
1621
    int32_t  *part_vtx_num = NULL;
 
1622
 
 
1623
    const fvm_nodal_section_t  *section = current_section->section;
 
1624
    const fvm_gnum_t  *g_vtx_num
 
1625
      = fvm_io_num_get_global_num(global_vertex_num);
 
1626
 
 
1627
    BFT_MALLOC(part_vtx_idx, section->n_elements + 1, fvm_lnum_t);
 
1628
 
 
1629
    l = 0;
 
1630
 
 
1631
    if (f.bf != NULL) { /* In binary mode, build cell -> vertex connectivity */
 
1632
 
 
1633
      part_vtx_idx[0] = 0;
 
1634
      for (i = 0; i < section->n_elements; i++) {
 
1635
        cell_length = 0;
 
1636
        for (j = section->face_index[i]; j < section->face_index[i+1]; j++) {
 
1637
          face_id = FVM_ABS(section->face_num[j]) - 1;
 
1638
          face_length = (  section->vertex_index[face_id+1]
 
1639
                         - section->vertex_index[face_id]);
 
1640
          cell_length += face_length;
 
1641
        }
 
1642
        part_vtx_idx[i+1] = part_vtx_idx[i] + cell_length;
 
1643
      }
 
1644
 
 
1645
    }
 
1646
 
 
1647
    /* In text mode, add zeroes to cell vertex connectivity to mark face
 
1648
       bounds (so as to add newlines) */
 
1649
 
 
1650
    else { /* we are in text mode if f.bf == NULL */
 
1651
 
 
1652
      part_vtx_idx[0] = 0;
 
1653
      for (i = 0; i < section->n_elements; i++) {
 
1654
        cell_length = 0;
 
1655
        for (j = section->face_index[i]; j < section->face_index[i+1]; j++) {
 
1656
          face_id = FVM_ABS(section->face_num[j]) - 1;
 
1657
          face_length = (  section->vertex_index[face_id+1]
 
1658
                         - section->vertex_index[face_id]);
 
1659
          cell_length += face_length + 1;
 
1660
        }
 
1661
        part_vtx_idx[i+1] = part_vtx_idx[i] + cell_length;
 
1662
      }
 
1663
 
 
1664
    }
 
1665
 
 
1666
    BFT_MALLOC(part_vtx_num, part_vtx_idx[section->n_elements], fvm_lnum_t);
 
1667
 
 
1668
    l = 0;
 
1669
 
 
1670
    for (i = 0; i < section->n_elements; i++) {
 
1671
      for (j = section->face_index[i]; j < section->face_index[i+1]; j++) {
 
1672
        if (section->face_num[j] > 0) {
 
1673
          face_id = section->face_num[j] - 1;
 
1674
          for (k = section->vertex_index[face_id];
 
1675
               k < section->vertex_index[face_id+1];
 
1676
               k++)
 
1677
            part_vtx_num[l++] = g_vtx_num[section->vertex_num[k] - 1];
 
1678
        }
 
1679
        else {
 
1680
          face_id = -section->face_num[j] - 1;
 
1681
          k = section->vertex_index[face_id];
 
1682
          part_vtx_num[l++] = g_vtx_num[section->vertex_num[k] - 1];
 
1683
          for (k = section->vertex_index[face_id+1] - 1;
 
1684
               k > section->vertex_index[face_id];
 
1685
               k--)
 
1686
            part_vtx_num[l++] = g_vtx_num[section->vertex_num[k] - 1];
 
1687
        }
 
1688
        if (f.bf == NULL)
 
1689
          part_vtx_num[l++] = 0; /* mark face limits in text mode */
 
1690
      }
 
1691
 
 
1692
    }
 
1693
 
 
1694
    /* Now distribute and write cells -> vertices connectivity */
 
1695
 
 
1696
    _write_indexed_connect_g(section->global_element_num,
 
1697
                             part_vtx_idx,
 
1698
                             part_vtx_num,
 
1699
                             comm,
 
1700
                             f);
 
1701
 
 
1702
    BFT_FREE(part_vtx_num);
 
1703
    BFT_FREE(part_vtx_idx);
 
1704
 
 
1705
    current_section = current_section->next;
 
1706
 
 
1707
  } while (   current_section != NULL
 
1708
           && current_section->continues_previous == true);
 
1709
 
 
1710
  return current_section;
 
1711
}
 
1712
 
 
1713
#endif /* defined(HAVE_MPI) */
 
1714
 
 
1715
/*----------------------------------------------------------------------------
 
1716
 * Write polyhedra from a nodal mesh to an EnSight Gold file in serial mode
 
1717
 *
 
1718
 * parameters:
 
1719
 *   export_section <-- pointer to EnSight section helper structure
 
1720
 *   f              <-- associated file handle
 
1721
 *
 
1722
 * returns:
 
1723
 *  pointer to next EnSight section helper structure in list
 
1724
 *----------------------------------------------------------------------------*/
 
1725
 
 
1726
static const fvm_writer_section_t *
 
1727
_export_nodal_polyhedra_l(const fvm_writer_section_t  *export_section,
 
1728
                          _ensight_file_t              f)
 
1729
{
 
1730
  int  face_sgn;
 
1731
  fvm_lnum_t  i, j, k, l;
 
1732
  size_t  i_buf;
 
1733
 
 
1734
  fvm_lnum_t  face_length, face_id;
 
1735
 
 
1736
  size_t    buffer_size = 0;
 
1737
  int32_t  *buffer = NULL;
 
1738
 
 
1739
  const fvm_writer_section_t  *current_section;
 
1740
 
 
1741
  /* Write number of faces per cell */
 
1742
  /*--------------------------------*/
 
1743
 
 
1744
  current_section = export_section;
 
1745
 
 
1746
  do { /* loop on sections which should be appended */
 
1747
 
 
1748
    const fvm_nodal_section_t  *section = current_section->section;
 
1749
 
 
1750
    if (f.tf != NULL) { /* Text mode */
 
1751
      for (i = 0; i < section->n_elements; i++)
 
1752
        bft_file_printf(f.tf, "%10d\n",
 
1753
                        (int)(  section->face_index[i+1]
 
1754
                              - section->face_index[i]));
 
1755
    }
 
1756
    else { /* binary mode */
 
1757
 
 
1758
      /* First, allocate a buffer large enough so that the number of
 
1759
         writes is limited, small enough so that the memory overhead is
 
1760
         minimal; polyhedral connectivity is at least 4 faces x 3 vertices
 
1761
         per cell, usually quite a bit more, so this is 1/3 of the minimum */
 
1762
 
 
1763
      if (buffer_size < (size_t)section->n_elements * 4) {
 
1764
        buffer_size = section->n_elements * 4;
 
1765
        BFT_REALLOC(buffer, buffer_size, int32_t);
 
1766
      }
 
1767
 
 
1768
      /* Now fill buffer and write */
 
1769
 
 
1770
      for (i = 0, i_buf = 0; i < section->n_elements; i++) {
 
1771
        if (i_buf == buffer_size) {
 
1772
          fvm_file_write_global(f.bf, buffer, sizeof(int32_t), i_buf);
 
1773
          i_buf = 0;
 
1774
        }
 
1775
        buffer[i_buf++] = (int)(  section->face_index[i+1]
 
1776
                                - section->face_index[i]);
 
1777
      }
 
1778
      if (i_buf > 0)
 
1779
        fvm_file_write_global(f.bf, buffer, sizeof(int32_t), i_buf);
 
1780
 
 
1781
    }
 
1782
 
 
1783
    current_section = current_section->next;
 
1784
 
 
1785
  } while (   current_section != NULL
 
1786
           && current_section->continues_previous == true);
 
1787
 
 
1788
  /* Write number of vertices/face */
 
1789
  /*-------------------------------*/
 
1790
 
 
1791
  current_section = export_section;
 
1792
 
 
1793
  do { /* loop on sections which should be appended */
 
1794
 
 
1795
    const fvm_nodal_section_t  *section = current_section->section;
 
1796
 
 
1797
    for (i = 0, i_buf = 0; i < section->n_elements; i++) {
 
1798
 
 
1799
      /* Loop on cell faces */
 
1800
 
 
1801
      for (j = section->face_index[i];
 
1802
           j < section->face_index[i+1];
 
1803
           j++) {
 
1804
 
 
1805
        if (section->face_num[j] > 0)
 
1806
          face_id = section->face_num[j] - 1;
 
1807
        else
 
1808
          face_id = -section->face_num[j] - 1;
 
1809
 
 
1810
        face_length = (  section->vertex_index[face_id+1]
 
1811
                       - section->vertex_index[face_id]);
 
1812
 
 
1813
        if (f.tf != NULL)
 
1814
          bft_file_printf(f.tf, "%10d\n",
 
1815
                          (int)face_length);
 
1816
        else {
 
1817
          if (i_buf == buffer_size) {
 
1818
            fvm_file_write_global(f.bf, buffer, sizeof(int32_t), i_buf);
 
1819
            i_buf = 0;
 
1820
          }
 
1821
          buffer[i_buf++] = (int)face_length;
 
1822
        }
 
1823
 
 
1824
      }
 
1825
 
 
1826
    }
 
1827
 
 
1828
    if (f.bf != NULL && i_buf > 0)
 
1829
      fvm_file_write_global(f.bf, buffer, sizeof(int32_t), i_buf);
 
1830
 
 
1831
    current_section = current_section->next;
 
1832
 
 
1833
  } while (   current_section != NULL
 
1834
           && current_section->continues_previous == true);
 
1835
 
 
1836
  /* Write cell/vertex connectivity */
 
1837
  /*--------------------------------*/
 
1838
 
 
1839
  current_section = export_section;
 
1840
 
 
1841
  do { /* loop on sections which should be appended */
 
1842
 
 
1843
    const fvm_nodal_section_t  *section = current_section->section;
 
1844
 
 
1845
    for (i = 0, i_buf = 0; i < section->n_elements; i++) {
 
1846
 
 
1847
      /* Loop on cell faces */
 
1848
 
 
1849
      for (j = section->face_index[i];
 
1850
           j < section->face_index[i+1];
 
1851
           j++) {
 
1852
 
 
1853
        /* Print face vertex numbers */
 
1854
 
 
1855
        if (section->face_num[j] > 0) {
 
1856
          face_id = section->face_num[j] - 1;
 
1857
          face_sgn = 1;
 
1858
        }
 
1859
        else {
 
1860
          face_id = -section->face_num[j] - 1;
 
1861
          face_sgn = -1;
 
1862
        }
 
1863
 
 
1864
        face_length = (  section->vertex_index[face_id+1]
 
1865
                       - section->vertex_index[face_id]);
 
1866
 
 
1867
        if (f.tf != NULL) { /* text mode */
 
1868
          for (k = 0; k < face_length; k++) {
 
1869
            l =   section->vertex_index[face_id]
 
1870
                + (face_length + (k*face_sgn))%face_length;
 
1871
            bft_file_printf(f.tf, "%10d", (int)section->vertex_num[l]);
 
1872
          }
 
1873
          bft_file_printf(f.tf, "\n");
 
1874
        }
 
1875
        else { /* binary mode */
 
1876
          for (k = 0; k < face_length; k++) {
 
1877
            l =   section->vertex_index[face_id]
 
1878
                + (face_length + (k*face_sgn))%face_length;
 
1879
            if (i_buf == buffer_size) {
 
1880
              fvm_file_write_global(f.bf, buffer, sizeof(int32_t), i_buf);
 
1881
              i_buf = 0;
 
1882
            }
 
1883
            buffer[i_buf++] = (int)section->vertex_num[l];
 
1884
          }
 
1885
        }
 
1886
 
 
1887
      } /* End of loop on cell faces */
 
1888
 
 
1889
    } /* End of loop on polyhedral cells */
 
1890
 
 
1891
    if (f.bf != NULL && i_buf > 0)
 
1892
      fvm_file_write_global(f.bf, buffer, sizeof(int32_t), i_buf);
 
1893
 
 
1894
    current_section = current_section->next;
 
1895
 
 
1896
  } while (   current_section != NULL
 
1897
           && current_section->continues_previous == true);
 
1898
 
 
1899
  if (buffer != NULL)
 
1900
    BFT_FREE(buffer);
 
1901
 
 
1902
  return current_section;
 
1903
}
 
1904
 
 
1905
#if defined(HAVE_MPI)
 
1906
 
 
1907
/*----------------------------------------------------------------------------
 
1908
 * Write polygons from a nodal mesh to an EnSight Gold file in parallel mode
 
1909
 *
 
1910
 * parameters:
 
1911
 *   export_section    <-- pointer to EnSight section helper structure
 
1912
 *   global_vertex_num <-- pointer to vertex global numbering
 
1913
 *   comm              <-- associated MPI communicator
 
1914
 *   f                 <-- associated file handle
 
1915
 *
 
1916
 * returns:
 
1917
 *  pointer to next EnSight section helper structure in list
 
1918
 *----------------------------------------------------------------------------*/
 
1919
 
 
1920
static const fvm_writer_section_t *
 
1921
_export_nodal_polygons_g(const fvm_writer_section_t  *export_section,
 
1922
                         const fvm_io_num_t          *global_vertex_num,
 
1923
                         MPI_Comm                     comm,
 
1924
                         _ensight_file_t              f)
 
1925
{
 
1926
  const fvm_writer_section_t  *current_section;
 
1927
 
 
1928
  /* Export number of vertices per polygon by blocks */
 
1929
  /*-------------------------------------------------*/
 
1930
 
 
1931
  current_section = export_section;
 
1932
 
 
1933
  do { /* loop on sections which should be appended */
 
1934
 
 
1935
    const fvm_nodal_section_t  *section = current_section->section;
 
1936
 
 
1937
    _write_lengths_g(section->global_element_num,
 
1938
                     section->vertex_index,
 
1939
                     comm,
 
1940
                     f);
 
1941
 
 
1942
    current_section = current_section->next;
 
1943
 
 
1944
  } while (   current_section != NULL
 
1945
           && current_section->continues_previous == true);
 
1946
 
 
1947
  /* Export face->vertex connectivity by blocks */
 
1948
  /*--------------------------------------------*/
 
1949
 
 
1950
  current_section = export_section;
 
1951
 
 
1952
  do { /* loop on sections which should be appended */
 
1953
 
 
1954
    fvm_lnum_t  i, j, k;
 
1955
    fvm_lnum_t  *_part_vtx_idx = NULL;
 
1956
    const fvm_lnum_t  *part_vtx_idx = NULL;
 
1957
    int32_t  *part_vtx_num = NULL;
 
1958
 
 
1959
    const fvm_nodal_section_t  *section = current_section->section;
 
1960
    const fvm_gnum_t  *g_vtx_num
 
1961
      = fvm_io_num_get_global_num(global_vertex_num);
 
1962
 
 
1963
    if (f.bf != NULL) /* In binary mode, use existing index */
 
1964
      part_vtx_idx = section->vertex_index;
 
1965
 
 
1966
    /* In text mode, add zeroes to cell vertex connectivity to mark face
 
1967
       bounds (so as to add newlines) */
 
1968
 
 
1969
    else { /* we are in text mode if f.bf == NULL */
 
1970
 
 
1971
      BFT_MALLOC(_part_vtx_idx, section->n_elements + 1, fvm_lnum_t);
 
1972
 
 
1973
      _part_vtx_idx[0] = 0;
 
1974
      for (i = 0; i < section->n_elements; i++)
 
1975
        _part_vtx_idx[i+1] = _part_vtx_idx[i] + (  section->vertex_index[i+1]
 
1976
                                                 - section->vertex_index[i]) + 1;
 
1977
 
 
1978
      part_vtx_idx = _part_vtx_idx;
 
1979
    }
 
1980
 
 
1981
    /* Build connectivity array */
 
1982
 
 
1983
    BFT_MALLOC(part_vtx_num, part_vtx_idx[section->n_elements], int32_t);
 
1984
 
 
1985
    if (f.bf != NULL) { /* binary mode */
 
1986
      for (i = 0, k = 0; i < section->n_elements; i++) {
 
1987
        for (j = section->vertex_index[i];
 
1988
             j < section->vertex_index[i+1];
 
1989
             j++)
 
1990
          part_vtx_num[k++] = g_vtx_num[section->vertex_num[j] - 1];
 
1991
      }
 
1992
    }
 
1993
 
 
1994
    else { /* text mode */
 
1995
      for (i = 0, k = 0; i < section->n_elements; i++) {
 
1996
        for (j = section->vertex_index[i];
 
1997
             j < section->vertex_index[i+1];
 
1998
             j++)
 
1999
          part_vtx_num[k++] = g_vtx_num[section->vertex_num[j] - 1];
 
2000
        part_vtx_num[k++] = 0; /* mark face bounds in text mode */
 
2001
      }
 
2002
    }
 
2003
 
 
2004
    /* Now distribute and write cell -> vertices connectivity */
 
2005
 
 
2006
    _write_indexed_connect_g(section->global_element_num,
 
2007
                             part_vtx_idx,
 
2008
                             part_vtx_num,
 
2009
                             comm,
 
2010
                             f);
 
2011
 
 
2012
    BFT_FREE(part_vtx_num);
 
2013
    if (_part_vtx_idx != NULL)
 
2014
      BFT_FREE(_part_vtx_idx);
 
2015
 
 
2016
    current_section = current_section->next;
 
2017
 
 
2018
  } while (   current_section != NULL
 
2019
           && current_section->continues_previous == true);
 
2020
 
 
2021
  return current_section;
 
2022
}
 
2023
 
 
2024
#endif /* defined(HAVE_MPI) */
 
2025
 
 
2026
/*----------------------------------------------------------------------------
 
2027
 * Write polygons from a nodal mesh to a text file in serial mode
 
2028
 *
 
2029
 * parameters:
 
2030
 *   export_section <-- pointer to EnSight section helper structure
 
2031
 *   f              <-- associated file handle
 
2032
 *
 
2033
 * returns:
 
2034
 *  pointer to next EnSight section helper structure in list
 
2035
*----------------------------------------------------------------------------*/
 
2036
 
 
2037
static const fvm_writer_section_t *
 
2038
_export_nodal_polygons_l(const fvm_writer_section_t  *export_section,
 
2039
                         _ensight_file_t              f)
 
2040
 
 
2041
 
 
2042
{
 
2043
  fvm_lnum_t  i, j;
 
2044
  size_t  i_buf;
 
2045
 
 
2046
  size_t    buffer_size = 0;
 
2047
  int32_t  *buffer = NULL;
 
2048
 
 
2049
  const fvm_writer_section_t  *current_section = NULL;
 
2050
 
 
2051
  /* Print face connectivity directly, without using extra buffers */
 
2052
 
 
2053
  /* First loop on all polygonal faces, to write number of vertices */
 
2054
  /*----------------------------------------------------------------*/
 
2055
 
 
2056
  current_section = export_section;
 
2057
 
 
2058
  do { /* Loop on sections that should be grouped */
 
2059
 
 
2060
    const fvm_nodal_section_t  *section = current_section->section;
 
2061
 
 
2062
    if (f.tf != NULL) { /* Text mode */
 
2063
      for (i = 0; i < section->n_elements; i++)
 
2064
        bft_file_printf(f.tf, "%10d\n", (int)(  section->vertex_index[i+1]
 
2065
                                           - section->vertex_index[i]));
 
2066
    }
 
2067
    else { /* binary mode */
 
2068
 
 
2069
      /* First, allocate a buffer large enough so that the number of
 
2070
         writes is limited, small enough so that the memory overhead is
 
2071
         minimal; polygonal connectivity is at least 3 vertices per face,
 
2072
         usually 5 or more, so this is 1/3 of the minimum */
 
2073
 
 
2074
      if (buffer_size < (size_t)section->n_elements) {
 
2075
        buffer_size = section->n_elements;
 
2076
        BFT_REALLOC(buffer, buffer_size, int32_t);
 
2077
      }
 
2078
 
 
2079
      /* Now fill buffer and write */
 
2080
 
 
2081
      for (i = 0, i_buf = 0; i < section->n_elements; i++) {
 
2082
        if (i_buf == buffer_size) {
 
2083
          fvm_file_write_global(f.bf, buffer, sizeof(int32_t), i_buf);
 
2084
          i_buf = 0;
 
2085
        }
 
2086
        buffer[i_buf++] = (int)(  section->vertex_index[i+1]
 
2087
                                - section->vertex_index[i]);
 
2088
      }
 
2089
      if (i_buf > 0)
 
2090
        fvm_file_write_global(f.bf, buffer, sizeof(int32_t), i_buf);
 
2091
    }
 
2092
 
 
2093
    current_section = current_section->next;
 
2094
 
 
2095
  } while (   current_section != NULL
 
2096
           && current_section->continues_previous == true);
 
2097
 
 
2098
  /* Loop on all polygonal faces */
 
2099
  /*-----------------------------*/
 
2100
 
 
2101
  current_section = export_section;
 
2102
 
 
2103
  do { /* Loop on sections that should be grouped */
 
2104
 
 
2105
    const fvm_nodal_section_t  *section = current_section->section;
 
2106
 
 
2107
    for (i = 0, i_buf = 0; i < section->n_elements; i++) {
 
2108
 
 
2109
      /* Print face vertex numbers */
 
2110
 
 
2111
      if (f.tf != NULL) { /* text mode */
 
2112
        for (j = section->vertex_index[i];
 
2113
             j < section->vertex_index[i+1];
 
2114
             j++)
 
2115
          bft_file_printf(f.tf, "%10d", (int)section->vertex_num[j]);
 
2116
        bft_file_printf(f.tf, "\n");
 
2117
      }
 
2118
      else { /* binary mode */
 
2119
        for (j = section->vertex_index[i];
 
2120
             j < section->vertex_index[i+1];
 
2121
             j++) {
 
2122
          if (i_buf == buffer_size) {
 
2123
            fvm_file_write_global(f.bf, buffer, sizeof(int32_t), i_buf);
 
2124
            i_buf = 0;
 
2125
          }
 
2126
          buffer[i_buf++] = (int)section->vertex_num[j];
 
2127
        }
 
2128
      }
 
2129
 
 
2130
    } /* End of loop on polygonal faces */
 
2131
 
 
2132
    if (f.bf != NULL && i_buf > 0)
 
2133
      fvm_file_write_global(f.bf, buffer, sizeof(int32_t), i_buf);
 
2134
 
 
2135
    current_section = current_section->next;
 
2136
 
 
2137
  } while (   current_section != NULL
 
2138
           && current_section->continues_previous == true);
 
2139
 
 
2140
  if (buffer != NULL)
 
2141
    BFT_FREE(buffer);
 
2142
 
 
2143
  return current_section;
 
2144
}
 
2145
 
 
2146
#if defined(HAVE_MPI)
 
2147
 
 
2148
/*----------------------------------------------------------------------------
 
2149
 * Write tesselated element cell -> vertex connectivity to an EnSight Gold
 
2150
 * file in parallel mode.
 
2151
 *
 
2152
 * parameters:
 
2153
 *   global_vertex_num  <-- vertex global numbering
 
2154
 *   global_element_num <-- global element numbering
 
2155
 *   tesselation        <-- element tesselation description
 
2156
 *   type               <-- tesselated sub-element type
 
2157
 *   extra_vertex_base  <-- starting number for added vertices
 
2158
 *   comm               <-- associated MPI communicator
 
2159
 *   f                  <-- associated file handle
 
2160
 *----------------------------------------------------------------------------*/
 
2161
 
 
2162
static void
 
2163
_write_tesselated_connect_g(const fvm_io_num_t       *global_vertex_num,
 
2164
                            const fvm_io_num_t       *global_element_num,
 
2165
                            const fvm_tesselation_t  *tesselation,
 
2166
                            fvm_element_t             type,
 
2167
                            const fvm_gnum_t          extra_vertex_base,
 
2168
                            MPI_Comm                  comm,
 
2169
                            _ensight_file_t           f)
 
2170
{
 
2171
  int  rank, n_ranks;
 
2172
  fvm_lnum_t  i;
 
2173
  fvm_part_to_block_info_t bi;
 
2174
 
 
2175
  fvm_lnum_t  part_size = 0;
 
2176
 
 
2177
  fvm_lnum_t  end_id = 0;
 
2178
  fvm_gnum_t  n_g_sub_elements = 0, global_num_end = 0;
 
2179
  fvm_gnum_t  block_size = 0, block_start = 0, block_end = 0;
 
2180
 
 
2181
  fvm_part_to_block_t  *d = NULL;
 
2182
  fvm_lnum_t  *part_index, *block_index = NULL;
 
2183
  int32_t     *part_vtx_num = NULL, *block_vtx_num = NULL;
 
2184
  fvm_gnum_t  *part_vtx_gnum = NULL;
 
2185
 
 
2186
  size_t  min_block_size
 
2187
    = fvm_parall_get_min_coll_buf_size() / sizeof(int32_t);
 
2188
 
 
2189
  const int  stride = fvm_nodal_n_vertices_element[type];
 
2190
  const fvm_lnum_t  n_elements = fvm_tesselation_n_elements(tesselation);
 
2191
  const fvm_gnum_t  n_g_elements
 
2192
    = fvm_io_num_get_global_count(global_element_num);
 
2193
  const fvm_lnum_t  n_sub_elements
 
2194
    = fvm_tesselation_n_sub_elements(tesselation, type);
 
2195
  const fvm_lnum_t  *sub_element_idx
 
2196
      = fvm_tesselation_sub_elt_index(tesselation, type);
 
2197
  const fvm_gnum_t  *g_elt_num
 
2198
    = fvm_io_num_get_global_num(global_element_num);
 
2199
 
 
2200
  /* Get info on the current MPI communicator */
 
2201
 
 
2202
  MPI_Comm_rank(comm, &rank);
 
2203
  MPI_Comm_size(comm, &n_ranks);
 
2204
 
 
2205
  /* Adjust min block size based on mean number of sub-elements */
 
2206
 
 
2207
  fvm_tesselation_get_global_size(tesselation,
 
2208
                                  type,
 
2209
                                  &n_g_sub_elements,
 
2210
                                  NULL);
 
2211
 
 
2212
  min_block_size /= (n_g_sub_elements/n_g_elements) * stride;
 
2213
 
 
2214
  /* Decode connectivity */
 
2215
 
 
2216
  part_size = n_sub_elements * stride;
 
2217
  assert(sub_element_idx[n_elements]*stride == part_size);
 
2218
 
 
2219
  global_num_end = n_g_elements + 1;
 
2220
 
 
2221
  if (n_elements > 0) {
 
2222
    BFT_MALLOC(part_vtx_num, part_size, int32_t);
 
2223
    BFT_MALLOC(part_vtx_gnum, part_size, fvm_gnum_t);
 
2224
  }
 
2225
 
 
2226
  end_id = fvm_tesselation_decode_g(tesselation,
 
2227
                                    type,
 
2228
                                    0,
 
2229
                                    part_size,
 
2230
                                    &global_num_end,
 
2231
                                    global_vertex_num,
 
2232
                                    extra_vertex_base,
 
2233
                                    part_vtx_gnum,
 
2234
                                    comm);
 
2235
 
 
2236
  assert(end_id == n_elements);
 
2237
  assert(global_num_end == n_g_elements + 1);
 
2238
 
 
2239
  /* Convert to write type */
 
2240
 
 
2241
  if (n_elements > 0) {
 
2242
    for (i = 0; i < part_size; i++)
 
2243
      part_vtx_num[i] = part_vtx_gnum[i];
 
2244
    BFT_FREE(part_vtx_gnum);
 
2245
  }
 
2246
 
 
2247
  /* Allocate memory for additionnal indexes and decoded connectivity */
 
2248
 
 
2249
  bi = fvm_part_to_block_compute_sizes(rank,
 
2250
                                       n_ranks,
 
2251
                                       0,
 
2252
                                       min_block_size,
 
2253
                                       n_g_elements);
 
2254
 
 
2255
  BFT_MALLOC(block_index, bi.gnum_range[1] - bi.gnum_range[0] + 1, fvm_lnum_t);
 
2256
  BFT_MALLOC(part_index, n_elements + 1, fvm_lnum_t);
 
2257
 
 
2258
  d = fvm_part_to_block_create_by_gnum(comm, bi, n_elements, g_elt_num);
 
2259
 
 
2260
  part_index[0] = 0;
 
2261
  for (i = 0; i < n_elements; i++) {
 
2262
    part_index[i+1] = part_index[i] + (  sub_element_idx[i+1]
 
2263
                                       - sub_element_idx[i]) * stride;
 
2264
  }
 
2265
 
 
2266
  /* Copy index */
 
2267
 
 
2268
  fvm_part_to_block_copy_index(d,
 
2269
                               part_index,
 
2270
                               block_index);
 
2271
 
 
2272
  block_size = (block_index[bi.gnum_range[1] - bi.gnum_range[0]]);
 
2273
 
 
2274
  /* Copy connectivity */
 
2275
 
 
2276
  BFT_MALLOC(block_vtx_num, block_size, int32_t);
 
2277
 
 
2278
  fvm_part_to_block_copy_indexed(d,
 
2279
                                 sizeof(int32_t),
 
2280
                                 part_index,
 
2281
                                 part_vtx_num,
 
2282
                                 block_index,
 
2283
                                 block_vtx_num);
 
2284
 
 
2285
  fvm_part_to_block_destroy(&d);
 
2286
 
 
2287
  BFT_FREE(part_vtx_num);
 
2288
  BFT_FREE(part_index);
 
2289
  BFT_FREE(block_index);
 
2290
 
 
2291
  /* Write to file */
 
2292
 
 
2293
  block_size /= stride;
 
2294
 
 
2295
  MPI_Scan(&block_size, &block_end, 1, FVM_MPI_GNUM, MPI_SUM, comm);
 
2296
  block_end += 1;
 
2297
  block_start = block_end - block_size;
 
2298
 
 
2299
  _write_block_connect_g(stride,
 
2300
                         block_start,
 
2301
                         block_end,
 
2302
                         block_vtx_num,
 
2303
                         comm,
 
2304
                         f);
 
2305
 
 
2306
  /* Free remaining memory */
 
2307
 
 
2308
  BFT_FREE(block_vtx_num);
 
2309
}
 
2310
 
 
2311
/*----------------------------------------------------------------------------
 
2312
 * Write tesselated element connectivity from a nodal mesh to an EnSight Gold
 
2313
 * file in parallel mode
 
2314
 *
 
2315
 * parameters:
 
2316
 *   export_section    <-- pointer to EnSight section helper structure
 
2317
 *   global_vertex_num <-- pointer to vertex global numbering
 
2318
 *   comm              <-- associated MPI communicator
 
2319
 *   f                 <-- associated file handle
 
2320
 *
 
2321
 * returns:
 
2322
 *  pointer to next EnSight section helper structure in list
 
2323
 *----------------------------------------------------------------------------*/
 
2324
 
 
2325
static const fvm_writer_section_t *
 
2326
_export_nodal_tesselated_g(const fvm_writer_section_t  *export_section,
 
2327
                           const fvm_io_num_t          *global_vertex_num,
 
2328
                           MPI_Comm                     comm,
 
2329
                           _ensight_file_t              f)
 
2330
{
 
2331
  const fvm_writer_section_t  *current_section;
 
2332
 
 
2333
  /* Export face->vertex connectivity by blocks */
 
2334
  /*--------------------------------------------*/
 
2335
 
 
2336
  current_section = export_section;
 
2337
 
 
2338
  do { /* loop on sections which should be appended */
 
2339
 
 
2340
    const fvm_nodal_section_t  *section = current_section->section;
 
2341
 
 
2342
    _write_tesselated_connect_g(global_vertex_num,
 
2343
                                section->global_element_num,
 
2344
                                section->tesselation,
 
2345
                                current_section->type,
 
2346
                                current_section->extra_vertex_base,
 
2347
                                comm,
 
2348
                                f);
 
2349
 
 
2350
    current_section = current_section->next;
 
2351
 
 
2352
  } while (   current_section != NULL
 
2353
           && current_section->continues_previous == true);
 
2354
 
 
2355
  return current_section;
 
2356
}
 
2357
 
 
2358
#endif /* defined(HAVE_MPI) */
 
2359
 
 
2360
/*----------------------------------------------------------------------------
 
2361
 * Write tesselated element connectivity from a nodal mesh to an EnSight Gold
 
2362
 * file in parallel mode
 
2363
 *
 
2364
 * parameters:
 
2365
 *   export_section <-- pointer to EnSight section helper structure
 
2366
 *   f              <-- associated file handle
 
2367
 *
 
2368
 * returns:
 
2369
 *  pointer to next EnSight section helper structure in list
 
2370
 *----------------------------------------------------------------------------*/
 
2371
 
 
2372
static const fvm_writer_section_t *
 
2373
_export_nodal_tesselated_l(const fvm_writer_section_t  *export_section,
 
2374
                           _ensight_file_t              f)
 
2375
{
 
2376
  const fvm_writer_section_t  *current_section;
 
2377
 
 
2378
  current_section = export_section;
 
2379
 
 
2380
  do { /* loop on sections which should be appended */
 
2381
 
 
2382
    const fvm_nodal_section_t  *section = current_section->section;
 
2383
 
 
2384
    fvm_lnum_t  start_id, end_id;
 
2385
    fvm_lnum_t  n_sub_elements_max;
 
2386
    fvm_lnum_t  n_buffer_elements_max = section->n_elements;
 
2387
    fvm_lnum_t *vertex_num = NULL;
 
2388
 
 
2389
    const fvm_lnum_t *sub_element_idx
 
2390
      = fvm_tesselation_sub_elt_index(section->tesselation,
 
2391
                                      export_section->type);
 
2392
 
 
2393
    fvm_tesselation_get_global_size(section->tesselation,
 
2394
                                    export_section->type,
 
2395
                                    NULL,
 
2396
                                    &n_sub_elements_max);
 
2397
    if (n_sub_elements_max > n_buffer_elements_max)
 
2398
      n_buffer_elements_max = n_sub_elements_max;
 
2399
 
 
2400
    BFT_MALLOC(vertex_num,
 
2401
               (  n_buffer_elements_max
 
2402
                * fvm_nodal_n_vertices_element[export_section->type]),
 
2403
               fvm_lnum_t);
 
2404
 
 
2405
    for (start_id = 0;
 
2406
         start_id < section->n_elements;
 
2407
         start_id = end_id) {
 
2408
 
 
2409
      end_id
 
2410
        = fvm_tesselation_decode(section->tesselation,
 
2411
                                 current_section->type,
 
2412
                                 start_id,
 
2413
                                 n_buffer_elements_max,
 
2414
                                 export_section->extra_vertex_base,
 
2415
                                 vertex_num);
 
2416
 
 
2417
      _write_connect_l(fvm_nodal_n_vertices_element[export_section->type],
 
2418
                       (  sub_element_idx[end_id]
 
2419
                        - sub_element_idx[start_id]),
 
2420
                       vertex_num,
 
2421
                       f);
 
2422
 
 
2423
    }
 
2424
 
 
2425
    BFT_FREE(vertex_num);
 
2426
 
 
2427
    current_section = current_section->next;
 
2428
 
 
2429
  } while (   current_section != NULL
 
2430
           && current_section->continues_previous == true);
 
2431
 
 
2432
  return current_section;
 
2433
}
 
2434
 
 
2435
#if defined(HAVE_MPI)
 
2436
 
 
2437
/*----------------------------------------------------------------------------
 
2438
 * Write strided elements from a nodal mesh to an EnSight Gold file in
 
2439
 * parallel mode
 
2440
 *
 
2441
 * parameters:
 
2442
 *   export_section    <-- pointer to EnSight section helper structure
 
2443
 *   global_vertex_num <-- pointer to vertex global numbering
 
2444
 *   comm              <-- associated MPI communicator
 
2445
 *   f                 <-- associated file handle
 
2446
 *
 
2447
 * returns:
 
2448
 *  pointer to next EnSight section helper structure in list
 
2449
 *----------------------------------------------------------------------------*/
 
2450
 
 
2451
static const fvm_writer_section_t *
 
2452
_export_nodal_strided_g(const fvm_writer_section_t  *export_section,
 
2453
                        const fvm_io_num_t          *global_vertex_num,
 
2454
                        MPI_Comm                     comm,
 
2455
                        _ensight_file_t              f)
 
2456
{
 
2457
  int  rank, n_ranks;
 
2458
  fvm_lnum_t  i, j;
 
2459
 
 
2460
  const fvm_writer_section_t  *current_section;
 
2461
 
 
2462
  /* Get info on the current MPI communicator */
 
2463
 
 
2464
  MPI_Comm_rank(comm, &rank);
 
2465
  MPI_Comm_size(comm, &n_ranks);
 
2466
 
 
2467
  /* Export vertex connectivity */
 
2468
 
 
2469
  current_section = export_section;
 
2470
 
 
2471
  do { /* loop on sections which should be appended */
 
2472
 
 
2473
    fvm_part_to_block_info_t bi;
 
2474
 
 
2475
    fvm_lnum_t  block_size = 0;
 
2476
    fvm_part_to_block_t  *d = NULL;
 
2477
    int32_t  *part_vtx_num = NULL, *block_vtx_num = NULL;
 
2478
 
 
2479
    const fvm_nodal_section_t  *section = current_section->section;
 
2480
    const int  stride = fvm_nodal_n_vertices_element[section->type];
 
2481
 
 
2482
    const size_t  min_block_size
 
2483
      = fvm_parall_get_min_coll_buf_size() / (sizeof(int32_t) * stride);
 
2484
 
 
2485
    const fvm_lnum_t  n_elements
 
2486
      = fvm_io_num_get_local_count(section->global_element_num);
 
2487
    const fvm_gnum_t  n_g_elements
 
2488
      = fvm_io_num_get_global_count(section->global_element_num);
 
2489
    const fvm_gnum_t  *g_elt_num
 
2490
      = fvm_io_num_get_global_num(section->global_element_num);
 
2491
    const fvm_gnum_t  *g_vtx_num
 
2492
      = fvm_io_num_get_global_num(global_vertex_num);
 
2493
 
 
2494
    /* Prepare distribution structures */
 
2495
 
 
2496
    bi = fvm_part_to_block_compute_sizes(rank,
 
2497
                                         n_ranks,
 
2498
                                         0,
 
2499
                                         min_block_size,
 
2500
                                         n_g_elements);
 
2501
 
 
2502
    d = fvm_part_to_block_create_by_gnum(comm,
 
2503
                                         bi,
 
2504
                                         n_elements,
 
2505
                                         g_elt_num);
 
2506
 
 
2507
    /* Build connectivity */
 
2508
 
 
2509
    block_size = bi.gnum_range[1] - bi.gnum_range[0];
 
2510
 
 
2511
    BFT_MALLOC(block_vtx_num, block_size*stride, int32_t);
 
2512
    BFT_MALLOC(part_vtx_num, n_elements*stride, int32_t);
 
2513
 
 
2514
    for (i = 0; i < n_elements; i++) {
 
2515
      for (j = 0; j < stride; j++) {
 
2516
        part_vtx_num[i*stride + j]
 
2517
          = g_vtx_num[section->vertex_num[i*stride + j] - 1];
 
2518
      }
 
2519
    }
 
2520
 
 
2521
    fvm_part_to_block_copy_array(d,
 
2522
                                 sizeof(int32_t),
 
2523
                                 stride,
 
2524
                                 part_vtx_num,
 
2525
                                 block_vtx_num);
 
2526
 
 
2527
    BFT_FREE(part_vtx_num);
 
2528
 
 
2529
    _write_block_connect_g(stride,
 
2530
                           bi.gnum_range[0],
 
2531
                           bi.gnum_range[1],
 
2532
                           block_vtx_num,
 
2533
                           comm,
 
2534
                           f);
 
2535
 
 
2536
    BFT_FREE(block_vtx_num);
 
2537
 
 
2538
    fvm_part_to_block_destroy(&d);
 
2539
 
 
2540
    current_section = current_section->next;
 
2541
 
 
2542
  } while (   current_section != NULL
 
2543
           && current_section->continues_previous == true);
 
2544
 
 
2545
  return current_section;
 
2546
}
 
2547
 
 
2548
/*----------------------------------------------------------------------------
 
2549
 * Write field values associated with nodal values of a nodal mesh to
 
2550
 * an EnSight Gold file in serial mode.
 
2551
 *
 
2552
 * Output fields ar either scalar or 3d vectors or scalars, and are
 
2553
 * non interlaced. Input arrays may be less than 2d, in which case the z
 
2554
 * values are set to 0, and may be interlaced or not.
 
2555
 *
 
2556
 * parameters:
 
2557
 *   mesh             <-- pointer to nodal mesh structure
 
2558
 *   divide_polyhedra <-- true if polyhedra are tesselated
 
2559
 *   input_dim        <-- input field dimension
 
2560
 *   output_dim       <-- output field dimension
 
2561
 *   interlace        <-- indicates if field in memory is interlaced
 
2562
 *   n_parent_lists   <-- indicates if field values are to be obtained
 
2563
 *                        directly through the local entity index (when 0) or
 
2564
 *                        through the parent entity numbers (when 1 or more)
 
2565
 *   parent_num_shift <-- parent list to common number index shifts;
 
2566
 *                        size: n_parent_lists
 
2567
 *   datatype         <-- input data type (output is real)
 
2568
 *   field_values     <-- array of associated field value arrays
 
2569
 *   comm             <-- associated MPI communicator
 
2570
 *   f                <-- associated file handle
 
2571
 *----------------------------------------------------------------------------*/
 
2572
 
 
2573
static void
 
2574
_export_field_values_ng(const fvm_nodal_t        *mesh,
 
2575
                        _Bool                     divide_polyhedra,
 
2576
                        int                       input_dim,
 
2577
                        int                       output_dim,
 
2578
                        fvm_interlace_t           interlace,
 
2579
                        int                       n_parent_lists,
 
2580
                        const fvm_lnum_t          parent_num_shift[],
 
2581
                        fvm_datatype_t            datatype,
 
2582
                        const void         *const field_values[],
 
2583
                        _ensight_file_t           f,
 
2584
                        MPI_Comm                  comm)
 
2585
{
 
2586
  int  i;
 
2587
  fvm_part_to_block_info_t  bi;
 
2588
 
 
2589
  fvm_lnum_t  part_size = 0, block_size = 0;
 
2590
  float  *part_values = NULL, *block_values = NULL;
 
2591
  fvm_part_to_block_t  *d = NULL;
 
2592
 
 
2593
  /* Initialize distribution info */
 
2594
 
 
2595
  _vertex_part_to_block_create(mesh,
 
2596
                               divide_polyhedra,
 
2597
                               comm,
 
2598
                               &bi,
 
2599
                               &d);
 
2600
 
 
2601
  part_size = fvm_part_to_block_get_n_part_ents(d);
 
2602
  block_size = bi.gnum_range[1] - bi.gnum_range[0];
 
2603
 
 
2604
  BFT_MALLOC(part_values, part_size, float);
 
2605
  BFT_MALLOC(block_values, block_size, float);
 
2606
 
 
2607
  for (i = 0; i < output_dim; i++) {
 
2608
 
 
2609
    fvm_lnum_t  start_id = 0;
 
2610
    fvm_lnum_t  end_id = mesh->n_vertices;
 
2611
 
 
2612
    /* Distribute partition to block values */
 
2613
 
 
2614
    if (i < input_dim) {
 
2615
 
 
2616
      int j;
 
2617
 
 
2618
      /* Main vertices */
 
2619
 
 
2620
      fvm_convert_array(input_dim,
 
2621
                        i,
 
2622
                        1, /* stride */
 
2623
                        start_id,
 
2624
                        end_id,
 
2625
                        interlace,
 
2626
                        datatype,
 
2627
                        FVM_FLOAT,
 
2628
                        n_parent_lists,
 
2629
                        parent_num_shift,
 
2630
                        mesh->parent_vertex_num,
 
2631
                        field_values,
 
2632
                        part_values);
 
2633
 
 
2634
      /* Additional vertices in case of tesselation
 
2635
         (end_id == part_size with no tesselation or if all tesselated
 
2636
         sections have been accounted for).*/
 
2637
 
 
2638
      for (j = 0; end_id < part_size && j < mesh->n_sections; j++) {
 
2639
 
 
2640
        const fvm_nodal_section_t  *section = mesh->sections[j];
 
2641
 
 
2642
        assert(divide_polyhedra == true);
 
2643
 
 
2644
        if (section->type == FVM_CELL_POLY && section->tesselation != NULL) {
 
2645
 
 
2646
          fvm_lnum_t  n_extra_vertices
 
2647
            = fvm_tesselation_n_vertices_add(section->tesselation);
 
2648
 
 
2649
          start_id = end_id;
 
2650
          end_id = start_id + n_extra_vertices;
 
2651
 
 
2652
          fvm_tesselation_vertex_values(section->tesselation,
 
2653
                                        input_dim,
 
2654
                                        i,
 
2655
                                        1, /* stride, */
 
2656
                                        0,
 
2657
                                        n_extra_vertices,
 
2658
                                        interlace,
 
2659
                                        datatype,
 
2660
                                        FVM_FLOAT,
 
2661
                                        n_parent_lists,
 
2662
                                        parent_num_shift,
 
2663
                                        mesh->parent_vertex_num,
 
2664
                                        field_values,
 
2665
                                        part_values + start_id);
 
2666
 
 
2667
        }
 
2668
 
 
2669
      } /* End of loops on tesselated sections */
 
2670
 
 
2671
      assert(end_id == part_size);
 
2672
 
 
2673
      fvm_part_to_block_copy_array(d,
 
2674
                                   sizeof(float),
 
2675
                                   1,
 
2676
                                   part_values,
 
2677
                                   block_values);
 
2678
 
 
2679
    }
 
2680
 
 
2681
    /* Zero extra dimensions */
 
2682
 
 
2683
    else {
 
2684
      fvm_lnum_t j;
 
2685
      for (j = 0; j < block_size; j++)
 
2686
        block_values[j] = 0.0;
 
2687
    }
 
2688
 
 
2689
    _write_block_floats_g(bi.gnum_range[0],
 
2690
                          bi.gnum_range[1],
 
2691
                          block_values,
 
2692
                          comm,
 
2693
                          f);
 
2694
  }
 
2695
 
 
2696
  BFT_FREE(block_values);
 
2697
  BFT_FREE(part_values);
 
2698
 
 
2699
  fvm_part_to_block_destroy(&d);
 
2700
}
 
2701
 
 
2702
#endif /* defined(HAVE_MPI) */
 
2703
 
 
2704
/*----------------------------------------------------------------------------
 
2705
 * Write field values associated with nodal values of a nodal mesh to
 
2706
 * an EnSight Gold file in serial mode.
 
2707
 *
 
2708
 * Output fields ar either scalar or 3d vectors or scalars, and are
 
2709
 * non interlaced. Input arrays may be less than 2d, in which case the z
 
2710
 * values are set to 0, and may be interlaced or not.
 
2711
 *
 
2712
 * parameters:
 
2713
 *   n_entities         <-- number of entities
 
2714
 *   input_dim          <-- input field dimension
 
2715
 *   output_dim         <-- output field dimension
 
2716
 *   interlace          <-- indicates if field in memory is interlaced
 
2717
 *   n_parent_lists     <-- indicates if field values are to be obtained
 
2718
 *                          directly through the local entity index (when 0) or
 
2719
 *                          through the parent entity numbers (when 1 or more)
 
2720
 *   parent_num_shift   <-- parent list to common number index shifts;
 
2721
 *                          size: n_parent_lists
 
2722
 *   datatype           <-- input data type (output is real)
 
2723
 *   field_values       <-- array of associated field value arrays
 
2724
 *   f                  <-- associated file handle
 
2725
 *----------------------------------------------------------------------------*/
 
2726
 
 
2727
static void
 
2728
_export_field_values_nl(const fvm_nodal_t           *mesh,
 
2729
                        fvm_writer_field_helper_t   *helper,
 
2730
                        int                          input_dim,
 
2731
                        fvm_interlace_t              interlace,
 
2732
                        int                          n_parent_lists,
 
2733
                        const fvm_lnum_t             parent_num_shift[],
 
2734
                        fvm_datatype_t               datatype,
 
2735
                        const void            *const field_values[],
 
2736
                        _ensight_file_t              f)
 
2737
{
 
2738
  int  i;
 
2739
  size_t  output_size;
 
2740
  float  *output_buffer;
 
2741
 
 
2742
  int output_dim = fvm_writer_field_helper_field_dim(helper);
 
2743
 
 
2744
  const size_t  output_buffer_size
 
2745
    = mesh->n_vertices >  16 ? (mesh->n_vertices / 4) : mesh->n_vertices;
 
2746
 
 
2747
  BFT_MALLOC(output_buffer, output_buffer_size, float);
 
2748
 
 
2749
  for (i = 0; i < output_dim; i++) {
 
2750
 
 
2751
    while (fvm_writer_field_helper_step_n(helper,
 
2752
                                          mesh,
 
2753
                                          input_dim,
 
2754
                                          i,
 
2755
                                          interlace,
 
2756
                                          n_parent_lists,
 
2757
                                          parent_num_shift,
 
2758
                                          datatype,
 
2759
                                          field_values,
 
2760
                                          output_buffer,
 
2761
                                          output_buffer_size,
 
2762
                                          &output_size) == 0) {
 
2763
 
 
2764
      _write_block_floats_l(output_size,
 
2765
                            output_buffer,
 
2766
                            f);
 
2767
 
 
2768
    }
 
2769
  }
 
2770
 
 
2771
  BFT_FREE(output_buffer);
 
2772
}
 
2773
 
 
2774
#if defined(HAVE_MPI)
 
2775
 
 
2776
/*----------------------------------------------------------------------------
 
2777
 * Write field values associated with element values of a nodal mesh to
 
2778
 * an EnSight Gold file.
 
2779
 *
 
2780
 * Output fields ar either scalar or 3d vectors or scalars, and are
 
2781
 * non interlaced. Input arrays may be less than 2d, in which case the z
 
2782
 * values are set to 0, and may be interlaced or not.
 
2783
 *
 
2784
 * parameters:
 
2785
 *   export_section   <-- pointer to EnSight section helper structure
 
2786
 *   helper           <-- pointer to general writer helper structure
 
2787
 *   input_dim        <-- input field dimension
 
2788
 *   output_dim       <-- output field dimension
 
2789
 *   interlace        <-- indicates if field in memory is interlaced
 
2790
 *   n_parent_lists   <-- indicates if field values are to be obtained
 
2791
 *                        directly through the local entity index (when 0) or
 
2792
 *                        through the parent entity numbers (when 1 or more)
 
2793
 *   parent_num_shift <-- parent list to common number index shifts;
 
2794
 *                        size: n_parent_lists
 
2795
 *   datatype         <-- indicates the data type of (source) field values
 
2796
 *   field_values     <-- array of associated field value arrays
 
2797
 *   comm             <-- associated MPI communicator
 
2798
 *   f                <-- associated file handle
 
2799
 *
 
2800
 * returns:
 
2801
 *  pointer to next EnSight section helper structure in list
 
2802
 *----------------------------------------------------------------------------*/
 
2803
 
 
2804
static const fvm_writer_section_t *
 
2805
_export_field_values_eg(const fvm_writer_section_t      *export_section,
 
2806
                        int                              input_dim,
 
2807
                        int                              output_dim,
 
2808
                        fvm_interlace_t                  interlace,
 
2809
                        int                              n_parent_lists,
 
2810
                        const fvm_lnum_t                 parent_num_shift[],
 
2811
                        fvm_datatype_t                   datatype,
 
2812
                        const void                *const field_values[],
 
2813
                        MPI_Comm                         comm,
 
2814
                        _ensight_file_t                  f)
 
2815
{
 
2816
  int  rank, n_ranks;
 
2817
  int  i;
 
2818
  fvm_lnum_t  j, k;
 
2819
 
 
2820
  fvm_part_to_block_info_t  bi;
 
2821
  fvm_part_to_block_t  *d = NULL;
 
2822
 
 
2823
  int         n_sections = 0;
 
2824
  _Bool       have_tesselation = false;
 
2825
  fvm_lnum_t  part_size = 0, block_size = 0;
 
2826
  fvm_gnum_t  block_sub_size = 0, block_start = 0, block_end = 0;
 
2827
  fvm_gnum_t  n_g_elements = 0;
 
2828
 
 
2829
  int  *part_n_sub = NULL, *block_n_sub = NULL;
 
2830
  float  *part_values = NULL, *block_values = NULL, *_block_values = NULL;
 
2831
 
 
2832
  fvm_gnum_t        *_g_elt_num = NULL;
 
2833
  const fvm_gnum_t  *g_elt_num
 
2834
    = fvm_io_num_get_global_num(export_section->section->global_element_num);
 
2835
 
 
2836
  const fvm_writer_section_t  *current_section = NULL;
 
2837
 
 
2838
  size_t  min_block_size
 
2839
    = fvm_parall_get_min_coll_buf_size() / sizeof(int32_t);
 
2840
 
 
2841
  MPI_Comm_rank(comm, &rank);
 
2842
  MPI_Comm_size(comm, &n_ranks);
 
2843
 
 
2844
  /* Loop on sections to count output size */
 
2845
 
 
2846
  current_section = export_section;
 
2847
  do {
 
2848
 
 
2849
    const fvm_nodal_section_t  *section = current_section->section;
 
2850
 
 
2851
    n_sections += 1;
 
2852
    n_g_elements += fvm_io_num_get_global_count(section->global_element_num);
 
2853
    part_size += fvm_io_num_get_local_count(section->global_element_num);
 
2854
    if (current_section->type != section->type)
 
2855
      have_tesselation = true;
 
2856
 
 
2857
    current_section = current_section->next;
 
2858
 
 
2859
  } while (   current_section != NULL
 
2860
           && current_section->continues_previous == true);
 
2861
 
 
2862
  /* Build global numbering if necessary */
 
2863
 
 
2864
  if (n_sections > 1) {
 
2865
 
 
2866
    fvm_lnum_t start_id = 0;
 
2867
 
 
2868
    BFT_MALLOC(_g_elt_num, part_size, fvm_gnum_t);
 
2869
    g_elt_num = _g_elt_num;
 
2870
 
 
2871
    /* loop on sections which should be appended */
 
2872
 
 
2873
    current_section = export_section;
 
2874
    do {
 
2875
 
 
2876
      const fvm_nodal_section_t  *section = current_section->section;
 
2877
      const fvm_lnum_t section_size
 
2878
        = fvm_io_num_get_local_count(section->global_element_num);
 
2879
 
 
2880
      memcpy(_g_elt_num + start_id,
 
2881
             fvm_io_num_get_global_num(section->global_element_num),
 
2882
             sizeof(fvm_gnum_t)*section_size);
 
2883
      start_id += section_size;
 
2884
 
 
2885
      current_section = current_section->next;
 
2886
 
 
2887
    } while (   current_section != NULL
 
2888
             && current_section->continues_previous == true);
 
2889
  }
 
2890
 
 
2891
  /* Build sub-element count if necessary */
 
2892
 
 
2893
  if (have_tesselation) {
 
2894
 
 
2895
    fvm_lnum_t start_id = 0;
 
2896
 
 
2897
    BFT_MALLOC(part_n_sub, part_size, int);
 
2898
 
 
2899
    current_section = export_section;
 
2900
    do {
 
2901
 
 
2902
      const fvm_nodal_section_t  *section = current_section->section;
 
2903
      const fvm_lnum_t section_size
 
2904
        = fvm_io_num_get_local_count(section->global_element_num);
 
2905
 
 
2906
      if (current_section->type != section->type) {
 
2907
        const fvm_lnum_t  *sub_element_idx
 
2908
          = fvm_tesselation_sub_elt_index(section->tesselation,
 
2909
                                          current_section->type);
 
2910
        for (j = 0; j < section_size; j++)
 
2911
          part_n_sub[start_id + j] = sub_element_idx[j+1] - sub_element_idx[j];
 
2912
      }
 
2913
      else {
 
2914
        for (j = 0; j < section_size; j++)
 
2915
          part_n_sub[start_id + j] = 1;
 
2916
      }
 
2917
      start_id += section_size;
 
2918
 
 
2919
      current_section = current_section->next;
 
2920
 
 
2921
    } while (   current_section != NULL
 
2922
             && current_section->continues_previous == true);
 
2923
  }
 
2924
 
 
2925
  /* Build distribution structures */
 
2926
 
 
2927
  bi = fvm_part_to_block_compute_sizes(rank,
 
2928
                                       n_ranks,
 
2929
                                       0,
 
2930
                                       min_block_size,
 
2931
                                       n_g_elements);
 
2932
 
 
2933
  block_size = bi.gnum_range[1] - bi.gnum_range[0];
 
2934
 
 
2935
  d = fvm_part_to_block_create_by_gnum(comm, bi, part_size, g_elt_num);
 
2936
 
 
2937
  if (_g_elt_num != NULL)
 
2938
    fvm_part_to_block_transfer_gnum(d, _g_elt_num);
 
2939
 
 
2940
  g_elt_num = NULL;
 
2941
  _g_elt_num = NULL;
 
2942
 
 
2943
  /* Distribute sub-element info in case of tesselation */
 
2944
 
 
2945
  if (have_tesselation) {
 
2946
 
 
2947
    BFT_MALLOC(block_n_sub, block_size, int);
 
2948
    fvm_part_to_block_copy_array(d,
 
2949
                                 sizeof(int),
 
2950
                                 1,
 
2951
                                 part_n_sub,
 
2952
                                 block_n_sub);
 
2953
    BFT_FREE(part_n_sub);
 
2954
 
 
2955
    for (j = 0; j < block_size; j++)
 
2956
      block_sub_size += block_n_sub[j];
 
2957
 
 
2958
  }
 
2959
  else
 
2960
    block_sub_size = block_size;
 
2961
 
 
2962
  /* To save space, in case of tesselation, part_values and _block_n_sub
 
2963
     point to the same memory space, as they are not needed simultaneously.
 
2964
     Without tesselation, _block_n_sub simply points to block_n_sub */
 
2965
 
 
2966
  BFT_MALLOC(part_values,
 
2967
             FVM_MAX(part_size, (fvm_lnum_t)block_sub_size),
 
2968
             float);
 
2969
  BFT_MALLOC(block_values, block_size, float);
 
2970
 
 
2971
  if (have_tesselation) {
 
2972
    MPI_Scan(&block_sub_size, &block_end, 1, FVM_MPI_GNUM, MPI_SUM, comm);
 
2973
    block_end += 1;
 
2974
    block_start = block_end - block_sub_size;
 
2975
    _block_values = part_values;
 
2976
  }
 
2977
  else {
 
2978
    block_start = bi.gnum_range[0];
 
2979
    block_end = bi.gnum_range[1];
 
2980
    _block_values = block_values;
 
2981
  }
 
2982
 
 
2983
  /* Loop on dimension (de-interlace vectors, always 3D for EnSight) */
 
2984
 
 
2985
  for (i = 0; i < output_dim; i++) {
 
2986
 
 
2987
    /* Distribute partition to block values */
 
2988
 
 
2989
    if (i < input_dim) {
 
2990
 
 
2991
      fvm_lnum_t start_id = 0;
 
2992
      fvm_lnum_t src_shift = 0;
 
2993
 
 
2994
      /* loop on sections which should be appended */
 
2995
 
 
2996
      current_section = export_section;
 
2997
      do {
 
2998
 
 
2999
        const fvm_nodal_section_t  *section = current_section->section;
 
3000
 
 
3001
        if (n_parent_lists == 0)
 
3002
          src_shift = export_section->num_shift;
 
3003
 
 
3004
        fvm_convert_array(input_dim,
 
3005
                          i,
 
3006
                          1,
 
3007
                          src_shift,
 
3008
                          section->n_elements + src_shift,
 
3009
                          interlace,
 
3010
                          datatype,
 
3011
                          FVM_FLOAT,
 
3012
                          n_parent_lists,
 
3013
                          parent_num_shift,
 
3014
                          section->parent_element_num,
 
3015
                          field_values,
 
3016
                          part_values + start_id);
 
3017
 
 
3018
        start_id += fvm_io_num_get_local_count(section->global_element_num);
 
3019
 
 
3020
        current_section = current_section->next;
 
3021
 
 
3022
      } while (   current_section != NULL
 
3023
               && current_section->continues_previous == true);
 
3024
 
 
3025
      /* Distribute part values */
 
3026
 
 
3027
      fvm_part_to_block_copy_array(d,
 
3028
                                   sizeof(float),
 
3029
                                   1,
 
3030
                                   part_values,
 
3031
                                   block_values);
 
3032
 
 
3033
      /* Scatter values to sub-elements in case of tesselation */
 
3034
 
 
3035
      if (have_tesselation) {
 
3036
        fvm_lnum_t  l = 0;
 
3037
        for (j = 0; j < block_size; j++) {
 
3038
          for (k = 0; k < block_n_sub[j]; k++)
 
3039
            _block_values[l++] = block_values[j];
 
3040
        }
 
3041
      }
 
3042
 
 
3043
    }
 
3044
 
 
3045
    /* Zero extra dimensions */
 
3046
 
 
3047
    else {
 
3048
      for (j = 0; j < (fvm_lnum_t)block_sub_size; j++)
 
3049
        block_values[j] = 0.0;
 
3050
    }
 
3051
 
 
3052
    /* Write block values */
 
3053
 
 
3054
    _write_block_floats_g(block_start,
 
3055
                          block_end,
 
3056
                          _block_values,
 
3057
                          comm,
 
3058
                          f);
 
3059
 
 
3060
  } /* end of loop on spatial dimension */
 
3061
 
 
3062
  BFT_FREE(block_values);
 
3063
  BFT_FREE(part_values);
 
3064
 
 
3065
  fvm_part_to_block_destroy(&d);
 
3066
 
 
3067
  if (block_n_sub != NULL)
 
3068
    BFT_FREE(block_n_sub);
 
3069
 
 
3070
  return current_section;
 
3071
}
 
3072
 
 
3073
#endif /* defined(HAVE_MPI) */
 
3074
 
 
3075
/*----------------------------------------------------------------------------
 
3076
 * Write field values associated with element values of a nodal mesh to
 
3077
 * an EnSight Gold file.
 
3078
 *
 
3079
 * Output fields ar either scalar or 3d vectors or scalars, and are
 
3080
 * non interlaced. Input arrays may be less than 2d, in which case the z
 
3081
 * values are set to 0, and may be interlaced or not.
 
3082
 *
 
3083
 * parameters:
 
3084
 *   export_section   <-- pointer to EnSight section helper structure
 
3085
 *   helper           <-- pointer to general writer helper structure
 
3086
 *   input_dim        <-- input field dimension
 
3087
 *   interlace        <-- indicates if field in memory is interlaced
 
3088
 *   n_parent_lists   <-- indicates if field values are to be obtained
 
3089
 *                        directly through the local entity index (when 0) or
 
3090
 *                        through the parent entity numbers (when 1 or more)
 
3091
 *   parent_num_shift <-- parent list to common number index shifts;
 
3092
 *                        size: n_parent_lists
 
3093
 *   datatype         <-- indicates the data type of (source) field values
 
3094
 *   field_values     <-- array of associated field value arrays
 
3095
 *   f                <-- associated file handle
 
3096
 *
 
3097
 * returns:
 
3098
 *  pointer to next EnSight section helper structure in list
 
3099
 *----------------------------------------------------------------------------*/
 
3100
 
 
3101
static const fvm_writer_section_t *
 
3102
_export_field_values_el(const fvm_writer_section_t      *export_section,
 
3103
                        fvm_writer_field_helper_t       *helper,
 
3104
                        int                              input_dim,
 
3105
                        fvm_interlace_t                  interlace,
 
3106
                        int                              n_parent_lists,
 
3107
                        const fvm_lnum_t                 parent_num_shift[],
 
3108
                        fvm_datatype_t                   datatype,
 
3109
                        const void                *const field_values[],
 
3110
                        _ensight_file_t                  f)
 
3111
{
 
3112
  int  i;
 
3113
  size_t  input_size = 0, output_size = 0;
 
3114
  size_t  min_output_buffer_size = 0, output_buffer_size = 0;
 
3115
  float  *output_buffer = NULL;
 
3116
 
 
3117
  const fvm_writer_section_t  *current_section = NULL;
 
3118
 
 
3119
  int output_dim = fvm_writer_field_helper_field_dim(helper);
 
3120
 
 
3121
  /* Blocking for arbitrary buffer size, but should be small enough
 
3122
     to add little additional memory requirement (in proportion), large
 
3123
     enough to limit number of write and gather calls. */
 
3124
 
 
3125
  fvm_writer_field_helper_get_size(helper,
 
3126
                                   &input_size,
 
3127
                                   &output_size,
 
3128
                                   NULL,
 
3129
                                   &min_output_buffer_size);
 
3130
 
 
3131
  output_buffer_size = input_size / 4;
 
3132
  output_buffer_size = FVM_MAX(output_buffer_size, min_output_buffer_size);
 
3133
  output_buffer_size = FVM_MAX(output_buffer_size, 128);
 
3134
  output_buffer_size = FVM_MIN(output_buffer_size, output_size);
 
3135
 
 
3136
  BFT_MALLOC(output_buffer, output_buffer_size, float);
 
3137
 
 
3138
  /* Loop on dimension (de-interlace vectors, always 3D for EnSight) */
 
3139
 
 
3140
  for (i = 0; i < output_dim; i++) {
 
3141
 
 
3142
    _Bool loop_on_sections = true;
 
3143
 
 
3144
    current_section = export_section;
 
3145
 
 
3146
    while (loop_on_sections == true) {
 
3147
 
 
3148
      while (fvm_writer_field_helper_step_e(helper,
 
3149
                                            current_section,
 
3150
                                            input_dim,
 
3151
                                            i,
 
3152
                                            interlace,
 
3153
                                            n_parent_lists,
 
3154
                                            parent_num_shift,
 
3155
                                            datatype,
 
3156
                                            field_values,
 
3157
                                            output_buffer,
 
3158
                                            output_buffer_size,
 
3159
                                            &output_size) == 0) {
 
3160
 
 
3161
        _write_block_floats_l(output_size,
 
3162
                              output_buffer,
 
3163
                              f);
 
3164
 
 
3165
      }
 
3166
 
 
3167
      current_section = current_section->next;
 
3168
 
 
3169
      if (   current_section == NULL
 
3170
          || current_section->continues_previous == false)
 
3171
        loop_on_sections = false;
 
3172
 
 
3173
    } /* while (loop on sections) */
 
3174
 
 
3175
  } /* end of loop on spatial dimension */
 
3176
 
 
3177
  BFT_FREE(output_buffer);
 
3178
 
 
3179
  return current_section;
 
3180
}
 
3181
 
 
3182
/*============================================================================
 
3183
 * Public function definitions
 
3184
 *============================================================================*/
 
3185
 
 
3186
/*----------------------------------------------------------------------------
 
3187
 * Initialize FVM to EnSight Gold file writer.
 
3188
 *
 
3189
 * Options are:
 
3190
 *   text                output text files
 
3191
 *   binary              output binary files (default)
 
3192
 *   big_endian          force binary files to big-endian
 
3193
 *   discard_polygons    do not output polygons or related values
 
3194
 *   discard_polyhedra   do not output polyhedra or related values
 
3195
 *   divide_polygons     tesselate polygons with triangles
 
3196
 *   divide_polyhedra    tesselate polyhedra with tetrahedra and pyramids
 
3197
 *                       (adding a vertex near each polyhedron's center)
 
3198
 *
 
3199
 * parameters:
 
3200
 *   name           <-- base output case name.
 
3201
 *   options        <-- whitespace separated, lowercase options list
 
3202
 *   time_dependecy <-- indicates if and how meshes will change with time
 
3203
 *   comm           <-- associated MPI communicator.
 
3204
 *
 
3205
 * returns:
 
3206
 *   pointer to opaque EnSight Gold writer structure.
 
3207
 *----------------------------------------------------------------------------*/
 
3208
 
 
3209
#if defined(HAVE_MPI)
 
3210
void *
 
3211
fvm_to_ensight_init_writer(const char             *name,
 
3212
                           const char             *path,
 
3213
                           const char             *options,
 
3214
                           fvm_writer_time_dep_t   time_dependency,
 
3215
                           MPI_Comm                comm)
 
3216
#else
 
3217
void *
 
3218
fvm_to_ensight_init_writer(const char             *name,
 
3219
                           const char             *path,
 
3220
                           const char             *options,
 
3221
                           fvm_writer_time_dep_t   time_dependency)
 
3222
#endif
 
3223
{
 
3224
  fvm_to_ensight_writer_t  *this_writer = NULL;
 
3225
 
 
3226
  /* Initialize writer */
 
3227
 
 
3228
  BFT_MALLOC(this_writer, 1, fvm_to_ensight_writer_t);
 
3229
 
 
3230
  BFT_MALLOC(this_writer->name, strlen(name) + 1, char);
 
3231
  strcpy(this_writer->name, name);
 
3232
 
 
3233
  this_writer->text_mode = false;
 
3234
  this_writer->swap_endian = false;
 
3235
  this_writer->discard_polygons = false;
 
3236
  this_writer->discard_polyhedra = false;
 
3237
  this_writer->divide_polygons = false;
 
3238
  this_writer->divide_polyhedra = false;
 
3239
 
 
3240
  this_writer->rank = 0;
 
3241
  this_writer->n_ranks = 1;
 
3242
 
 
3243
#if defined(HAVE_MPI)
 
3244
  {
 
3245
    int mpi_flag, rank, n_ranks;
 
3246
    MPI_Initialized(&mpi_flag);
 
3247
 
 
3248
    if (mpi_flag && comm != MPI_COMM_NULL) {
 
3249
      this_writer->comm = comm;
 
3250
      MPI_Comm_rank(this_writer->comm, &rank);
 
3251
      MPI_Comm_size(this_writer->comm, &n_ranks);
 
3252
      this_writer->rank = rank;
 
3253
      this_writer->n_ranks = n_ranks;
 
3254
    }
 
3255
    else
 
3256
      this_writer->comm = MPI_COMM_NULL;
 
3257
  }
 
3258
#endif /* defined(HAVE_MPI) */
 
3259
 
 
3260
  /* Parse options */
 
3261
 
 
3262
  if (options != NULL) {
 
3263
 
 
3264
    int i1, i2, l_opt;
 
3265
    int l_tot = strlen(options);
 
3266
 
 
3267
    i1 = 0; i2 = 0;
 
3268
    while (i1 < l_tot) {
 
3269
 
 
3270
      for (i2 = i1; i2 < l_tot && options[i2] != ' '; i2++);
 
3271
      l_opt = i2 - i1;
 
3272
 
 
3273
      if ((l_opt == 4) && (strncmp(options + i1, "text", l_opt) == 0))
 
3274
        this_writer->text_mode = true;
 
3275
      else if ((l_opt == 6) && (strncmp(options + i1, "binary", l_opt) == 0))
 
3276
        this_writer->text_mode = false;
 
3277
 
 
3278
      else if (   (l_opt == 10)
 
3279
               && (strncmp(options + i1, "big_endian", l_opt) == 0)) {
 
3280
        int int_endian = 0;
 
3281
        this_writer->text_mode = false;
 
3282
        /* Check if system is "big-endian" or "little-endian" */
 
3283
        *((char *)(&int_endian)) = '\1';
 
3284
        if (int_endian == 1)
 
3285
          this_writer->swap_endian = 1;
 
3286
      }
 
3287
 
 
3288
      else if (   (l_opt == 16)
 
3289
               && (strncmp(options + i1, "discard_polygons", l_opt) == 0))
 
3290
        this_writer->discard_polygons = true;
 
3291
      else if (   (l_opt == 17)
 
3292
               && (strncmp(options + i1, "discard_polyhedra", l_opt) == 0))
 
3293
        this_writer->discard_polyhedra = true;
 
3294
 
 
3295
      else if (   (l_opt == 15)
 
3296
               && (strncmp(options + i1, "divide_polygons", l_opt) == 0))
 
3297
        this_writer->divide_polygons = true;
 
3298
      else if (   (l_opt == 16)
 
3299
               && (strncmp(options + i1, "divide_polyhedra", l_opt) == 0))
 
3300
        this_writer->divide_polyhedra = true;
 
3301
 
 
3302
      for (i1 = i2 + 1; i1 < l_tot && options[i1] == ' '; i1++);
 
3303
 
 
3304
    }
 
3305
 
 
3306
  }
 
3307
 
 
3308
  this_writer->case_info = fvm_to_ensight_case_create(name,
 
3309
                                                      path,
 
3310
                                                      time_dependency);
 
3311
 
 
3312
  /* Return writer */
 
3313
 
 
3314
  return this_writer;
 
3315
}
 
3316
 
 
3317
/*----------------------------------------------------------------------------
 
3318
 * Finalize FVM to EnSight Gold file writer.
 
3319
 *
 
3320
 * parameters:
 
3321
 *   this_writer_p <-- pointer to opaque Ensight Gold writer structure.
 
3322
 *
 
3323
 * returns:
 
3324
 *   NULL pointer
 
3325
 *----------------------------------------------------------------------------*/
 
3326
 
 
3327
void *
 
3328
fvm_to_ensight_finalize_writer(void  *this_writer_p)
 
3329
{
 
3330
  fvm_to_ensight_writer_t  *this_writer
 
3331
                             = (fvm_to_ensight_writer_t *)this_writer_p;
 
3332
 
 
3333
  BFT_FREE(this_writer->name);
 
3334
 
 
3335
  fvm_to_ensight_case_destroy(this_writer->case_info);
 
3336
 
 
3337
  BFT_FREE(this_writer);
 
3338
 
 
3339
  return NULL;
 
3340
}
 
3341
 
 
3342
/*----------------------------------------------------------------------------
 
3343
 * Associate new time step with an EnSight geometry.
 
3344
 *
 
3345
 * parameters:
 
3346
 *   this_writer_p <-- pointer to associated writer
 
3347
 *   time_step     <-- time step number
 
3348
 *   time_value    <-- time_value number
 
3349
 *----------------------------------------------------------------------------*/
 
3350
 
 
3351
void
 
3352
fvm_to_ensight_set_mesh_time(void          *this_writer_p,
 
3353
                             const int      time_step,
 
3354
                             const double   time_value)
 
3355
{
 
3356
  fvm_to_ensight_writer_t  *this_writer
 
3357
                             = (fvm_to_ensight_writer_t *)this_writer_p;
 
3358
 
 
3359
  fvm_to_ensight_case_set_geom_time(this_writer->case_info,
 
3360
                                    time_step,
 
3361
                                    time_value);
 
3362
}
 
3363
 
 
3364
/*----------------------------------------------------------------------------
 
3365
 * Indicate if a elements of a given type in a mesh associated to a given
 
3366
 * EnSight Gold file writer need to be tesselated.
 
3367
 *
 
3368
 * parameters:
 
3369
 *   this_writer_p <-- pointer to associated writer
 
3370
 *   mesh          <-- pointer to nodal mesh structure that should be written
 
3371
 *   element_type  <-- element type we are interested in
 
3372
 *
 
3373
 * returns:
 
3374
 *   1 if tesselation of the given element type is needed, 0 otherwise
 
3375
 *----------------------------------------------------------------------------*/
 
3376
 
 
3377
int
 
3378
fvm_to_ensight_needs_tesselation(fvm_writer_t       *this_writer_p,
 
3379
                                 const fvm_nodal_t  *mesh,
 
3380
                                 fvm_element_t       element_type)
 
3381
{
 
3382
  int  i;
 
3383
  int  retval = 0;
 
3384
  fvm_to_ensight_writer_t  *this_writer
 
3385
                             = (fvm_to_ensight_writer_t *)this_writer_p;
 
3386
 
 
3387
  const int  export_dim = fvm_nodal_get_max_entity_dim(mesh);
 
3388
 
 
3389
  /* Initial count and allocation */
 
3390
 
 
3391
  if (   (   element_type == FVM_FACE_POLY
 
3392
          && this_writer->divide_polygons == true)
 
3393
      || (   element_type == FVM_CELL_POLY
 
3394
          && this_writer->divide_polyhedra == true)) {
 
3395
 
 
3396
    for (i = 0; i < mesh->n_sections; i++) {
 
3397
 
 
3398
      const fvm_nodal_section_t  *const  section = mesh->sections[i];
 
3399
 
 
3400
      /* Output if entity dimension equal to highest in mesh
 
3401
         (i.e. no output of faces if cells present, or edges
 
3402
         if cells or faces) */
 
3403
 
 
3404
      if (section->entity_dim == export_dim) {
 
3405
        if (section->type == element_type)
 
3406
          retval = 1;
 
3407
      }
 
3408
 
 
3409
    }
 
3410
 
 
3411
  }
 
3412
 
 
3413
  return retval;
 
3414
}
 
3415
 
 
3416
/*----------------------------------------------------------------------------
 
3417
 * Write nodal mesh to a an EnSight Gold file
 
3418
 *
 
3419
 * parameters:
 
3420
 *   this_writer_p <-- pointer to associated writer
 
3421
 *   mesh          <-- pointer to nodal mesh structure that should be written
 
3422
 *----------------------------------------------------------------------------*/
 
3423
 
 
3424
void
 
3425
fvm_to_ensight_export_nodal(void               *this_writer_p,
 
3426
                            const fvm_nodal_t  *mesh)
 
3427
{
 
3428
  int  part_num;
 
3429
 
 
3430
  const fvm_writer_section_t  *export_section = NULL;
 
3431
  fvm_writer_section_t        *export_list = NULL;
 
3432
  fvm_to_ensight_writer_t     *this_writer
 
3433
                                  = (fvm_to_ensight_writer_t *)this_writer_p;
 
3434
  _ensight_file_t  f = {NULL, NULL};
 
3435
 
 
3436
  const int  rank = this_writer->rank;
 
3437
  const int  n_ranks = this_writer->n_ranks;
 
3438
 
 
3439
  /* Initialization */
 
3440
  /*----------------*/
 
3441
 
 
3442
  fvm_to_ensight_case_file_info_t  file_info;
 
3443
 
 
3444
  /* Get part number */
 
3445
 
 
3446
  part_num = fvm_to_ensight_case_get_part_num(this_writer->case_info,
 
3447
                                              mesh->name);
 
3448
  if (part_num == 0)
 
3449
    part_num = fvm_to_ensight_case_add_part(this_writer->case_info,
 
3450
                                            mesh->name);
 
3451
 
 
3452
  /* Open geometry file in append mode */
 
3453
 
 
3454
  file_info = fvm_to_ensight_case_get_geom_file(this_writer->case_info);
 
3455
 
 
3456
  f = _open_ensight_file(this_writer,
 
3457
                         file_info.name,
 
3458
                         file_info.queried);
 
3459
 
 
3460
  if (file_info.queried == false)
 
3461
    _write_geom_headers(this_writer, f);
 
3462
 
 
3463
  /* Part header */
 
3464
 
 
3465
  _write_string(f, "part");
 
3466
  _write_int(f, part_num);
 
3467
  if (mesh->name != NULL)
 
3468
    _write_string(f, mesh->name);
 
3469
  else
 
3470
    _write_string(f, "unnamed");
 
3471
 
 
3472
  /* Build list of sections that are used here, in order of output */
 
3473
 
 
3474
  export_list = fvm_writer_export_list(mesh,
 
3475
                                       fvm_nodal_get_max_entity_dim(mesh),
 
3476
                                       true,
 
3477
                                       this_writer->discard_polygons,
 
3478
                                       this_writer->discard_polyhedra,
 
3479
                                       this_writer->divide_polygons,
 
3480
                                       this_writer->divide_polyhedra);
 
3481
 
 
3482
  /* Vertex coordinates */
 
3483
  /*--------------------*/
 
3484
 
 
3485
#if defined(HAVE_MPI)
 
3486
  if (n_ranks > 1)
 
3487
    _export_vertex_coords_g(this_writer, mesh, f);
 
3488
#endif
 
3489
 
 
3490
  if (n_ranks == 1)
 
3491
    _export_vertex_coords_l(this_writer, mesh, f);
 
3492
 
 
3493
  /* If no sections are present (i.e. we may only have vertices),
 
3494
     add  "point" elements */
 
3495
 
 
3496
  if (export_list == NULL) {
 
3497
 
 
3498
#if defined(HAVE_MPI)
 
3499
    if (n_ranks > 1)
 
3500
      _export_point_elements_g(mesh, this_writer->comm, f);
 
3501
#endif
 
3502
    if (n_ranks == 1)
 
3503
      _export_point_elements_l(mesh, f);
 
3504
 
 
3505
  }
 
3506
 
 
3507
  /* Element connectivity */
 
3508
  /*----------------------*/
 
3509
 
 
3510
  export_section = export_list;
 
3511
 
 
3512
  while (export_section != NULL) {
 
3513
 
 
3514
    const fvm_nodal_section_t  *section = export_section->section;
 
3515
 
 
3516
    /* Print header if start of corresponding EnSight section */
 
3517
 
 
3518
    if (export_section->continues_previous == false) {
 
3519
 
 
3520
      fvm_gnum_t n_g_elements = 0;
 
3521
      const fvm_writer_section_t  *next_section = export_section;
 
3522
 
 
3523
      do {
 
3524
 
 
3525
        if (next_section->section->type == export_section->type)
 
3526
          n_g_elements += fvm_nodal_section_n_g_elements(next_section->section);
 
3527
 
 
3528
        else {
 
3529
          fvm_gnum_t n_g_sub_elements = 0;
 
3530
          fvm_tesselation_get_global_size(next_section->section->tesselation,
 
3531
                                          next_section->type,
 
3532
                                          &n_g_sub_elements,
 
3533
                                          NULL);
 
3534
          n_g_elements += n_g_sub_elements;
 
3535
        }
 
3536
 
 
3537
        next_section = next_section->next;
 
3538
 
 
3539
      } while (next_section != NULL && next_section->continues_previous == true);
 
3540
 
 
3541
      _write_string(f, _ensight_type_name[export_section->type]);
 
3542
      _write_int(f, n_g_elements);
 
3543
    }
 
3544
 
 
3545
    /* Output for strided (regular) element types */
 
3546
    /*--------------------------------------------*/
 
3547
 
 
3548
    if (section->stride > 0) {
 
3549
 
 
3550
#if defined(HAVE_MPI)
 
3551
 
 
3552
      if (n_ranks > 1)
 
3553
        export_section = _export_nodal_strided_g(export_section,
 
3554
                                                 mesh->global_vertex_num,
 
3555
                                                 this_writer->comm,
 
3556
                                                 f);
 
3557
 
 
3558
#endif /* defined(HAVE_MPI) */
 
3559
 
 
3560
      if (n_ranks == 1) { /* start of output in serial mode */
 
3561
 
 
3562
        _write_connect_l(section->stride,
 
3563
                         section->n_elements,
 
3564
                         section->vertex_num,
 
3565
                         f);
 
3566
 
 
3567
        export_section = export_section->next;
 
3568
 
 
3569
      }
 
3570
 
 
3571
    } /* end of output for strided element types */
 
3572
 
 
3573
    /* Output for tesselated polygons or polyhedra */
 
3574
    /*---------------------------------------------*/
 
3575
 
 
3576
    else if (export_section->type != section->type) {
 
3577
 
 
3578
#if defined(HAVE_MPI)
 
3579
 
 
3580
      /* output in parallel mode */
 
3581
 
 
3582
      if (n_ranks > 1)
 
3583
        export_section = _export_nodal_tesselated_g(export_section,
 
3584
                                                    mesh->global_vertex_num,
 
3585
                                                    this_writer->comm,
 
3586
                                                    f);
 
3587
#endif /* defined(HAVE_MPI) */
 
3588
 
 
3589
      if (n_ranks == 1)
 
3590
        export_section = _export_nodal_tesselated_l(export_section,
 
3591
                                                    f);
 
3592
 
 
3593
    }
 
3594
 
 
3595
    /* Output for polygons */
 
3596
    /*---------------------*/
 
3597
 
 
3598
    else if (export_section->type == FVM_FACE_POLY) {
 
3599
#if defined(HAVE_MPI)
 
3600
 
 
3601
      /* output in parallel mode */
 
3602
 
 
3603
      if (n_ranks > 1)
 
3604
        export_section = _export_nodal_polygons_g(export_section,
 
3605
                                                  mesh->global_vertex_num,
 
3606
                                                  this_writer->comm,
 
3607
                                                  f);
 
3608
#endif /* defined(HAVE_MPI) */
 
3609
 
 
3610
      if (n_ranks == 1)
 
3611
        export_section = _export_nodal_polygons_l(export_section,
 
3612
                                                  f);
 
3613
 
 
3614
    }
 
3615
 
 
3616
    /* Output for polyhedra */
 
3617
    /*----------------------*/
 
3618
 
 
3619
    else if (export_section->type == FVM_CELL_POLY) {
 
3620
 
 
3621
#if defined(HAVE_MPI)
 
3622
 
 
3623
      /* output in parallel mode */
 
3624
 
 
3625
      if (n_ranks > 1)
 
3626
        export_section =_export_nodal_polyhedra_g(export_section,
 
3627
                                                  mesh->global_vertex_num,
 
3628
                                                  this_writer->comm,
 
3629
                                                  f);
 
3630
 
 
3631
#endif /* defined(HAVE_MPI) */
 
3632
 
 
3633
      if (n_ranks == 1)
 
3634
        export_section = _export_nodal_polyhedra_l(export_section,
 
3635
                                                   f);
 
3636
 
 
3637
    }
 
3638
 
 
3639
  } /* End of loop on sections */
 
3640
 
 
3641
  BFT_FREE(export_list);
 
3642
 
 
3643
  /* Close geometry file and update case file */
 
3644
  /*------------------------------------------*/
 
3645
 
 
3646
  _free_ensight_file(&f);
 
3647
 
 
3648
  fvm_to_ensight_case_write_case(this_writer->case_info, rank);
 
3649
}
 
3650
 
 
3651
/*----------------------------------------------------------------------------
 
3652
 * Write field associated with a nodal mesh to an EnSight Gold file.
 
3653
 *
 
3654
 * Assigning a negative value to the time step indicates a time-independent
 
3655
 * field (in which case the time_value argument is unused).
 
3656
 *
 
3657
 * parameters:
 
3658
 *   this_writer_p    <-- pointer to associated writer
 
3659
 *   mesh             <-- pointer to associated nodal mesh structure
 
3660
 *   name             <-- variable name
 
3661
 *   location         <-- variable definition location (nodes or elements)
 
3662
 *   dimension        <-- variable dimension (0: constant, 1: scalar,
 
3663
 *                        3: vector, 6: sym. tensor, 9: asym. tensor)
 
3664
 *   interlace        <-- indicates if variable in memory is interlaced
 
3665
 *   n_parent_lists   <-- indicates if variable values are to be obtained
 
3666
 *                        directly through the local entity index (when 0) or
 
3667
 *                        through the parent entity numbers (when 1 or more)
 
3668
 *   parent_num_shift <-- parent number to value array index shifts;
 
3669
 *                        size: n_parent_lists
 
3670
 *   datatype         <-- indicates the data type of (source) field values
 
3671
 *   time_step        <-- number of the current time step
 
3672
 *   time_value       <-- associated time value
 
3673
 *   field_values     <-- array of associated field value arrays
 
3674
 *----------------------------------------------------------------------------*/
 
3675
 
 
3676
void
 
3677
fvm_to_ensight_export_field(void                  *this_writer_p,
 
3678
                            const fvm_nodal_t     *mesh,
 
3679
                            const char            *name,
 
3680
                            fvm_writer_var_loc_t   location,
 
3681
                            int                    dimension,
 
3682
                            fvm_interlace_t        interlace,
 
3683
                            int                    n_parent_lists,
 
3684
                            const fvm_lnum_t       parent_num_shift[],
 
3685
                            fvm_datatype_t         datatype,
 
3686
                            int                    time_step,
 
3687
                            double                 time_value,
 
3688
                            const void      *const field_values[])
 
3689
{
 
3690
  int   output_dim, part_num;
 
3691
  fvm_to_ensight_case_file_info_t  file_info;
 
3692
 
 
3693
  const fvm_writer_section_t  *export_section = NULL;
 
3694
  fvm_writer_field_helper_t  *helper = NULL;
 
3695
  fvm_writer_section_t  *export_list = NULL;
 
3696
  fvm_to_ensight_writer_t  *this_writer
 
3697
                             = (fvm_to_ensight_writer_t *)this_writer_p;
 
3698
  _ensight_file_t  f = {NULL, NULL};
 
3699
 
 
3700
  const int  rank = this_writer->rank;
 
3701
  const int  n_ranks = this_writer->n_ranks;
 
3702
 
 
3703
  /* Initialization */
 
3704
  /*----------------*/
 
3705
 
 
3706
  /* Dimension */
 
3707
 
 
3708
  output_dim = dimension;
 
3709
  if (dimension == 2)
 
3710
    output_dim = 3;
 
3711
  else if (dimension > 3 && dimension != 6 && dimension != 9)
 
3712
    bft_error(__FILE__, __LINE__, 0,
 
3713
              _("Data of dimension %d not handled"), dimension);
 
3714
 
 
3715
  /* Get part number */
 
3716
 
 
3717
  part_num = fvm_to_ensight_case_get_part_num(this_writer->case_info,
 
3718
                                              mesh->name);
 
3719
  if (part_num == 0)
 
3720
    part_num = fvm_to_ensight_case_add_part(this_writer->case_info,
 
3721
                                            mesh->name);
 
3722
 
 
3723
  /* Open variable file */
 
3724
 
 
3725
  file_info = fvm_to_ensight_case_get_var_file(this_writer->case_info,
 
3726
                                               name,
 
3727
                                               output_dim,
 
3728
                                               location,
 
3729
                                               time_step,
 
3730
                                               time_value);
 
3731
 
 
3732
  f = _open_ensight_file(this_writer, file_info.name, file_info.queried);
 
3733
 
 
3734
  if (file_info.queried == false) {
 
3735
 
 
3736
    char buf[81] = "";
 
3737
 
 
3738
    /* New files start with description line */
 
3739
#if HAVE_SNPRINTF
 
3740
    if (time_step > -1)
 
3741
      snprintf(buf, 80, "%s (time values: %d, %g)",
 
3742
               name, time_step, time_value);
 
3743
    else
 
3744
      strncpy(buf, name, 80);
 
3745
#else
 
3746
    strncpy(buf, name, 80);
 
3747
#endif
 
3748
    buf[80] = '\0';
 
3749
    _write_string(f, buf);
 
3750
  }
 
3751
 
 
3752
  /* Initialize writer helper */
 
3753
  /*--------------------------*/
 
3754
 
 
3755
  /* Build list of sections that are used here, in order of output */
 
3756
 
 
3757
  export_list = fvm_writer_export_list(mesh,
 
3758
                                       fvm_nodal_get_max_entity_dim(mesh),
 
3759
                                       true,
 
3760
                                       this_writer->discard_polygons,
 
3761
                                       this_writer->discard_polyhedra,
 
3762
                                       this_writer->divide_polygons,
 
3763
                                       this_writer->divide_polyhedra);
 
3764
 
 
3765
  if (n_ranks == 1)
 
3766
    helper = fvm_writer_field_helper_create(mesh,
 
3767
                                            export_list,
 
3768
                                            output_dim,
 
3769
                                            FVM_NO_INTERLACE,
 
3770
                                            FVM_FLOAT,
 
3771
                                            location);
 
3772
 
 
3773
  /* Part header */
 
3774
 
 
3775
  _write_string(f, "part");
 
3776
  _write_int(f, part_num);
 
3777
 
 
3778
  /* Per node variable */
 
3779
  /*-------------------*/
 
3780
 
 
3781
  if (location == FVM_WRITER_PER_NODE) {
 
3782
 
 
3783
    _write_string(f, "coordinates");
 
3784
 
 
3785
#if defined(HAVE_MPI)
 
3786
 
 
3787
    if (n_ranks > 1)
 
3788
      _export_field_values_ng(mesh,
 
3789
                              this_writer->divide_polyhedra,
 
3790
                              dimension,
 
3791
                              output_dim,
 
3792
                              interlace,
 
3793
                              n_parent_lists,
 
3794
                              parent_num_shift,
 
3795
                              datatype,
 
3796
                              field_values,
 
3797
                              f,
 
3798
                              this_writer->comm);
 
3799
 
 
3800
#endif /* defined(HAVE_MPI) */
 
3801
 
 
3802
    if (n_ranks == 1)
 
3803
      _export_field_values_nl(mesh,
 
3804
                              helper,
 
3805
                              dimension,
 
3806
                              interlace,
 
3807
                              n_parent_lists,
 
3808
                              parent_num_shift,
 
3809
                              datatype,
 
3810
                              field_values,
 
3811
                              f);
 
3812
  }
 
3813
 
 
3814
  /* Per element variable */
 
3815
  /*----------------------*/
 
3816
 
 
3817
  else if (location == FVM_WRITER_PER_ELEMENT) {
 
3818
 
 
3819
    export_section = export_list;
 
3820
 
 
3821
    while (export_section != NULL) {
 
3822
 
 
3823
      /* Print header if start of corresponding EnSight section */
 
3824
 
 
3825
      if (export_section->continues_previous == false)
 
3826
        _write_string(f, _ensight_type_name[export_section->type]);
 
3827
 
 
3828
      /* Output per grouped sections */
 
3829
 
 
3830
#if defined(HAVE_MPI)
 
3831
 
 
3832
      if (n_ranks > 1)
 
3833
        export_section = _export_field_values_eg(export_section,
 
3834
                                                 dimension,
 
3835
                                                 output_dim,
 
3836
                                                 interlace,
 
3837
                                                 n_parent_lists,
 
3838
                                                 parent_num_shift,
 
3839
                                                 datatype,
 
3840
                                                 field_values,
 
3841
                                                 this_writer->comm,
 
3842
                                                 f);
 
3843
 
 
3844
#endif /* defined(HAVE_MPI) */
 
3845
 
 
3846
      if (n_ranks == 1)
 
3847
        export_section = _export_field_values_el(export_section,
 
3848
                                                 helper,
 
3849
                                                 dimension,
 
3850
                                                 interlace,
 
3851
                                                 n_parent_lists,
 
3852
                                                 parent_num_shift,
 
3853
                                                 datatype,
 
3854
                                                 field_values,
 
3855
                                                 f);
 
3856
 
 
3857
    } /* End of loop on sections */
 
3858
 
 
3859
  } /* End for per element variable */
 
3860
 
 
3861
  /* Free helper structures */
 
3862
  /*------------------------*/
 
3863
 
 
3864
  if (helper != NULL)
 
3865
    helper = fvm_writer_field_helper_destroy(helper);
 
3866
 
 
3867
  BFT_FREE(export_list);
 
3868
 
 
3869
  /* Close variable file and update case file */
 
3870
  /*------------------------------------------*/
 
3871
 
 
3872
  _free_ensight_file(&f);
 
3873
 
 
3874
  fvm_to_ensight_case_write_case(this_writer->case_info, rank);
 
3875
}
 
3876
 
 
3877
/*----------------------------------------------------------------------------*/
 
3878
 
 
3879
#ifdef __cplusplus
 
3880
}
 
3881
#endif /* __cplusplus */