common_io.c 14.9 KB
Newer Older
1
2
3
4
/*******************************************************************************
 * This file is part of SWIFT.
 * Coypright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk),
 *                    Matthieu Schaller (matthieu.schaller@durham.ac.uk).
5
 *
6
7
8
9
 * This program 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 3 of the License, or
 * (at your option) any later version.
10
 *
11
12
13
14
 * This program 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.
15
 *
16
17
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 ******************************************************************************/

/* Config parameters. */
#include "../config.h"

#if defined(HAVE_HDF5)

/* Some standard headers. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <hdf5.h>
#include <math.h>
33
34
35
#ifdef WITH_MPI
#include <mpi.h>
#endif
36
37
38
39
40
41
42
43
44
45
46
47
48
49

#include "const.h"
#include "cycle.h"
#include "lock.h"
#include "task.h"
#include "part.h"
#include "space.h"
#include "scheduler.h"
#include "engine.h"
#include "error.h"
#include "kernel.h"
#include "common_io.h"

/**
50
 * @brief Converts a C data type to the HDF5 equivalent.
51
52
 *
 * This function is a trivial wrapper around the HDF5 types but allows
53
54
 * to change the exact storage types matching the code types in a transparent
 *way.
55
 */
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
hid_t hdf5Type(enum DATA_TYPE type) {
  switch (type) {
    case INT:
      return H5T_NATIVE_INT;
    case UINT:
      return H5T_NATIVE_UINT;
    case LONG:
      return H5T_NATIVE_LONG;
    case ULONG:
      return H5T_NATIVE_ULONG;
    case LONGLONG:
      return H5T_NATIVE_LLONG;
    case ULONGLONG:
      return H5T_NATIVE_ULLONG;
    case FLOAT:
      return H5T_NATIVE_FLOAT;
    case DOUBLE:
      return H5T_NATIVE_DOUBLE;
    case CHAR:
      return H5T_C_S1;
    default:
      error("Unknown type");
      return 0;
  }
80
81
82
83
84
}

/**
 * @brief Returns the memory size of the data type
 */
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
size_t sizeOfType(enum DATA_TYPE type) {
  switch (type) {
    case INT:
      return sizeof(int);
    case UINT:
      return sizeof(unsigned int);
    case LONG:
      return sizeof(long);
    case ULONG:
      return sizeof(unsigned long);
    case LONGLONG:
      return sizeof(long long);
    case ULONGLONG:
      return sizeof(unsigned long long);
    case FLOAT:
      return sizeof(float);
    case DOUBLE:
      return sizeof(double);
    case CHAR:
      return sizeof(char);
    default:
      error("Unknown type");
      return 0;
  }
109
110
111
112
113
114
115
116
117
118
119
120
}

/**
 * @brief Reads an attribute from a given HDF5 group.
 *
 * @param grp The group from which to read.
 * @param name The name of the attribute to read.
 * @param type The #DATA_TYPE of the attribute.
 * @param data (output) The attribute read from the HDF5 group.
 *
 * Calls #error() if an error occurs.
 */
121
122
void readAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data) {
  hid_t h_attr = 0, h_err = 0;
123
124

  h_attr = H5Aopen(grp, name, H5P_DEFAULT);
125
126
127
  if (h_attr < 0) {
    error("Error while opening attribute '%s'", name);
  }
128
129

  h_err = H5Aread(h_attr, hdf5Type(type), data);
130
131
132
  if (h_err < 0) {
    error("Error while reading attribute '%s'", name);
  }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147

  H5Aclose(h_attr);
}

/**
 * @brief Write an attribute to a given HDF5 group.
 *
 * @param grp The group in which to write.
 * @param name The name of the attribute to write.
 * @param type The #DATA_TYPE of the attribute.
 * @param data The attribute to write.
 * @param num The number of elements to write
 *
 * Calls #error() if an error occurs.
 */
148
149
150
151
void writeAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data,
                    int num) {
  hid_t h_space = 0, h_attr = 0, h_err = 0;
  hsize_t dim[1] = {num};
152
153

  h_space = H5Screate(H5S_SIMPLE);
154
155
156
  if (h_space < 0) {
    error("Error while creating dataspace for attribute '%s'.", name);
  }
157
158

  h_err = H5Sset_extent_simple(h_space, 1, dim, NULL);
159
160
161
  if (h_err < 0) {
    error("Error while changing dataspace shape for attribute '%s'.", name);
  }
162
163

  h_attr = H5Acreate1(grp, name, hdf5Type(type), h_space, H5P_DEFAULT);
164
165
166
  if (h_attr < 0) {
    error("Error while creating attribute '%s'.", name);
  }
167
168

  h_err = H5Awrite(h_attr, hdf5Type(type), data);
169
170
171
  if (h_err < 0) {
    error("Error while reading attribute '%s'.", name);
  }
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

  H5Sclose(h_space);
  H5Aclose(h_attr);
}

