PLUTO
write_vtk.c
Go to the documentation of this file.
1 /* ///////////////////////////////////////////////////////////////////// */
2 /*!
3  \file
4  \brief Write data in VTK format.
5 
6  Collection of basic functions to write VTK files using the
7  simple legacy format.
8  Files can be written in serial or parallel mode and consists of the
9  basic five parts :
10 
11  -# File version and identifier
12  -# Header consisting of a string
13  -# File format
14  -# Dataset structure: describes the gwometry and topology of the
15  dataset.
16  -# Dataset attributes. This section is used to write the actual binary
17  data as a vector or scalar data.
18 
19  The mesh topology and the variable datasets are written using single
20  precision (4 bytes) binary format.
21  VTK file are usually written following big endian order.
22  Therefore, we swap endianity only if local architecture has little
23  endian ordering.
24 
25  The WriteVTK_Header() function provides the basic functionality for
26  steps 1, 2, 3 and 4. Only processor 0 does the actual writing.
27  For cartesian/cylindrical geometries the default grid topology is
28  "RECTILINEAR_GRIDS" whereas for polar/spherical we employ
29  "STRUCTURED_GRID" to provide a convenient mapping to a cartesian mesh.\n
30  <b> Note for 2D datasets</b>: in order to produce a strictly 2D
31  dataset we always set the third coordinate (x3) to zero.
32  For this reason, in 2D spherical cordinates we swap the role of the
33  "y" and "z" coordinates.
34 
35  The WriteVTK_Vector() is fully parallel and is used to write data with
36  the vector attribute (by default these include velocity and magnetic
37  fields).
38 
39  The WriteVTK_Scalar() is fully parallel and is used to write data with
40  the scalar attribute (by default these include density, pressure, tracer
41  and user-defined variables).
42 
43  \b Reference
44 
45  http://www.vtk.org/VTK/img/file-formats.pdf
46 
47  \author A. Mignone (mignone@ph.unito.it)
48  \date Aug 17, 2015
49 */
50 /* ///////////////////////////////////////////////////////////////////// */
51 #include "pluto.h"
52 
53 #define RECTILINEAR_GRID 14
54 #define STRUCTURED_GRID 35
55 
56 #ifndef VTK_FORMAT
57  #if GEOMETRY == CARTESIAN || GEOMETRY == CYLINDRICAL
58  #define VTK_FORMAT RECTILINEAR_GRID
59  #else
60  #define VTK_FORMAT STRUCTURED_GRID
61  #endif
62 #endif
63 
64 #ifndef VTK_TIME_INFO /* Enable this keyword only if you're using */
65  #define VTK_TIME_INFO NO /* VisIt to display data results */
66 #endif
67 
68 /* ---------------------------------------------------------
69  The following macros are specific to this file only
70  and are used to ease up serial/parallel implementation
71  for writing strings and real arrays
72  --------------------------------------------------------- */
73 
74 #ifdef PARALLEL
75  #define VTK_HEADER_WRITE_STRING(header) \
76  AL_Write_header (header, strlen(header), MPI_CHAR, SZ_Float_Vect);
77  #define VTK_HEADER_WRITE_FLTARR(arr, nelem) \
78  AL_Write_header (arr, nelem, MPI_FLOAT, SZ_Float_Vect);
79  #define VTK_HEADER_WRITE_DBLARR(arr, nelem) \
80  AL_Write_header (arr, nelem, MPI_DOUBLE, SZ_Float_Vect);
81 #else
82  #define VTK_HEADER_WRITE_STRING(header) \
83  fprintf (fvtk,header);
84  #define VTK_HEADER_WRITE_FLTARR(arr,nelem) \
85  fwrite(arr, sizeof(float), nelem, fvtk);
86  #define VTK_HEADER_WRITE_DBLARR(arr,nelem) \
87  fwrite(arr, sizeof(double), nelem, fvtk);
88 #endif
89 
90 /* ********************************************************************* */
91 void WriteVTK_Header (FILE *fvtk, Grid *grid)
92 /*!
93  * Write VTK header in parallel or serial mode.
94  * In parallel mode only processor 0 does the actual writing
95  * (see al_io.c/AL_Write_header).
96  *
97  *
98  * \param [in] fvtk pointer to file
99  * \param [in] grid pointer to an array of Grid structures
100  *
101  * \todo Write the grid using several processors.
102  *********************************************************************** */
103 {
104  int i, j, k;
105  int nx1, nx2, nx3;
106  char header[1024];
107  float x1, x2, x3;
108  static float ***node_coord, *xnode, *ynode, *znode;
109 
110 /* ------------------------------------------------
111  get global dimensions
112  ------------------------------------------------ */
113 
114  nx1 = grid[IDIR].gend + 1 - grid[IDIR].nghost;
115  nx2 = grid[JDIR].gend + 1 - grid[JDIR].nghost;
116  nx3 = grid[KDIR].gend + 1 - grid[KDIR].nghost;
117 
118 /* -------------------------------------------------------------
119  Allocate memory and define node coordinates only once.
120  ------------------------------------------------------------- */
121 
122  if (node_coord == NULL){
123  node_coord = ARRAY_3D(nx2 + JOFFSET, nx1 + IOFFSET, 3, float);
124 
125  #if VTK_FORMAT == RECTILINEAR_GRID
126  xnode = ARRAY_1D(nx1 + IOFFSET, float);
127  ynode = ARRAY_1D(nx2 + JOFFSET, float);
128  znode = ARRAY_1D(nx3 + KOFFSET, float);
129 
130  for (i = 0; i < nx1 + IOFFSET; i++){
131  x1 = (float)(grid[IDIR].xl_glob[i+IBEG]);
132  if (IsLittleEndian()) SWAP_VAR(x1);
133  xnode[i] = x1;
134  }
135  for (j = 0; j < nx2 + JOFFSET; j++){
136  x2 = (float)(grid[JDIR].xl_glob[j+JBEG]);
137  if (IsLittleEndian()) SWAP_VAR(x2);
138  ynode[j] = x2;
139  }
140  for (k = 0; k < nx3 + KOFFSET; k++){
141  x3 = (float)(grid[KDIR].xl_glob[k+KBEG]);
142  if (IsLittleEndian()) SWAP_VAR(x3);
143  #if DIMENSIONS == 2
144  znode[k] = 0.0;
145  #else
146  znode[k] = x3;
147  #endif
148  }
149  #endif
150  }
151 
152 /* ----------------------------------------------------------
153  Part I, II, III:
154  Write file header on string "header"
155  ---------------------------------------------------------- */
156 
157  sprintf(header,"# vtk DataFile Version 2.0\n");
158  sprintf(header+strlen(header),"PLUTO %s VTK Data\n",PLUTO_VERSION);
159  sprintf(header+strlen(header),"BINARY\n");
160  #if VTK_FORMAT == RECTILINEAR_GRID
161  sprintf(header+strlen(header),"DATASET %s\n","RECTILINEAR_GRID");
162  #elif VTK_FORMAT == STRUCTURED_GRID
163  sprintf(header+strlen(header),"DATASET %s\n","STRUCTURED_GRID");
164  #endif
165 
166  VTK_HEADER_WRITE_STRING(header);
167 
168  /* -- generate time info -- */
169 
170  #if VTK_TIME_INFO == YES
171  sprintf (header,"FIELD FieldData 1\n");
172  sprintf (header+strlen(header),"TIME 1 1 double\n");
173  double tt=g_time;
174  if (IsLittleEndian()) SWAP_VAR(tt);
175  VTK_HEADER_WRITE_STRING(header);
176  VTK_HEADER_WRITE_DBLARR(&tt, 1);
178 
179  #endif /* VTK_TIME_INFO */
180 
181  sprintf(header,"DIMENSIONS %d %d %d\n",
182  nx1 + IOFFSET, nx2 + JOFFSET, nx3 + KOFFSET);
183  VTK_HEADER_WRITE_STRING(header);
184 
185 #if VTK_FORMAT == RECTILINEAR_GRID
186 
187  /* -- reset header string and keep going -- */
188 
189  sprintf(header,"X_COORDINATES %d float\n", nx1 + IOFFSET);
190  VTK_HEADER_WRITE_STRING(header);
191  VTK_HEADER_WRITE_FLTARR(xnode, nx1 + IOFFSET);
192 
193  sprintf(header,"\nY_COORDINATES %d float\n", nx2 + JOFFSET);
194  VTK_HEADER_WRITE_STRING(header);
195  VTK_HEADER_WRITE_FLTARR(ynode, nx2 + JOFFSET);
196 
197  sprintf(header,"\nZ_COORDINATES %d float\n", nx3 + KOFFSET);
198  VTK_HEADER_WRITE_STRING(header);
199  VTK_HEADER_WRITE_FLTARR(znode, nx3 + KOFFSET);
200 
201  sprintf (header,"\nCELL_DATA %d\n", nx1*nx2*nx3);
202  VTK_HEADER_WRITE_STRING (header);
203 
204 #elif VTK_FORMAT == STRUCTURED_GRID
205 
206  sprintf(header,"POINTS %d float\n", (nx1+IOFFSET)*(nx2+JOFFSET)*(nx3+KOFFSET));
207  VTK_HEADER_WRITE_STRING(header);
208 
209 /* ---------------------------------------------------------------
210  Part IV: (structured) grid information
211  --------------------------------------------------------------- */
212 
213  x1 = x2 = x3 = 0.0;
214  for (k = 0; k < nx3 + KOFFSET; k++){
215  for (j = 0; j < nx2 + JOFFSET; j++){
216  for (i = 0; i < nx1 + IOFFSET; i++){
217  D_EXPAND(x1 = grid[IDIR].xl_glob[IBEG + i]; ,
218  x2 = grid[JDIR].xl_glob[JBEG + j]; ,
219  x3 = grid[KDIR].xl_glob[KBEG + k];)
220 
221  #if (GEOMETRY == CARTESIAN) || (GEOMETRY == CYLINDRICAL)
222  node_coord[j][i][0] = x1;
223  node_coord[j][i][1] = x2;
224  node_coord[j][i][2] = x3;
225  #elif GEOMETRY == POLAR
226  node_coord[j][i][0] = x1*cos(x2);
227  node_coord[j][i][1] = x1*sin(x2);
228  node_coord[j][i][2] = x3;
229  #elif GEOMETRY == SPHERICAL
230  #if DIMENSIONS == 2
231  node_coord[j][i][0] = x1*sin(x2);
232  node_coord[j][i][1] = x1*cos(x2);
233  node_coord[j][i][2] = 0.0;
234  #elif DIMENSIONS == 3
235  node_coord[j][i][0] = x1*sin(x2)*cos(x3);
236  node_coord[j][i][1] = x1*sin(x2)*sin(x3);
237  node_coord[j][i][2] = x1*cos(x2);
238  #endif
239  #endif
240 
241  if (IsLittleEndian()){
242  SWAP_VAR(node_coord[j][i][0]);
243  SWAP_VAR(node_coord[j][i][1]);
244  SWAP_VAR(node_coord[j][i][2]);
245  }
246  }}
247  VTK_HEADER_WRITE_FLTARR(node_coord[0][0],3*(nx1+IOFFSET)*(nx2+JOFFSET));
248  }
249 
250  sprintf (header,"\nCELL_DATA %d\n", nx1*nx2*nx3);
251  VTK_HEADER_WRITE_STRING(header);
252 
253 #endif
254 }
255 #undef STRUCTERED_GRID
256 #undef RECTILINEAR_GRID
257 
258 /* ********************************************************************* */
259 void WriteVTK_Vector (FILE *fvtk, Data_Arr V, double unit,
260  char *var_name, Grid *grid)
261 /*!
262  * Write VTK vector field data.
263  * This is enabled only when VTK_VECTOR_DUMP is set to \c YES.
264  * For generality purposes, vectors are written always with 3
265  * components, even when there're only 2 being used.
266  *
267  * The following Maple script has been used to find vector
268  * components from cyl/sph to cartesian:
269  *
270  * \code
271  restart;
272  with(linalg);
273  Acyl := matrix (3,3,[ cos(phi), sin(phi), 0,
274  -sin(phi), cos(phi), 0,
275  0 , 0 , 1]);
276  Asph := matrix (3,3,[ sin(theta)*cos(phi), sin(theta)*sin(phi), cos(theta),
277  cos(theta)*cos(phi), cos(theta)*sin(phi), -sin(theta),
278  -sin(phi) , cos(phi) , 0]);
279  Bcyl := simplify(inverse(Acyl));
280  Bsph := simplify(inverse(Asph));
281  * \endcode
282  *
283  * \param [in] fvtk pointer to file
284  * \param [in] V a 4D array [nv][k][j][i] containing the vector
285  * components (nv) defined at cell centers (k,j,i).
286  * The index nv = 0 marks the vector first component.
287  * \param [in] unit the corresponding cgs unit (if specified, 1 otherwise)
288  * \param [in] var_name the variable name appearing in the VTK file
289  * \param [in] grid pointer to an array of Grid structures
290  *********************************************************************** */
291 {
292  int i,j,k;
293  int vel_field, mag_field;
294  char header[512];
295  static Float_Vect ***vect3D;
296  double v[3], x1, x2, x3;
297 
298  if (vect3D == NULL){
300  }
301 
302 /* --------------------------------------------------------
303  Write VTK vector fields
304  -------------------------------------------------------- */
305 
306  v[0] = v[1] = v[2] = 0.0;
307  x1 = x2 = x3 = 0.0;
308 
309  vel_field = (strcmp(var_name,"vx1") == 0);
310  mag_field = (strcmp(var_name,"bx1") == 0);
311  if (vel_field || mag_field) {
312  DOM_LOOP(k,j,i){
313  D_EXPAND(v[0] = V[0][k][j][i]; x1 = grid[IDIR].x[i]; ,
314  v[1] = V[1][k][j][i]; x2 = grid[JDIR].x[j]; ,
315  v[2] = V[2][k][j][i]; x3 = grid[KDIR].x[k];)
316 
317  VectorCartesianComponents(v, x1, x2, x3);
318  vect3D[k][j][i].v1 = (float)v[0]*unit;
319  vect3D[k][j][i].v2 = (float)v[1]*unit;
320  vect3D[k][j][i].v3 = (float)v[2]*unit;
321 
322  if (IsLittleEndian()){
323  SWAP_VAR(vect3D[k][j][i].v1);
324  SWAP_VAR(vect3D[k][j][i].v2);
325  SWAP_VAR(vect3D[k][j][i].v3);
326  }
327 
328  } /* endfor DOM_LOOP(k,j,i) */
329 
330  if (vel_field)
331  sprintf (header,"\nVECTORS %dD_Velocity_Field float\n", DIMENSIONS);
332  else
333  sprintf (header,"\nVECTORS %dD_Magnetic_Field float\n", DIMENSIONS);
334 
335  VTK_HEADER_WRITE_STRING(header);
336  WriteBinaryArray (vect3D[0][0], sizeof(Float_Vect), SZ_Float_Vect, fvtk, -1);
337  }
338 }
339 
340 /* ********************************************************************* */
341 void WriteVTK_Scalar (FILE *fvtk, double ***V, double unit,
342  char *var_name, Grid *grid)
343 /*!
344  * Write VTK scalar field.
345  *
346  * \param [in] fvtk pointer to file (handle)
347  * \param [in] V pointer to 3D data array
348  * \param [in] unit the corresponding cgs unit (if specified, 1 otherwise)
349  * \param [in] var_name the variable name appearing in the VTK file
350  * \param [in] grid pointer to an array of Grid structures
351  *********************************************************************** */
352 {
353  int i,j,k;
354  char header[512];
355  float ***Vflt;
356 
357  sprintf (header,"\nSCALARS %s float\n", var_name);
358  sprintf (header,"%sLOOKUP_TABLE default\n",header);
359 
360  #ifdef PARALLEL
361  MPI_Barrier (MPI_COMM_WORLD);
362  AL_Write_header (header, strlen(header), MPI_CHAR, SZ_float);
363  #else
364  fprintf (fvtk, "%s",header);
365  #endif
366 
367  Vflt = Convert_dbl2flt(V, unit, IsLittleEndian());
368  WriteBinaryArray (Vflt[0][0], sizeof(float), SZ_float, fvtk, -1);
369 }
int AL_Write_header(void *vbuffer, int nelem, AL_Datatype type, int sz_ptr)
Definition: al_io.c:285
double **** Data_Arr
Definition: pluto.h:492
DOM_LOOP(k, j, i)
Definition: analysis.c:22
float v1
Definition: structs.h:314
int SZ_float
Definition: globals.h:27
float v2
Definition: structs.h:314
#define VTK_HEADER_WRITE_STRING(header)
Definition: write_vtk.c:82
long int NX2_TOT
Total number of zones in the X2 direction (boundaries included) for the local processor.
Definition: globals.h:57
#define VTK_HEADER_WRITE_FLTARR(arr, nelem)
Definition: write_vtk.c:84
#define PLUTO_VERSION
Definition: pluto.h:16
float v3
Definition: structs.h:314
int gend
Global end index for the global array.
Definition: structs.h:114
#define ARRAY_3D(nx, ny, nz, type)
Definition: prototypes.h:172
float *** Convert_dbl2flt(double ***Vdbl, double unit, int swap_endian)
Definition: bin_io.c:216
#define KDIR
Definition: pluto.h:195
int SZ_Float_Vect
Definition: globals.h:29
#define SWAP_VAR(x)
Definition: macros.h:115
#define IDIR
Definition: pluto.h:193
Definition: structs.h:78
long int NX3_TOT
Total number of zones in the X3 direction (boundaries included) for the local processor.
Definition: globals.h:59
int j
Definition: analysis.c:2
int IsLittleEndian(void)
Definition: tools.c:40
#define VTK_HEADER_WRITE_DBLARR(arr, nelem)
Definition: write_vtk.c:86
int nghost
Number of ghost zones.
Definition: structs.h:104
int k
Definition: analysis.c:2
double * xl_glob
Cell left interface.
Definition: structs.h:82
double * x
Definition: structs.h:80
#define GEOMETRY
Definition: definitions_01.h:4
void WriteVTK_Scalar(FILE *fvtk, double ***V, double unit, char *var_name, Grid *grid)
Definition: write_vtk.c:341
void VectorCartesianComponents(double *v, double x1, double x2, double x3)
Definition: math_misc.c:227
#define CARTESIAN
Definition: pluto.h:33
#define CYLINDRICAL
Definition: pluto.h:34
PLUTO main header file.
#define ARRAY_1D(nx, type)
Definition: prototypes.h:170
D_EXPAND(tot/[n]=(double) grid[IDIR].np_int_glob;, tot/[n]=(double) grid[JDIR].np_int_glob;, tot/[n]=(double) grid[KDIR].np_int_glob;)
Definition: analysis.c:27
int i
Definition: analysis.c:2
double g_time
The current integration time.
Definition: globals.h:117
long int KBEG
Lower grid index of the computational domain in the the X3 direction for the local processor...
Definition: globals.h:43
void WriteVTK_Vector(FILE *fvtk, Data_Arr V, double unit, char *var_name, Grid *grid)
Definition: write_vtk.c:259
#define JDIR
Definition: pluto.h:194
long int JBEG
Lower grid index of the computational domain in the the X2 direction for the local processor...
Definition: globals.h:39
void WriteBinaryArray(void *V, size_t dsize, int sz, FILE *fl, int istag)
Definition: bin_io.c:98
long int NX1_TOT
Total number of zones in the X1 direction (boundaries included) for the local processor.
Definition: globals.h:55
long int IBEG
Lower grid index of the computational domain in the the X1 direction for the local processor...
Definition: globals.h:35
#define DIMENSIONS
Definition: definitions_01.h:2
void WriteVTK_Header(FILE *fvtk, Grid *grid)
Definition: write_vtk.c:91