/*============================================================================
 * Write a nodal representation associated with a mesh and associated
 * variables to EnSight Gold files
 *============================================================================*/

/*
  This file is part of the "Finite Volume Mesh" library, intended to provide
  finite volume mesh and associated fields I/O and manipulation services.

  Copyright (C) 2004-2006  EDF

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

/*----------------------------------------------------------------------------
 * Standard C library headers
 *----------------------------------------------------------------------------*/

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*----------------------------------------------------------------------------
 * BFT library headers
 *----------------------------------------------------------------------------*/

#include <bft_error.h>
#include <bft_mem.h>
#include <bft_file.h>

/*----------------------------------------------------------------------------
 *  Local headers
 *----------------------------------------------------------------------------*/

#include <fvm_config_defs.h>
#include <fvm_defs.h>
#include <fvm_convert_array.h>
#include <fvm_gather.h>
#include <fvm_io_num.h>
#include <fvm_nodal.h>
#include <fvm_nodal_priv.h>
#include <fvm_parall.h>
#include <fvm_to_ensight_case.h>
#include <fvm_writer_helper.h>
#include <fvm_writer_priv.h>

/*----------------------------------------------------------------------------
 *  Header for the current file
 *----------------------------------------------------------------------------*/

#include <fvm_to_ensight.h>

/*----------------------------------------------------------------------------*/

#ifdef __cplusplus
extern "C" {
#if 0
} /* Fake brace to force back Emacs auto-indentation back to column 0 */
#endif
#endif /* __cplusplus */

/*============================================================================
 * Local Type Definitions
 *============================================================================*/

/*----------------------------------------------------------------------------
 * EnSight Gold writer structure
 *----------------------------------------------------------------------------*/

typedef struct {

  char        *name;             /* Writer name */

  int          rank;             /* Rank of current process in communicator */
  int          n_ranks;          /* Number of processes in communicator */

  _Bool        text_mode;        /* true if using text output */
  _Bool        swap_endian;      /* true if binary file endianness must
                                    be changed */

  _Bool        discard_polygons;   /* Option to discard polygonal elements */
  _Bool        discard_polyhedra;  /* Option to discard polyhedral elements */

  _Bool        divide_polygons;    /* Option to tesselate polygonal elements */
  _Bool        divide_polyhedra;   /* Option to tesselate polyhedral elements */

  fvm_to_ensight_case_t  *case_info;  /* Associated case structure */

#if defined(FVM_HAVE_MPI)
  MPI_Comm     comm;             /* Associated MPI communicator */
#endif

} fvm_to_ensight_writer_t;

/*============================================================================
 * Static global variables
 *============================================================================*/

static const char  *_ensight_type_name[FVM_N_ELEMENT_TYPES] = {"bar2",
                                                               "tria3",
                                                               "quad4",
                                                               "nsided",
                                                               "tetra4",
                                                               "pyramid5",
                                                               "penta6",
                                                               "hexa8",
                                                               "nfaced"};

/*============================================================================
 * Private function definitions
 *============================================================================*/

/*----------------------------------------------------------------------------
 * Count number of extra vertices when tesselations are present
 *
 * parameters:
 *   this_writer         <-- pointer to associated writer
 *   mesh                <-- pointer to nodal mesh structure
 *   n_extra_vertices_g  --> global number of extra vertices (optional)
 *   n_extra_vertices    --> local number of extra vertices (optional)
 *----------------------------------------------------------------------------*/

static void
_count_extra_vertices(const fvm_to_ensight_writer_t  *this_writer,
                      const fvm_nodal_t              *mesh,
                      fvm_gnum_t                     *n_extra_vertices_g,
                      fvm_lnum_t                     *n_extra_vertices)
{
  int  i;

  const int  export_dim = fvm_nodal_get_max_entity_dim(mesh);

  /* Initial count and allocation */

  if (n_extra_vertices_g != NULL)
    *n_extra_vertices_g = 0;
  if (n_extra_vertices != NULL)
    *n_extra_vertices   = 0;

  for (i = 0 ; i < mesh->n_sections ; i++) {

    const fvm_nodal_section_t  *const  section = mesh->sections[i];

    /* Output if entity dimension equal to highest in mesh
       (i.e. no output of faces if cells present, or edges
       if cells or faces) */

    if (   section->entity_dim == export_dim
        && section->type == FVM_CELL_POLY
        && section->tesselation != NULL
        && this_writer->divide_polyhedra == true) {

      if (n_extra_vertices_g != NULL)
        *n_extra_vertices_g
          += fvm_tesselation_n_g_vertices_add(section->tesselation);

      if (n_extra_vertices != NULL)
        *n_extra_vertices
          += fvm_tesselation_n_vertices_add(section->tesselation);

    }

  }

}

/*----------------------------------------------------------------------------
 * Write string to a text or C binary EnSight Gold file
 *
 * parameters:
 *   f                <-- file to write to
 *   s                <-- string to write
 *----------------------------------------------------------------------------*/

static void
_write_string(bft_file_t  *f,
              const char  *s)
{
  size_t  i;
  char  buf[82];
  bft_file_type_t  type;

  /* If called by non I/O rank, return */
  if (f == NULL)
    return;

  type = bft_file_get_type(f);

  if (type == BFT_FILE_TYPE_TEXT) {
    strncpy(buf, s, 80);
    buf[80] = '\0';
    bft_file_printf(f, "%s\n", buf);
  }

  else {
    strncpy(buf, s, 80);
    buf[80] = '\0';
    for (i = strlen(buf) ; i < 80 ; i++)
      buf[i] = ' ';
    bft_file_write(buf, 1, 80, f);
  }

}

/*----------------------------------------------------------------------------
 * Write integer to a text or C binary EnSight Gold file
 *
 * parameters:
 *   f                <-- file to write to
 *   n                <-- integer value to write
 *----------------------------------------------------------------------------*/

inline static void
_write_int(bft_file_t  *f,
           const int    n)
{
  /* If called by non I/O rank, return */
  if (f == NULL)
    return;

  if (bft_file_get_type(f) == BFT_FILE_TYPE_TEXT)
    bft_file_printf(f, "%10d\n", n);

  else
    bft_file_write(&n, sizeof(int), 1, f);
}

/*----------------------------------------------------------------------------
 * Initialize FVM to EnSight Gold geometry file.
 *
 * parameters:
 *   this_writer_p <-- pointer to opaque Ensight Gold writer structure.
 *----------------------------------------------------------------------------*/

static void
_init_geom_file(fvm_to_ensight_writer_t  *this_writer)
{
  if (this_writer->rank == 0) {

    bft_file_t *f;
    bft_file_type_t file_type;
    fvm_to_ensight_case_file_info_t  file_info;

    if (this_writer->text_mode == true)
      file_type = BFT_FILE_TYPE_TEXT;
    else
      file_type = BFT_FILE_TYPE_BINARY;

    /* Write file header (future calls will be in append mode) */

    file_info = fvm_to_ensight_case_get_geom_file(this_writer->case_info);

    f = bft_file_open(file_info.name,
                      BFT_FILE_MODE_WRITE,
                      file_type);

    if (this_writer->swap_endian == true)
      bft_file_set_swap_endian(f, 1);

    if (this_writer->text_mode == false)
      _write_string(f, "C Binary");
    /* 1st description line */
    {
      char buf[81] = "";
      if (this_writer->name != NULL)
        strncpy(buf, this_writer->name, 80);
      buf[80] = '\0';
      _write_string(f, buf);
    }
    /* 2nd description line */
    _write_string(f, "Output by FVM library version "FVM_VERSION);
    _write_string(f, "node id assign");
    _write_string(f, "element id assign");

    f = bft_file_free(f);
  }

}

/*----------------------------------------------------------------------------
 * Write slice of a vector of floats to an EnSight Gold file
 *
 * parameters:
 *   num_start      <-- global number of first element for this slice
 *   num_end        <-- global number of past the last element for this slice
 *   values         <-- pointer to values slice array
 *   f              <-- file to write to
 *----------------------------------------------------------------------------*/

static void
_write_slice_values(fvm_gnum_t    num_start,
                    fvm_gnum_t    num_end,
                    const float   values[],
                    bft_file_t   *f)
{
  size_t  i;
  fvm_gnum_t  j;

  /* If called by non I/O rank or no values, return */
  if (f == NULL || (num_start > num_end))
    return;

  if (bft_file_get_type(f) == BFT_FILE_TYPE_TEXT) {
    for (i = 0, j = num_start ; j < num_end ; i++, j++)
      bft_file_printf(f, "%12.5e\n", values[i]);
  }
  else
    bft_file_write(values, sizeof(float), num_end - num_start, f);
}

/*----------------------------------------------------------------------------
 * Return extra vertex coordinates when tesselations are present
 *
 * parameters:
 *   this_writer_p <-- pointer to associated writer
 *   mesh          <-- pointer to nodal mesh structure that should be written
 *
 * returns:
 *   array containing all extra vertex coordinates
 *----------------------------------------------------------------------------*/

static fvm_coord_t *
_extra_vertex_coords(const fvm_to_ensight_writer_t  *this_writer,
                     const fvm_nodal_t              *mesh)
{
  int  i;
  fvm_lnum_t  n_extra_vertices_section;

  fvm_lnum_t  n_extra_vertices = 0;
  size_t  coord_shift = 0;
  fvm_coord_t  *coords = NULL;

  _count_extra_vertices(this_writer,
                        mesh,
                        NULL,
                        &n_extra_vertices);

  if (n_extra_vertices > 0) {

    const int  export_dim = fvm_nodal_get_max_entity_dim(mesh);

    BFT_MALLOC(coords, n_extra_vertices * 3, fvm_coord_t);

    for (i = 0 ; i < mesh->n_sections ; i++) {

      const fvm_nodal_section_t  *const  section = mesh->sections[i];

      /* Output if entity dimension equal to highest in mesh
         (i.e. no output of faces if cells present, or edges
         if cells or faces) */

      if (   section->entity_dim == export_dim
          && section->type == FVM_CELL_POLY
          && section->tesselation != NULL
          && this_writer->divide_polyhedra == true) {

        n_extra_vertices_section
          = fvm_tesselation_n_vertices_add(section->tesselation);

        if (n_extra_vertices_section > 0) {

          fvm_tesselation_vertex_coords(section->tesselation,
                                        coords + coord_shift);

          coord_shift += n_extra_vertices_section * 3;

        }

      }
    }
  }

  return coords;
}

#if defined(FVM_HAVE_MPI)

/*----------------------------------------------------------------------------
 * Write vertex coordinates to an EnSight Gold file in serial mode
 *
 * parameters:
 *   this_writer   <-- pointer to associated writer
 *   mesh          <-- pointer to nodal mesh structure
 *   comm          <-- associated MPI communicator
 *   global_s_size <-- global slice size
 *   f             <-- pointer to associated file
 *----------------------------------------------------------------------------*/