/**
 * @brief Write a string as an attribute to a given HDF5 group.
 *
 * @param grp The group in which to write.
 * @param name The name of the attribute to write.
 * @param str The string to write.
 * @param length The length of the string
 *
 * Calls #error() if an error occurs.
 */
187
188
void writeStringAttribute(hid_t grp, char* name, char* str, int length) {
  hid_t h_space = 0, h_attr = 0, h_err = 0, h_type = 0;
189
190

  h_space = H5Screate(H5S_SCALAR);
191
192
193
  if (h_space < 0) {
    error("Error while creating dataspace for attribute '%s'.", name);
  }
194
195

  h_type = H5Tcopy(H5T_C_S1);
196
197
198
  if (h_type < 0) {
    error("Error while copying datatype 'H5T_C_S1'.");
  }
199
200

  h_err = H5Tset_size(h_type, length);
201
202
203
  if (h_err < 0) {
    error("Error while resizing attribute tyep to '%i'.", length);
  }
204
205

  h_attr = H5Acreate1(grp, name, h_type, h_space, H5P_DEFAULT);
206
207
208
  if (h_attr < 0) {
    error("Error while creating attribute '%s'.", name);
  }
209

210
211
212
213
  h_err = H5Awrite(h_attr, h_type, str);
  if (h_err < 0) {
    error("Error while reading attribute '%s'.", name);
  }
214
215
216
217
218
219
220
221
222
223
224
225

  H5Tclose(h_type);
  H5Sclose(h_space);
  H5Aclose(h_attr);
}

/**
 * @brief Writes a double value as an attribute
 * @param grp The groupm in which to write
 * @param name The name of the attribute
 * @param data The value to write
 */
226
void writeAttribute_d(hid_t grp, char* name, double data) {
227
228
229
230
231
232
233
234
235
  writeAttribute(grp, name, DOUBLE, &data, 1);
}

/**
 * @brief Writes a float value as an attribute
 * @param grp The groupm in which to write
 * @param name The name of the attribute
 * @param data The value to write
 */
236
void writeAttribute_f(hid_t grp, char* name, float data) {
237
238
239
240
241
242
243
244
245
246
  writeAttribute(grp, name, FLOAT, &data, 1);
}

/**
 * @brief Writes an int value as an attribute
 * @param grp The groupm in which to write
 * @param name The name of the attribute
 * @param data The value to write
 */

247
void writeAttribute_i(hid_t grp, char* name, int data) {
248
249
250
251
252
253
254
255
256
  writeAttribute(grp, name, INT, &data, 1);
}

/**
 * @brief Writes a long value as an attribute
 * @param grp The groupm in which to write
 * @param name The name of the attribute
 * @param data The value to write
 */
257
void writeAttribute_l(hid_t grp, char* name, long data) {
258
259
260
261
262
263
264
265
266
  writeAttribute(grp, name, LONG, &data, 1);
}

/**
 * @brief Writes a string value as an attribute
 * @param grp The groupm in which to write
 * @param name The name of the attribute
 * @param str The string to write
 */
267
void writeAttribute_s(hid_t grp, char* name, char* str) {
268
269
270
  writeStringAttribute(grp, name, str, strlen(str));
}

271
272
273
274
275
/* ------------------------------------------------------------------------------------------------
 * This part writes the XMF file descriptor enabling a visualisation through
 * ParaView
 * ------------------------------------------------------------------------------------------------
 */
276
277
278
279
/**
 * @brief Writes the current model of SPH to the file
 * @param h_file The (opened) HDF5 file in which to write
 */
