From e744b60750abd5a3e4d1f364a170790e2a8ee69f Mon Sep 17 00:00:00 2001 From: eschnett Date: Tue, 1 Feb 2011 16:10:41 +0000 Subject: Add utilities from CactusExternal/HDF5 git-svn-id: http://svn.cactuscode.org/projects/ExternalLibraries/HDF5/trunk@29 fb53df36-e548-4a1e-8150-ab98cbd5e786 --- src/make.configuration.defn | 4 + src/make.configuration.deps | 21 ++ src/util/hdf5_double_to_single.c | 340 +++++++++++++++++++++++++++++++ src/util/hdf5_extract.c | 418 +++++++++++++++++++++++++++++++++++++++ src/util/hdf5_merge.c | 373 ++++++++++++++++++++++++++++++++++ 5 files changed, 1156 insertions(+) create mode 100644 src/make.configuration.defn create mode 100644 src/make.configuration.deps create mode 100644 src/util/hdf5_double_to_single.c create mode 100644 src/util/hdf5_extract.c create mode 100644 src/util/hdf5_merge.c diff --git a/src/make.configuration.defn b/src/make.configuration.defn new file mode 100644 index 0000000..86f52ea --- /dev/null +++ b/src/make.configuration.defn @@ -0,0 +1,4 @@ +# make.configuration.defn file for thorn HDF5 + +# Define this thorn's utilities +ALL_UTILS += hdf5_merge hdf5_extract hdf5_double_to_single diff --git a/src/make.configuration.deps b/src/make.configuration.deps new file mode 100644 index 0000000..402c629 --- /dev/null +++ b/src/make.configuration.deps @@ -0,0 +1,21 @@ +# make.configuration.deps file for thorn HDF5 + +HDF5_BUILD_DIR = $(BUILD_DIR)/HDF5 +HDF5_SRC_DIR = $(PACKAGE_DIR)/ExternalLibraries/HDF5/src/util + +HDF5_CFLAGS = -DCCODE $(CFLAGS) -I$(CONFIG) -I$(BINDINGS_DIR)/include -I$(FLESH_DIR)/include $(HDF5_INC_DIRS:%=-I%) +HDF5_LDFLAGS = $(DEBUG_LD) $(LDFLAGS) $(EXTRAFLAGS) $(GENERAL_LIBRARIES) + + + +# Compile +$(HDF5_BUILD_DIR)/%.o: $(HDF5_SRC_DIR)/%.c + @echo "Compiling $<" + -$(MKDIR) $(MKDIRFLAGS) $(HDF5_BUILD_DIR) 2> /dev/null + $(CC) $< $(HDF5_CFLAGS) -c -o $@ + +# Link +$(UTIL_DIR)/%: $(HDF5_BUILD_DIR)/%.o + @echo "Creating $* in $(UTIL_DIR) from $<" + -$(MKDIR) $(MKDIRFLAGS) $(UTIL_DIR) 2> /dev/null + $(LD) $< $(HDF5_LDFLAGS) -o $@ diff --git a/src/util/hdf5_double_to_single.c b/src/util/hdf5_double_to_single.c new file mode 100644 index 0000000..870ccc7 --- /dev/null +++ b/src/util/hdf5_double_to_single.c @@ -0,0 +1,340 @@ + /*@@ + @file hdf5_double_to_single.c + @date Thu 10 Jan 2002 + @author Thomas Radke + @desc + This utility program copies a Cactus HDF5 datafile reverting + double-precision datasets into single-precision. + @enddesc + @version $Id: hdf5_double_to_single.c,v 1.3 2009/09/29 14:38:14 schnetter Exp $ + @@*/ + +#include "cctk.h" + +#define H5_USE_16_API 1 +#include + +#include +#include +#include + +/* the rcs ID and its dummy function to use it */ +static const char *rcsid = "$Header: /cactusdevcvs/CactusExternal/HDF5/src/util/hdf5_double_to_single.c,v 1.3 2009/09/29 14:38:14 schnetter Exp $"; +CCTK_FILEVERSION(CactusExternal_HDF5_util_hdf5_double_to_single_c) + + +/*****************************************************************************/ +/* macro definitions */ +/*****************************************************************************/ +/* macro to do an HDF5 call, check its return code, and print a warning + in case of an error */ +#define CHECK_ERROR(hdf5_call) \ + do \ + { \ + int _error_code = hdf5_call; \ + \ + \ + if (_error_code < 0) \ + { \ + fprintf (stderr, "WARNING: line %d: HDF5 call '%s' returned " \ + "error code %d\n", \ + __LINE__, #hdf5_call, _error_code); \ + nerrors++; \ + } \ + } while (0) + + +/*****************************************************************************/ +/* global variables */ +/*****************************************************************************/ +/* NOTE: although it isn't good programming practice + we make these variables global for convenience + since they are accessed from recursively or + indirectly called routines which only get passed + a single user-supplied argument */ +static char *pathname = NULL; /* pathname of the current object */ +static unsigned int nerrors = 0; /* global error counter */ + +/*****************************************************************************/ +/* local function prototypes */ +/*****************************************************************************/ +static herr_t CopyObject (hid_t copy_from, const char *objectname, void *arg); +static herr_t CopyAttribute (hid_t src, const char *attr_name, void *arg); + + + /*@@ + @routine main + @date Thu 10 Jan 2002 + @author Thomas Radke + @desc + Main routine of the HDF5 double-to-single converter + @enddesc + + @calls CopyObject + + @var argc + @vdesc number of command line arguments + @vtype int + @vio in + @endvar + @var argv + @vdesc command line arguments + @vtype char *[] + @vio in + @endvar + + @returntype int + @returndesc + 0 for success, negative return values indicate an error + @endreturndesc +@@*/ +int main (int argc, char *argv[]) +{ + hid_t infile, outfile; + + + /* give some help if called with incorrect number of parameters */ + if (argc != 3) + { + fprintf (stderr, "Usage: %s \n", argv[0]); + fprintf (stderr, " eg, %s alp.h5 alp_single.h5\n\n", argv[0]); + return (0); + } + + H5E_BEGIN_TRY + { + /* open the input file */ + infile = H5Fopen (argv[1], H5F_ACC_RDONLY, H5P_DEFAULT); + if (infile < 0) + { + fprintf (stderr, "ERROR: Cannot open HDF5 input file '%s' !\n\n",argv[1]); + return (-1); + } + + /* create output file */ + outfile = H5Fcreate (argv[2], H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + if (outfile < 0) + { + fprintf (stderr, "ERROR: Cannot create HDF5 output file '%s' !\n\n", + argv[2]); + return (-1); + } + } H5E_END_TRY + + printf ("\n --------------------------------------------------\n" + " Cactus 4 HDF5 double-to-single precision Converter\n" + " --------------------------------------------------\n"); + + /* do the copying by iterating over all objects */ + pathname = ""; + CHECK_ERROR (H5Giterate (infile, "/", NULL, CopyObject, &outfile)); + + /* finally, close all open files */ + CHECK_ERROR (H5Fclose (infile)); + CHECK_ERROR (H5Fclose (outfile)); + + /* report status */ + if (nerrors == 0) + { + printf ("\n\n *** All Cactus data successfully converted. ***\n\n"); + } + else + { + fprintf (stderr, "\n\n *** WARNING: %u errors occured during " + "conversion. ***\n\n", nerrors); + } + + return (0); +} + + +/*****************************************************************************/ +/* local routines */ +/*****************************************************************************/ + /*@@ + @routine CopyObject + @date Thu 10 Jan 2002 + @author Thomas Radke + @desc + Iterator recursively called by H5Giterate() for every object + in the input file + @enddesc + + @calls CopyAttribute + + @var from + @vdesc identifier for the group the current object belongs to + @vtype hid_t + @vio in + @endvar + @var objectname + @vdesc name of the current object + @vtype const char * + @vio in + @endvar + @var _to + @vdesc user-supplied argument indicating the output object identifier + @vtype hid_t + @vio in + @endvar + + @returntype int + @returndesc + 0 - continue the iteration for following group objects + 1 - short-curcuit, no further iteration of this group + @endreturndesc +@@*/ +static herr_t CopyObject (hid_t from, + const char *objectname, + void *_to) +{ + hid_t to, datatype, dataspace; + H5G_stat_t objectinfo; + char *current_pathname; + size_t objectsize; + char *data; + + + /* build the full pathname for the current to object to process */ + current_pathname = pathname; + pathname = (char *) malloc (strlen (current_pathname) + + strlen (objectname) + 2); + sprintf (pathname, "%s/%s", current_pathname, objectname); + + /* get the output object identifier */ + to = *(hid_t *) _to; + + /* check the type of the current object */ + CHECK_ERROR (H5Gget_objinfo (from, objectname, 0, &objectinfo)); + if (objectinfo.type == H5G_GROUP) + { + printf (" copying group '%s'\n", pathname); + + CHECK_ERROR (from = H5Gopen (from, objectname)); + CHECK_ERROR (to = H5Gcreate (to, objectname, 0)); + /* iterate over all objects in the (first) input file */ + CHECK_ERROR (H5Giterate (from, ".", NULL, CopyObject, &to)); + CHECK_ERROR (H5Aiterate (from, NULL, CopyAttribute, &to)); + CHECK_ERROR (H5Gclose (to)); + CHECK_ERROR (H5Gclose (from)); + } + else if (objectinfo.type == H5G_DATASET) + { + CHECK_ERROR (from = H5Dopen (from, objectname)); + CHECK_ERROR (dataspace = H5Dget_space (from)); + CHECK_ERROR (datatype = H5Dget_type (from)); + if (H5Tget_class (datatype) == H5T_FLOAT) + { + CHECK_ERROR (H5Tclose (datatype)); + CHECK_ERROR (datatype = H5Tcopy (H5T_NATIVE_FLOAT)); + printf (" converting dataset '%s'\n", pathname); + } + else + { + printf (" copying dataset '%s'\n", pathname); + } + CHECK_ERROR (to = H5Dcreate (to, objectname, datatype, dataspace, + H5P_DEFAULT)); + objectsize = H5Tget_size (datatype); + if (H5Sis_simple (dataspace)) + { + objectsize *= H5Sget_simple_extent_npoints (dataspace); + } + if (objectsize > 0) + { + data = (char *) malloc (objectsize); + CHECK_ERROR (H5Dread (from, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, + data)); + CHECK_ERROR (H5Dwrite (to, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT,data)); + free (data); + } + CHECK_ERROR (H5Aiterate (from, NULL, CopyAttribute, &to)); + CHECK_ERROR (H5Dclose (to)); + CHECK_ERROR (H5Dclose (from)); + CHECK_ERROR (H5Sclose (dataspace)); + CHECK_ERROR (H5Tclose (datatype)); + } + else + { + fprintf (stderr, "WARNING: Found object '%s' which is neither a group " + "nor a dataset ! Object will not be copied.\n", pathname); + nerrors++; + } + + /* reset the pathname */ + free (pathname); + pathname = current_pathname; + + return (0); +} + + + /*@@ + @routine CopyAttribute + @date Thu 10 Jan 2002 + @author Thomas Radke + @desc + Iterator recursively called by H5Aiterate() for every attribute + of an object (dataset or group) + @enddesc + + @var from + @vdesc identifier for the group or dataset to read the attribute from + @vtype hid_t + @vio in + @endvar + @var attrname + @vdesc name of the current attribute + @vtype const char * + @vio in + @endvar + @var _to + @vdesc user-supplied argument indicating the group or dataset + to copy the attribute to + @vtype hid_t + @vio in + @endvar + + @returntype int + @returndesc + 0 - continue the iteration for following attributes + @endreturndesc +@@*/ +static herr_t CopyAttribute (hid_t from, + const char *attrname, + void *_to) +{ + hid_t attr, datatype, dataspace, to; + size_t attrsize; + void *value; + + + /* get the target group/dataset identifier */ + to = *(hid_t *) _to; + + /* open the attribute given by its name, get type, dataspace, and value + and just copy it */ + CHECK_ERROR (attr = H5Aopen_name (from, attrname)); + CHECK_ERROR (datatype = H5Aget_type (attr)); + CHECK_ERROR (dataspace = H5Aget_space (attr)); + attrsize = H5Tget_size (datatype); + if (H5Sis_simple (dataspace) > 0) + { + attrsize *= H5Sget_simple_extent_npoints (dataspace); + } + if (attrsize > 0) + { + value = malloc (attrsize); + CHECK_ERROR (H5Aread (attr, datatype, value)); + CHECK_ERROR (H5Aclose (attr)); + CHECK_ERROR (attr = H5Acreate (to, attrname, datatype, dataspace, + H5P_DEFAULT)); + CHECK_ERROR (H5Awrite (attr, datatype, value)); + free (value); + } + CHECK_ERROR (H5Aclose (attr)); + CHECK_ERROR (H5Sclose (dataspace)); + CHECK_ERROR (H5Tclose (datatype)); + + return (0); +} diff --git a/src/util/hdf5_extract.c b/src/util/hdf5_extract.c new file mode 100644 index 0000000..75de6bd --- /dev/null +++ b/src/util/hdf5_extract.c @@ -0,0 +1,418 @@ + /*@@ + @file hdf5_extract.c + @date Thu 19 Feb 2002 + @author Thomas Radke + @desc + This utility program extracts objects from an HDF5 file and writes + them into a new one. + @enddesc + @version $Id: hdf5_extract.c,v 1.3 2009/09/29 14:38:14 schnetter Exp $ + @@*/ + +#include "cctk.h" + +#define H5_USE_16_API 1 +#include + +#include +#include +#include + +/* the rcs ID and its dummy function to use it */ +static const char *rcsid = "$Header: /cactusdevcvs/CactusExternal/HDF5/src/util/hdf5_extract.c,v 1.3 2009/09/29 14:38:14 schnetter Exp $"; +CCTK_FILEVERSION(CactusExternal_HDF5_util_hdf5_extract_c) + + +/*****************************************************************************/ +/* macro definitions */ +/*****************************************************************************/ +/* macro to do an HDF5 call, check its return code, and print a warning + in case of an error */ +#define CHECK_ERROR(hdf5_call) \ + do \ + { \ + int _error_code = hdf5_call; \ + \ + \ + if (_error_code < 0) \ + { \ + fprintf (stderr, "WARNING: line %d: HDF5 call '%s' returned " \ + "error code %d\n", \ + __LINE__, #hdf5_call, _error_code); \ + nerrors++; \ + } \ + } while (0) + + +/*****************************************************************************/ +/* global variables */ +/*****************************************************************************/ +/* NOTE: although it isn't good programming practice + we make these variables global for convenience + since they are accessed from recursively or + indirectly called routines which only get passed + a single user-supplied argument */ +static char *pathname = NULL; /* pathname of the current object */ +static unsigned int nerrors = 0; /* global error counter */ +static unsigned int check_parents = 0; /* flag to check for parent groups */ + +/*****************************************************************************/ +/* local function prototypes */ +/*****************************************************************************/ +static herr_t CopyObject (hid_t from, const char *objectname, void *_to); +static herr_t CopyAttribute (hid_t src, const char *attr_name, void *arg); + + + /*@@ + @routine main + @date Thu 19 Feb 2002 + @author Thomas Radke + @desc + Main routine of the HDF5 file extractor + @enddesc + + @calls CopyObject + + @var argc + @vdesc number of command line arguments + @vtype int + @vio in + @endvar + @var argv + @vdesc command line arguments + @vtype char *[] + @vio in + @endvar + + @returntype int + @returndesc + 0 for success, negative return values indicate an error + @endreturndesc +@@*/ +int main (int argc, char *argv[]) +{ + char objectname[256]; + FILE *listfile; + hid_t infile, outfile; + + + /* give some help if called with incorrect number of parameters */ + if (argc != 4) + { + fprintf (stderr, "Usage: %s \n", argv[0]); + fprintf (stderr, " where can be created from the output of the h5ls command\n\n"); + fprintf (stderr, " eg, h5ls alp.h5 > listfile\n" + " # now edit listfile to select all datasets to be extracted\n" + " # (don't forget to remove backslashes and the trailing 'Dataset {...}')\n" + " %s extract_list alp.h5 alp_extract.h5\n\n", argv[0]); + + return (0); + } + + /* open the list file */ + listfile = fopen (argv[1], "r"); + if (listfile == NULL) + { + fprintf (stderr, "ERROR: Cannot open list file '%s' !\n\n", argv[1]); + return (-1); + } + + H5E_BEGIN_TRY + { + /* open the input file */ + infile = H5Fopen (argv[2], H5F_ACC_RDONLY, H5P_DEFAULT); + if (infile < 0) + { + fprintf (stderr, "ERROR: Cannot open HDF5 input file '%s' !\n\n",argv[2]); + return (-1); + } + + /* try to open an existing outfile file in append mode, + if this fails create it as a new file */ + outfile = H5Fopen (argv[3], H5F_ACC_RDWR, H5P_DEFAULT); + if (outfile < 0) + { + outfile = H5Fcreate (argv[3], H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + } + if (outfile < 0) + { + fprintf (stderr, "ERROR: Cannot create HDF5 output file '%s' !\n\n", + argv[3]); + return (-1); + } + } H5E_END_TRY + + printf ("\n ----------------------------\n" + " Cactus 4 HDF5 File Extractor\n" + " ----------------------------\n"); + + /* do the copying by iterating over all objects */ + while (fgets (objectname, sizeof (objectname), listfile)) + { + /* get rid of the trailing newline */ + objectname[strlen (objectname) - 1] = 0; + pathname = ""; + + check_parents = 1; + CopyObject (infile, objectname, &outfile); + } + + /* finally, close all open files */ + CHECK_ERROR (H5Fclose (infile)); + CHECK_ERROR (H5Fclose (outfile)); + fclose (listfile); + + /* report status */ + if (nerrors == 0) + { + printf ("\n\n *** All objects successfully extracted. ***\n\n"); + } + else + { + fprintf (stderr, "\n\n *** WARNING: %u errors occured during " + "data extraction. ***\n\n", nerrors); + } + + return (0); +} + + +/*****************************************************************************/ +/* local routines */ +/*****************************************************************************/ + /*@@ + @routine CopyObject + @date Thu 19 Feb 2002 + @author Thomas Radke + @desc + Copies an object with given name from the input file into the + output file. + @enddesc + + @calls CopyAttribute + + @var from + @vdesc input group handle + @vtype hid_t + @vio in + @endvar + @var objectname + @vdesc name of the object to extract + @vtype const char * + @vio in + @endvar + @var _to + @vdesc output group handle + @vtype void * + @vio in + @endvar + + @returntype herr_t + @returndesc + 0 - continue the iteration for following group objects + 1 - short-curcuit, no further iteration of this group + @endreturndesc +@@*/ +static herr_t CopyObject (hid_t from, + const char *objectname, + void *_to) +{ + hid_t to, datatype, dataspace, from_group, to_group; + H5G_stat_t objectinfo; + char *current_pathname; + size_t objectsize; + herr_t result; + char *data, *slash; + + + /* get the output object identifier */ + to = *(hid_t *) _to; + + /* check whether the requested object was already extracted */ + H5E_BEGIN_TRY + { + result = H5Gget_objinfo (to, objectname, 0, &objectinfo); + } H5E_END_TRY + if (result >= 0) + { + fprintf (stderr, "WARNING: object '%s' was already extracted\n",objectname); + return (0); + } + + /* check whether the requested object exists */ + H5E_BEGIN_TRY + { + result = H5Gget_objinfo (from, objectname, 0, &objectinfo); + } H5E_END_TRY + if (result < 0) + { + fprintf (stderr, "WARNING: object '%s' will not be extracted (object " + "doesn't exist)\n", objectname); + nerrors++; + return (0); + } + + /* make sure that all parent groups exist */ + if (check_parents) + { + slash = pathname; + /* skip leading slashes */ + while (*slash == '/') + { + slash++; + } + + /* now go through all groups (separated by slashes) */ + while ((slash = strchr (slash, '/')) != NULL) + { + *slash = 0; + + /* try to create the group */ + H5E_BEGIN_TRY + { + to_group = H5Gcreate (to, pathname, 0); + } H5E_END_TRY + if (to_group >= 0) + { + /* copy all attributes */ + CHECK_ERROR (from_group = H5Gopen (from, pathname)); + CHECK_ERROR (H5Aiterate (from_group, NULL, CopyAttribute, &to_group)); + CHECK_ERROR (H5Gclose (from_group)); + CHECK_ERROR (H5Gclose (to_group)); + } + *slash++ = '/'; + } + check_parents = 0; + } + + /* build the full pathname for the current to object to process */ + current_pathname = pathname; + pathname = (char *) malloc (strlen (current_pathname) + + strlen (objectname) + 2); + sprintf (pathname, "%s/%s", current_pathname, objectname); + + /* check the type of the current object */ + if (objectinfo.type == H5G_GROUP) + { + printf (" copying group '%s'\n", pathname); + + CHECK_ERROR (from = H5Gopen (from, objectname)); + CHECK_ERROR (to = H5Gcreate (to, objectname, 0)); + /* iterate over all objects in the (first) input file */ + CHECK_ERROR (H5Giterate (from, ".", NULL, CopyObject, &to)); + CHECK_ERROR (H5Aiterate (from, NULL, CopyAttribute, &to)); + CHECK_ERROR (H5Gclose (to)); + CHECK_ERROR (H5Gclose (from)); + } + else if (objectinfo.type == H5G_DATASET) + { + CHECK_ERROR (from = H5Dopen (from, objectname)); + CHECK_ERROR (dataspace = H5Dget_space (from)); + CHECK_ERROR (datatype = H5Dget_type (from)); + + printf (" copying dataset '%s'\n", pathname); + CHECK_ERROR (to = H5Dcreate (to, objectname, datatype, dataspace, + H5P_DEFAULT)); + objectsize = H5Tget_size (datatype); + if (H5Sis_simple (dataspace)) + { + objectsize *= H5Sget_simple_extent_npoints (dataspace); + } + if (objectsize > 0) + { + data = (char *) malloc (objectsize); + CHECK_ERROR (H5Dread (from, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, + data)); + CHECK_ERROR (H5Dwrite (to, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT,data)); + free (data); + } + CHECK_ERROR (H5Aiterate (from, NULL, CopyAttribute, &to)); + CHECK_ERROR (H5Dclose (to)); + CHECK_ERROR (H5Dclose (from)); + CHECK_ERROR (H5Sclose (dataspace)); + CHECK_ERROR (H5Tclose (datatype)); + } + else + { + fprintf (stderr, "WARNING: Found object '%s' which is neither a group " + "nor a dataset ! Object will not be copied.\n", pathname); + nerrors++; + } + + /* reset the pathname */ + free (pathname); + pathname = current_pathname; + + return (0); +} + + + /*@@ + @routine CopyAttribute + @date Thu 19 Feb 2002 + @author Thomas Radke + @desc + Iterator recursively called by H5Aiterate() for every attribute + of an object (dataset or group) + @enddesc + + @var from + @vdesc identifier for the group or dataset to read the attribute from + @vtype hid_t + @vio in + @endvar + @var attrname + @vdesc name of the current attribute + @vtype const char * + @vio in + @endvar + @var _to + @vdesc user-supplied argument indicating the group or dataset + to copy the attribute to + @vtype hid_t + @vio in + @endvar + + @returntype int + @returndesc + 0 - continue the iteration for following attributes + @endreturndesc +@@*/ +static herr_t CopyAttribute (hid_t from, + const char *attrname, + void *_to) +{ + hid_t attr, datatype, dataspace, to; + size_t attrsize; + void *value; + + + /* get the target group/dataset identifier */ + to = *(hid_t *) _to; + + /* open the attribute given by its name, get type, dataspace, and value + and just copy it */ + CHECK_ERROR (attr = H5Aopen_name (from, attrname)); + CHECK_ERROR (datatype = H5Aget_type (attr)); + CHECK_ERROR (dataspace = H5Aget_space (attr)); + attrsize = H5Tget_size (datatype); + if (H5Sis_simple (dataspace) > 0) + { + attrsize *= H5Sget_simple_extent_npoints (dataspace); + } + if (attrsize > 0) + { + value = malloc (attrsize); + CHECK_ERROR (H5Aread (attr, datatype, value)); + CHECK_ERROR (H5Aclose (attr)); + CHECK_ERROR (attr = H5Acreate (to, attrname, datatype, dataspace, + H5P_DEFAULT)); + CHECK_ERROR (H5Awrite (attr, datatype, value)); + free (value); + } + CHECK_ERROR (H5Aclose (attr)); + CHECK_ERROR (H5Sclose (dataspace)); + CHECK_ERROR (H5Tclose (datatype)); + + return (0); +} diff --git a/src/util/hdf5_merge.c b/src/util/hdf5_merge.c new file mode 100644 index 0000000..2d6a0fd --- /dev/null +++ b/src/util/hdf5_merge.c @@ -0,0 +1,373 @@ + /*@@ + @file hdf5_merge.c + @date Thu 10 Jan 2002 + @author Thomas Radke + @desc + This utility program takes a list of Cactus HDF5 datafiles, + merges them at the group hierarchy level and dumps the resulting + tree to a new HDF5 file. + @enddesc + @version $Id: hdf5_merge.c,v 1.3 2009/09/29 14:38:14 schnetter Exp $ + @@*/ + +#include "cctk.h" + +#define H5_USE_16_API 1 +#include + +#include +#include +#include + +/* the rcs ID and its dummy function to use it */ +static const char *rcsid = "$Header: /cactusdevcvs/CactusExternal/HDF5/src/util/hdf5_merge.c,v 1.3 2009/09/29 14:38:14 schnetter Exp $"; +CCTK_FILEVERSION(CactusExternal_HDF5_util_hdf5_merge_c) + + +/*****************************************************************************/ +/* macro definitions */ +/*****************************************************************************/ +/* macro to do an HDF5 call, check its return code, and print a warning + in case of an error */ +#define CHECK_ERROR(hdf5_call) \ + do \ + { \ + int _error_code = hdf5_call; \ + \ + \ + if (_error_code < 0) \ + { \ + fprintf (stderr, "WARNING: line %d: HDF5 call '%s' returned " \ + "error code %d\n", \ + __LINE__, #hdf5_call, _error_code); \ + nerrors++; \ + } \ + } while (0) + + +/*****************************************************************************/ +/* global variables */ +/*****************************************************************************/ +/* NOTE: although it isn't good programming practice + we make these variables global for convenience + since they are accessed from recursively or + indirectly called routines which only get passed + a single user-supplied argument */ +static char *pathname = NULL; /* pathname of the current object */ +static unsigned int nerrors = 0; /* global error counter */ + +/*****************************************************************************/ +/* local function prototypes */ +/*****************************************************************************/ +static herr_t CopyObject (hid_t copy_from, const char *objectname, void *arg); +static herr_t CopyAttribute (hid_t src, const char *attr_name, void *arg); + + + /*@@ + @routine main + @date Sat 24 Feb 2001 + @author Thomas Radke + @desc + Main routine of the HDF5 file merger + @enddesc + + @calls CopyObject + + @var argc + @vdesc number of command line arguments + @vtype int + @vio in + @endvar + @var argv + @vdesc command line arguments + @vtype char *[] + @vio in + @endvar + + @returntype int + @returndesc + 0 for success, negative return values indicate an error + @endreturndesc +@@*/ +int main (int argc, char *argv[]) +{ + int i; + hid_t *infiles, outfile; + + + /* give some help if called with incorrect number of parameters */ + if (argc < 3) + { + fprintf (stderr, "Usage: %s [ ...] \n",argv[0]); + fprintf (stderr, " eg, %s alp.time*.h5 alp.h5" + "\n\n", argv[0]); + return (0); + } + + H5E_BEGIN_TRY + { + /* open the input files */ + infiles = (hid_t *) malloc ((argc - 2) * sizeof (hid_t)); + for (i = 0; i < argc - 2; i++) + { + infiles[i] = H5Fopen (argv[i + 1], H5F_ACC_RDONLY, H5P_DEFAULT); + if (infiles[i] < 0) + { + fprintf (stderr, "ERROR: Cannot open HDF5 input file '%s' !\n\n", + argv[i + 1]); + return (-1); + } + } + + /* try to open an existing outfile file in append mode, + if this fails create it as a new file */ + outfile = H5Fopen (argv[argc-1], H5F_ACC_RDWR, H5P_DEFAULT); + if (outfile < 0) + { + outfile = H5Fcreate (argv[argc-1], H5F_ACC_TRUNC, H5P_DEFAULT, + H5P_DEFAULT); + } + if (outfile < 0) + { + fprintf (stderr, "ERROR: Cannot open HDF5 output file '%s' !\n\n", + argv[argc - 1]); + return (-1); + } + } H5E_END_TRY + + printf ("\n -------------------------\n" + " Cactus 4 HDF5 File Merger\n" + " -------------------------\n"); + + /* do the copying by iterating over all objects */ + for (i = 0; i < argc - 2; i++) + { + printf ("\n Merging objects from input file '%s' into output file '%s'\n", + argv[i + 1], argv[argc-1]); + pathname = ""; + CHECK_ERROR (H5Giterate (infiles[i], "/", NULL, CopyObject, &outfile)); + } + + /* finally, close all open files */ + for (i = 0; i < argc - 2; i++) + { + CHECK_ERROR (H5Fclose (infiles[i])); + } + CHECK_ERROR (H5Fclose (outfile)); + free (infiles); + + /* report status */ + if (nerrors == 0) + { + printf ("\n\n *** All input files successfully merged. ***\n\n"); + } + else + { + fprintf (stderr, "\n\n *** WARNING: %u errors occured during " + "file merging. ***\n\n", nerrors); + } + + return (0); +} + + +/*****************************************************************************/ +/* local routines */ +/*****************************************************************************/ + /*@@ + @routine CopyObject + @date Sat 24 Feb 2001 + @author Thomas Radke + @desc + Iterator recursively called by H5Giterate() for every object + in the input file + It copies the current object to the output file if it didn't + already exist there. + @enddesc + + @calls CopyAttribute + + @var from + @vdesc identifier for the group the current object belongs to + @vtype hid_t + @vio in + @endvar + @var objectname + @vdesc name of the current object + @vtype const char * + @vio in + @endvar + @var _to + @vdesc user-supplied argument indicating the output object identifier + @vtype hid_t + @vio in + @endvar + + @returntype int + @returndesc + 0 - continue the iteration for following group objects + 1 - short-curcuit, no further iteration of this group + @endreturndesc +@@*/ +static herr_t CopyObject (hid_t from, + const char *objectname, + void *_to) +{ + int i; + hid_t to, datatype, dataspace; + H5G_stat_t objectinfo; + char *current_pathname; + size_t objectsize; + void *data; + + + /* get the output object identifier */ + to = *(hid_t *) _to; + + /* check whether an object by that name already exists */ + H5E_BEGIN_TRY + { + i = H5Gget_objinfo (to, objectname, 0, &objectinfo) >= 0; + } H5E_END_TRY + if (i) + { + printf (" object '%s/%s' will not be copied (already exists)\n", + pathname, objectname); + return (0); + } + + /* build the full pathname for the current to object to process */ + current_pathname = pathname; + pathname = (char *) malloc (strlen (current_pathname) + + strlen (objectname) + 2); + sprintf (pathname, "%s/%s", current_pathname, objectname); + + /* check the type of the current object */ + CHECK_ERROR (H5Gget_objinfo (from, objectname, 0, &objectinfo)); + if (objectinfo.type == H5G_GROUP) + { + printf (" copying group '%s'\n", pathname); + + CHECK_ERROR (from = H5Gopen (from, objectname)); + CHECK_ERROR (to = H5Gcreate (to, objectname, 0)); + /* iterate over all objects in the (first) input file */ + CHECK_ERROR (H5Giterate (from, ".", NULL, CopyObject, &to)); + CHECK_ERROR (H5Aiterate (from, NULL, CopyAttribute, &to)); + CHECK_ERROR (H5Gclose (to)); + CHECK_ERROR (H5Gclose (from)); + } + else if (objectinfo.type == H5G_DATASET) + { + printf (" copying dataset '%s'\n", pathname); + + CHECK_ERROR (from = H5Dopen (from, objectname)); + CHECK_ERROR (datatype = H5Dget_type (from)); + CHECK_ERROR (dataspace = H5Dget_space (from)); + CHECK_ERROR (to = H5Dcreate (to, objectname, datatype, dataspace, + H5P_DEFAULT)); + objectsize = H5Sget_select_npoints (dataspace) * H5Tget_size (datatype); + if (objectsize > 0) + { + data = malloc (objectsize); + if (data == NULL) + { + fprintf (stderr, "failled to allocate %d bytes of memory, giving up\n", + (int) objectsize); + exit (-1); + } + CHECK_ERROR (H5Dread (from, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, + data)); + CHECK_ERROR (H5Dwrite (to, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT,data)); + free (data); + } + CHECK_ERROR (H5Aiterate (from, NULL, CopyAttribute, &to)); + CHECK_ERROR (H5Dclose (to)); + CHECK_ERROR (H5Dclose (from)); + CHECK_ERROR (H5Sclose (dataspace)); + CHECK_ERROR (H5Tclose (datatype)); + } + else + { + fprintf (stderr, "WARNING: Found object '%s' which is not neither a " + "group nor a dataset ! Object will not be copied.\n", + pathname); + nerrors++; + } + + /* reset the pathname */ + free (pathname); + pathname = current_pathname; + + return (0); +} + + + /*@@ + @routine CopyAttribute + @date Sat 24 Feb 2001 + @author Thomas Radke + @desc + Iterator recursively called by H5Aiterate() for every attribute + of an object (dataset or group) + @enddesc + + @var from + @vdesc identifier for the group or dataset to read the attribute from + @vtype hid_t + @vio in + @endvar + @var attrname + @vdesc name of the current attribute + @vtype const char * + @vio in + @endvar + @var _to + @vdesc user-supplied argument indicating the group or dataset + to copy the attribute to + @vtype hid_t + @vio in + @endvar + + @returntype int + @returndesc + 0 - continue the iteration for following attributes + @endreturndesc +@@*/ +static herr_t CopyAttribute (hid_t from, + const char *attrname, + void *_to) +{ + hid_t attr, datatype, dataspace, to; + size_t attrsize; + void *value; + + + /* get the target group/dataset identifier */ + to = *(hid_t *) _to; + + /* open the attribute given by its name, get type, dataspace, and value + and just copy it */ + CHECK_ERROR (attr = H5Aopen_name (from, attrname)); + CHECK_ERROR (datatype = H5Aget_type (attr)); + CHECK_ERROR (dataspace = H5Aget_space (attr)); + attrsize = H5Tget_size (datatype); + if (H5Sis_simple (dataspace) > 0) + { + attrsize *= H5Sget_simple_extent_npoints (dataspace); + } + if (attrsize > 0) + { + value = malloc (attrsize); + CHECK_ERROR (H5Aread (attr, datatype, value)); + CHECK_ERROR (H5Aclose (attr)); + CHECK_ERROR (attr = H5Acreate (to, attrname, datatype, dataspace, + H5P_DEFAULT)); + CHECK_ERROR (H5Awrite (attr, datatype, value)); + free (value); + } + CHECK_ERROR (H5Aclose (attr)); + CHECK_ERROR (H5Sclose (dataspace)); + CHECK_ERROR (H5Tclose (datatype)); + + return (0); +} -- cgit v1.2.3