static void
_export_vertex_coords_g(const fvm_to_ensight_writer_t  *this_writer,
                        const fvm_nodal_t              *mesh,
                        MPI_Comm                        comm,
                        fvm_gnum_t                      global_s_size,
                        bft_file_t                     *f)
{
  size_t      stride;
  fvm_lnum_t  i, j;

  fvm_gnum_t   global_num_start;
  fvm_gnum_t   global_num_end;

  int          rank;
  int          section_id;

  fvm_gnum_t   n_g_extra_vertices = 0;
  fvm_lnum_t   n_extra_vertices = 0;
  fvm_coord_t  *extra_vertex_coords = NULL;
  float        *coords_tmp = NULL;
  float        *global_coords_s = NULL;

  fvm_gather_slice_t  *vertices_slice = NULL;

  const double      *vertex_coords = mesh->vertex_coords;
  const fvm_lnum_t  *parent_vertex_num = mesh->parent_vertex_num;
  const fvm_lnum_t  n_vertices
                      = fvm_io_num_get_local_count(mesh->global_vertex_num);
  const fvm_gnum_t  n_g_vertices
                      = fvm_io_num_get_global_count(mesh->global_vertex_num);

  /* Get info on the current MPI communicator */

  MPI_Comm_rank(comm, &rank);

  /* Compute extra vertex coordinates if present */

  _count_extra_vertices(this_writer,
                        mesh,
                        &n_g_extra_vertices,
                        &n_extra_vertices);

  extra_vertex_coords = _extra_vertex_coords(this_writer,
                                             mesh);

  /* Vertex coordinates */
  /*--------------------*/

  stride = (size_t)(mesh->dim);

  BFT_MALLOC(coords_tmp, FVM_MAX(n_vertices, n_extra_vertices), float);
  BFT_MALLOC(global_coords_s, global_s_size, float);

  if (rank == 0) {
    _write_string(f, "coordinates");
    _write_int(f, (int)(n_g_vertices + n_g_extra_vertices));
  }

  vertices_slice = fvm_gather_slice_create(mesh->global_vertex_num,
                                           global_s_size,
                                           comm);

  /* Loop on dimension (de-interlace coordinates, always 3D for EnSight) */

  for (j = 0 ; j < 3 ; j++) {

    if (j < mesh->dim) {
      if (parent_vertex_num != NULL) {
        for (i = 0 ; i < n_vertices ; i++)
          coords_tmp[i]
            = (float)(vertex_coords[(parent_vertex_num[i]-1)*stride + j]);
      }
      else {
        for (i = 0 ; i < n_vertices ; i++)
          coords_tmp[i] = (float)(vertex_coords[i*stride + j]);
      }
    }
    else {
      for (i = 0 ; i < n_vertices ; i++)
        coords_tmp[i] = 0.0;
    }

    /* loop on slices in parallel mode */

    if (j > 0)
      fvm_gather_slice_reinitialize(vertices_slice);

    while (fvm_gather_slice_advance(vertices_slice,
                                    &global_num_start,
                                    &global_num_end) == 0) {

      fvm_gather_array(coords_tmp,
                       global_coords_s,
                       MPI_FLOAT,
                       1,
                       mesh->global_vertex_num,
                       comm,
                       vertices_slice);

      if (rank == 0)
        _write_slice_values(global_num_start,
                            global_num_end,
                            global_coords_s,
                            f);

    }

    /* Now handle extra vertices */
    /*---------------------------*/

    if (n_g_extra_vertices > 0) {

      fvm_lnum_t extra_vertices_count = 0;

      for (section_id = 0 ; section_id < mesh->n_sections ; section_id++) {

        fvm_gather_slice_t  *extra_vertices_slice = NULL;
        const fvm_nodal_section_t  *const  section = mesh->sections[section_id];

        /* Output if entity dimension equal to highest in mesh
           (i.e. no output of faces if cells present, or edges
           if cells or faces) */

        if (   section->entity_dim == mesh->dim
            && section->type == FVM_CELL_POLY
            && section->tesselation != NULL
            && this_writer->divide_polyhedra == true) {

          const fvm_io_num_t *extra_vertex_num
            = fvm_tesselation_global_vertex_num(section->tesselation);
          const fvm_lnum_t n_extra_vertices_section
            = fvm_tesselation_n_vertices_add(section->tesselation);

          for (i = 0 ; i < n_extra_vertices ; i++)
            coords_tmp[i]
              = (float)(extra_vertex_coords[  (i+extra_vertices_count)*stride
                                            + j]);

          extra_vertices_slice = fvm_gather_slice_create(extra_vertex_num,
                                                         global_s_size,
                                                         comm);

          /* loop on slices in parallel mode */

          while (fvm_gather_slice_advance(extra_vertices_slice,
                                          &global_num_start,
                                          &global_num_end) == 0) {

            fvm_gather_array(coords_tmp,
                             global_coords_s,
                             MPI_FLOAT,
                             1,
                             extra_vertex_num,
                             comm,
                             extra_vertices_slice);

            if (rank == 0)
              _write_slice_values(global_num_start,
                                  global_num_end,
                                  global_coords_s,
                                  f);

          }

          fvm_gather_slice_destroy(extra_vertices_slice);

          extra_vertices_count += n_extra_vertices_section;

        }

      } /* end of loop on sections for extra vertices */

    } /* end handling for extra vertices */

  } /* end of loop on spatial dimension */

  fvm_gather_slice_destroy(vertices_slice);

  BFT_FREE(global_coords_s);
  BFT_FREE(coords_tmp);

  if (extra_vertex_coords != NULL)
    BFT_FREE(extra_vertex_coords);
}

#endif /* defined(FVM_HAVE_MPI) */

/*----------------------------------------------------------------------------
 * Write vertex coordinates to an EnSight Gold file in serial mode
 *
 * parameters:
 *   this_writer <-- pointer to associated writer
 *   mesh        <-- pointer to nodal mesh structure
 *   f           <-- pointer to associated file
 *----------------------------------------------------------------------------*/

static void
_export_vertex_coords_l(const fvm_to_ensight_writer_t  *this_writer,
                        const fvm_nodal_t              *mesh,
                        bft_file_t                     *f)
{
  fvm_lnum_t   i, j;
  fvm_lnum_t   n_extra_vertices = 0;
  fvm_coord_t  *extra_vertex_coords = NULL;
  float        *coords_tmp = NULL;

  const fvm_lnum_t   n_vertices = mesh->n_vertices;
  const double      *vertex_coords = mesh->vertex_coords;
  const fvm_lnum_t  *parent_vertex_num = mesh->parent_vertex_num;

  const size_t  stride = (size_t)(mesh->dim);

  /* Compute extra vertex coordinates if present */

  _count_extra_vertices(this_writer,
                        mesh,
                        NULL,
                        &n_extra_vertices);

  extra_vertex_coords = _extra_vertex_coords(this_writer,
                                             mesh);

  /* Vertex coordinates */
  /*--------------------*/

  BFT_MALLOC(coords_tmp, FVM_MAX(n_vertices, n_extra_vertices), float);

  _write_string(f, "coordinates");
  _write_int(f, n_vertices + n_extra_vertices);

  /* Loop on dimension (de-interlace coordinates, always 3D for EnSight) */

  for (j = 0 ; j < 3 ; j++) {

    /* First, handle regular vertices */

    if (j < mesh->dim) {
      if (parent_vertex_num != NULL) {
        for (i = 0 ; i < n_vertices ; i++)
          coords_tmp[i]
            = (float)(vertex_coords[(parent_vertex_num[i]-1)*stride + j]);
      }
      else {
        for (i = 0 ; i < n_vertices ; i++)
          coords_tmp[i] = (float)(vertex_coords[i*stride + j]);
      }
    }
    else {
      for (i = 0 ; i < (n_vertices) ; i++)
        coords_tmp[i] = 0.0;
    }

    _write_slice_values(1,
                        (fvm_gnum_t)(n_vertices + 1),
                        coords_tmp,
                        f);

    /* Handle extra vertices (only occur with polyhedra tesselations in 3d) */

    for (i = 0 ; i < n_extra_vertices ; i++)
      coords_tmp[i] = (float)(extra_vertex_coords[i*stride + j]);

    if (n_extra_vertices > 0)
      _write_slice_values(1,
                          (fvm_gnum_t)(n_extra_vertices + 1),
                          coords_tmp,
                          f);

  } /* end of loop on mesh dimension */

  BFT_FREE(coords_tmp);

  if (extra_vertex_coords != NULL)
    BFT_FREE(extra_vertex_coords);
}

/*----------------------------------------------------------------------------
 * Write "trivial" point elements to an EnSight Gold file
 *
 * parameters:
 *   n_g_vertices     <-- number of vertices
 *   buffer_size      <-- size of write buffer
 *   buffer           --- write buffer (for binary mode)
 *   f                <-- file to write to
 *----------------------------------------------------------------------------*/

static void
_export_point_elements_l(fvm_gnum_t   n_g_vertices,
                         size_t       buffer_size,
                         int          buffer[],
                         bft_file_t  *f)
{
  fvm_gnum_t  i;
  int  j = 1;

  _write_string(f, "point");
  _write_int(f, (int)n_g_vertices);

  if (bft_file_get_type(f) == BFT_FILE_TYPE_TEXT) { /* Text mode */

    for (i = 0 ; i < n_g_vertices ; i++)
      bft_file_printf(f, "%10d\n", j++);

  }
  else { /* Binary mode */

    size_t  k;
    int  j_end = n_g_vertices + 1;

    while (j < j_end) {
      for (k = 0 ;  j < j_end  && k < buffer_size ; k++)
        buffer[k] = j++;
      bft_file_write(buffer, sizeof(int), k, f);
    }

  }
}

#if defined(FVM_HAVE_MPI)

/*----------------------------------------------------------------------------
 * Write strided global connectivity slice to an EnSight Gold file
 *
 * parameters:
 *   stride           <-- number of vertices per element type
 *   num_start        <-- global number of first element for this slice
 *   num_end          <-- global number of past last element for this slice
 *   global_connect_s <-- global connectivity slice array
 *   buffer_size      <-- size of write buffer
 *   buffer           --- write buffer (for binary mode)
 *   f                <-- file to write to
 *----------------------------------------------------------------------------*/

static void
_write_slice_connect_g(int                stride,
                       fvm_gnum_t         num_start,
                       fvm_gnum_t         num_end,
                       const fvm_gnum_t   global_connect_s[],
                       size_t             buffer_size,
                       int                buffer[],
                       bft_file_t        *f)
{
  size_t  i;
  fvm_gnum_t  j;

  /* If called by non I/O rank, return */
  if (f == NULL)
    return;

  if (bft_file_get_type(f) == BFT_FILE_TYPE_TEXT) { /* Text mode */

    switch(stride) {

    case 2: /* edge */
      for (i = 0, j = num_start ; j < num_end ; i++, j++)
        bft_file_printf(f, "%10d%10d\n",
                        (int)global_connect_s[i*2],
                        (int)global_connect_s[i*2+1]);
      break;

    case 3: /* FVM_FACE_TRIA */
      for (i = 0, j = num_start ; j < num_end ; i++, j++)
        bft_file_printf(f, "%10d%10d%10d\n",
                        (int)global_connect_s[i*3],
                        (int)global_connect_s[i*3+1],
                        (int)global_connect_s[i*3+2]);
      break;

    case 4: /* FVM_FACE_QUAD or FVM_CELL_TETRA */
      for (i = 0, j = num_start ; j < num_end ; i++, j++)
        bft_file_printf(f, "%10d%10d%10d%10d\n",
                        (int)global_connect_s[i*4],
                        (int)global_connect_s[i*4+1],
                        (int)global_connect_s[i*4+2],
                        (int)global_connect_s[i*4+3]);
      break;

    case 5: /* FVM_CELL_PYRAM */
      for (i = 0, j = num_start ; j < num_end ; i++, j++)
        bft_file_printf(f, "%10d%10d%10d%10d%10d\n",
                        (int)global_connect_s[i*5],
                        (int)global_connect_s[i*5+1],
                        (int)global_connect_s[i*5+2],
                        (int)global_connect_s[i*5+3],
                        (int)global_connect_s[i*5+4]);
      break;

    case 6: /* FVM_CELL_PRISM */
      for (i = 0, j = num_start ; j < num_end ; i++, j++)
        bft_file_printf(f, "%10d%10d%10d%10d%10d%10d\n",
                        (int)global_connect_s[i*6],
                        (int)global_connect_s[i*6+1],
                        (int)global_connect_s[i*6+2],
                        (int)global_connect_s[i*6+3],
                        (int)global_connect_s[i*6+4],
                        (int)global_connect_s[i*6+5]);
      break;

    case 8: /* FVM_CELL_HEXA */
      for (i = 0, j = num_start ; j < num_end ; i++, j++)
        bft_file_printf(f,
                        "%10d%10d%10d%10d%10d%10d%10d%10d\n",
                        (int)global_connect_s[i*8],
                        (int)global_connect_s[i*8+1],
                        (int)global_connect_s[i*8+2],
                        (int)global_connect_s[i*8+3],
                        (int)global_connect_s[i*8+4],
                        (int)global_connect_s[i*8+5],
                        (int)global_connect_s[i*8+6],
                        (int)global_connect_s[i*8+7]);
      break;

    default:
      assert(0);
    }

  }
  else { /* Binary mode */

    size_t  k = 0;
    size_t  n_values = (num_end - num_start)*stride;

    while (k < n_values) {
      for (i = 0 ; i < buffer_size && k < n_values ; i++)
        buffer[i] = (int)(global_connect_s[k++]);
      bft_file_write(buffer, sizeof(int), i, f);
    }

  }

}

#endif /* defined(FVM_HAVE_MPI) */

/*----------------------------------------------------------------------------
 * Write strided local connectivity to an EnSight Gold file
 *
 * parameters:
 *   stride      <-- number of vertices per element type
 *   n_elems     <-- number of elements
 *   connect     <-- connectivity array
 *   buffer_size <-- size of write buffer
 *   buffer      --- write buffer (for binary mode)
 *   f           <-- file to write to
 *----------------------------------------------------------------------------*/