280
281
void writeSPHflavour(hid_t h_file) {
  hid_t h_grpsph = 0;
282
283

  h_grpsph = H5Gcreate1(h_file, "/SPH", 0);
284
  if (h_grpsph < 0) error("Error while creating SPH group");
285
286
287
288
289
290
291

  writeAttribute_f(h_grpsph, "Kernel eta", const_eta_kernel);
  writeAttribute_f(h_grpsph, "Weighted N_ngb", kernel_nwneigh);
  writeAttribute_f(h_grpsph, "Delta N_ngb", const_delta_nwneigh);
  writeAttribute_f(h_grpsph, "Hydro gamma", const_hydro_gamma);

#ifdef LEGACY_GADGET2_SPH
292
293
294
295
296
297
  writeAttribute_s(h_grpsph, "Thermal Conductivity Model",
                   "(No treatment) Legacy Gadget-2 as in Springel (2005)");
  writeAttribute_s(h_grpsph, "Viscosity Model",
                   "Legacy Gadget-2 as in Springel (2005)");
  writeAttribute_f(h_grpsph, "Viscosity alpha", const_viscosity_alpha);
  writeAttribute_f(h_grpsph, "Viscosity beta", 3.f);
298
#else
299
300
301
302
303
304
305
306
307
308
309
  writeAttribute_s(h_grpsph, "Thermal Conductivity Model",
                   "Price (2008) without switch");
  writeAttribute_f(h_grpsph, "Thermal Conductivity alpha",
                   const_conductivity_alpha);
  writeAttribute_s(h_grpsph, "Viscosity Model",
                   "Morris & Monaghan (1997), Rosswog, Davies, Thielemann & "
                   "Piran (2000) with additional Balsara (1995) switch");
  writeAttribute_f(h_grpsph, "Viscosity alpha_min", const_viscosity_alpha_min);
  writeAttribute_f(h_grpsph, "Viscosity alpha_max", const_viscosity_alpha_max);
  writeAttribute_f(h_grpsph, "Viscosity beta", 2.f);
  writeAttribute_f(h_grpsph, "Viscosity decay length", const_viscosity_length);
310
311
#endif

312
313
314
315
316
317
318
  writeAttribute_f(h_grpsph, "CFL parameter", const_cfl);
  writeAttribute_f(h_grpsph, "Maximal ln(Delta h) change over dt",
                   const_ln_max_h_change);
  writeAttribute_f(h_grpsph, "Maximal Delta h change over dt",
                   exp(const_ln_max_h_change));
  writeAttribute_f(h_grpsph, "Maximal Delta u change over dt",
                   const_max_u_change);
319
320
321
322
323
324
325
326
  writeAttribute_s(h_grpsph, "Kernel", kernel_name);

  H5Gclose(h_grpsph);
}

/**
 * @brief Writes the current Unit System
 * @param h_file The (opened) HDF5 file in which to write
327
 * @param us The UnitSystem used in the run
328
 */
329
330
void writeUnitSystem(hid_t h_file, struct UnitSystem* us) {
  hid_t h_grpunit = 0;
331
332

  h_grpunit = H5Gcreate1(h_file, "/Units", 0);
333
334
335
336
337
338
339
340
341
342
343
344
  if (h_grpunit < 0) error("Error while creating Unit System group");

  writeAttribute_d(h_grpunit, "Unit mass in cgs (U_M)",
                   getBaseUnit(us, UNIT_MASS));
  writeAttribute_d(h_grpunit, "Unit length in cgs (U_L)",
                   getBaseUnit(us, UNIT_LENGTH));
  writeAttribute_d(h_grpunit, "Unit time in cgs (U_t)",
                   getBaseUnit(us, UNIT_TIME));
  writeAttribute_d(h_grpunit, "Unit current in cgs (U_I)",
                   getBaseUnit(us, UNIT_CURRENT));
  writeAttribute_d(h_grpunit, "Unit temperature in cgs (U_T)",
                   getBaseUnit(us, UNIT_TEMPERATURE));
345
346
347
348
349
350
351
352
353
354
355

  H5Gclose(h_grpunit);
}

/**
 * @brief Prepares the XMF file for the new entry
 *
 * Creates a temporary file on the disk in order to copy the right lines.
 *
 * @todo Use a proper XML library to avoid stupid copies.
 */
356
FILE* prepareXMFfile() {
357
358
359
360
361
  char buffer[1024];

  FILE* xmfFile = fopen("output.xmf", "r");
  FILE* tempFile = fopen("output_temp.xmf", "w");

362
  if (xmfFile == NULL) error("Unable to open current XMF file.");
363

364
  if (tempFile == NULL) error("Unable to open temporary file.");
365
366
367

  /* First we make a temporary copy of the XMF file and count the lines */
  int counter = 0;
368
369
370
371
  while (fgets(buffer, 1024, xmfFile) != NULL) {
    counter++;
    fprintf(tempFile, "%s", buffer);
  }
372
373
  fclose(tempFile);
  fclose(xmfFile);
374

375
376
377
378
  /* We then copy the XMF file back up to the closing lines */
  xmfFile = fopen("output.xmf", "w");
  tempFile = fopen("output_temp.xmf", "r");

379
  if (xmfFile == NULL) error("Unable to open current XMF file.");
380

381
  if (tempFile == NULL) error("Unable to open temporary file.");
382
383

  int i = 0;
384
385
386
387
  while (fgets(buffer, 1024, tempFile) != NULL && i < counter - 3) {
    i++;
    fprintf(xmfFile, "%s", buffer);
  }
388
389
390
  fprintf(xmfFile, "\n");
  fclose(tempFile);
  remove("output_temp.xmf");
391

392
393
394
395
396
397
  return xmfFile;
}

