Logo Search packages:      
Sourcecode: ecs version File versions  Download package

ecs_comm.c

/*============================================================================
 * Base functions for writing Kernel I/O files.
 *============================================================================*/

/*
  This file is part of the Code_Saturne Preprocessor, element of the
  Code_Saturne CFD tool.

  Copyright (C) 1999-2007 EDF S.A., France

  contact: saturne-support@edf.fr

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

  The Code_Saturne Preprocessor 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 General Public License for more details.

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


#include "ecs_config.h"

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

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

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

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

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

#include "ecs_chaine_glob.h"
#include "ecs_def.h"

/*----------------------------------------------------------------------------
 *  Headers for the current file
 *----------------------------------------------------------------------------*/

#include "ecs_comm.h"

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

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

/*=============================================================================
 * Macro definitions
 *============================================================================*/

/*=============================================================================
 * Local type definitions
 *============================================================================*/

/*----------------------------------------------------------------------------
 * Structure defining an output writer
 *----------------------------------------------------------------------------*/

struct _ecs_comm_t {

  char           *name;             /* Writer name */

  bft_file_t     *f;                /* Associated file structure pointer */

  size_t          header_size;      /* Header default size */
  size_t          header_align;     /* Header alignment */
  size_t          body_align;       /* Body alignment */

  size_t          cur_pos;          /* Current position in file */

};

/*============================================================================
 * Local function defintions
 *============================================================================*/

/*----------------------------------------------------------------------------
 * Write padding zeroes to ensure following alignement if necessary
 *----------------------------------------------------------------------------*/

static void
_write_pad(ecs_comm_t  *comm,
           size_t       alignment)
{
  size_t pad_size = (alignment - (comm->cur_pos % alignment)) % alignment;

  if (pad_size > 0) {

    char padding[128] = "";
    size_t rem_size = pad_size;

    memset(padding, 0, sizeof(padding));

    while (rem_size > 0) {
      size_t write_size = ECS_MIN(rem_size, sizeof(padding));
      bft_file_write(padding, 1, write_size, comm->f);
      rem_size -= write_size;
    }

    comm->cur_pos += pad_size;
  }
}

/*----------------------------------------------------------------------------
 * Write a record to the interface file
 *----------------------------------------------------------------------------*/

static void
_write_rec(ecs_comm_t  *comm,
           const void  *rec,
           size_t       n_elts,
           ecs_type_t   datatype)
{
  size_t t_size;

  assert(comm != NULL) ;
  assert(rec  != NULL) ;

  /* Determine size associated with type */

  switch (datatype) {
  case ECS_TYPE_ecs_int_t:
    t_size = sizeof(ecs_int_t) ;
    break ;
  case ECS_TYPE_ecs_real_t:
    t_size = sizeof(ecs_real_t) ;
    break ;
  case ECS_TYPE_ecs_size_t:
    t_size = sizeof(ecs_size_t) ;
    break ;
  case ECS_TYPE_char:
    t_size = sizeof(char) ;
    break ;
  case ECS_TYPE_size_t:
    t_size = 8 ;
    break ;
  default:
    assert(   datatype == ECS_TYPE_ecs_int_t
           || datatype == ECS_TYPE_ecs_real_t
           || datatype == ECS_TYPE_ecs_size_t
           || datatype == ECS_TYPE_size_t
           || datatype == ECS_TYPE_char);
  }

  /* write record to file */
  /*----------------------*/

  if (datatype != ECS_TYPE_size_t || sizeof(size_t) == 8) {
    bft_file_write(rec, t_size, n_elts, comm->f);
    comm->cur_pos += n_elts*t_size;
  }

  else { /* if (datatype == ECS_TYPE_size_t && sizeof(size_t) != 8) */

    size_t i;

    assert(sizeof(unsigned long long) == 8) ;

    for (i = 0; i < n_elts; i++) {
      const unsigned char *rp = rec;
      unsigned long long _rec = *((const size_t *)(rp + i*sizeof(size_t)));
      assert(sizeof(long long) == 8);
      bft_file_write(&_rec, 8, 1, comm->f);
      comm->cur_pos += 8;
    }

  }
}

/*----------------------------------------------------------------------------
 * Open output file and write base file description headers
 *----------------------------------------------------------------------------*/