static void
_write_connect_l(int                stride,
                 fvm_lnum_t         n_elems,
                 const fvm_lnum_t   connect[],
                 size_t             buffer_size,
                 int                buffer[],
                 bft_file_t        *f)
{
  fvm_lnum_t  i;

  if (bft_file_get_type(f) == BFT_FILE_TYPE_TEXT) { /* Text mode */

    switch(stride) {

    case 2: /* edge */
      for (i = 0 ; i < n_elems ; i++)
        bft_file_printf(f, "%10d%10d\n",
                        (int)connect[i*2],
                        (int)connect[i*2+1]);
      break;

    case 3: /* FVM_FACE_TRIA */
      for (i = 0 ; i < n_elems ; i++)
        bft_file_printf(f, "%10d%10d%10d\n",
                        (int)connect[i*3],
                        (int)connect[i*3+1],
                        (int)connect[i*3+2]);
      break;

    case 4: /* FVM_FACE_QUAD or FVM_CELL_TETRA */
      for (i = 0 ; i < n_elems ; i++)
        bft_file_printf(f, "%10d%10d%10d%10d\n",
                        (int)connect[i*4],
                        (int)connect[i*4+1],
                        (int)connect[i*4+2],
                        (int)connect[i*4+3]);
      break;

    case 5: /* FVM_CELL_PYRAM */
      for (i = 0 ; i < n_elems ; i++)
        bft_file_printf(f, "%10d%10d%10d%10d%10d\n",
                        (int)connect[i*5],
                        (int)connect[i*5+1],
                        (int)connect[i*5+2],
                        (int)connect[i*5+3],
                        (int)connect[i*5+4]);
      break;

    case 6: /* FVM_CELL_PRISM */
      for (i = 0 ; i < n_elems ; i++)
        bft_file_printf(f, "%10d%10d%10d%10d%10d%10d\n",
                        (int)connect[i*6],
                        (int)connect[i*6+1],
                        (int)connect[i*6+2],
                        (int)connect[i*6+3],
                        (int)connect[i*6+4],
                        (int)connect[i*6+5]);
      break;

    case 8: /* FVM_CELL_HEXA */
      for (i = 0 ; i < n_elems ; i++)
        bft_file_printf(f,
                        "%10d%10d%10d%10d%10d%10d%10d%10d\n",
                        (int)connect[i*8],
                        (int)connect[i*8+1],
                        (int)connect[i*8+2],
                        (int)connect[i*8+3],
                        (int)connect[i*8+4],
                        (int)connect[i*8+5],
                        (int)connect[i*8+6],
                        (int)connect[i*8+7]);
      break;

    default:
      assert(0);
    }

  }
  else { /* Binary mode */

    size_t  j;
    size_t  k = 0;
    size_t  n_values = n_elems*stride;

    while (k < n_values) {
      for (j = 0 ; j < buffer_size && k < n_values  ; j++)
        buffer[j] = (int)(connect[k++]);
      bft_file_write(buffer, sizeof(int), j, f);
    }

  }

}

#if defined(FVM_HAVE_MPI)

/*----------------------------------------------------------------------------
 * Write indexed element lengths from a nodal mesh to an EnSight Gold
 * file in parallel mode
 *
 * parameters:
 *   global_element_num           <-- global element numbering
 *   vertex_index                 <-- pointer to element -> vertex index
 *   comm                         <-- associated MPI communicator
 *   n_ranks                      <-- number of processes in communicator
 *   global_s_size                <-- global slice size
 *   global_connect_s_size_caller <-- global connectivity slice size
 *                                    defined by caller
 *   global_connect_s_caller      --- global connectivity slice provided
 *                                    by caller
 *   text_mode                    <-- true if text output, false if binary
 *   buffer_size                  <-- size of write buffer
 *   buffer                       --- write buffer (for binary mode)
 *   f                            <-- pointer to associated file
 *----------------------------------------------------------------------------*/

static void
_write_lengths_g(const fvm_io_num_t  *global_element_num,
                 const fvm_lnum_t     vertex_index[],
                 MPI_Comm             comm,
                 fvm_gnum_t           global_s_size,
                 fvm_gnum_t           global_connect_s_size_caller,
                 fvm_gnum_t           global_connect_s_caller[],
                 _Bool                text_mode,
                 size_t               buffer_size,
                 int                  buffer[],
                 bft_file_t          *f)
{
  fvm_lnum_t  i;
  fvm_gnum_t  i_s;
  size_t      i_buf;

  int         rank;

  fvm_gnum_t  global_num_start;
  fvm_gnum_t  global_num_end;

  int        *lengths = NULL;
  int        *lengths_s = NULL;

  fvm_gnum_t   global_connect_s_size = global_connect_s_size_caller;
  fvm_gnum_t  *global_connect_s = global_connect_s_caller;

  fvm_gather_slice_t   *elements_slice = NULL;

  const fvm_lnum_t  n_elements = fvm_io_num_get_local_count(global_element_num);

  /* Get info on the current MPI communicator */

  MPI_Comm_rank(comm, &rank);

  /* Build local lengths */

  BFT_MALLOC(lengths, n_elements, fvm_lnum_t);

  for (i = 0 ; i < n_elements ; i++)
    lengths[i] = vertex_index[i+1] - vertex_index[i];

  /* Use global_connect_s memory area for lengths_s; if
     necessary, increase its size */

  if (  sizeof(fvm_lnum_t)*global_s_size
      > sizeof(fvm_gnum_t)*global_connect_s_size) {
    global_connect_s_size =   (global_s_size*sizeof(fvm_lnum_t))
                            / sizeof(fvm_gnum_t);
    if (global_connect_s == global_connect_s_caller)
      global_connect_s = NULL;
    BFT_REALLOC(global_connect_s, global_connect_s_size, fvm_gnum_t);
  }
  lengths_s = (int *)global_connect_s;

  /* Loop on slices */
  /*----------------*/

  elements_slice = fvm_gather_slice_create(global_element_num,
                                           global_s_size,
                                           comm);

  while (fvm_gather_slice_advance(elements_slice,
                                  &global_num_start,
                                  &global_num_end) == 0) {

    /* Gather number of vertices per element */

    fvm_gather_array(lengths,
                     lengths_s,
                     MPI_INT,
                     1,
                     global_element_num,
                     comm,
                     elements_slice);

    /* Do all printing for rank 0 */

    if (rank == 0) {

      /* Print number of vertices per element */

      if (text_mode == true) {
        for (i = 0, i_s = global_num_start ;
             i_s < global_num_end ;
             i++, i_s++)
          bft_file_printf(f, "%10d\n", lengths_s[i]);
      }
      else {
        for (i = 0, i_s = global_num_start, i_buf = 0 ;
             i_s < global_num_end ;
             i++, i_s++) {
          if (i_buf == buffer_size) {
            bft_file_write(buffer, sizeof(int), i_buf, f);
            i_buf = 0;
          }
          buffer[i_buf++] = (int)(lengths_s[i]);
        }
        if (i_buf > 0)
          bft_file_write(buffer, sizeof(int), i_buf, f);
      }

    }

  } /* end of loop on slices */

  fvm_gather_slice_destroy(elements_slice);

  BFT_FREE(lengths);

  if (global_connect_s != global_connect_s_caller)
    BFT_FREE(global_connect_s);

}

/*----------------------------------------------------------------------------
 * Write indexed element (polygons or polyhedra) cell -> vertex connectivity
 * to an EnSight Gold file in parallel mode.
 *
 * In text mode, zeroes may be used in place of extra vertex numbers
 * to indicate extra newlines (so as to place newline characters between
 * face -> vertex definitions for a polyhedral cell->vertex connectivity).
 *
 * parameters:
 *   global_vertex_num            <-- vertex global numbering
 *   global_element_num           <-- global element numbering
 *   vertex_index                 <-- element -> vertex index
 *   vertex_num                   <-- element -> vertex number
 *   comm                         <-- associated MPI communicator
 *   global_s_size                <-- global slice size
 *   global_connect_s_size_caller <-- global connectivity slice size
 *                                    defined by caller
 *   global_connect_s_caller      --- global connectivity slice provided
 *                                    by caller
 *   text_mode                    <-- true if text output, false if binary
 *   buffer_size                  <-- size of write buffer
 *   buffer                       --- write buffer (for binary mode)
 *   f                            <-- pointer to associated file
 *
 * returns:
 *  pointer to next EnSight section helper structure in list
 *----------------------------------------------------------------------------*/

static void
_write_indexed_connect_g(const fvm_io_num_t  *global_vertex_num,
                         const fvm_io_num_t  *global_element_num,
                         const fvm_lnum_t     vertex_index[],
                         const fvm_lnum_t     vertex_num[],
                         MPI_Comm             comm,
                         fvm_gnum_t           global_s_size,
                         fvm_gnum_t           global_connect_s_size_caller,
                         fvm_gnum_t           global_connect_s_caller[],
                         _Bool                text_mode,
                         size_t               buffer_size,
                         int                  buffer[],
                         bft_file_t          *f)
{
  fvm_lnum_t  i, j;
  fvm_gnum_t  i_s, j_s, k_s;
  size_t      i_buf;

  int         rank;

  fvm_gnum_t  global_num_start;
  fvm_gnum_t  global_num_end;

  fvm_gnum_t  *global_idx_s = NULL;

  fvm_gnum_t   global_connect_s_size = global_connect_s_size_caller;
  fvm_gnum_t   global_connect_s_size_prev = global_connect_s_size_caller;
  fvm_gnum_t  *global_connect_s = global_connect_s_caller;

  fvm_gather_slice_t   *elements_slice = NULL;

  /* Get info on the current MPI communicator */

  MPI_Comm_rank(comm, &rank);

  /* Allocate memory for additionnal indexes */

  BFT_MALLOC(global_idx_s, global_s_size + 1, fvm_gnum_t);

  /* Loop on slices */
  /*----------------*/

  elements_slice = fvm_gather_slice_create(global_element_num,
                                           global_s_size,
                                           comm);

  while (fvm_gather_slice_advance(elements_slice,
                                  &global_num_start,
                                  &global_num_end) == 0) {

    /* Gather element->vertices index */

    fvm_gather_slice_index(vertex_index,
                           global_idx_s,
                           global_element_num,
                           comm,
                           elements_slice);

    /* Recompute maximum value of global_num_end for this slice */

    fvm_gather_resize_indexed_slice(10,
                                    &global_num_end,
                                    &global_connect_s_size,
                                    comm,
                                    global_idx_s,
                                    elements_slice);

    /* If the buffer passed to this function is too small, allocate a
       larger one; in this case, we may as well keep it for all slices */

    if (global_connect_s_size_prev < global_connect_s_size) {
      if (global_connect_s == global_connect_s_caller)
        global_connect_s = NULL;
      BFT_REALLOC(global_connect_s, global_connect_s_size, fvm_gnum_t);
      global_connect_s_size_prev = global_connect_s_size;
    }

    /* Now gather element->vertices connectivity */

    fvm_gather_indexed_numbers(vertex_index,
                               vertex_num,
                               global_connect_s,
                               global_vertex_num,
                               global_element_num,
                               comm,
                               global_idx_s,
                               elements_slice);

    /* Do all printing for cells on rank 0 */

    if (rank == 0) {

      if (text_mode == true) {

        /* Print face connectivity */

        k_s = 0;

        /* Loop on elements in slice */

        for (i = 0, i_s = global_num_start ;
             i_s < global_num_end ;
             i++, i_s++) {

          /* Print element vertex numbers */

          for (j = 0, j_s = global_idx_s[i] ;
               j_s < global_idx_s[i+1] ;
               j++, j_s++) {
            if (global_connect_s[k_s] != 0)
              bft_file_printf(f, "%10d",
                              (int)global_connect_s[k_s++]);
            else {
              if (j_s < global_idx_s[i+1] - 1)
                bft_file_printf(f, "\n");
              k_s++;
            }
          }

          bft_file_printf(f, "\n");

          assert(k_s == global_idx_s[i+1]);

        } /* End of loop elements in slice */

      } /* End of text file specific treatement */

      else { /* text_mode = false */

        size_t  i_start = global_idx_s[0];
        size_t  i_end   = global_idx_s[global_num_end - global_num_start];

        for (i_s = i_start, i_buf = 0 ; i_s < i_end ; i_s++) {
          if (i_buf == buffer_size) {
            bft_file_write(buffer, sizeof(int), i_buf, f);
            i_buf = 0;
          }
          buffer[i_buf++] = (int)(global_connect_s[i_s]);
        }
        if (i_buf > 0)
          bft_file_write(buffer, sizeof(int), i_buf, f);

      } /* End of binary-file specific treatement */

    } /* End of printing for rank 0 for this slice */

  }

  /* Free memory */

  elements_slice = fvm_gather_slice_destroy(elements_slice);

  BFT_FREE(global_idx_s);

  if (global_connect_s != global_connect_s_caller)
    BFT_FREE(global_connect_s);
}