/**
 * @brief Writes the begin of the XMF file
 *
398
399
 * @todo Exploit the XML nature of the XMF format to write a proper XML writer
 *and simplify all the XMF-related stuff.
400
 */
401
void createXMFfile() {
402
403
404
405
  FILE* xmfFile = fopen("output.xmf", "w");

  fprintf(xmfFile, "<?xml version=\"1.0\" ?> \n");
  fprintf(xmfFile, "<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\" []> \n");
406
407
408
  fprintf(
      xmfFile,
      "<Xdmf xmlns:xi=\"http://www.w3.org/2003/XInclude\" Version=\"2.1\">\n");
409
  fprintf(xmfFile, "<Domain>\n");
410
411
412
  fprintf(xmfFile,
          "<Grid Name=\"TimeSeries\" GridType=\"Collection\" "
          "CollectionType=\"Temporal\">\n\n");
413
414
415
416
417
418
419
420
421

  fprintf(xmfFile, "</Grid>\n");
  fprintf(xmfFile, "</Domain>\n");
  fprintf(xmfFile, "</Xdmf>\n");

  fclose(xmfFile);
}

/**
422
423
 * @brief Writes the part of the XMF entry presenting the geometry of the
 *snapshot
424
425
426
427
428
429
 *
 * @param xmfFile The file to write in.
 * @param Nparts The number of particles.
 * @param hdfFileName The name of the HDF5 file corresponding to this output.
 * @param time The current simulation time.
 */
430
431
void writeXMFheader(FILE* xmfFile, long long Nparts, char* hdfFileName,
                    float time) {
432
  /* Write end of file */
433
434
435

  fprintf(xmfFile,
          "<Grid GridType=\"Collection\" CollectionType=\"Spatial\">\n");
436
437
  fprintf(xmfFile, "<Time Type=\"Single\" Value=\"%f\"/>\n", time);
  fprintf(xmfFile, "<Grid Name=\"Gas\" GridType=\"Uniform\">\n");
438
439
440
  fprintf(xmfFile,
          "<Topology TopologyType=\"Polyvertex\" Dimensions=\"%lld\"/>\n",
          Nparts);
441
  fprintf(xmfFile, "<Geometry GeometryType=\"XYZ\">\n");
442
443
444
445
446
  fprintf(xmfFile,
          "<DataItem Dimensions=\"%lld 3\" NumberType=\"Double\" "
          "Precision=\"8\" "
          "Format=\"HDF\">%s:/PartType0/Coordinates</DataItem>\n",
          Nparts, hdfFileName);
447
448
449
450
451
452
453
454
  fprintf(xmfFile, "</Geometry>");
}

/**
 * @brief Writes the end of the XMF file (closes all open markups)
 *
 * @param xmfFile The file to write in.
 */
455
void writeXMFfooter(FILE* xmfFile) {
456
  /* Write end of the section of this time step */
457

458
459
460
461
462
  fprintf(xmfFile, "\n</Grid>\n");
  fprintf(xmfFile, "</Grid>\n");
  fprintf(xmfFile, "\n</Grid>\n");
  fprintf(xmfFile, "</Domain>\n");
  fprintf(xmfFile, "</Xdmf>\n");
463

464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  fclose(xmfFile);
}

/**
 * @brief Writes the lines corresponding to an array of the HDF5 output
 *
 * @param xmfFile The file in which to write
 * @param fileName The name of the HDF5 file associated to this XMF descriptor.
 * @param name The name of the array in the HDF5 file.
 * @param N The number of particles.
 * @param dim The dimension of the quantity (1 for scalars, 3 for vectors).
 * @param type The type of the data to write.
 *
 * @todo Treat the types in a better way.
 */
479
480
481
482
483
484
485
486
487
488
void writeXMFline(FILE* xmfFile, char* fileName, char* name, long long N,
                  int dim, enum DATA_TYPE type) {
  fprintf(xmfFile,
          "<Attribute Name=\"%s\" AttributeType=\"%s\" Center=\"Node\">\n",
          name, dim == 1 ? "Scalar" : "Vector");
  if (dim == 1)
    fprintf(xmfFile,
            "<DataItem Dimensions=\"%lld\" NumberType=\"Double\" "
            "Precision=\"%d\" Format=\"HDF\">%s:/PartType0/%s</DataItem>\n",
            N, type == FLOAT ? 4 : 8, fileName, name);
489
  else
490
491
492
493
    fprintf(xmfFile,
            "<DataItem Dimensions=\"%lld %d\" NumberType=\"Double\" "
            "Precision=\"%d\" Format=\"HDF\">%s:/PartType0/%s</DataItem>\n",
            N, dim, type == FLOAT ? 4 : 8, fileName, name);
494
495
496
497
  fprintf(xmfFile, "</Attribute>\n");
}

#endif