/*============================================================================
* Write a nodal representation associated with a mesh to file
*============================================================================*/
/*
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_mem.h>
#include <bft_file.h>
#include <bft_printf.h>
/*----------------------------------------------------------------------------
* Local headers
*----------------------------------------------------------------------------*/
#include <fvm_config_defs.h>
#include <fvm_defs.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_writer_priv.h>
/*----------------------------------------------------------------------------
* Header for the current file
*----------------------------------------------------------------------------*/
#include <fvm_to_text.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
*============================================================================*/
/*----------------------------------------------------------------------------
* Text writer structure
*----------------------------------------------------------------------------*/
typedef struct {
bft_file_t *file; /* Output file */
fvm_writer_time_dep_t time_dependency; /* Mesh time dependency */
int rank; /* Rank of current process in communicator */
int n_ranks; /* Number of processes in communicator */
#if defined(FVM_HAVE_MPI)
MPI_Comm comm; /* Associated MPI communicator */
#endif
} fvm_to_text_writer_t;
/*============================================================================
* Static global variables
*============================================================================*/
/*============================================================================
* Private function definitions
*============================================================================*/
/*----------------------------------------------------------------------------
* Write slice of a vector of doubles to a text file
*
* parameters:
* stride <-- number of values per element
* 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_vector(const size_t stride,
const fvm_gnum_t num_start,
const fvm_gnum_t num_end,
const double values[],
bft_file_t *const f)
{
size_t i, k;
fvm_gnum_t j;
/* If called by non I/O rank, return */
if (f == NULL)
return;
switch(stride) {
case 1:
for (i = 0, j = num_start ; j < num_end ; i++, j++)
bft_file_printf(f, "%12lu : %12.5f\n",
(unsigned long)j,
values[i]);
break;
case 2:
for (i = 0, j = num_start ; j < num_end ; i++, j++)
bft_file_printf(f, "%12lu : %12.5f %12.5f\n",
(unsigned long)j,
values[2*i], values[2*i+1]);
break;
case 3:
for (i = 0, j = num_start ; j < num_end ; i++, j++)
bft_file_printf(f, "%12lu : %12.5f %12.5f %12.5f\n",
(unsigned long)j,
values[3*i], values[3*i+1], values[3*i+2]);
break;
default: /* Fallback, requiring more calls */
for (i = 0, j = num_start ; j < num_end ; i++, j++) {
bft_file_printf(f, "%12lu :", (unsigned long)j);
for (k = 0 ; k < stride ; k++)
bft_file_printf(f, " %12.5f",
values[stride*i+k]);
bft_file_printf(f, "\n");
}
break;
}
}
#if defined(FVM_HAVE_MPI)
/*----------------------------------------------------------------------------
* Write strided global connectivity slice to a text file
*
* parameters:
* stride <-- number of vertices per element type
* num_start <-- global number of first element for this slice
* num_end <-- global number of last element for this slice
* global_connect_s <-- global connectivity slice array
* f <-- file to write to
*----------------------------------------------------------------------------*/
static void
_write_slice_connect_g(const int stride,
const fvm_gnum_t num_start,
const fvm_gnum_t num_end,
const fvm_gnum_t global_connect_s[],
bft_file_t *const f)
{
fvm_gnum_t i, j;
/* If called by non I/O rank, return */
if (f == NULL)
return;
switch(stride) {
case 2: /* edge */
for (i = 0, j = num_start ; j < num_end ; i++, j++)
bft_file_printf(f, "%12lu : %12lu %12lu\n",
(unsigned long)j,
(unsigned long)global_connect_s[i*2],
(unsigned long)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, "%12lu : %12lu %12lu %12lu\n",
(unsigned long)j,
(unsigned long)global_connect_s[i*3],
(unsigned long)global_connect_s[i*3+1],
(unsigned long)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, "%12lu : %12lu %12lu %12lu %12lu\n",
(unsigned long)j,
(unsigned long)global_connect_s[i*4],
(unsigned long)global_connect_s[i*4+1],
(unsigned long)global_connect_s[i*4+2],
(unsigned long)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, "%12lu : %12lu %12lu %12lu %12lu %12lu\n",
(unsigned long)j,
(unsigned long)global_connect_s[i*5],
(unsigned long)global_connect_s[i*5+1],
(unsigned long)global_connect_s[i*5+2],
(unsigned long)global_connect_s[i*5+3],
(unsigned long)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, "%12lu : %12lu %12lu %12lu %12lu %12lu %12lu\n",
(unsigned long)j,
(unsigned long)global_connect_s[i*6],
(unsigned long)global_connect_s[i*6+1],
(unsigned long)global_connect_s[i*6+2],
(unsigned long)global_connect_s[i*6+3],
(unsigned long)global_connect_s[i*6+4],
(unsigned long)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,
"%12lu : "
"%12lu %12lu %12lu %12lu\n"
" "
"%12lu %12lu %12lu %12lu\n",
(unsigned long)j,
(unsigned long)global_connect_s[i*8],
(unsigned long)global_connect_s[i*8+1],
(unsigned long)global_connect_s[i*8+2],
(unsigned long)global_connect_s[i*8+3],
(unsigned long)global_connect_s[i*8+4],
(unsigned long)global_connect_s[i*8+5],
(unsigned long)global_connect_s[i*8+6],
(unsigned long)global_connect_s[i*8+7]);
break;
default:
assert(0);
}
}
#endif /* defined(FVM_HAVE_MPI) */
/*----------------------------------------------------------------------------
* Write strided local connectivity to a text file
*
* parameters:
* stride <-- number of vertices per element type
* n_elems <-- number of elements
* connect <-- connectivity array
* f <-- file to write to
*----------------------------------------------------------------------------*/
static void
_write_connect_l(const int stride,
const fvm_lnum_t n_elems,
const fvm_lnum_t connect[],
bft_file_t *const f)
{
fvm_lnum_t i;
switch(stride) {
case 2: /* edge */
for (i = 0 ; i < n_elems ; i++)
bft_file_printf(f, "%12lu : %12lu %12lu\n",
(unsigned long)(i+1),
(unsigned long)connect[i*2],
(unsigned long)connect[i*2+1]);
break;
case 3: /* FVM_FACE_TRIA */
for (i = 0 ; i < n_elems ; i++)
bft_file_printf(f, "%12lu : %12lu %12lu %12lu\n",
(unsigned long)(i+1),
(unsigned long)connect[i*3],
(unsigned long)connect[i*3+1],
(unsigned long)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, "%12lu : %12lu %12lu %12lu %12lu\n",
(unsigned long)(i+1),
(unsigned long)connect[i*4],
(unsigned long)connect[i*4+1],
(unsigned long)connect[i*4+2],
(unsigned long)connect[i*4+3]);
break;
case 5: /* FVM_CELL_PYRAM */
for (i = 0 ; i < n_elems ; i++)
bft_file_printf(f, "%12lu : %12lu %12lu %12lu %12lu %12lu\n",
(unsigned long)(i+1),
(unsigned long)connect[i*5],
(unsigned long)connect[i*5+1],
(unsigned long)connect[i*5+2],
(unsigned long)connect[i*5+3],
(unsigned long)connect[i*5+4]);
break;
case 6: /* FVM_CELL_PRISM */
for (i = 0 ; i < n_elems ; i++)
bft_file_printf(f, "%12lu : %12lu %12lu %12lu %12lu %12lu %12lu\n",
(unsigned long)(i+1),
(unsigned long)connect[i*6],
(unsigned long)connect[i*6+1],
(unsigned long)connect[i*6+2],
(unsigned long)connect[i*6+3],
(unsigned long)connect[i*6+4],
(unsigned long)connect[i*6+5]);
break;
case 8: /* FVM_CELL_HEXA */
for (i = 0 ; i < n_elems ; i++)
bft_file_printf(f,
"%12lu : "
"%12lu %12lu %12lu %12lu\n"
" "
"%12lu %12lu %12lu %12lu\n",
(unsigned long)(i+1),
(unsigned long)connect[i*8],
(unsigned long)connect[i*8+1],
(unsigned long)connect[i*8+2],
(unsigned long)connect[i*8+3],
(unsigned long)connect[i*8+4],
(unsigned long)connect[i*8+5],
(unsigned long)connect[i*8+6],
(unsigned long)connect[i*8+7]);
break;
default:
assert(0);
}
}
#if defined(FVM_HAVE_MPI)
/*----------------------------------------------------------------------------
* Write polyhedra from a nodal mesh to a text file in parallel mode
*
* parameters:
* section <-- pointer to nodal mesh section structure
* global_vertex_num <-- pointer to vertex global numbering
* comm <-- associated MPI communicator
* rank <-- rank in 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
* f <-- pointer to associated file
*----------------------------------------------------------------------------*/
static void
_export_nodal_polyhedra_g(const fvm_nodal_section_t *const section,
const fvm_io_num_t *const global_vertex_num,
MPI_Comm comm,
const int rank,
const fvm_gnum_t global_s_size,
const fvm_gnum_t global_connect_s_size_caller,
fvm_gnum_t global_connect_s_caller[],
bft_file_t *const f)
{
fvm_lnum_t i, j, k, l;
fvm_gnum_t i_s, j_s, k_s;
fvm_lnum_t cell_length, face_length;
fvm_lnum_t face_id;
fvm_gnum_t global_num_start = 1;
fvm_gnum_t global_num_end = 0;
fvm_gnum_t global_cell_face_idx_shift = 0 ;
fvm_gnum_t global_cell_vtx_idx_shift = 0 ;
fvm_lnum_t *face_lengths = NULL;
fvm_lnum_t *cell_vtx_idx = NULL;
fvm_lnum_t *cell_connect = NULL;
fvm_gnum_t *global_cell_face_idx_s = NULL;
fvm_gnum_t *global_face_lengths_s = NULL;
fvm_gnum_t *global_cell_vtx_idx_s = NULL;
fvm_gnum_t global_face_lengths_s_size = 0;
fvm_gnum_t global_face_lengths_s_size_prev = 0;
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_gnum_t n_g_polyhedra = fvm_io_num_get_global_count
(section->global_element_num);
/* Allocate memory for additionnal indexes */
BFT_MALLOC(global_cell_face_idx_s, global_s_size + 1, fvm_gnum_t);
BFT_MALLOC(global_cell_vtx_idx_s, global_s_size + 1, fvm_gnum_t);
/* Every face should have at least 3 vertices, so cell->vertex connectivity
should be at least 3 times the size of the cell->face connectivity;
So we choose 1/3 (rounded up) of the size of the cell->vertex slice
buffer as the initial size of the face_lengths slice buffer */
global_face_lengths_s_size = (global_connect_s_size / 3) + 1;
global_face_lengths_s_size_prev = global_face_lengths_s_size;
BFT_MALLOC(global_face_lengths_s, global_face_lengths_s_size, fvm_gnum_t);
/* Build local polyhedron indexes and connectivity information */
BFT_MALLOC(cell_vtx_idx,
section->n_elements + 1,
fvm_lnum_t);
BFT_MALLOC(face_lengths,
section->face_index[section->n_elements],
fvm_lnum_t);
j_s = 0;
l = 0;
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]);
face_lengths[l++] = face_length;
cell_length += face_length;
}
cell_vtx_idx[i+1] = cell_vtx_idx[i] + cell_length;
}
BFT_MALLOC(cell_connect,
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_connect[l++] = section->vertex_num[k];
}
else {
face_id = -section->face_num[j] - 1;
k = section->vertex_index[face_id] ;
cell_connect[l++] = section->vertex_num[k];
for (k = section->vertex_index[face_id+1] - 1 ;
k > section->vertex_index[face_id] ;
k--)
cell_connect[l++] = section->vertex_num[k];
}
}
}
/* Export by 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) {
/* Gather cell->vertices index */
fvm_gather_slice_index(cell_vtx_idx,
global_cell_vtx_idx_s,
section->global_element_num,
comm,
polyhedra_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_cell_vtx_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 cell->vertices connectivity */
fvm_gather_indexed_numbers(cell_vtx_idx,
cell_connect,
global_connect_s,
global_vertex_num,
section->global_element_num,
comm,
global_cell_vtx_idx_s,
polyhedra_slice);
/* Now build the slice index for number of vertices per face */
fvm_gather_slice_index(section->face_index,
global_cell_face_idx_s,
section->global_element_num,
comm,
polyhedra_slice);
/* If the face_lengths slice buffer is too small, allocate a
larger one; in this case, we may as well keep it for all slices */
if (rank == 0) {
global_face_lengths_s_size =
FVM_MAX(global_face_lengths_s_size,
global_cell_face_idx_s[global_num_end - global_num_start]);
}
MPI_Bcast(&global_face_lengths_s_size, 1, FVM_MPI_GNUM, 0, comm);
if (global_face_lengths_s_size_prev < global_face_lengths_s_size) {
BFT_REALLOC(global_face_lengths_s,
global_face_lengths_s_size, fvm_gnum_t);
global_face_lengths_s_size_prev = global_face_lengths_s_size;
}
/* Now gather the number of vertices per face */
fvm_gather_indexed_numbers(section->face_index,
face_lengths,
global_face_lengths_s,
NULL,
section->global_element_num,
comm,
global_cell_face_idx_s,
polyhedra_slice);
/* Do all printing for cells on rank 0 */
if (rank == 0) {
int line_values;
char str_num_cell[16];
char str_num_face[16];
char str_idx_cell[32];
char str_idx_face[32];
/* Print cell connectivity */
k_s = 0;
/* Loop on polyhedral cells in slice */
for (i = 0, i_s = global_num_start ; i_s < global_num_end ; i++, i_s++) {
/* Loop on cell faces */
for (j = 0, j_s = global_cell_face_idx_s[i] ;
j_s < global_cell_face_idx_s[i+1] ;
j++, j_s++) {
/* Print cell and face numbers and indexes */
if (j_s == global_cell_face_idx_s[i]) {
sprintf(str_num_cell, "%12lu", (unsigned long)i_s);
sprintf(str_idx_cell, "[%lu] :",
(unsigned long)(j_s + global_cell_face_idx_shift + 1));
}
else {
str_num_cell[0] = '\0';
str_idx_cell[0] = '\0';
}
sprintf(str_num_face, "%5u", (unsigned)(j+1));
sprintf(str_idx_face, "[%lu] :",
(unsigned long)(k_s + global_cell_vtx_idx_shift + 1));
bft_file_printf(f, "%12s %14s %5s %14s",
str_num_cell, str_idx_cell,
str_num_face, str_idx_face);
/* Print face vertex numbers */
line_values = 0;
for (k = 0 ; k < (fvm_lnum_t)global_face_lengths_s[j_s] ; k++) {
if (line_values > 2) {
line_values = 0;
bft_file_printf(f,"\n%48s", "");
}
bft_file_printf(f, " %12lu",
(unsigned long)global_connect_s[k_s++]);
line_values++;
}
bft_file_printf(f, "\n");
} /* End of loop on cell faces */
assert(k_s == global_cell_vtx_idx_s[i+1]);
} /* End of loop on polyhedral cells in slice */
if (global_num_end > n_g_polyhedra) {
str_num_cell[0] = '\0';
sprintf(str_idx_cell, "[%lu] :",
(unsigned long)(j_s + global_cell_face_idx_shift + 1));
str_num_face[0] = '\0';
sprintf(str_idx_face, "[%lu] :",
(unsigned long)(k_s + global_cell_vtx_idx_shift + 1));
bft_file_printf(f, "%12s %14s %5s %14s",
str_num_cell, str_idx_cell,
str_num_face, str_idx_face);
}
/* Update shift for conversion from slice index to true index */
global_cell_vtx_idx_shift
+= global_cell_vtx_idx_s[global_num_end - global_num_start];
global_cell_face_idx_shift
+= global_cell_face_idx_s[global_num_end - global_num_start];
} /* End of printing for rank 0 for this slice */
}
fvm_gather_slice_destroy(polyhedra_slice);
/* Free memory */
BFT_FREE(global_cell_face_idx_s);
BFT_FREE(global_cell_vtx_idx_s);
BFT_FREE(global_face_lengths_s);
BFT_FREE(cell_vtx_idx);
BFT_FREE(face_lengths);
BFT_FREE(cell_connect);
if (global_connect_s != global_connect_s_caller)
BFT_FREE(global_connect_s);
}
#endif /* defined(FVM_HAVE_MPI) */
/*----------------------------------------------------------------------------
* Write polyhedra from a nodal mesh to a text file in serial mode
*
* parameters:
* section <-- pointer to nodal mesh section structure
* f <-- pointer to associated file
*----------------------------------------------------------------------------*/
static void
_export_nodal_polyhedra_l(const fvm_nodal_section_t *const section,
bft_file_t *const f)
{
fvm_lnum_t i, j, k, l;
fvm_lnum_t connect_length, face_length;
fvm_lnum_t face_id;
int face_sgn, line_values;
char str_num_cell[16];
char str_num_face[16];
char str_idx_cell[32];
char str_idx_face[32];
/* Print cell connectivity directly, without using extra buffers */
connect_length = 0;
j = 0;
/* Loop on all polyhedral cells */
for (i = 0 ; i < section->n_elements ; i++) {
/* Loop on cell faces */
for (j = section->face_index[i] ;
j < section->face_index[i+1] ;
j++) {
/* Print cell and face numbers and indexes */
if (j == section->face_index[i]) {
sprintf(str_num_cell, "%12lu", (unsigned long)(i+1));
sprintf(str_idx_cell, "[%lu] :",
(unsigned long)(section->face_index[i] + 1));
}
else {
str_num_cell[0] = '\0';
str_idx_cell[0] = '\0';
}
sprintf(str_num_face, "%5u", (unsigned)(j-section->face_index[i]+1));
sprintf(str_idx_face, "[%lu] :", (unsigned long)(connect_length+1));
bft_file_printf(f, "%12s %14s %5s %14s",
str_num_cell, str_idx_cell,
str_num_face, str_idx_face);
/* 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;
}
line_values = 0;
face_length = ( section->vertex_index[face_id+1]
- section->vertex_index[face_id]);
connect_length += face_length;
for (k = 0 ; k < face_length ; k++) {
l = section->vertex_index[face_id]
+ (face_length + (k*face_sgn))%face_length;
if (line_values > 2) {
line_values = 0;
bft_file_printf(f,"\n%48s", "");
}
bft_file_printf(f, " %12lu",
(unsigned long)section->vertex_num[l]);
line_values++;
}
bft_file_printf(f, "\n");
} /* End of loop on cell faces */
} /* End of loop on polyhedral cells */
str_num_cell[0] = '\0';
sprintf(str_idx_cell, "[%lu] :", (unsigned long)(j + 1));
str_num_face[0] = '\0';
sprintf(str_idx_face, "[%lu] :", (unsigned long)(connect_length+1));
bft_file_printf(f, "%12s %14s %5s %14s",
str_num_cell, str_idx_cell,
str_num_face, str_idx_face);
}
#if defined(FVM_HAVE_MPI)
/*----------------------------------------------------------------------------
* Write polygons from a nodal mesh to a text file in parallel mode
*
* parameters:
* section <-- pointer to nodal mesh section structure
* global_vertex_num <-- pointer to vertex global numbering
* comm <-- associated MPI communicator
* rank <-- rank in 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
* f <-- pointer to associated file
*----------------------------------------------------------------------------*/
static void
_export_nodal_polygons_g(const fvm_nodal_section_t *const section,
const fvm_io_num_t *const global_vertex_num,
MPI_Comm comm,
const int rank,
const fvm_gnum_t global_s_size,
const fvm_gnum_t global_connect_s_size_caller,
fvm_gnum_t global_connect_s_caller[],
bft_file_t *const f)
{
fvm_lnum_t i, j;
fvm_gnum_t i_s, j_s;
fvm_gnum_t global_num_start;
fvm_gnum_t global_num_end;
fvm_gnum_t global_idx_shift = 0 ;
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 *polygons_slice = NULL;
const fvm_gnum_t n_g_polygons = fvm_io_num_get_global_count
(section->global_element_num);
/* Allocate memory for additionnal indexes */
BFT_MALLOC(global_idx_s, global_s_size + 1, fvm_gnum_t);
/* Export by slices */
polygons_slice = fvm_gather_slice_create(section->global_element_num,
global_s_size,
comm);
while (fvm_gather_slice_advance(polygons_slice,
&global_num_start,
&global_num_end) == 0) {
/* Gather face->vertices index */
fvm_gather_slice_index(section->vertex_index,
global_idx_s,
section->global_element_num,
comm,
polygons_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,
polygons_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 face->vertices connectivity */
fvm_gather_indexed_numbers(section->vertex_index,
section->vertex_num,
global_connect_s,
global_vertex_num,
section->global_element_num,
comm,
global_idx_s,
polygons_slice);
/* Do all printing for faces on rank 0 */
if (rank == 0) {
int line_values;
char str_num_face[16];
char str_idx_face[32];
/* Print face connectivity */
/* Loop on polygonal faces in slice */
for (i = 0, i_s = global_num_start ; i_s < global_num_end ; i++, i_s++) {
/* Print cell and face numbers and indexes */
sprintf(str_num_face, "%12lu", (unsigned long)i_s);
sprintf(str_idx_face, "[%lu] :",
(unsigned long)(global_idx_s[i] + global_idx_shift + 1));
bft_file_printf(f, "%12s %14s",
str_num_face, str_idx_face);
/* Print face vertex numbers */
line_values = 0;
for (j = 0, j_s = global_idx_s[i] ;
j_s < global_idx_s[i+1] ;
j++, j_s++) {
if (line_values > 2) {
line_values = 0;
bft_file_printf(f,"\n%27s", "");
}
bft_file_printf(f, " %12lu",
(unsigned long)global_connect_s[j_s]);
line_values++;
}
bft_file_printf(f, "\n");
} /* End of loop on polyhedral cells in slice */
if (global_num_end > n_g_polygons) {
str_num_face[0] = '\0';
sprintf(str_idx_face, "[%lu] :",
(unsigned long)(global_idx_s[i] + global_idx_shift + 1));
bft_file_printf(f, "%12s %14s",
str_num_face, str_idx_face);
}
/* Update shift for conversion from slice index to true index */
global_idx_shift
+= global_idx_s[global_num_end - global_num_start + 1];
} /* End of printing for rank 0 for this slice */
}
fvm_gather_slice_destroy(polygons_slice);
/* Free memory */
BFT_FREE(global_idx_s);
if (global_connect_s != global_connect_s_caller)
BFT_FREE(global_connect_s);
}
#endif /* defined(FVM_HAVE_MPI) */
/*----------------------------------------------------------------------------
* Write polygons from a nodal mesh to a text file in serial mode
*
* parameters:
* section <-- pointer to nodal mesh section structure
* f <-- pointer to associated file
*----------------------------------------------------------------------------*/
static void
_export_nodal_polygons_l(const fvm_nodal_section_t *const section,
bft_file_t *const f)
{
fvm_lnum_t i, j;
int line_values;
char str_num_face[16];
char str_idx_face[32];
/* Print face connectivity directly, without using extra buffers */
j = 0; /* Initialize here in case section->n_elements = 0 */
/* Loop on all polygonal faces */
for (i = 0 ; i < section->n_elements ; i++) {
/* Print face numbers and indexes */
sprintf(str_num_face, "%12lu", (unsigned long)(i+1));
sprintf(str_idx_face, "[%lu] :",
(unsigned long)(section->vertex_index[i] + 1));
bft_file_printf(f, "%12s %14s",
str_num_face, str_idx_face);
/* Print face vertex numbers */
line_values = 0;
for (j = section->vertex_index[i] ;
j < section->vertex_index[i+1] ;
j++) {
if (line_values > 2) {
line_values = 0;
bft_file_printf(f,"\n%27s", "");
}
bft_file_printf(f, " %12lu",
(unsigned long)section->vertex_num[j]);
line_values++;
}
bft_file_printf(f, "\n");
} /* End of loop on polygonal faces */
str_num_face[0] = '\0';
sprintf(str_idx_face, "[%lu] :", (unsigned long)(j + 1));
bft_file_printf(f, "%12s %14s",
str_num_face, str_idx_face);
}
/*============================================================================
* Public function definitions
*============================================================================*/
/*----------------------------------------------------------------------------
* Initialize FVM to text file writer.
*
* parameters:
* name <-- base output case name.
* options <-- whitespace separated, lowercase options list
* comm <-- associated MPI communicator.
*
* returns:
* pointer to opaque text file writer structure.
*----------------------------------------------------------------------------*/
#if defined(FVM_HAVE_MPI)
void *
fvm_to_text_init_writer(const char *const name,
const char *const path,
const char *const options,
const fvm_writer_time_dep_t time_dependency,
const MPI_Comm comm)
#else
void *
fvm_to_text_init_writer(const char *const name,
const char *const path,
const char *const options,
const fvm_writer_time_dep_t time_dependency)
#endif
{
fvm_to_text_writer_t *this_writer = NULL;
int rank = 0;
/* Initialize writer */
BFT_MALLOC(this_writer, 1, fvm_to_text_writer_t);
this_writer->time_dependency = time_dependency;
this_writer->rank = 0;
this_writer->n_ranks = 1;
#if defined(FVM_HAVE_MPI)
{
int mpi_flag, n_ranks;
MPI_Initialized(&mpi_flag);
if (mpi_flag) {
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) */
if (rank == 0) {
char * file_name;
int path_len = 0;
const char extension[] = ".txt";
if (path != NULL)
path_len = strlen(path);
BFT_MALLOC(file_name,
path_len + strlen(name) + strlen(extension) + 1,
char);
if (path != NULL)
strcpy(file_name, path);
else
file_name[0] = '\0';
strcat(file_name, name);
strcat(file_name, extension);
this_writer->file = bft_file_open(file_name,
BFT_FILE_MODE_WRITE,
BFT_FILE_TYPE_TEXT);
BFT_FREE(file_name);
}
else
this_writer->file = NULL;
/* Parse options */
if (rank == 0 && 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 + 1;
bft_file_printf(this_writer->file,
_("Option: %*s\n"), l_opt, options + i1);
i1 = i2;
}
}
/* Return writer */
return this_writer;
}
/*----------------------------------------------------------------------------
* Finalize FVM to text file writer.
*
* parameters:
* this_writer_p <-- pointer to opaque text file writer structure
*
* returns:
* NULL pointer
*----------------------------------------------------------------------------*/
void *
fvm_to_text_finalize_writer(void *this_writer_p)
{
fvm_to_text_writer_t *this_writer = (fvm_to_text_writer_t *)this_writer_p;
if (this_writer->file != NULL)
this_writer->file = bft_file_free(this_writer->file);
BFT_FREE(this_writer);
return NULL;
}
/*----------------------------------------------------------------------------
* Write nodal mesh to a text file
*
* parameters:
* this_writer_p <-- pointer to associated writer
* mesh <-- pointer to nodal mesh structure that should be written
*----------------------------------------------------------------------------*/
void
fvm_to_text_export_nodal(void *const this_writer_p,
const fvm_nodal_t *const mesh)
{
int section_id;
fvm_lnum_t i, j;
fvm_to_text_writer_t *this_writer = (fvm_to_text_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 = 0;
fvm_gnum_t n_g_edges = 0;
fvm_gnum_t n_g_faces = 0;
fvm_gnum_t n_g_cells = 0;
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 */
/*----------------*/
f = this_writer->file;
/* Buffer sizes required in parallel mode, global sizes always required */
/*----------------------------------------------------------------------*/
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);
for (section_id = 0 ; section_id < mesh->n_sections ; section_id++) {
const fvm_nodal_section_t *const section = mesh->sections[section_id];
switch(section->entity_dim) {
case 1:
n_g_edges += n_g_elements_section[section_id];
break;
case 2:
n_g_faces += n_g_elements_section[section_id];
break;
case 3:
n_g_cells += n_g_elements_section[section_id];
break;
default:
assert(0);
}
}
/* Global indicators */
/*--------------------*/
if (rank == 0) {
if (mesh->name != NULL)
bft_file_printf(f, _("\n"
"Mesh name: %s\n"),
mesh->name);
else
bft_file_printf(f, _("\n"
"Unnamed mesh\n"));
bft_file_printf(f, _("\n"
"Mesh dimension: %d\n"
"Number of domains: %d\n"
"Number of sections: %d\n"),
mesh->dim, mesh->n_doms, mesh->n_sections);
bft_file_printf(f, _("\n"
"Number of cells: %d\n"
"Number of faces: %d\n"
"Number of edges: %d\n"
"Number of vertices: %d\n"),
n_g_cells,
n_g_faces,
n_g_edges,
n_g_vertices);
}
/* Vertex coordinates */
/*--------------------*/
{
const int stride = mesh->dim;
const double *local_coords;
double *coords_tmp = NULL;
if (mesh->parent_vertex_num != NULL) {
BFT_MALLOC(coords_tmp, stride * mesh->n_vertices, double);
for (i = 0 ; i < mesh->n_vertices ; i++) {
for (j = 0 ; j < stride ; j++)
coords_tmp[i*stride + j]
= mesh->vertex_coords[(mesh->parent_vertex_num[i]-1)*stride + j];
}
local_coords = coords_tmp;
}
else
local_coords = mesh->vertex_coords;
if (rank == 0)
bft_file_printf(f, _("\nVertex coordinates:\n\n"));
/* loop on slices in parallel mode, use whole array in serial mode */
#if defined(FVM_HAVE_MPI)
if (n_ranks > 1) { /* start of output in parallel mode */
fvm_gnum_t global_num_start = 1;
fvm_gnum_t global_num_end = 0;
fvm_gather_slice_t *vertices_slice = NULL;
double *global_coords_s = NULL;
BFT_MALLOC(global_coords_s, global_s_size * stride, double);
vertices_slice = fvm_gather_slice_create(mesh->global_vertex_num,
global_s_size,
comm);
while (fvm_gather_slice_advance(vertices_slice,
&global_num_start,
&global_num_end) == 0) {
fvm_gather_array(local_coords,
global_coords_s,
MPI_DOUBLE,
(size_t)stride,
mesh->global_vertex_num,
comm,
vertices_slice);
if (rank == 0)
_write_slice_vector(stride,
global_num_start,
global_num_end,
global_coords_s,
f);
}
fvm_gather_slice_destroy(vertices_slice);
BFT_FREE(global_coords_s);
} /* end of output in parallel mode */
#endif /* defined(FVM_HAVE_MPI) */
if (n_ranks == 1) { /* start of output in serial mode */
_write_slice_vector(stride,
1,
(fvm_gnum_t)(mesh->n_vertices + 1),
local_coords,
f);
} /* end of output in serial mode */
if (coords_tmp != NULL)
BFT_FREE(coords_tmp);
}
/* 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
/* Section connectivity */
/*----------------------*/
for (section_id = 0 ; section_id < mesh->n_sections ; section_id++) {
const fvm_nodal_section_t *const section = mesh->sections[section_id];
if (rank == 0)
bft_file_printf(f, _("\nSection: %s\n"
" Number of elements: %lu\n\n"),
_(fvm_elements_type_name[section->type]),
(unsigned long)(n_g_elements_section[section_id]));
/* 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,
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,
f);
} /* end of output in serial mode */
} /* end of output for strided element types */
/* Output for polygons */
/*---------------------*/
else if (section->type == FVM_FACE_POLY) {
#if defined(FVM_HAVE_MPI)
/* output in parallel mode */
if (n_ranks > 1) {
_export_nodal_polygons_g(section,
mesh->global_vertex_num,
comm,
rank,
global_s_size,
global_connect_s_size,
global_connect_s,
f);
}
#endif /* defined(FVM_HAVE_MPI) */
if (n_ranks == 1)
_export_nodal_polygons_l(section, f);
}
/* Output for polyhedra */
/*----------------------*/
else if (section->type == FVM_CELL_POLY) {
#if defined(FVM_HAVE_MPI)
/* output in parallel mode */
if (n_ranks > 1) {
_export_nodal_polyhedra_g(section,
mesh->global_vertex_num,
comm,
rank,
global_s_size,
global_connect_s_size,
global_connect_s,
f);
}
#endif /* defined(FVM_HAVE_MPI) */
if (n_ranks == 1)
_export_nodal_polyhedra_l(section, f);
}
} /* End of loop on sections */
/* Free buffers */
/*--------------*/
BFT_FREE(n_g_elements_section);
/* 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 dump file */
/*-----------------*/
if (rank == 0)
bft_file_flush(f);
}
/*----------------------------------------------------------------------------*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
syntax highlighted by Code2HTML, v. 0.9.1