/*----------------------------------------------------------------------------
 * Write tesselated element cell -> vertex connectivity to an EnSight Gold
 * file in parallel mode.
 *
 * parameters:
 *   global_vertex_num            <-- vertex global numbering
 *   global_element_num           <-- global element numbering
 *   tesselation                  <-- element tesselation description
 *   type                         <-- tesselated sub-element type
 *   extra_vertex_base            <-- starting number for added vertices
 *   comm                         <-- associated MPI communicator
 *   global_s_size                <-- global slice size
 *   global_connect_s_size_caller <-- global connectivity slice size
 *                                    defined by caller
 *   global_connect_s_caller      --- global connectivity slice provided
 *                                    by caller
 *   buffer_size                  <-- size of write buffer
 *   buffer                       --- write buffer (for binary mode)
 *   f                            <-- pointer to associated file
 *
 * returns:
 *  pointer to next EnSight section helper structure in list
 *----------------------------------------------------------------------------*/

static void
_write_tesselated_connect_g(const fvm_io_num_t  *global_vertex_num,
                            const fvm_io_num_t  *global_element_num,
                            const fvm_tesselation_t  *tesselation,
                            fvm_element_t        type,
                            const fvm_gnum_t     extra_vertex_base,
                            MPI_Comm             comm,
                            fvm_gnum_t           global_s_size,
                            fvm_gnum_t           global_connect_s_size_caller,
                            fvm_gnum_t           global_connect_s_caller[],
                            size_t               buffer_size,
                            int                  buffer[],
                            bft_file_t          *f)
{
  int         rank;

  fvm_lnum_t  n_sub_elements_max, local_connect_size;
  fvm_gnum_t  global_num_start, global_num_end;

  fvm_lnum_t  start_id = 0;
  fvm_lnum_t  end_id = 0;

  fvm_lnum_t  *local_idx = NULL;
  fvm_gnum_t  *global_idx_s = NULL;
  fvm_gnum_t  *sub_elt_vertex_num = NULL;

  fvm_gnum_t   global_connect_s_size = global_connect_s_size_caller;
  fvm_gnum_t   global_connect_s_size_prev = global_connect_s_size_caller;
  fvm_gnum_t  *global_connect_s = global_connect_s_caller;

  fvm_gather_slice_t   *elements_slice = NULL;

  const fvm_lnum_t n_elements = fvm_tesselation_n_elements(tesselation);
  const int stride = fvm_nodal_n_vertices_element[type];

  /* Get info on the current MPI communicator */

  MPI_Comm_rank(comm, &rank);

  fvm_tesselation_get_global_size(tesselation,
                                  type,
                                  NULL,
                                  &n_sub_elements_max);

  /* Allocate memory for additionnal indexes and decoded connectivity */

  BFT_MALLOC(local_idx, n_elements + 1, fvm_lnum_t);
  BFT_MALLOC(global_idx_s, global_s_size + 1, fvm_gnum_t);

  local_connect_size = FVM_MAX(global_s_size,
                               (fvm_gnum_t)n_sub_elements_max*10);
  BFT_MALLOC(sub_elt_vertex_num, local_connect_size * stride, fvm_gnum_t);

  /* Loop on slices */
  /*----------------*/

  elements_slice = fvm_gather_slice_create(global_element_num,
                                           global_s_size,
                                           comm);

  while (fvm_gather_slice_advance(elements_slice,
                                  &global_num_start,
                                  &global_num_end) == 0) {

    /* Build element->vertices index */

    end_id
      = fvm_tesselation_range_index_g(tesselation,
                                      type,
                                      fvm_nodal_n_vertices_element[type],
                                      start_id,
                                      local_connect_size,
                                      &global_num_end,
                                      local_idx,
                                      comm);

    /* Check if the maximum id returned on some ranks leads to a
       lower global_num_end than initially required (due to the
       local buffer being too small) and adjust slice if necessary */

    fvm_gather_slice_limit(elements_slice, &global_num_end);

    /* Gather element->vertices index */

    fvm_gather_slice_index(local_idx,
                           global_idx_s,
                           global_element_num,
                           comm,
                           elements_slice);

    /* Recompute maximum value of global_num_end for this slice */

    fvm_gather_resize_indexed_slice(10,
                                    &global_num_end,
                                    &global_connect_s_size,
                                    comm,
                                    global_idx_s,
                                    elements_slice);

    /* If the buffer passed to this function is too small, allocate a
       larger one; in this case, we may as well keep it for all slices */

    if (global_connect_s_size_prev < global_connect_s_size) {
      if (global_connect_s == global_connect_s_caller)
        global_connect_s = NULL;
      BFT_REALLOC(global_connect_s, global_connect_s_size, fvm_gnum_t);
      global_connect_s_size_prev = global_connect_s_size;
    }

    /* Now decode tesselation */

    end_id = fvm_tesselation_decode_g(tesselation,
                                      type,
                                      start_id,
                                      local_connect_size,
                                      &global_num_end,
                                      global_vertex_num,
                                      extra_vertex_base,
                                      sub_elt_vertex_num,
                                      comm);

    /* No need to check if the maximum id returned on some ranks
       leads to a lower global_num_end than initially required
       (due to local buffer being full), as this was already done
       above for the local index */

    /* Now gather decoded element->vertices connectivity */

    fvm_gather_indexed(sub_elt_vertex_num,
                       global_connect_s,
                       FVM_MPI_GNUM,
                       local_idx,
                       global_element_num,
                       comm,
                       global_idx_s,
                       elements_slice);

    /* Do all printing for cells on rank 0 */

    if (rank == 0) {
      fvm_gnum_t num_start = global_idx_s[0] / stride;
      fvm_gnum_t num_end = global_idx_s[(  global_num_end
                                         - global_num_start)] / stride;
      _write_slice_connect_g(stride,
                             num_start,
                             num_end,
                             global_connect_s,
                             buffer_size,
                             buffer,
                             f);
    }

    start_id = end_id;
  }

  /* Free memory */

  elements_slice = fvm_gather_slice_destroy(elements_slice);

  BFT_FREE(sub_elt_vertex_num);
  BFT_FREE(global_idx_s);
  BFT_FREE(local_idx);

  if (global_connect_s != global_connect_s_caller)
    BFT_FREE(global_connect_s);
}

#endif /* defined(FVM_HAVE_MPI) */

#if defined(FVM_HAVE_MPI)

/*----------------------------------------------------------------------------
 * Write polyhedra from a nodal mesh to an EnSight Gold file in parallel mode
 *
 * parameters:
 *   export_section               <-- pointer to EnSight section helper structure
 *   global_vertex_num            <-- pointer to vertex global numbering
 *   comm                         <-- associated MPI communicator
 *   global_s_size                <-- global slice size
 *   global_connect_s_size_caller <-- global connectivity slice size
 *                                    defined by caller
 *   global_connect_s_caller      --- global connectivity slice provided
 *                                    by caller
 *   text_mode                    <-- true if text output, false if binary
 *   buffer_size                  <-- size of write buffer
 *   buffer                       --- write buffer (for binary mode)
 *   f                            <-- pointer to associated file
 *
 * returns:
 *  pointer to next EnSight section helper structure in list
 *----------------------------------------------------------------------------*/