static void
_file_open(ecs_comm_t  *comm,
           const char  *file_name)
{
  char header[64] = "";
  size_t sizes[3] = {comm->header_size,
                     comm->header_align,
                     comm->body_align};

  memset(header, 0, 64);

  /* BE stands for big-endian, allowing for future
     native file mode generation, using BE/LE */

  strncpy(header, "Code_Saturne I/O, BE, R0", 63);

  /* Open file */

  comm->f = bft_file_open(file_name,
                          BFT_FILE_MODE_WRITE,
                          BFT_FILE_TYPE_BINARY);

  bft_file_set_big_endian(comm->f);

  /* Write header and comment information */

  _write_rec(comm, header, 64, ECS_TYPE_char);

  memset(header, 0, 64);
  strncpy(header, "Face-based mesh definition, R0", 63);

  _write_rec(comm, header, 64, ECS_TYPE_char);

  _write_rec(comm, sizes, 3, ECS_TYPE_size_t);
}

/*----------------------------------------------------------------------------
 * Echo section output data
 *----------------------------------------------------------------------------*/

static void
_echo_header(const char   *name,
             size_t        n_values,
             const char   *datatype_name)
{
  char name_pad[33] = "";
  char type_pad[3] = "";

  if (strlen(name) < 32) {
    memset(name_pad, ' ', sizeof(name_pad));
    name_pad[32 - strlen(name)] = '\0';
  }
  if (strlen(datatype_name) < 2) {
    type_pad[0] = ' '; type_pad[1] = ' ';
    type_pad[2 - strlen(datatype_name)] = '\0';
  }

  if (n_values > 0)
    bft_printf(_("  Wrote: \"%s\"%s; Type: \"%s\"%s; Size: %lu\n"),
               name, name_pad, datatype_name, type_pad,
               (unsigned long)n_values);

  else
    bft_printf(_("  Wrote: \"%s\"\n"),
               name);

  bft_printf_flush();
}

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

ecs_comm_t *
ecs_comm_initialize(void)
{
  ecs_comm_t  * comm = NULL;

  const char    file_name[] = "preprocessor_output";

  /* Create structure */

  BFT_MALLOC(comm, 1, ecs_comm_t);

  BFT_MALLOC(comm->name, strlen(file_name) + 1, char) ;

  sprintf(comm->name, file_name) ;

  /* Initialize other fields */

  comm->header_size = 96;
  comm->header_align = 64;
  comm->body_align = 64;
  comm->cur_pos = 0;

  comm->f  = NULL ;

  /* Jump a line in log file */

  bft_printf("\n");

  /* Info on interface creation */

  bft_printf(_("  Opening file: %s\n"),
             comm->name);

  bft_printf("\n");

  bft_printf_flush();

  /* Create file descriptor */

  _file_open(comm, file_name);

  return comm ;
}

/*----------------------------------------------------------------------------
 * Close writer.
 *
 * arguments:
 *   comm <-- pointer to writer structure pointer
 *----------------------------------------------------------------------------*/

void
ecs_comm_finalize(ecs_comm_t **comm)
{
  ecs_comm_t *_comm = *comm;

  bft_printf("\n") ;

  bft_printf(_("  Closing file: %s\n"),
             _comm->name) ;

  if (_comm->f != NULL)
    _comm->f = bft_file_free(_comm->f) ;

  BFT_FREE(_comm->name) ;

  BFT_FREE(_comm) ;

  *comm = _comm;
}

/*----------------------------------------------------------------------------
 * Write a section to the Kernel I/O file.
 *
 * Grid locations and possibly indexes may be assigned to a section by
 * specifying a location id; the first time a given location id appears in
 * the file is considered a declaration. In the same manner, an index id
 * may be specified. Values of zero indicate no location or index base
 * is used. It is up to the calling code to ensure that total number of
 * values, location size, and number of values per location are consistent,
 * as this my be important for code reading the file.
 *
 * arguments:
 *   name              <-- section name
 *   location_id       <-- id of associated location
 *   index_id          <-- id of associated index
 *   n_location_values <-- number of values per location
 *   embed             <-- embed values in header
 *   values            <-- values to write
 *   value_type        <-- type of value to write
 *   comm              <-- Kernel I/O file output structure
 *----------------------------------------------------------------------------*/

void
ecs_comm_write_section(const char  *name,
                       size_t       n_values,
                       size_t       location_id,
                       size_t       index_id,
                       size_t       n_location_values,
                       bool         embed,
                       const void  *values,
                       ecs_type_t   value_type,
                       ecs_comm_t  *comm)
{
  /* Section is defined by:

     section size (in bytes): 8 bytes
     n_elts, location_id, index_id, n_location_values: 4*8 bytes
     name_size (including padding to 8 byte alignment): 8 bytes
     datatype_name: 8 bytes (bit 6 = '\0', bit 7 = embed flag)
     section name: strlen(name) + 1 + padding to 8 bytes
     optional embedded data: n_values*value_type_size
  */

  size_t header_sizes[6] = {56,       /* 6*8 +8 */
                            n_values,
                            location_id,
                            index_id,
                            n_location_values,
                            0};
  size_t name_size = 0;
  size_t name_pad_size = 0;
  size_t data_size = 0;
  char   datatype_name[8];
  char   name_pad[8];

  assert(comm != NULL);
  assert(name != NULL);

  /* Initialization */

  memset(datatype_name, 0, sizeof(datatype_name));
  memset(name_pad, 0, sizeof(name_pad));

  /* Section name */

  name_size = strlen(name);
  name_pad_size = 8-(name_size%8); /* At least 1 NULL
                                      character with this rule */

  header_sizes[0] += (name_size + name_pad_size);
  header_sizes[5] = (name_size + name_pad_size);

  /* Value type name */

  if (n_values > 0) {

    switch(value_type) {

    case ECS_TYPE_ecs_int_t:

      switch(sizeof(ecs_int_t)) {
      case 4:
        strcpy(datatype_name, "i4");
        break;
      case 8:
        strcpy(datatype_name, "i8");
        break;
      default:
        assert(sizeof(ecs_int_t) == 4 || sizeof(ecs_int_t) == 8);
      }
      break;

    case ECS_TYPE_ecs_real_t:

      switch(sizeof(ecs_real_t)) {
      case 4:
        strcpy(datatype_name, "r4");
        break;
      case 8:
        strcpy(datatype_name, "r8");
        break;
      default:
        assert(sizeof(ecs_real_t) == 4 || sizeof(ecs_real_t) == 8);
      }
      break;

    case ECS_TYPE_ecs_size_t:

      switch(sizeof(ecs_size_t)) {
      case 4:
        strcpy(datatype_name, "u4");
        break;
      case 8:
        strcpy(datatype_name, "u8");
        break;
      default:
        assert(sizeof(ecs_size_t) == 4 || sizeof(ecs_size_t) == 8);
      }
      break;

    case ECS_TYPE_size_t:

      strcpy(datatype_name, "u8");
      break;

    case ECS_TYPE_char:

      strcpy(datatype_name, "c ");
      break;

    default:

      assert(   value_type == ECS_TYPE_ecs_int_t
             || value_type == ECS_TYPE_ecs_real_t
             || value_type == ECS_TYPE_ecs_size_t
             || value_type == ECS_TYPE_size_t
             || value_type == ECS_TYPE_char);


    } /* End of switch on value_type */

  }

  if (embed == true) {

    datatype_name[7] = 'e';

    if (datatype_name[1] == '4')
      data_size = 4*n_values;
    else if (datatype_name[1] == '8')
      data_size = 8*n_values;
    else
      data_size = n_values;

    header_sizes[0] += data_size;

  }

  /* Only output data if file exists */

  if (comm->f != NULL) {

    /* Align if necessary */

    _write_pad(comm, comm->header_align);

    /* Write sizes */

    _write_rec(comm, header_sizes, 6, ECS_TYPE_size_t);

    /* Type information */

    _write_rec(comm, datatype_name, 8, ECS_TYPE_char);

    /* Section name */

    _write_rec(comm, name, name_size, ECS_TYPE_char);
    _write_rec(comm, name_pad, name_pad_size, ECS_TYPE_char);

    /* Embedded values */

    if (n_values > 0 && embed == true)
      _write_rec(comm, values, n_values, value_type);

    /* Ensure header is at least the size of the basic header block size,
       as reads may read at least this much data */

    if (header_sizes[0] < comm->header_size) {
      char   header_pad[64];
      size_t header_pad_size = comm->header_size - header_sizes[0];
      memset(header_pad, 0, sizeof(header_pad));
      while (header_pad_size > 0) {
        size_t write_size = ECS_MIN(header_pad_size, sizeof(header_pad));
        bft_file_write(header_pad, 1, write_size, comm->f);
        header_pad_size -= write_size;
        comm->cur_pos += write_size;
      }
    }

    /* If values are not embedded, handle separate value block */

    if (n_values > 0 && embed == false) {

      _write_pad(comm, comm->body_align);
      _write_rec(comm, values, n_values, value_type);

    }

  }

  /* Print message */

  _echo_header(name, n_values, datatype_name);
}

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

#ifdef __cplusplus
}
#endif /* __cplusplus */


Generated by  Doxygen 1.6.0   Back to index