static const fvm_writer_section_t *
_export_nodal_polyhedra_g(const fvm_writer_section_t  *export_section,
                          const fvm_io_num_t          *global_vertex_num,
                          MPI_Comm            comm,
                          fvm_gnum_t          global_s_size,
                          fvm_gnum_t          global_connect_s_size_caller,
                          fvm_gnum_t          global_connect_s_caller[],
                          _Bool               text_mode,
                          size_t              buffer_size,
                          int                 buffer[],
                          bft_file_t         *f)
{
  fvm_lnum_t  i, j, k, l;
  fvm_gnum_t  i_s;
  size_t      i_buf;

  fvm_lnum_t  cell_length, face_length;
  fvm_lnum_t  face_id;
  fvm_gnum_t  global_num_start;
  fvm_gnum_t  global_num_end;

  int         rank;

  fvm_lnum_t  n_face_lengths_max = 0;

  fvm_lnum_t  *face_lengths = NULL;
  fvm_lnum_t  *cell_vtx_idx = NULL;
  fvm_lnum_t  *cell_vtx_num = NULL;
  fvm_gnum_t  *global_idx_s = NULL;

  fvm_gnum_t   global_connect_s_size = global_connect_s_size_caller;
  fvm_gnum_t   global_connect_s_size_prev = global_connect_s_size_caller;
  fvm_gnum_t  *global_connect_s = global_connect_s_caller;

  fvm_gather_slice_t   *polyhedra_slice = NULL;

  const fvm_writer_section_t  *current_section;

  /* Get info on the current MPI communicator */

  MPI_Comm_rank(comm, &rank);

  /* Allocate memory for additionnal indexes */

  BFT_MALLOC(global_idx_s, global_s_size + 1, fvm_gnum_t);

  /* Export number of faces per polyhedron */
  /*---------------------------------------*/

  current_section = export_section;

  do { /* loop on sections which should be appended */

    const fvm_nodal_section_t  *section = current_section->section;

    _write_lengths_g(section->global_element_num,
                     section->face_index,
                     comm,
                     global_s_size,
                     global_connect_s_size,
                     global_connect_s,
                     text_mode,
                     buffer_size,
                     buffer,
                     f);

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  /* Export number of vertices per face per polyhedron */
  /*---------------------------------------------------*/

  current_section = export_section;

  do { /* loop on sections which should be appended */

    const fvm_nodal_section_t  *section = current_section->section;

    /* Build local polyhedron face lengths information */

    if (section->face_index[section->n_elements] > n_face_lengths_max) {
      BFT_REALLOC(face_lengths,
                  section->face_index[section->n_elements],
                  fvm_lnum_t);
      n_face_lengths_max = section->face_index[section->n_elements];
    }

    l = 0;
    for (i = 0 ; i < section->n_elements ; i++) {
      for (j = section->face_index[i] ; j < section->face_index[i+1] ; j++) {
        face_id = FVM_ABS(section->face_num[j]) - 1;
        face_length = (  section->vertex_index[face_id+1]
                       - section->vertex_index[face_id]);
        face_lengths[l++] = face_length;
      }
    }
    assert(l == section->face_index[section->n_elements]);

    /* Loop on slices */

    polyhedra_slice = fvm_gather_slice_create(section->global_element_num,
                                              global_s_size,
                                              comm);

    while (fvm_gather_slice_advance(polyhedra_slice,
                                    &global_num_start,
                                    &global_num_end) == 0) {

      /* Now build the slice index for number of vertices per face */

      fvm_gather_slice_index(section->face_index,
                             global_idx_s,
                             section->global_element_num,
                             comm,
                             polyhedra_slice);

      /* Recompute slice size */

      fvm_gather_resize_indexed_slice(10,
                                      &global_num_end,
                                      &global_connect_s_size,
                                      comm,
                                      global_idx_s,
                                      polyhedra_slice);

      /* If the buffer passed to this function is too small, allocate a
         larger one; in this case, we may as well keep it for all slices */

      if (global_connect_s_size_prev < global_connect_s_size) {
        if (global_connect_s == global_connect_s_caller)
          global_connect_s = NULL;
        BFT_REALLOC(global_connect_s, global_connect_s_size, fvm_gnum_t);
        global_connect_s_size_prev = global_connect_s_size;
      }

      /* Now gather the number of vertices per face */

      fvm_gather_indexed_numbers(section->face_index,
                                 face_lengths,
                                 global_connect_s,
                                 NULL,
                                 section->global_element_num,
                                 comm,
                                 global_idx_s,
                                 polyhedra_slice);

      /* Print number of vertices per face on rank 0 */

      if (rank == 0) {

        size_t  i_start = global_idx_s[0];
        size_t  i_end   = global_idx_s[global_num_end - global_num_start];

        if (text_mode == true) {

          for (i_s = i_start ; i_s < i_end ; i_s++)
            bft_file_printf(f, "%10d\n", global_connect_s[i_s]);

        }
        else { /* text_mode = false */

          for (i_s = i_start, i_buf = 0 ; i_s < i_end ; i_s++) {
            if (i_buf == buffer_size) {
              bft_file_write(buffer, sizeof(int), i_buf, f);
              i_buf = 0;
            }
            buffer[i_buf++] = (int)(global_connect_s[i_s]);
          }
          if (i_buf > 0)
            bft_file_write(buffer, sizeof(int), i_buf, f);

        }

      }

    } /* end of loop on slices */

    fvm_gather_slice_destroy(polyhedra_slice);

    BFT_FREE(face_lengths);

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  if (global_connect_s != global_connect_s_caller)
    BFT_FREE(global_connect_s);

  global_connect_s_size = global_connect_s_size_caller;
  global_connect_s = global_connect_s_caller;

  /* Export cell->vertex connectivity by slices */
  /*--------------------------------------------*/

  current_section = export_section;

  do { /* loop on sections which should be appended */

    const fvm_nodal_section_t  *section = current_section->section;
    const fvm_io_num_t  *_global_vertex_num = global_vertex_num;

    BFT_MALLOC(cell_vtx_idx, section->n_elements + 1, fvm_lnum_t);

    l = 0;

    /* In text mode, add zeroes to cell vertex connectivity to mark face
       limits (so as to add newlines) */

    if (text_mode == true) {

      cell_vtx_idx[0] = 0;
      for (i = 0 ; i < section->n_elements ; i++) {
        cell_length = 0;
        for (j = section->face_index[i] ; j < section->face_index[i+1] ; j++) {
          face_id = FVM_ABS(section->face_num[j]) - 1;
          face_length = (  section->vertex_index[face_id+1]
                         - section->vertex_index[face_id]);
          cell_length += face_length + 1;
        }
        cell_vtx_idx[i+1] = cell_vtx_idx[i] + cell_length;
      }

    }
    else { /* In binary mode, simply build true cell -> vertex connectivity */

      cell_vtx_idx[0] = 0;
      for (i = 0 ; i < section->n_elements ; i++) {
        cell_length = 0;
        for (j = section->face_index[i] ; j < section->face_index[i+1] ; j++) {
          face_id = FVM_ABS(section->face_num[j]) - 1;
          face_length = (  section->vertex_index[face_id+1]
                         - section->vertex_index[face_id]);
          cell_length += face_length;
        }
        cell_vtx_idx[i+1] = cell_vtx_idx[i] + cell_length;
      }

    }

    BFT_MALLOC(cell_vtx_num, cell_vtx_idx[section->n_elements], fvm_lnum_t);

    l = 0;

    for (i = 0 ; i < section->n_elements ; i++) {
      for (j = section->face_index[i] ; j < section->face_index[i+1] ; j++) {
        if (section->face_num[j] > 0) {
          face_id = section->face_num[j] - 1;
          for (k = section->vertex_index[face_id] ;
               k < section->vertex_index[face_id+1] ;
               k++)
            cell_vtx_num[l++] = section->vertex_num[k];
        }
        else {
          face_id = -section->face_num[j] - 1;
          k = section->vertex_index[face_id] ;
          cell_vtx_num[l++] = section->vertex_num[k];
          for (k = section->vertex_index[face_id+1] - 1 ;
               k > section->vertex_index[face_id] ;
               k--)
            cell_vtx_num[l++] = section->vertex_num[k];
        }
        if (text_mode == true)
          cell_vtx_num[l++] = 0; /* mark face limits in text mode */
      }

    }

    /* In text mode, we must apply global vertex numberings here so as to add
       zeroes to cell vertex connectivity to mark face limits; in binary mode,
       we have a regular indexed connectivity, so local vertex numbers may be
       converted to global numbers by fvm_gather_...() functions */

    if (text_mode == true) {
      if (global_vertex_num != NULL) {
        const fvm_gnum_t * g_v_num
          = fvm_io_num_get_global_num(global_vertex_num);
        for (l = 0; l < cell_vtx_idx[section->n_elements]; l++) {
          if (cell_vtx_num[l] != 0)
            cell_vtx_num[l] = g_v_num[cell_vtx_num[l] - 1];
        }
      }
      _global_vertex_num = NULL;
    }

    _write_indexed_connect_g(_global_vertex_num,
                             section->global_element_num,
                             cell_vtx_idx,
                             cell_vtx_num,
                             comm,
                             global_s_size,
                             global_connect_s_size,
                             global_connect_s,
                             text_mode,
                             buffer_size,
                             buffer,
                             f);

    BFT_FREE(cell_vtx_idx);
    BFT_FREE(cell_vtx_num);

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  /* Free memory */

  BFT_FREE(global_idx_s);

  return current_section;
}

#endif /* defined(FVM_HAVE_MPI) */

/*----------------------------------------------------------------------------
 * Write polyhedra from a nodal mesh to an EnSight Gold file in serial mode
 *
 * parameters:
 *   export_section <-- pointer to EnSight section helper structure
 *   text_mode      <-- true if text output, false if binary
 *   buffer_size    <-- size of write buffer
 *   buffer         --- write buffer (for binary mode)
 *   f              <-- pointer to associated file
 *
 * returns:
 *  pointer to next EnSight section helper structure in list
 *----------------------------------------------------------------------------*/

static const fvm_writer_section_t *
_export_nodal_polyhedra_l(const fvm_writer_section_t  *export_section,
                          _Bool                        text_mode,
                          size_t                       buffer_size,
                          int                          buffer[],
                          bft_file_t                  *f)


{
  fvm_lnum_t  i, j, k, l;
  size_t  i_buf;

  fvm_lnum_t  face_length;
  fvm_lnum_t  face_id;

  int  face_sgn;

  const fvm_writer_section_t  *current_section;

  /* Print cell connectivity directly, without using extra buffers */

  /* Write number of faces per cell */
  /*--------------------------------*/

  current_section = export_section;

  do { /* loop on sections which should be appended */

    const fvm_nodal_section_t  *section = current_section->section;

    if (text_mode == true) {
      for (i = 0 ; i < section->n_elements ; i++)
        bft_file_printf(f, "%10d\n",
                        (int)(  section->face_index[i+1]
                              - section->face_index[i]));
    }
    else {
      for (i = 0, i_buf = 0 ; i < section->n_elements ; i++) {
        if (i_buf == buffer_size) {
          bft_file_write(buffer, sizeof(int), i_buf, f);
          i_buf = 0;
        }
        buffer[i_buf++] = (int)(  section->face_index[i+1]
                                - section->face_index[i]);
      }
      if (i_buf > 0)
        bft_file_write(buffer, sizeof(int), i_buf, f);
    }

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  /* Write number of vertices/face */
  /*-------------------------------*/

  current_section = export_section;

  do { /* loop on sections which should be appended */

    const fvm_nodal_section_t  *section = current_section->section;

    for (i = 0, i_buf = 0 ; i < section->n_elements ; i++) {

      /* Loop on cell faces */

      for (j = section->face_index[i] ;
           j < section->face_index[i+1] ;
           j++) {

        if (section->face_num[j] > 0)
          face_id = section->face_num[j] - 1;
        else
          face_id = -section->face_num[j] - 1;

        face_length = (  section->vertex_index[face_id+1]
                       - section->vertex_index[face_id]);

        if (text_mode == true)
          bft_file_printf(f, "%10d\n",
                          (int)face_length);
        else {
          if (i_buf == buffer_size) {
            bft_file_write(buffer, sizeof(int), i_buf, f);
            i_buf = 0;
          }
          buffer[i_buf++] = (int)face_length;
        }

      }

    }

    if (text_mode == false && i_buf > 0)
      bft_file_write(buffer, sizeof(int), i_buf, f);

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  /* Write cell/vertex connectivity */
  /*--------------------------------*/

  current_section = export_section;

  do { /* loop on sections which should be appended */

    const fvm_nodal_section_t  *section = current_section->section;

    for (i = 0, i_buf = 0 ; i < section->n_elements ; i++) {

      /* Loop on cell faces */

      for (j = section->face_index[i] ;
           j < section->face_index[i+1] ;
           j++) {

        /* Print face vertex numbers */

        if (section->face_num[j] > 0) {
          face_id = section->face_num[j] - 1;
          face_sgn = 1;
        }
        else {
          face_id = -section->face_num[j] - 1;
          face_sgn = -1;
        }

        face_length = (  section->vertex_index[face_id+1]
                       - section->vertex_index[face_id]);

        if (text_mode == true) {
          for (k = 0 ; k < face_length ; k++) {
            l =   section->vertex_index[face_id]
                + (face_length + (k*face_sgn))%face_length;
            bft_file_printf(f, "%10d", (int)section->vertex_num[l]);
          }
          bft_file_printf(f, "\n");
        }
        else { /* text_mode == false */
          for (k = 0 ; k < face_length ; k++) {
            l =   section->vertex_index[face_id]
                + (face_length + (k*face_sgn))%face_length;
            if (i_buf == buffer_size) {
              bft_file_write(buffer, sizeof(int), i_buf, f);
              i_buf = 0;
            }
            buffer[i_buf++] = (int)section->vertex_num[l];
          }
        }

      } /* End of loop on cell faces */

    } /* End of loop on polyhedral cells */

    if (text_mode == false && i_buf > 0)
      bft_file_write(buffer, sizeof(int), i_buf, f);

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  return current_section;
}

#if defined(FVM_HAVE_MPI)

/*----------------------------------------------------------------------------
 * Write polygons from a nodal mesh to an EnSight Gold file in parallel mode
 *
 * parameters:
 *   export_section               <-- pointer to EnSight section
 *                                    helper structure
 *   global_vertex_num            <-- pointer to vertex global numbering
 *   comm                         <-- associated MPI communicator
 *   n_ranks                      <-- number of processes in communicator
 *   global_s_size                <-- global slice size
 *   global_connect_s_size        <-- global connectivity slice size
 *   global_connect_s             --- global connectivity slice
 *   text_mode                    <-- true if text output, false if binary
 *   buffer_size                  <-- size of write buffer
 *   buffer                       --- write buffer (for binary mode)
 *   f                            <-- pointer to associated file
 *
 * returns:
 *  pointer to next EnSight section helper structure in list
 *----------------------------------------------------------------------------*/

static const fvm_writer_section_t *
_export_nodal_polygons_g(const fvm_writer_section_t  *export_section,
                         const fvm_io_num_t          *global_vertex_num,
                         MPI_Comm                  comm,
                         fvm_gnum_t                global_s_size,
                         fvm_gnum_t                global_connect_s_size,
                         fvm_gnum_t                global_connect_s[],
                         _Bool                     text_mode,
                         size_t                    buffer_size,
                         int                       buffer[],
                         bft_file_t               *f)
{
  const fvm_writer_section_t  *current_section;

  /* Export number of vertices per polygon by slices */
  /*-------------------------------------------------*/

  current_section = export_section;

  do { /* loop on sections which should be appended */

    const fvm_nodal_section_t  *section = current_section->section;

    _write_lengths_g(section->global_element_num,
                     section->vertex_index,
                     comm,
                     global_s_size,
                     global_connect_s_size,
                     global_connect_s,
                     text_mode,
                     buffer_size,
                     buffer,
                     f);

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  /* Export face->vertex connectivity by slices */
  /*--------------------------------------------*/

  current_section = export_section;

  do { /* loop on sections which should be appended */

    const fvm_nodal_section_t  *section = current_section->section;

    _write_indexed_connect_g(global_vertex_num,
                             section->global_element_num,
                             section->vertex_index,
                             section->vertex_num,
                             comm,
                             global_s_size,
                             global_connect_s_size,
                             global_connect_s,
                             text_mode,
                             buffer_size,
                             buffer,
                             f);

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  return current_section;
}

#endif /* defined(FVM_HAVE_MPI) */

/*----------------------------------------------------------------------------
 * Write polygons from a nodal mesh to a text file in serial mode
 *
 * parameters:
 *   export_section <-- pointer to EnSight section helper structure
 *   text_mode      <-- true if text output, false if binary
 *   buffer_size    <-- size of write buffer
 *   buffer         --- write buffer (for binary mode)
 *   f              <-- pointer to associated file
 *
 * returns:
 *  pointer to next EnSight section helper structure in list
*----------------------------------------------------------------------------*/

static const fvm_writer_section_t *
_export_nodal_polygons_l(const fvm_writer_section_t  *export_section,
                         _Bool                        text_mode,
                         size_t                       buffer_size,
                         int                          buffer[],
                         bft_file_t                  *f)


{
  fvm_lnum_t  i, j;
  size_t  i_buf;

  const fvm_writer_section_t  *current_section = NULL;

  /* Print face connectivity directly, without using extra buffers */

  /* First loop on all polygonal faces, to write number of vertices */
  /*----------------------------------------------------------------*/

  current_section = export_section;

  do { /* Loop on sections that should be grouped */

    const fvm_nodal_section_t  *section = current_section->section;

    if (text_mode == true) {
      for (i = 0 ; i < section->n_elements ; i++)
        bft_file_printf(f, "%10d\n", (int)(  section->vertex_index[i+1]
                                           - section->vertex_index[i]));
    }
    else {
      for (i = 0, i_buf = 0 ; i < section->n_elements ; i++) {
        if (i_buf == buffer_size) {
          bft_file_write(buffer, sizeof(int), i_buf, f);
          i_buf = 0;
        }
        buffer[i_buf++] = (int)(  section->vertex_index[i+1]
                                - section->vertex_index[i]);
      }
      if (i_buf > 0)
        bft_file_write(buffer, sizeof(int), i_buf, f);
    }

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  /* Loop on all polygonal faces */
  /*-----------------------------*/

  current_section = export_section;

  do { /* Loop on sections that should be grouped */

    const fvm_nodal_section_t  *section = current_section->section;

    for (i = 0, i_buf = 0 ; i < section->n_elements ; i++) {

      /* Print face vertex numbers */

      if (text_mode == true) {
        for (j = section->vertex_index[i] ;
             j < section->vertex_index[i+1] ;
             j++)
          bft_file_printf(f, "%10d", (int)section->vertex_num[j]);
        bft_file_printf(f, "\n");
      }
      else { /* text_mode = false */
        for (j = section->vertex_index[i] ;
             j < section->vertex_index[i+1] ;
             j++) {
          if (i_buf == buffer_size) {
            bft_file_write(buffer, sizeof(int), i_buf, f);
            i_buf = 0;
          }
          buffer[i_buf++] = (int)section->vertex_num[j];
        }
      }

    } /* End of loop on polygonal faces */

    if (text_mode == false && i_buf > 0)
      bft_file_write(buffer, sizeof(int), i_buf, f);

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  return current_section;
}

#if defined(FVM_HAVE_MPI)

/*----------------------------------------------------------------------------
 * Write tesselated element connectivity from a nodal mesh to an EnSight Gold
 * file in parallel mode
 *
 * parameters:
 *   export_section               <-- pointer to EnSight section
 *                                    helper structure
 *   global_vertex_num            <-- pointer to vertex global numbering
 *   comm                         <-- associated MPI communicator
 *   global_s_size                <-- global slice size
 *   global_connect_s_size_caller <-- global connectivity slice size
 *                                    defined by caller
 *   global_connect_s_caller      --- global connectivity slice provided
 *                                    by caller
 *   buffer_size                  <-- size of write buffer
 *   buffer                       --- write buffer (for binary mode)
 *   f                            <-- pointer to associated file
 *
 * returns:
 *  pointer to next EnSight section helper structure in list
 *----------------------------------------------------------------------------*/

static const fvm_writer_section_t *
_export_nodal_tesselated_g(const fvm_writer_section_t  *export_section,
                           const fvm_io_num_t          *global_vertex_num,
                           MPI_Comm                  comm,
                           fvm_gnum_t                global_s_size,
                           fvm_gnum_t                global_connect_s_size,
                           fvm_gnum_t                global_connect_s[],
                           size_t                    buffer_size,
                           int                       buffer[],
                           bft_file_t               *f)
{
  const fvm_writer_section_t  *current_section;

  /* Export face->vertex connectivity by slices */
  /*--------------------------------------------*/

  current_section = export_section;

  do { /* loop on sections which should be appended */

    const fvm_nodal_section_t  *section = current_section->section;

    _write_tesselated_connect_g(global_vertex_num,
                                section->global_element_num,
                                section->tesselation,
                                current_section->type,
                                current_section->extra_vertex_base,
                                comm,
                                global_s_size,
                                global_connect_s_size,
                                global_connect_s,
                                buffer_size,
                                buffer,
                                f);

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  return current_section;
}

#endif /* defined(FVM_HAVE_MPI) */

/*----------------------------------------------------------------------------
 * Write tesselated element connectivity from a nodal mesh to an EnSight Gold
 * file in parallel mode
 *
 * parameters:
 *   export_section               <-- pointer to EnSight section
 *                                    helper structure
 *   tesselation                  <-- element tesselation description
 *   buffer_size                  <-- size of write buffer
 *   buffer                       --- write buffer (for binary mode)
 *   f                            <-- pointer to associated file
 *
 * returns:
 *  pointer to next EnSight section helper structure in list
 *----------------------------------------------------------------------------*/

static const fvm_writer_section_t *
_export_nodal_tesselated_l(const fvm_writer_section_t  *export_section,
                           size_t                       buffer_size,
                           int                          buffer[],
                           bft_file_t                  *f)
{
  const fvm_writer_section_t  *current_section;

  current_section = export_section;

  do { /* loop on sections which should be appended */

    const fvm_nodal_section_t  *section = current_section->section;

    fvm_lnum_t  start_id, end_id;
    fvm_lnum_t  n_sub_elements_max;
    fvm_lnum_t  n_buffer_elements_max = section->n_elements;
    fvm_lnum_t *vertex_num = NULL;

    const fvm_lnum_t *sub_element_idx
      = fvm_tesselation_sub_elt_index(section->tesselation,
                                      export_section->type);

    fvm_tesselation_get_global_size(section->tesselation,
                                    export_section->type,
                                    NULL,
                                    &n_sub_elements_max);
    if (n_sub_elements_max > n_buffer_elements_max)
      n_buffer_elements_max = n_sub_elements_max;

    BFT_MALLOC(vertex_num,
               (  n_buffer_elements_max
                * fvm_nodal_n_vertices_element[export_section->type]),
               fvm_lnum_t);

    for (start_id = 0;
         start_id < section->n_elements;
         start_id = end_id) {

      end_id
        = fvm_tesselation_decode(section->tesselation,
                                 current_section->type,
                                 start_id,
                                 n_buffer_elements_max,
                                 export_section->extra_vertex_base,
                                 vertex_num);

      _write_connect_l(fvm_nodal_n_vertices_element[export_section->type],
                       (  sub_element_idx[end_id]
                        - sub_element_idx[start_id]),
                       vertex_num,
                       buffer_size,
                       buffer,
                       f);

    }

    BFT_FREE(vertex_num);

    current_section = current_section->next;

  } while (   current_section != NULL
           && current_section->continues_previous == true);

  return current_section;
}

/*----------------------------------------------------------------------------
 * Write field values associated with nodal values of a nodal mesh to
 * an EnSight Gold file in serial mode.
 *
 * Output fields ar either scalar or 3d vectors or scalars, and are
 * non interlaced. Input arrays may be less than 2d, in which case the z
 * values are set to 0, and may be interlaced or not.
 *
 * parameters:
 *   n_entities         <-- number of entities
 *   input_dim          <-- input field dimension
 *   output_dim         <-- output field dimension
 *   interlace          <-- indicates if field in memory is interlaced
 *   n_parent_lists     <-- indicates if field values are to be obtained
 *                          directly through the local entity index (when 0) or
 *                          through the parent entity numbers (when 1 or more)
 *   parent_num_shift   <-- parent list to common number index shifts;
 *                          size: n_parent_lists
 *   datatype           <-- input data type (output is real)
 *   field_values       <-- pointer to arre (output is real)
 *   rank               <-- rank of current process in communicator
 *   output_buffer_size <-- output buffer size
 *   output_buffer      --- output buffer (size output_buffer_size)
 *   f                  <-- pointer to associated file
 *----------------------------------------------------------------------------*/

static void
_export_field_values_n(const fvm_nodal_t           *mesh,
                       fvm_writer_field_helper_t   *helper,
                       int                          input_dim,
                       fvm_interlace_t              interlace,
                       int                          n_parent_lists,
                       const fvm_lnum_t             parent_num_shift[],
                       fvm_datatype_t               datatype,
                       const void            *const field_values[],
                       int                          rank,
                       size_t                       output_buffer_size,
                       float                        output_buffer[],
                       bft_file_t                  *f)
{
  int  i;
  size_t  output_size;

  int output_dim = fvm_writer_field_helper_field_dim(helper);

  for (i = 0 ; i < output_dim ; i++) {

    while (fvm_writer_field_helper_step_n(helper,
                                          mesh,
                                          input_dim,
                                          i,
                                          interlace,
                                          n_parent_lists,
                                          parent_num_shift,
                                          datatype,
                                          field_values,
                                          output_buffer,
                                          output_buffer_size,
                                          &output_size) == 0) {

      if (rank == 0)
        _write_slice_values(0,
                            output_size,
                            output_buffer,
                            f);

    }

  }

}

/*----------------------------------------------------------------------------
 * Write field values associated with element values of a nodal mesh to
 * an EnSight Gold file.
 *
 * Output fields ar either scalar or 3d vectors or scalars, and are
 * non interlaced. Input arrays may be less than 2d, in which case the z
 * values are set to 0, and may be interlaced or not.
 *
 * parameters:
 *   export_section     <-- pointer to EnSight section helper structure
 *   helper             <-- pointer to general writer helper structure
 *   input_dim          <-- input field dimension
 *   interlace          <-- indicates if field in memory is interlaced
 *   n_parent_lists     <-- indicates if field values are to be obtained
 *                          directly through the local entity index (when 0) or
 *                          through the parent entity numbers (when 1 or more)
 *   parent_num_shift   <-- parent list to common number index shifts;
 *                          size: n_parent_lists
 *   datatype           <-- indicates the data type of (source) field values
 *   field_values       <-- array of associated field value arrays
 *   rank               <-- rank of current process in communicator
 *   output_buffer_size <-- output buffer size
 *   output_buffer      --- output buffer (size output_buffer_size)
 *   f                  <-- pointer to associated file
 *
 * returns:
 *  pointer to next EnSight section helper structure in list
 *----------------------------------------------------------------------------*/

static const fvm_writer_section_t *
_export_field_values_e(const fvm_writer_section_t      *export_section,
                       fvm_writer_field_helper_t       *helper,
                       int                              input_dim,
                       fvm_interlace_t                  interlace,
                       int                              n_parent_lists,
                       const fvm_lnum_t                 parent_num_shift[],
                       fvm_datatype_t                   datatype,
                       const void                *const field_values[],
                       int                              rank,
                       size_t                           output_buffer_size,
                       float                            output_buffer[],
                       bft_file_t                      *f)
{
  int  i;
  size_t  output_size;

  const fvm_writer_section_t  *current_section = NULL;

  int output_dim = fvm_writer_field_helper_field_dim(helper);

  /* Loop on dimension (de-interlace vectors, always 3D for EnSight) */

  for (i = 0 ; i < output_dim ; i++) {

    _Bool loop_on_sections = true;

    current_section = export_section;

    while (loop_on_sections == true) {

      while (fvm_writer_field_helper_step_e(helper,
                                            current_section,
                                            input_dim,
                                            i,
                                            interlace,
                                            n_parent_lists,
                                            parent_num_shift,
                                            datatype,
                                            field_values,
                                            output_buffer,
                                            output_buffer_size,
                                            &output_size) == 0) {

        if (rank == 0)
          _write_slice_values(0,
                              output_size,
                              output_buffer,
                              f);

      }

      current_section = current_section->next;

      if (   current_section == NULL
          || current_section->continues_previous == false)
        loop_on_sections = false;

    } /* while (loop on sections) */

  } /* end of loop on spatial dimension */

  return current_section;
}

/*============================================================================
 * Public function definitions
 *============================================================================*/

/*----------------------------------------------------------------------------
 * Initialize FVM to EnSight Gold file writer.
 *
 * Options are:
 *   text                output text files
 *   binary              output binary files (default)
 *   big_endian          force binary files to big-endian
 *   discard_polygons    do not output polygons or related values
 *   discard_polyhedra   do not output polyhedra or related values
 *   divide_polygons     tesselate polygons with triangles
 *   divide_polyhedra    tesselate polyhedra with tetrahedra and pyramids
 *                       (adding a vertex near each polyhedron's center)
 *
 * parameters:
 *   name           <-- base output case name.
 *   options        <-- whitespace separated, lowercase options list
 *   time_dependecy <-- indicates if and how meshes will change with time
 *   comm           <-- associated MPI communicator.
 *
 * returns:
 *   pointer to opaque EnSight Gold writer structure.
 *----------------------------------------------------------------------------*/

#if defined(FVM_HAVE_MPI)
void *
fvm_to_ensight_init_writer(const char             *name,
                           const char             *path,
                           const char             *options,
                           fvm_writer_time_dep_t   time_dependency,
                           MPI_Comm                comm)
#else
void *
fvm_to_ensight_init_writer(const char             *name,
                           const char             *path,
                           const char             *options,
                           fvm_writer_time_dep_t   time_dependency)
#endif
{
  fvm_to_ensight_writer_t  *this_writer = NULL;

  /* Initialize writer */

  BFT_MALLOC(this_writer, 1, fvm_to_ensight_writer_t);

  BFT_MALLOC(this_writer->name, strlen(name) + 1, char);
  strcpy(this_writer->name, name);

  this_writer->text_mode = false;
  this_writer->swap_endian = false;
  this_writer->discard_polygons = false;
  this_writer->discard_polyhedra = false;
  this_writer->divide_polygons = false;
  this_writer->divide_polyhedra = false;

  this_writer->rank = 0;
  this_writer->n_ranks = 1;

#if defined(FVM_HAVE_MPI)
  {
    int mpi_flag, rank, n_ranks;
    MPI_Initialized(&mpi_flag);

    if (mpi_flag && comm != MPI_COMM_NULL) {
      this_writer->comm = comm;
      MPI_Comm_rank(this_writer->comm, &rank);
      MPI_Comm_size(this_writer->comm, &n_ranks);
      this_writer->rank = rank;
      this_writer->n_ranks = n_ranks;
    }
    else
      this_writer->comm = MPI_COMM_NULL;
  }
#endif /* defined(FVM_HAVE_MPI) */

  /* Parse options */

  if (options != NULL) {

    int i1, i2, l_opt;
    int l_tot = strlen(options);

    i1 = 0; i2 = 0;
    while (i1 < l_tot) {

      for (i2 = i1 ; i2 < l_tot && options[i2] != ' ' ; i2++);
      l_opt = i2 - i1;

      if ((l_opt == 4) && (strncmp(options + i1, "text", l_opt) == 0))
        this_writer->text_mode = true;
      else if ((l_opt == 6) && (strncmp(options + i1, "binary", l_opt) == 0))
        this_writer->text_mode = false;

      else if (   (l_opt == 10)
               && (strncmp(options + i1, "big_endian", l_opt) == 0)) {
        int int_endian = 0;
        this_writer->text_mode = false;
        /* Check if system is "big-endian" or "little-endian" */
        *((char *)(&int_endian)) = '\1';
        if (int_endian == 1)
          this_writer->swap_endian = 1;
      }

      else if (   (l_opt == 16)
               && (strncmp(options + i1, "discard_polygons", l_opt) == 0))
        this_writer->discard_polygons = true;
      else if (   (l_opt == 17)
               && (strncmp(options + i1, "discard_polyhedra", l_opt) == 0))
        this_writer->discard_polyhedra = true;

      else if (   (l_opt == 15)
               && (strncmp(options + i1, "divide_polygons", l_opt) == 0))
        this_writer->divide_polygons = true;
      else if (   (l_opt == 16)
               && (strncmp(options + i1, "divide_polyhedra", l_opt) == 0))
        this_writer->divide_polyhedra = true;

      for (i1 = i2 + 1 ; i1 < l_tot && options[i1] == ' ' ; i1++);

    }

  }

  this_writer->case_info = fvm_to_ensight_case_create(name,
                                                      path,
                                                      time_dependency);

  /* Initialize geometry file name */

  if (time_dependency == FVM_WRITER_FIXED_MESH)
    _init_geom_file(this_writer);

  /* Return writer */

  return this_writer;
}

/*----------------------------------------------------------------------------
 * Finalize FVM to EnSight Gold file writer.
 *
 * parameters:
 *   this_writer_p <-- pointer to opaque Ensight Gold writer structure.
 *
 * returns:
 *   NULL pointer
 *----------------------------------------------------------------------------*/

void *
fvm_to_ensight_finalize_writer(void  *this_writer_p)
{
  fvm_to_ensight_writer_t  *this_writer
                             = (fvm_to_ensight_writer_t *)this_writer_p;

  BFT_FREE(this_writer->name);

  fvm_to_ensight_case_destroy(this_writer->case_info);

  BFT_FREE(this_writer);

  return NULL;
}

/*----------------------------------------------------------------------------
 * Associate new time step with an EnSight geometry.
 *
 * parameters:
 *   this_writer_p <-- pointer to associated writer
 *   time_step     <-- time step number
 *   time_value    <-- time_value number
 *----------------------------------------------------------------------------*/

void
fvm_to_ensight_set_mesh_time(void          *this_writer_p,
                             const int      time_step,
                             const double   time_value)
{
  fvm_to_ensight_writer_t  *this_writer
                             = (fvm_to_ensight_writer_t *)this_writer_p;

  fvm_to_ensight_case_set_geom_time(this_writer->case_info,
                                    time_step,
                                    time_value);
}

/*----------------------------------------------------------------------------
 * Indicate if a elements of a given type in a mesh associated to a given
 * EnSight Gold file writer need to be tesselated.
 *
 * parameters:
 *   this_writer_p <-- pointer to associated writer
 *   mesh          <-- pointer to nodal mesh structure that should be written
 *   element_type  <-- element type we are interested in
 *
 * returns:
 *   1 if tesselation of the given element type is needed, 0 otherwise
 *----------------------------------------------------------------------------*/

int
fvm_to_ensight_needs_tesselation(fvm_writer_t       *this_writer_p,
                                 const fvm_nodal_t  *mesh,
                                 fvm_element_t       element_type)
{
  int  i;
  int  retval = 0;
  fvm_to_ensight_writer_t  *this_writer
                             = (fvm_to_ensight_writer_t *)this_writer_p;

  const int  export_dim = fvm_nodal_get_max_entity_dim(mesh);

  /* Initial count and allocation */

  if (   (   element_type == FVM_FACE_POLY
          && this_writer->divide_polygons == true)
      || (   element_type == FVM_CELL_POLY
          && this_writer->divide_polyhedra == true)) {

    for (i = 0 ; i < mesh->n_sections ; i++) {

      const fvm_nodal_section_t  *const  section = mesh->sections[i];

      /* Output if entity dimension equal to highest in mesh
         (i.e. no output of faces if cells present, or edges
         if cells or faces) */

      if (section->entity_dim == export_dim) {
        if (section->type == element_type)
          retval = 1;
      }

    }

  }

  return retval;
}

/*----------------------------------------------------------------------------
 * Write nodal mesh to a an EnSight Gold file
 *
 * parameters:
 *   this_writer_p <-- pointer to associated writer
 *   mesh          <-- pointer to nodal mesh structure that should be written
 *----------------------------------------------------------------------------*/

void
fvm_to_ensight_export_nodal(void               *this_writer_p,
                            const fvm_nodal_t  *mesh)
{
  int     part_num;
  size_t  write_connect_buffer_size = 0;
  int    *write_connect_buffer = NULL;

  const fvm_writer_section_t  *export_section = NULL;
  fvm_writer_section_t  *export_list = NULL;
  fvm_to_ensight_writer_t  *this_writer
                             = (fvm_to_ensight_writer_t *)this_writer_p;
  bft_file_t  *f = NULL;

  fvm_gnum_t   global_connect_s_size, global_s_size;
  fvm_gnum_t   n_g_vertices;
  fvm_gnum_t  *n_g_elements_section = NULL;

#if defined(FVM_HAVE_MPI)

  fvm_gnum_t  *global_connect_s = NULL;
  MPI_Comm    comm = this_writer->comm;

#endif

  const int  rank = this_writer->rank;
  const int  n_ranks = this_writer->n_ranks;

  /* Initialization */
  /*----------------*/

  /* Get part number */

  part_num = fvm_to_ensight_case_get_part_num(this_writer->case_info,
                                              mesh->name);
  if (part_num == 0)
    part_num = fvm_to_ensight_case_add_part(this_writer->case_info,
                                            mesh->name);

  /* Open geometry file in append mode */

  if (rank == 0) {

    bft_file_type_t                  file_type;
    fvm_to_ensight_case_file_info_t  file_info;

    if (this_writer->text_mode == true)
      file_type = BFT_FILE_TYPE_TEXT;
    else

      file_type = BFT_FILE_TYPE_BINARY;

    file_info = fvm_to_ensight_case_get_geom_file(this_writer->case_info);

    if (file_info.queried == false)
      _init_geom_file(this_writer); /* Create, write header, and close file */

    f = bft_file_open(file_info.name,
                      BFT_FILE_MODE_APPEND,
                      file_type);

    if (this_writer->swap_endian == true)
      bft_file_set_swap_endian(f, 1);
  }

  /* Part header */

  if (rank == 0) {
    _write_string(f, "part");
    _write_int(f, part_num);
    if (mesh->name != NULL)
      _write_string(f, mesh->name);
    else
      _write_string(f, "unnamed");
  }

  /* Build list of sections that are used here, in order of output */

  export_list = fvm_writer_export_list(mesh,
                                       true,
                                       this_writer->discard_polygons,
                                       this_writer->discard_polyhedra,
                                       this_writer->divide_polygons,
                                       this_writer->divide_polyhedra);

  /* Buffer and global sizes required in parallel mode and for binary output */
  /*-------------------------------------------------------------------------*/

  BFT_MALLOC(n_g_elements_section, mesh->n_sections, fvm_gnum_t);

  fvm_writer_def_nodal_buf_size(mesh,
                                n_ranks,
                                12,
                                5,
                                &n_g_vertices,
                                n_g_elements_section,
                                &global_s_size,
                                &global_connect_s_size);

  /* Avoid too many small communications with large processor counts */

  if (n_ranks > 1 && global_connect_s_size > 0) {
    size_t min_buffer_size =   fvm_parall_get_min_coll_buf_size()
                             / sizeof(fvm_gnum_t);
    if (min_buffer_size > global_connect_s_size) {
      fvm_gnum_t global_s_size_min = global_s_size * (  min_buffer_size
                                                      / global_connect_s_size);
      if (global_s_size_min > global_s_size) {
        global_s_size = global_s_size_min;
        global_connect_s_size = min_buffer_size;
      }
    }
  }

  /* Vertex coordinates */
  /*--------------------*/

#if defined(FVM_HAVE_MPI)

  if (n_ranks > 1 )
    _export_vertex_coords_g(this_writer,
                            mesh,
                            comm,
                            global_s_size,
                            f);

#endif

  if (n_ranks == 1)
    _export_vertex_coords_l(this_writer,
                            mesh,
                            f);

  /* Allocate connectivity buffer for use wih all types of elements */

#if defined(FVM_HAVE_MPI)

  if (n_ranks > 1)
    BFT_MALLOC(global_connect_s, global_connect_s_size, fvm_gnum_t);

#endif

  /* Buffer required in binary mode */
  /*--------------------------------*/

  if (rank == 0) {
    if (this_writer->text_mode == true) {
      write_connect_buffer_size = 0;
      write_connect_buffer = NULL;
    }
    else { /* Arbitrary write buffer size, small enough to add little
              additional memory requirement (in proportion), large enough
              to limit number of write calls */
      write_connect_buffer_size = (global_s_size + 4) / 4;
      BFT_MALLOC(write_connect_buffer, write_connect_buffer_size, int);
    }
  }

  /* If no sections are present (i.e. we may only have vertices),
     add  "point" elements */

  if (export_list == NULL && rank == 0)
    _export_point_elements_l(n_g_vertices,
                             write_connect_buffer_size,
                             write_connect_buffer,
                             f);

  /* Element connectivity */
  /*----------------------*/

  export_section = export_list;

  while (export_section != NULL) {

    const fvm_nodal_section_t  *section = export_section->section;

    /* Print header if start of corresponding EnSight section */

    if (export_section->continues_previous == false && rank == 0) {

      fvm_gnum_t n_g_elements = 0;
      const fvm_writer_section_t  *next_section = export_section;

      do {

        if (next_section->section->type == export_section->type)
          n_g_elements += fvm_nodal_section_n_g_elements(next_section->section);

        else {
          fvm_gnum_t n_g_sub_elements = 0;
          fvm_tesselation_get_global_size(next_section->section->tesselation,
                                          next_section->type,
                                          &n_g_sub_elements,
                                          NULL);
          n_g_elements += n_g_sub_elements;
        }

        next_section = next_section->next;

      } while (next_section != NULL && next_section->continues_previous == true);

      _write_string(f, _ensight_type_name[export_section->type]);
      _write_int(f, n_g_elements);
    }

    /* Output for strided (regular) element types */
    /*--------------------------------------------*/

    if (section->stride > 0) {

#if defined(FVM_HAVE_MPI)

      if (n_ranks > 1) { /* start of output in parallel mode */

        fvm_gnum_t   global_num_start;
        fvm_gnum_t   global_num_end;

        fvm_gather_slice_t  *elements_slice = NULL;

        elements_slice
          = fvm_gather_slice_create(section->global_element_num,
                                    global_s_size,
                                    comm);

        while (fvm_gather_slice_advance(elements_slice,
                                        &global_num_start,
                                        &global_num_end) == 0) {

          fvm_gather_strided_connect(section->vertex_num,
                                     global_connect_s,
                                     section->stride,
                                     mesh->global_vertex_num,
                                     section->global_element_num,
                                     comm,
                                     elements_slice);

          if (rank == 0)
            _write_slice_connect_g(section->stride,
                                   global_num_start,
                                   global_num_end,
                                   global_connect_s,
                                   write_connect_buffer_size,
                                   write_connect_buffer,
                                   f);

        }

        fvm_gather_slice_destroy(elements_slice);

      } /* end of output in parallel mode */

#endif /* defined(FVM_HAVE_MPI) */

      if (n_ranks == 1) { /* start of output in serial mode */

        _write_connect_l(section->stride,
                         section->n_elements,
                         section->vertex_num,
                         write_connect_buffer_size,
                         write_connect_buffer,
                         f);

      }

      export_section = export_section->next;

    } /* end of output for strided element types */

    /* Output for tesselated polygons or polyhedra */
    /*---------------------------------------------*/

    else if (export_section->type != section->type) {

#if defined(FVM_HAVE_MPI)

      /* output in parallel mode */

      if (n_ranks > 1) {

        export_section = _export_nodal_tesselated_g(export_section,
                                                    mesh->global_vertex_num,
                                                    comm,
                                                    global_s_size,
                                                    global_connect_s_size,
                                                    global_connect_s,
                                                    write_connect_buffer_size,
                                                    write_connect_buffer,
                                                    f);

      }

#endif /* defined(FVM_HAVE_MPI) */

      if (n_ranks == 1) {

        export_section = _export_nodal_tesselated_l(export_section,
                                                    write_connect_buffer_size,
                                                    write_connect_buffer,
                                                    f);

      }

    }

    /* Output for polygons */
    /*---------------------*/

    else if (export_section->type == FVM_FACE_POLY) {

#if defined(FVM_HAVE_MPI)

      /* output in parallel mode */

      if (n_ranks > 1) {

        export_section = _export_nodal_polygons_g(export_section,
                                                  mesh->global_vertex_num,
                                                  comm,
                                                  global_s_size,
                                                  global_connect_s_size,
                                                  global_connect_s,
                                                  this_writer->text_mode,
                                                  write_connect_buffer_size,
                                                  write_connect_buffer,
                                                  f);

      }

#endif /* defined(FVM_HAVE_MPI) */

      if (n_ranks == 1) {

        /* Export as polygons */

        export_section = _export_nodal_polygons_l(export_section,
                                                  this_writer->text_mode,
                                                  write_connect_buffer_size,
                                                  write_connect_buffer,
                                                  f);

      }

    }

    /* Output for polyhedra */
    /*----------------------*/

    else if (export_section->type == FVM_CELL_POLY) {

#if defined(FVM_HAVE_MPI)

      /* output in parallel mode */

      if (n_ranks > 1)

        export_section =_export_nodal_polyhedra_g(export_section,
                                                  mesh->global_vertex_num,
                                                  comm,
                                                  global_s_size,
                                                  global_connect_s_size,
                                                  global_connect_s,
                                                  this_writer->text_mode,
                                                  write_connect_buffer_size,
                                                  write_connect_buffer,
                                                  f);

#endif /* defined(FVM_HAVE_MPI) */

      if (n_ranks == 1)

        export_section = _export_nodal_polyhedra_l(export_section,
                                                   this_writer->text_mode,
                                                   write_connect_buffer_size,
                                                   write_connect_buffer,
                                                   f);

    }

  } /* End of loop on sections */

  BFT_FREE(export_list);

  /* Free buffers */
  /*--------------*/

  BFT_FREE(n_g_elements_section);

  if (write_connect_buffer != NULL) {
    write_connect_buffer_size = 0;
    BFT_FREE(write_connect_buffer);
  }

  /* Free buffers required in parallel mode */

#if defined(FVM_HAVE_MPI)

  if (n_ranks > 1)
    BFT_FREE(global_connect_s);

#endif /* defined(FVM_HAVE_MPI) */

  /* Close geometry file and update case file */
  /*------------------------------------------*/

  if (rank == 0)
    bft_file_free(f);

  if (rank == 0)
    fvm_to_ensight_case_write_case(this_writer->case_info);
}

/*----------------------------------------------------------------------------
 * Write field associated with a nodal mesh to an EnSight Gold file.
 *
 * Assigning a negative value to the time step indicates a time-independent
 * field (in which case the time_value argument is unused).
 *
 * parameters:
 *   this_writer_p    <-- pointer to associated writer
 *   mesh             <-- pointer to associated nodal mesh structure
 *   name             <-- variable name
 *   location         <-- variable definition location (nodes or elements)
 *   dimension        <-- variable dimension (0: constant, 1: scalar,
 *                        3: vector, 6: sym. tensor, 9: asym. tensor)
 *   interlace        <-- indicates if variable in memory is interlaced
 *   n_parent_lists   <-- indicates if variable values are to be obtained
 *                        directly through the local entity index (when 0) or
 *                        through the parent entity numbers (when 1 or more)
 *   parent_num_shift <-- parent number to value array index shifts;
 *                        size: n_parent_lists
 *   datatype         <-- indicates the data type of (source) field values
 *   time_step        <-- number of the current time step
 *   time_value       <-- associated time value
 *   field_values     <-- array of associated field value arrays
 *----------------------------------------------------------------------------*/

void
fvm_to_ensight_export_field(void                  *this_writer_p,
                            const fvm_nodal_t     *mesh,
                            const char            *name,
                            fvm_writer_var_loc_t   location,
                            int                    dimension,
                            fvm_interlace_t        interlace,
                            int                    n_parent_lists,
                            const fvm_lnum_t       parent_num_shift[],
                            fvm_datatype_t         datatype,
                            int                    time_step,
                            double                 time_value,
                            const void      *const field_values[])
{
  int     output_dim;
  int     part_num;
  size_t  input_size = 0;
  size_t  output_size = 0;
  size_t  min_var_buffer_size = 0;
  size_t  var_buffer_size = 0;
  float  *var_buffer = NULL;

  const fvm_writer_section_t  *export_section = NULL;
  fvm_writer_field_helper_t  *helper = NULL;
  fvm_writer_section_t  *export_list = NULL;
  fvm_to_ensight_writer_t  *this_writer
                             = (fvm_to_ensight_writer_t *)this_writer_p;
  bft_file_t  *f = NULL;

  const int  rank = this_writer->rank;
  const int  n_ranks = this_writer->n_ranks;

  /* Initialization */
  /*----------------*/

  /* Dimension */

  output_dim = dimension;
  if (dimension == 2)
    output_dim = 3;
  else if (dimension > 3 && dimension != 6 && dimension != 9)
    bft_error(__FILE__, __LINE__, 0,
              _("Data of dimension %d not handled"), dimension);

  /* Get part number */

  part_num = fvm_to_ensight_case_get_part_num(this_writer->case_info,
                                              mesh->name);
  if (part_num == 0)
    part_num = fvm_to_ensight_case_add_part(this_writer->case_info,
                                            mesh->name);

  /* Open variable file */

  if (rank == 0) {

    bft_file_type_t                  file_type;
    bft_file_mode_t                  file_mode;
    fvm_to_ensight_case_file_info_t  file_info;

    if (this_writer->text_mode == true)
      file_type = BFT_FILE_TYPE_TEXT;
    else
      file_type = BFT_FILE_TYPE_BINARY;

    file_info = fvm_to_ensight_case_get_var_file(this_writer->case_info,
                                                 name,
                                                 output_dim,
                                                 location,
                                                 time_step,
                                                 time_value);

    if (file_info.queried == true)
      file_mode = BFT_FILE_MODE_APPEND;
    else
      file_mode = BFT_FILE_MODE_WRITE;

    f = bft_file_open(file_info.name,
                      file_mode,
                      file_type);

    if (this_writer->swap_endian == true)
      bft_file_set_swap_endian(f, 1);

    /* New files start with description line */

    if (file_mode == BFT_FILE_MODE_WRITE){
      char buf[81] = "";
#if HAVE_SNPRINTF
      if (time_step > -1)
        snprintf(buf, 80, "%s (time values: %d, %g)",
                 name, time_step, time_value);
      else
        strncpy(buf, name, 80);
#else
      strncpy(buf, name, 80);
#endif
      buf[80] = '\0';
      _write_string(f, buf);
    }

  }

  /* Initialize writer helper */
  /*--------------------------*/

  /* Build list of sections that are used here, in order of output */

  export_list = fvm_writer_export_list(mesh,
                                       true,
                                       this_writer->discard_polygons,
                                       this_writer->discard_polyhedra,
                                       this_writer->divide_polygons,
                                       this_writer->divide_polyhedra);

  helper = fvm_writer_field_helper_create(mesh,
                                          export_list,
                                          output_dim,
                                          FVM_NO_INTERLACE,
                                          FVM_FLOAT,
                                          location);

#if defined(FVM_HAVE_MPI)

  fvm_writer_field_helper_init_g(helper,
                                 export_list,
                                 mesh,
                                 this_writer->comm);

#endif

  /* Buffer size computation and allocation */
  /*----------------------------------------*/

  fvm_writer_field_helper_get_size(helper,
                                   &input_size,
                                   &output_size,
                                   NULL,
                                   &min_var_buffer_size);

  /* Slicing allows for arbitrary buffer size, but should be small enough
     to add little additional memory requirement (in proportion), large
     enough to limit number of write and gather calls. */

  if (n_ranks > 1) {
    size_t min_buffer_size = fvm_parall_get_min_coll_buf_size() / sizeof(float);
    var_buffer_size = input_size / n_ranks;
    if (var_buffer_size < min_buffer_size)
      var_buffer_size = min_buffer_size;
  }
  else
    var_buffer_size = input_size / 4;

  var_buffer_size = FVM_MAX(var_buffer_size, min_var_buffer_size);
  var_buffer_size = FVM_MAX(var_buffer_size, 128);
  var_buffer_size = FVM_MIN(var_buffer_size, output_size);

  BFT_MALLOC(var_buffer, var_buffer_size, float);

  /* Part header */

  if (rank == 0) {
    _write_string(f, "part");
    _write_int(f, part_num);
  }

  /* Per node variable */
  /*-------------------*/

  if (location == FVM_WRITER_PER_NODE) {

    if (rank == 0)
      _write_string(f, "coordinates");

    _export_field_values_n(mesh,
                           helper,
                           dimension,
                           interlace,
                           n_parent_lists,
                           parent_num_shift,
                           datatype,
                           field_values,
                           rank,
                           var_buffer_size,
                           var_buffer,
                           f);

  }

  /* Per element variable */
  /*----------------------*/

  else if (location == FVM_WRITER_PER_ELEMENT) {

    export_section = export_list;

    while (export_section != NULL) {

      /* Print header if start of corresponding EnSight section */

      if (export_section->continues_previous == false && rank == 0)
        _write_string(f, _ensight_type_name[export_section->type]);

      /* Output per grouped sections */

      export_section = _export_field_values_e(export_section,
                                              helper,
                                              dimension,
                                              interlace,
                                              n_parent_lists,
                                              parent_num_shift,
                                              datatype,
                                              field_values,
                                              rank,
                                              var_buffer_size,
                                              var_buffer,
                                              f);

    } /* End of loop on sections */

  } /* End for per element variable */

  /* Free buffers and helper structures */
  /*------------------------------------*/

  BFT_FREE(var_buffer);

  helper = fvm_writer_field_helper_destroy(helper);

  BFT_FREE(export_list);

  /* Close variable file and update case file */
  /*------------------------------------------*/

  if (rank == 0)
    bft_file_free(f);

  if (rank == 0)
    fvm_to_ensight_case_write_case(this_writer->case_info);
}

/*----------------------------------------------------------------------------*/

#ifdef __cplusplus
}
#endif /* __cplusplus */


syntax highlighted by Code2HTML, v. 0.9.1