/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright by The HDF Group. * * All rights reserved. * * * * This file is part of HDF5. The full HDF5 copyright notice, including * * terms governing use, modification, and redistribution, is contained in * * the COPYING file, which can be found at the root of the source code * * distribution tree, or in https://www.hdfgroup.org/licenses. * * If you do not have access to either file, you may request a copy from * * help@hdfgroup.org. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "H5private.h" #include "h5tools.h" #include "h5tools_utils.h" #include "h5diff.h" #include "ph5diff.h" #define ATTR_NAME_MAX 255 /*------------------------------------------------------------------------- * printf formatting *------------------------------------------------------------------------- */ #define F_FORMAT "%-15g %-15g %-15g\n" #define LD_FORMAT "%-15Lg %-15Lg %-15Lg\n" #define I_FORMAT "%-15d %-15d %-15d\n" #define S_FORMAT "%-16s %-17s\n" #define UI_FORMAT "%-15u %-15u %-15u\n" #define LI_FORMAT "%-15ld %-15ld %-15ld\n" #define ULI_FORMAT "%-15lu %-15lu %-15lu\n" #define LLI_FORMAT "%-15lld %-15lld %-15lld\n" #define ULLI_FORMAT "%-15llu %-15llu %-15llu\n" /* with -p option */ #define F_FORMAT_P "%-15.10g %-15.10g %-15.10g %-14.10g\n" #define LD_FORMAT_P "%-15.10Lg %-15.10Lg %-15.10Lg %-14.10Lg\n" #define I_FORMAT_P "%-15d %-15d %-15d %-14f\n" #define UI_FORMAT_P "%-15u %-15u %-15u %-14f\n" #define LI_FORMAT_P "%-15ld %-15ld %-15ld %-14f\n" #define ULI_FORMAT_P "%-15lu %-15lu %-15lu %-14f\n" #define LLI_FORMAT_P "%-15lld %-15lld %-15lld %-14f\n" #define ULLI_FORMAT_P "%-15llu %-15llu %-15lld %-14f\n" #define SPACES " " /* not comparable */ #define F_FORMAT_P_NOTCOMP "%-15.10g %-15.10g %-15.10g not comparable\n" #define LD_FORMAT_P_NOTCOMP "%-15.10Lg %-15.10Lg %-15.10Lg not comparable\n" #define I_FORMAT_P_NOTCOMP "%-15d %-15d %-15d not comparable\n" #define UI_FORMAT_P_NOTCOMP "%-15u %-15u %-15u not comparable\n" #define LI_FORMAT_P_NOTCOMP "%-15ld %-15ld %-15ld not comparable\n" #define ULI_FORMAT_P_NOTCOMP "%-15lu %-15lu %-15lu not comparable\n" #define LLI_FORMAT_P_NOTCOMP "%-15lld %-15lld %-15lld not comparable\n" #define ULLI_FORMAT_P_NOTCOMP "%-15llu %-15llu %-15lld not comparable\n" /* if system EPSILON is defined, use the system EPSILON; otherwise, use constants that are close to most EPSILON values */ #ifndef FLT_EPSILON #define FLT_EPSILON 1.19209E-07 #endif #ifndef DBL_EPSILON #define DBL_EPSILON 2.22045E-16 #endif /*------------------------------------------------------------------------- * -p relative error formula * * We assume the true value of a quantity to be A (value in first dataset) * and the measured or inferred value to be B (value in second dataset). * The relative error is defined by * * B - A * -------- * A * *------------------------------------------------------------------------- */ static bool not_comparable; #define PER(A, B) \ do { \ per = -1; \ not_comparable = false; \ both_zero = false; \ if (H5_DBL_ABS_EQUAL(0, (double)(A)) && H5_DBL_ABS_EQUAL(0, (double)(B))) \ both_zero = true; \ if (!H5_DBL_ABS_EQUAL(0, (double)(A))) \ per = (double)ABS((double)((B) - (A)) / (double)(A)); \ else \ not_comparable = true; \ } while (0) #define PER_UNSIGN(TYPE, A, B) \ do { \ per = -1; \ not_comparable = false; \ both_zero = false; \ if (H5_DBL_ABS_EQUAL(0, (double)(A)) && H5_DBL_ABS_EQUAL(0, (double)(B))) \ both_zero = true; \ if (!H5_DBL_ABS_EQUAL(0, (double)(A))) \ per = ABS((double)((TYPE)((B) - (A))) / (double)(A)); \ else \ not_comparable = true; \ } while (0) #define PDIFF(a, b) (((b) > (a)) ? ((b) - (a)) : ((a) - (b))) typedef struct mcomp_t { unsigned n; /* number of members */ hid_t *ids; /* member type id */ size_t *offsets; struct mcomp_t **m; /* members */ } mcomp_t; /*------------------------------------------------------------------------- * local prototypes *------------------------------------------------------------------------- */ static bool all_zero(const void *_mem, size_t size); static int ull2float(unsigned long long ull_value, float *f_value); static hsize_t character_compare(char *mem1, char *mem2, hsize_t elemtno, size_t u, diff_opt_t *opts); static hsize_t character_compare_opt(unsigned char *mem1, unsigned char *mem2, hsize_t elemtno, diff_opt_t *opts); static bool equal_float(float value, float expected, diff_opt_t *opts); static bool equal_double(double value, double expected, diff_opt_t *opts); static bool equal_ldouble(long double value, long double expected, diff_opt_t *opts); static int print_data(diff_opt_t *opts); static void print_pos(diff_opt_t *opts, hsize_t elemtno, size_t u); static void h5diff_print_char(char ch); static hsize_t diff_region(hid_t obj1_id, hid_t obj2_id, hid_t region1_id, hid_t region2_id, diff_opt_t *opts); static hsize_t diff_datum(void *_mem1, void *_mem2, hsize_t elemtno, diff_opt_t *opts, hid_t container1_id, hid_t container2_id, mcomp_t *members); /* element diffs */ static hsize_t diff_float_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_double_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_ldouble_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); #ifdef H5_HAVE__FLOAT16 static hsize_t diff_float16_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); #endif static hsize_t diff_schar_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_uchar_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_short_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_ushort_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_int_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_uint_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_long_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_ulong_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_llong_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); static hsize_t diff_ullong_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts); /*------------------------------------------------------------------------- * NaN detection *------------------------------------------------------------------------- */ typedef enum dtype_t { FLT_FLOAT, FLT_DOUBLE, FLT_LDOUBLE } dtype_t; /*------------------------------------------------------------------------- * XCAO, 11/10/2010 * added to improve performance for compound datasets */ static void get_member_types(hid_t tid, mcomp_t *members); static void close_member_types(mcomp_t *members); /*------------------------------------------------------------------------- * Function: diff_array * * Purpose: compare two memory buffers; * * Return: number of differences found *------------------------------------------------------------------------- */ hsize_t diff_array(void *_mem1, void *_mem2, diff_opt_t *opts, hid_t container1_id, hid_t container2_id) { hsize_t nfound = 0; /* number of differences found */ size_t size; /* size of datum */ unsigned char *mem1 = (unsigned char *)_mem1; unsigned char *mem2 = (unsigned char *)_mem2; hsize_t i; mcomp_t members; H5T_class_t type_class; H5TOOLS_START_DEBUG(" - rank:%d hs_nelmts:%" PRIuHSIZE " errstat:%d", opts->rank, opts->hs_nelmts, opts->err_stat); opts->print_header = 1; /* enable print header */ /* get the size. */ size = H5Tget_size(opts->m_tid); type_class = H5Tget_class(opts->m_tid); /* Fast comparison first for atomic type by memcmp(). * It is OK not to list non-atomic type here because it will not be caught * by the condition, but it gives more clarity for code planning */ if (type_class != H5T_REFERENCE && type_class != H5T_COMPOUND && type_class != H5T_STRING && type_class != H5T_VLEN && memcmp(mem1, mem2, size * opts->hs_nelmts) == 0) { H5TOOLS_ENDDEBUG(":Fast comparison - errstat:%d", opts->err_stat); return 0; } H5TOOLS_DEBUG("type_class:%d", type_class); switch (type_class) { case H5T_NO_CLASS: case H5T_TIME: case H5T_NCLASSES: default: H5TOOLS_DEBUG("type_class:INVALID"); assert(0); break; /*------------------------------------------------------------------------- * float and integer atomic types *------------------------------------------------------------------------- */ case H5T_FLOAT: H5TOOLS_DEBUG("type_class:H5T_FLOAT"); #ifdef H5_HAVE__FLOAT16 if (H5Tequal(opts->m_tid, H5T_NATIVE_FLOAT16)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_float16_element(mem1, mem2, i, opts); mem1 += sizeof(H5__Float16); mem2 += sizeof(H5__Float16); if (opts->count_bool && nfound >= opts->count) return nfound; } } else #endif if (H5Tequal(opts->m_tid, H5T_NATIVE_FLOAT)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_float_element(mem1, mem2, i, opts); mem1 += sizeof(float); mem2 += sizeof(float); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_DOUBLE)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_double_element(mem1, mem2, i, opts); mem1 += sizeof(double); mem2 += sizeof(double); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_LDOUBLE)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_ldouble_element(mem1, mem2, i, opts); mem1 += sizeof(long double); mem2 += sizeof(long double); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } break; case H5T_INTEGER: H5TOOLS_DEBUG("type_class:H5T_INTEGER"); if (H5Tequal(opts->m_tid, H5T_NATIVE_SCHAR)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_schar_element(mem1, mem2, i, opts); mem1 += sizeof(char); mem2 += sizeof(char); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_UCHAR)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_uchar_element(mem1, mem2, i, opts); mem1 += sizeof(unsigned char); mem2 += sizeof(unsigned char); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_SHORT)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_short_element(mem1, mem2, i, opts); mem1 += sizeof(short); mem2 += sizeof(short); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_USHORT)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_ushort_element(mem1, mem2, i, opts); mem1 += sizeof(unsigned short); mem2 += sizeof(unsigned short); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_INT)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_int_element(mem1, mem2, i, opts); mem1 += sizeof(int); mem2 += sizeof(int); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_UINT)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_int_element(mem1, mem2, i, opts); mem1 += sizeof(unsigned int); mem2 += sizeof(unsigned int); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_LONG)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_long_element(mem1, mem2, i, opts); mem1 += sizeof(long); mem2 += sizeof(long); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_ULONG)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_ulong_element(mem1, mem2, i, opts); mem1 += sizeof(unsigned long); mem2 += sizeof(unsigned long); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_LLONG)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_llong_element(mem1, mem2, i, opts); mem1 += sizeof(long long); mem2 += sizeof(long long); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } else if (H5Tequal(opts->m_tid, H5T_NATIVE_ULLONG)) { for (i = 0; i < opts->hs_nelmts; i++) { nfound += diff_ullong_element(mem1, mem2, i, opts); mem1 += sizeof(unsigned long long); mem2 += sizeof(unsigned long long); if (opts->count_bool && nfound >= opts->count) return nfound; } /* nelmts */ } break; /*------------------------------------------------------------------------- * Other types than float and integer *------------------------------------------------------------------------- */ case H5T_COMPOUND: case H5T_STRING: case H5T_BITFIELD: case H5T_OPAQUE: case H5T_ENUM: case H5T_ARRAY: case H5T_VLEN: case H5T_REFERENCE: H5TOOLS_DEBUG("type_class:OTHER"); memset(&members, 0, sizeof(mcomp_t)); get_member_types(opts->m_tid, &members); for (i = 0; i < opts->hs_nelmts; i++) { H5TOOLS_DEBUG("opts->pos[%" PRIuHSIZE "]:%" PRIuHSIZE " - nelmts:%" PRIuHSIZE, i, opts->pos[i], opts->hs_nelmts); nfound += diff_datum(mem1 + i * size, mem2 + i * size, i, opts, container1_id, container2_id, &members); if (opts->count_bool && nfound >= opts->count) break; } /* i */ close_member_types(&members); } /* switch */ H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_datum * * Purpose: compare the values pointed to in _MEM1 and _MEM2 of type M_TYPE * * Return: number of differences found * * The comparison of the 2 buffers read from the files is made datum by datum. * * H5T_INTEGER and H5T_FLOAT * Copy the buffer into a compatible local datum and do a numerical * compare of this datum * H5T_COMPOUND * Recursively call this function for each member * H5T_ARRAY * Recursively call this function for each element * H5T_VLEN * Recursively call this function for each element * H5T_STRING * compare byte by byte in a cycle from 0 to type_size. this type_size is the * value obtained by the get_size function but it is the string length for * variable sized strings * H5T_OPAQUE * compare byte by byte in a cycle from 0 to type_size * H5T_BITFIELD * compare byte by byte in a cycle from 0 to type_size * H5T_ENUM * for each pair of elements being compared, both bit patterns are converted to * their corresponding enumeration constant and a string comparison is made * H5T_REFERENCE * Dereference the object and compare the type (basic object type). *------------------------------------------------------------------------- */ static hsize_t diff_datum(void *_mem1, void *_mem2, hsize_t elemtno, diff_opt_t *opts, hid_t container1_id, hid_t container2_id, mcomp_t *members) { unsigned char *mem1 = (unsigned char *)_mem1; unsigned char *mem2 = (unsigned char *)_mem2; size_t u; size_t type_size; H5T_sign_t type_sign; H5T_class_t type_class; size_t offset; unsigned nmembs; unsigned j; size_t size = 0; bool iszero1; bool iszero2; hsize_t nfound = 0; /* differences found */ diff_err_t ret_value = opts->err_stat; H5TOOLS_START_DEBUG("ph:%d elemtno:%" PRIuHSIZE " - errstat:%d", opts->print_header, elemtno, opts->err_stat); type_size = H5Tget_size(opts->m_tid); type_class = H5Tget_class(opts->m_tid); /* Fast comparison first for atomic type by memcmp(). * It is OK not to list non-atomic type here because it will not be caught * by the condition, but it gives more clarity for code planning */ if (type_class != H5T_REFERENCE && type_class != H5T_COMPOUND && type_class != H5T_STRING && type_class != H5T_VLEN && memcmp(mem1, mem2, type_size) == 0) H5TOOLS_GOTO_DONE(opts->err_stat); switch (H5Tget_class(opts->m_tid)) { case H5T_NO_CLASS: case H5T_TIME: case H5T_NCLASSES: default: H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Invalid type class"); break; /*------------------------------------------------------------------------- * H5T_COMPOUND *------------------------------------------------------------------------- */ case H5T_COMPOUND: H5TOOLS_DEBUG("H5T_COMPOUND"); { diff_opt_t cmpd_opts; cmpd_opts = *opts; nmembs = members->n; for (j = 0; j < nmembs; j++) { offset = members->offsets[j]; cmpd_opts.m_tid = members->ids[j]; nfound += diff_datum(mem1 + offset, mem2 + offset, elemtno, &cmpd_opts, container1_id, container2_id, members->m[j]); } opts->err_stat = opts->err_stat | cmpd_opts.err_stat; opts->print_header = cmpd_opts.print_header; opts->not_cmp = cmpd_opts.not_cmp; } break; /*------------------------------------------------------------------------- * H5T_STRING *------------------------------------------------------------------------- */ case H5T_STRING: H5TOOLS_DEBUG("H5T_STRING"); { char *s = NULL; char *sx = NULL; char *s1 = NULL; char *s2 = NULL; size_t size1; size_t size2; size_t sizex; size_t size_mtype = H5Tget_size(opts->m_tid); H5T_str_t pad = H5Tget_strpad(opts->m_tid); /* if variable length string */ if (H5Tis_variable_str(opts->m_tid)) { H5TOOLS_DEBUG("H5T_STRING variable"); /* Get pointer to first string */ s1 = *(char **)((void *)mem1); if (s1) size1 = strlen(s1); else size1 = 0; /* Get pointer to second string */ s2 = *(char **)((void *)mem2); if (s2) size2 = strlen(s2); else size2 = 0; } else if (H5T_STR_NULLTERM == pad) { H5TOOLS_DEBUG("H5T_STRING null term"); /* Get pointer to first string */ s1 = (char *)mem1; if (s1) size1 = strlen(s1); else size1 = 0; if (size1 > size_mtype) size1 = size_mtype; /* Get pointer to second string */ s2 = (char *)mem2; if (s2) size2 = strlen(s2); else size2 = 0; if (size2 > size_mtype) size2 = size_mtype; } else { /* Get pointer to first string */ s1 = (char *)mem1; size1 = size_mtype; /* Get pointer to second string */ s2 = (char *)mem2; size2 = size_mtype; } /* * compare for shorter string * TODO: this code need to be improved to handle the difference * of length of strings. * For now mimic the previous way. */ H5TOOLS_DEBUG("string size:%ld", size1); H5TOOLS_DEBUG("string size:%ld", size2); if (size1 != size2) { H5TOOLS_DEBUG("string sizes difference"); nfound++; } if (size1 < size2) { size = size1; s = s1; sizex = size2; sx = s2; } else { size = size2; s = s2; sizex = size1; sx = s1; } /* check for NULL pointer for string */ if (s != NULL) { /* try fast compare first */ if ((memcmp(s, sx, size) == 0) && (size1 != size2)) { for (u = size; u < sizex; u++) character_compare(s + u, sx + u, elemtno, u, opts); } else for (u = 0; u < size; u++) nfound += character_compare(s + u, sx + u, elemtno, u, opts); } /* end check for NULL pointer for string */ } break; /*------------------------------------------------------------------------- * H5T_BITFIELD *------------------------------------------------------------------------- */ case H5T_BITFIELD: H5TOOLS_DEBUG("H5T_BITFIELD"); /* byte-by-byte comparison */ for (u = 0; u < type_size; u++) nfound += character_compare_opt(mem1 + u, mem2 + u, elemtno, opts); break; /*------------------------------------------------------------------------- * H5T_OPAQUE *------------------------------------------------------------------------- */ case H5T_OPAQUE: H5TOOLS_DEBUG("H5T_OPAQUE"); /* byte-by-byte comparison */ for (u = 0; u < type_size; u++) nfound += character_compare_opt(mem1 + u, mem2 + u, elemtno, opts); break; /*------------------------------------------------------------------------- * H5T_ENUM *------------------------------------------------------------------------- */ case H5T_ENUM: /* For enumeration types we compare the names instead of the * integer values. For each pair of elements being * compared, we convert both bit patterns to their corresponding * enumeration constant and do a string comparison */ H5TOOLS_DEBUG("H5T_ENUM"); { char enum_name1[1024]; char enum_name2[1024]; herr_t err1; herr_t err2; /* disable error reporting */ H5E_BEGIN_TRY { /* If the enum value cannot be converted to a string * it is set to an error string for later output. */ err1 = H5Tenum_nameof(opts->m_tid, mem1, enum_name1, sizeof enum_name1); if (err1 < 0) snprintf(enum_name1, sizeof(enum_name1), "**INVALID VALUE**"); err2 = H5Tenum_nameof(opts->m_tid, mem2, enum_name2, sizeof enum_name2); if (err2 < 0) snprintf(enum_name2, sizeof(enum_name2), "**INVALID VALUE**"); /* One or more bad enum values */ if (err1 < 0 || err2 < 0) { /* If the two values cannot be converted to a string * (probably due to them being invalid enum values), * don't attempt to convert them - just report errors. */ nfound += 1; opts->print_percentage = 0; print_pos(opts, elemtno, 0); if (print_data(opts)) { parallel_print(S_FORMAT, enum_name1, enum_name2); } } else { /* Both enum values were valid */ if (strcmp(enum_name1, enum_name2) != 0) { nfound = 1; opts->print_percentage = 0; print_pos(opts, elemtno, 0); if (print_data(opts)) { parallel_print(S_FORMAT, enum_name1, enum_name2); } } else { for (u = 0; u < type_size; u++) nfound += character_compare_opt(mem1 + u, mem2 + u, elemtno, opts); } } /* enable error reporting */ } H5E_END_TRY } break; /*------------------------------------------------------------------------- * H5T_ARRAY *------------------------------------------------------------------------- */ case H5T_ARRAY: { hsize_t adims[H5S_MAX_RANK]; int ndims; diff_opt_t arr_opts; H5TOOLS_DEBUG("H5T_ARRAY ph=%d", opts->print_header); arr_opts = *opts; H5TOOLS_DEBUG("Check opts: hs_nelmts:%" PRIuHSIZE " to %" PRIuHSIZE " rank:%d to %d", opts->hs_nelmts, arr_opts.hs_nelmts, opts->rank, arr_opts.rank); /* get the array's base datatype for each element */ arr_opts.m_tid = H5Tget_super(opts->m_tid); size = H5Tget_size(arr_opts.m_tid); ndims = H5Tget_array_ndims(opts->m_tid); H5Tget_array_dims2(opts->m_tid, adims); assert(ndims >= 1 && ndims <= H5S_MAX_RANK); H5TOOLS_DEBUG("attr ph=%d", arr_opts.print_header); /* calculate the number of array elements */ for (u = 0, arr_opts.hs_nelmts = 1; u < (unsigned)ndims; u++) arr_opts.hs_nelmts *= adims[u]; for (u = 0; u < arr_opts.hs_nelmts; u++) { nfound += diff_datum(mem1 + u * size, mem2 + u * size, elemtno, &arr_opts, container1_id, container2_id, members); } opts->err_stat = opts->err_stat | arr_opts.err_stat; opts->print_header = arr_opts.print_header; opts->not_cmp = arr_opts.not_cmp; H5Tclose(arr_opts.m_tid); } break; /*------------------------------------------------------------------------- * H5T_REFERENCE *------------------------------------------------------------------------- */ case H5T_REFERENCE: H5TOOLS_DEBUG("H5T_REFERENCE"); iszero1 = all_zero(_mem1, H5Tget_size(opts->m_tid)); iszero2 = all_zero(_mem2, H5Tget_size(opts->m_tid)); if (iszero1 != iszero2) { nfound++; H5TOOLS_GOTO_DONE(opts->err_stat); } else if (!iszero1 && !iszero2) { hid_t obj1_id = H5I_INVALID_HID; hid_t obj2_id = H5I_INVALID_HID; diff_opt_t ref_opts; /*------------------------------------------------------------------------- * H5T_STD_REF * Reference *------------------------------------------------------------------------- */ ref_opts = *opts; ref_opts.obj_name[0] = NULL; ref_opts.obj_name[1] = NULL; if (H5Tequal(ref_opts.m_tid, H5T_STD_REF)) { /* if (type_size == H5R_STD_REF_SIZE) */ hid_t region1_id = H5I_INVALID_HID; hid_t region2_id = H5I_INVALID_HID; H5R_ref_t *ref1_buf = (H5R_ref_t *)_mem1; H5R_ref_t *ref2_buf = (H5R_ref_t *)_mem2; H5O_type_t obj1_type = -1; /* Object type */ H5O_type_t obj2_type = -1; /* Object type */ H5R_type_t ref_type; /* Reference type */ H5TOOLS_DEBUG("H5T_REFERENCE - H5T_STD_REF"); ref_type = H5Rget_type(ref1_buf); switch (ref_type) { case H5R_OBJECT1: H5TOOLS_DEBUG("ref_type is H5R_OBJECT1"); if (H5Rget_obj_type3(ref1_buf, H5P_DEFAULT, &obj1_type) >= 0) { if (H5Rget_obj_type3(ref2_buf, H5P_DEFAULT, &obj2_type) >= 0) { /* check object type */ if (obj1_type == obj2_type) { switch (obj1_type) { case H5O_TYPE_DATASET: if ((obj1_id = H5Ropen_object(ref1_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { if ((obj2_id = H5Ropen_object(ref2_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { nfound = diff_datasetid(obj1_id, obj2_id, opts->obj_name[0], opts->obj_name[1], &ref_opts); if (H5Dclose(obj2_id) < 0) { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Dclose H5R_OBJECT1 failed"); } } else { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Ropen_object object 2 failed"); } if (H5Dclose(obj1_id) < 0) { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Dclose H5R_OBJECT1 failed"); } } else { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Ropen_object object 1 failed"); } break; case H5O_TYPE_GROUP: case H5O_TYPE_NAMED_DATATYPE: case H5O_TYPE_MAP: case H5O_TYPE_UNKNOWN: case H5O_TYPE_NTYPES: default: if (ref_opts.mode_verbose) parallel_print("Warning: Comparison not possible of " "object types referenced: <%s> and <%s>\n", opts->obj_name[0], opts->obj_name[1]); ref_opts.not_cmp = 1; break; } /* end switch */ } else { parallel_print("Different object types referenced: <%s> and <%s>", opts->obj_name[0], opts->obj_name[1]); ref_opts.not_cmp = 1; ref_opts.err_stat = H5DIFF_ERR; } } else { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Rget_obj_type3 object 2 failed"); } } else { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Rget_obj_type3 object 1 failed"); } break; case H5R_DATASET_REGION1: H5TOOLS_DEBUG("ref_type is H5R_DATASET_REGION1"); if ((obj1_id = H5Ropen_object(ref1_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { if ((obj2_id = H5Ropen_object(ref2_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { if ((region1_id = H5Ropen_region(ref1_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { if ((region2_id = H5Ropen_region(ref2_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { nfound = diff_region(obj1_id, obj2_id, region1_id, region2_id, &ref_opts); if (H5Sclose(region2_id) < 0) H5TOOLS_INFO("H5Sclose H5R_DATASET_REGION1 failed"); } if (H5Sclose(region1_id) < 0) H5TOOLS_INFO("H5Sclose H5R_DATASET_REGION1 failed"); } if (H5Dclose(obj2_id) < 0) H5TOOLS_INFO("H5Oclose H5R_DATASET_REGION1 failed"); } else { H5TOOLS_INFO("H5Ropen_object H5R_DATASET_REGION1 failed"); } if (H5Dclose(obj1_id) < 0) H5TOOLS_INFO("H5Oclose H5R_DATASET_REGION1 failed"); } else { H5TOOLS_INFO("H5Ropen_object H5R_DATASET_REGION1 failed"); } break; case H5R_OBJECT2: H5TOOLS_DEBUG("ref_type is H5R_OBJECT2"); if (H5Rget_obj_type3(ref1_buf, H5P_DEFAULT, &obj1_type) >= 0) { if (H5Rget_obj_type3(ref2_buf, H5P_DEFAULT, &obj2_type) >= 0) { /* check object type */ if (obj1_type == obj2_type) { if ((obj1_id = H5Ropen_object(ref1_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { if ((obj2_id = H5Ropen_object(ref2_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { switch (obj1_type) { case H5O_TYPE_DATASET: H5TOOLS_DEBUG("ref_type is H5R_OBJECT2 : DATASET"); nfound = diff_datasetid(obj1_id, obj2_id, opts->obj_name[0], opts->obj_name[1], &ref_opts); break; case H5O_TYPE_GROUP: H5TOOLS_DEBUG("ref_type is H5R_OBJECT2 : GROUP"); if (ref_opts.mode_verbose) parallel_print( "Warning: Comparison not possible of group " "object types referenced: <%s> and <%s>\n", opts->obj_name[0], opts->obj_name[1]); ref_opts.not_cmp = 1; break; case H5O_TYPE_NAMED_DATATYPE: H5TOOLS_DEBUG("ref_type is H5R_OBJECT2 : NAMED"); if (ref_opts.mode_verbose) parallel_print("Warning: Comparison not possible " "of named datatypes object types " "referenced: <%s> and <%s>\n", opts->obj_name[0], opts->obj_name[1]); ref_opts.not_cmp = 1; break; case H5O_TYPE_MAP: case H5O_TYPE_UNKNOWN: case H5O_TYPE_NTYPES: default: if (ref_opts.mode_verbose) parallel_print( "Warning: Comparison not possible of object " "types referenced: <%s> and <%s>\n", opts->obj_name[0], opts->obj_name[1]); ref_opts.not_cmp = 1; break; } /* end switch */ if (H5Oclose(obj2_id) < 0) { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Oclose H5R_OBJECT2 failed"); } } else { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Ropen_object object 2 failed"); } if (H5Oclose(obj1_id) < 0) { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Oclose H5R_OBJECT2 failed"); } } else { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Ropen_object object 1 failed"); } } else { parallel_print("Different object types referenced: <%s> and <%s>", opts->obj_name[0], opts->obj_name[1]); ref_opts.not_cmp = 1; ref_opts.err_stat = H5DIFF_ERR; } } else { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Rget_obj_type3 object 2 failed"); } } else { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Rget_obj_type3 object 1 failed"); } break; case H5R_DATASET_REGION2: H5TOOLS_DEBUG("ref_type is H5R_DATASET_REGION2"); /* if (obj_id < 0) - could mean that no reference was written do not throw failure */ if ((obj1_id = H5Ropen_object(ref1_buf, H5P_DEFAULT, H5P_DEFAULT)) < 0) { H5TOOLS_INFO("H5Ropen_object H5R_DATASET_REGION2 object 1 failed"); } else { if ((obj2_id = H5Ropen_object(ref2_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { H5TOOLS_DEBUG("open_region - H5R_DATASET_REGION2"); if ((region1_id = H5Ropen_region(ref1_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { if (h5tools_is_zero(ref1_buf, H5Tget_size(H5T_STD_REF))) { H5TOOLS_DEBUG("NULL H5R_DATASET_REGION2"); } else { if ((region2_id = H5Ropen_region(ref2_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { if (h5tools_is_zero(ref2_buf, H5Tget_size(H5T_STD_REF))) { H5TOOLS_DEBUG("NULL H5R_DATASET_REGION2"); } else { nfound = diff_region(obj1_id, obj2_id, region1_id, region2_id, &ref_opts); } if (H5Sclose(region2_id) < 0) H5TOOLS_INFO("H5Sclose H5R_DATASET_REGION2 failed"); } else H5TOOLS_INFO("H5Ropen_region H5R_DATASET_REGION2 failed"); } /* end else to if (h5tools_is_zero(... */ if (H5Sclose(region1_id) < 0) H5TOOLS_INFO("H5Sclose H5R_DATASET_REGION2 failed"); } else H5TOOLS_ERROR(H5DIFF_ERR, "H5Ropen_region H5R_DATASET_REGION2 failed"); if (H5Dclose(obj2_id) < 0) { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Dclose H5R_DATASET_REGION2 failed"); } } else { H5TOOLS_INFO("H5Ropen_object H5R_DATASET_REGION2 object 2 failed"); } if (H5Dclose(obj1_id) < 0) { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Dclose H5R_DATASET_REGION2 failed"); } } break; case H5R_ATTR: { char name1[ATTR_NAME_MAX]; char name2[ATTR_NAME_MAX]; H5TOOLS_DEBUG("ref_type is H5R_ATTR"); if ((obj1_id = H5Ropen_attr(ref1_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { if ((obj2_id = H5Ropen_attr(ref2_buf, H5P_DEFAULT, H5P_DEFAULT)) >= 0) { /* get name */ if (H5Aget_name(obj1_id, (size_t)ATTR_NAME_MAX, name1) >= 0) { /* get name */ if (H5Aget_name(obj2_id, (size_t)ATTR_NAME_MAX, name2) >= 0) { H5TOOLS_DEBUG("H5R_ATTR diff_attr_data - name1=%s, name2=%s", name1, name2); nfound = diff_attr_data(obj1_id, obj2_id, name1, name2, opts->obj_name[0], opts->obj_name[1], &ref_opts); } else { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Aget_name second attribute failed"); } } else { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Aget_name first attribute failed"); } if (H5Aclose(obj2_id) < 0) { ref_opts.err_stat = H5DIFF_ERR; H5TOOLS_INFO("H5Aclose H5R_ATTR failed"); } } else { parallel_print("Warning: Cannot open referenced attribute2\n"); H5TOOLS_INFO("H5Ropen_attr object 2 failed"); } if (H5Aclose(obj1_id) < 0) { H5TOOLS_INFO("H5Aclose H5R_ATTR failed"); } } else { parallel_print("Warning: Cannot open referenced attribute1\n"); H5TOOLS_INFO("H5Ropen_attr object 1 failed"); } } break; case H5R_BADTYPE: case H5R_MAXTYPE: default: break; } /* end switch */ if (H5Rdestroy(ref2_buf) < 0) H5TOOLS_INFO("H5Rdestroy H5R_OBJECT1 failed"); if (H5Rdestroy(ref1_buf) < 0) H5TOOLS_INFO("H5Rdestroy H5R_OBJECT1 failed"); H5TOOLS_DEBUG("H5T_REFERENCE - H5T_STD_REF complete nfound:%" PRIuHSIZE " - errstat:%d", nfound, ref_opts.err_stat); } /*------------------------------------------------------------------------- * H5T_STD_REF_DSETREG * Dataset region reference *------------------------------------------------------------------------- */ else if (H5Tequal(ref_opts.m_tid, H5T_STD_REF_DSETREG)) { /* if (type_size == H5R_DSET_REG_REF_BUF_SIZE) */ H5TOOLS_DEBUG("H5T_STD_REF_DSETREG"); } /*dataset reference*/ /*------------------------------------------------------------------------- * H5T_STD_REF_OBJ * Object references. get the type and OID of the referenced object *------------------------------------------------------------------------- */ else if (H5Tequal(ref_opts.m_tid, H5T_STD_REF_OBJ)) { /* if (type_size == H5R_OBJ_REF_BUF_SIZE) */ H5TOOLS_DEBUG("H5T_STD_REF_OBJ"); } /*object reference*/ opts->print_header = ref_opts.print_header; opts->not_cmp = ref_opts.not_cmp; opts->err_stat = ref_opts.err_stat | ret_value; } /*is zero*/ H5TOOLS_DEBUG("H5T_REFERENCE complete"); break; /*------------------------------------------------------------------------- * H5T_VLEN *------------------------------------------------------------------------- */ case H5T_VLEN: { diff_opt_t vl_opts; H5TOOLS_DEBUG("H5T_VLEN"); vl_opts = *opts; /* get the VL sequences's base datatype for each element */ vl_opts.m_tid = H5Tget_super(opts->m_tid); size = H5Tget_size(vl_opts.m_tid); /* get the number of sequence elements */ vl_opts.hs_nelmts = ((hvl_t *)((void *)mem1))->len; for (j = 0; j < vl_opts.hs_nelmts; j++) nfound += diff_datum(((char *)(((hvl_t *)((void *)mem1))->p)) + j * size, ((char *)(((hvl_t *)((void *)mem2))->p)) + j * size, elemtno, /* Extra (void *) cast to quiet "cast to create alignment" warning - 2019/07/05, QAK */ &vl_opts, container1_id, container2_id, members); opts->print_header = vl_opts.print_header; opts->not_cmp = vl_opts.not_cmp; opts->err_stat = opts->err_stat | vl_opts.err_stat; H5Tclose(vl_opts.m_tid); } break; /*------------------------------------------------------------------------- * H5T_INTEGER *------------------------------------------------------------------------- */ case H5T_INTEGER: H5TOOLS_DEBUG("H5T_INTEGER"); type_sign = H5Tget_sign(opts->m_tid); /*------------------------------------------------------------------------- * H5T_NATIVE_SCHAR *------------------------------------------------------------------------- */ if (type_size == 1 && type_sign != H5T_SGN_NONE) { if (type_size != sizeof(char)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not char size"); nfound += diff_schar_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_SCHAR*/ /*------------------------------------------------------------------------- * H5T_NATIVE_UCHAR *------------------------------------------------------------------------- */ else if (type_size == 1 && type_sign == H5T_SGN_NONE) { if (type_size != sizeof(unsigned char)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not unsigned char size"); nfound += diff_uchar_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_UCHAR*/ /*------------------------------------------------------------------------- * H5T_NATIVE_SHORT *------------------------------------------------------------------------- */ else if (type_size == 2 && type_sign != H5T_SGN_NONE) { if (type_size != sizeof(short)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not short size"); nfound += diff_short_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_SHORT*/ /*------------------------------------------------------------------------- * H5T_NATIVE_USHORT *------------------------------------------------------------------------- */ else if (type_size == 2 && type_sign == H5T_SGN_NONE) { if (type_size != sizeof(unsigned short)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not unsigned short size"); nfound += diff_ushort_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_USHORT*/ /*------------------------------------------------------------------------- * H5T_NATIVE_INT *------------------------------------------------------------------------- */ else if (type_size == 4 && type_sign != H5T_SGN_NONE) { if (type_size != sizeof(int)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not int size"); nfound += diff_int_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_INT*/ /*------------------------------------------------------------------------- * H5T_NATIVE_UINT *------------------------------------------------------------------------- */ else if (type_size == 4 && type_sign == H5T_SGN_NONE) { if (type_size != sizeof(unsigned int)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not unsigned int size"); nfound += diff_uint_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_UINT*/ /*------------------------------------------------------------------------- * H5T_NATIVE_LONG *------------------------------------------------------------------------- */ else if (type_size == 8 && type_sign != H5T_SGN_NONE) { if (type_size != sizeof(long)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not long size"); nfound += diff_long_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_LONG*/ /*------------------------------------------------------------------------- * H5T_NATIVE_ULONG *------------------------------------------------------------------------- */ else if (type_size == 8 && type_sign == H5T_SGN_NONE) { if (type_size != sizeof(unsigned long)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not unsigned long size"); nfound += diff_ulong_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_ULONG*/ /*------------------------------------------------------------------------- * H5T_NATIVE_LLONG *------------------------------------------------------------------------- */ else if (type_size == 16 && type_sign != H5T_SGN_NONE) { if (type_size != sizeof(long long)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not long long size"); nfound += diff_llong_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_LLONG*/ /*------------------------------------------------------------------------- * H5T_NATIVE_ULLONG *------------------------------------------------------------------------- */ else if (type_size == 16 && type_sign == H5T_SGN_NONE) { if (type_size != sizeof(unsigned long long)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not unsigned long long size"); nfound += diff_ullong_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_ULLONG*/ break; /* H5T_INTEGER class */ /*------------------------------------------------------------------------- * H5T_FLOAT *------------------------------------------------------------------------- */ case H5T_FLOAT: H5TOOLS_DEBUG("H5T_FLOAT"); #ifdef H5_HAVE__FLOAT16 /*------------------------------------------------------------------------- * H5T_NATIVE_FLOAT16 *------------------------------------------------------------------------- */ if (type_size == H5_SIZEOF__FLOAT16) { if (type_size != sizeof(H5__Float16)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not _Float16 size"); nfound += diff_float16_element(mem1, mem2, elemtno, opts); } else #endif /*------------------------------------------------------------------------- * H5T_NATIVE_FLOAT *------------------------------------------------------------------------- */ if (type_size == 4) { if (type_size != sizeof(float)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not float size"); nfound += diff_float_element(mem1, mem2, elemtno, opts); } /*------------------------------------------------------------------------- * H5T_NATIVE_DOUBLE *------------------------------------------------------------------------- */ else if (type_size == 8) { if (type_size != sizeof(double)) H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not double size"); nfound += diff_double_element(mem1, mem2, elemtno, opts); } #if H5_SIZEOF_LONG_DOUBLE != H5_SIZEOF_DOUBLE /*------------------------------------------------------------------------- * H5T_NATIVE_LDOUBLE *------------------------------------------------------------------------- */ else if (type_size == H5_SIZEOF_LONG_DOUBLE) { if (type_size != sizeof(long double)) { H5TOOLS_GOTO_ERROR(H5DIFF_ERR, "Type size is not long double size"); } nfound += diff_ldouble_element(mem1, mem2, elemtno, opts); } /*H5T_NATIVE_LDOUBLE*/ #endif /* H5_SIZEOF_LONG_DOUBLE */ break; /* H5T_FLOAT class */ } /* switch */ done: opts->err_stat = opts->err_stat | ret_value; H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: all_zero * * Purpose: Determines if memory is initialized to all zero bytes. * * Return: true if all bytes are zero; false otherwise *------------------------------------------------------------------------- */ static bool all_zero(const void *_mem, size_t size) { const unsigned char *mem = (const unsigned char *)_mem; while (size-- > 0) if (mem[size]) return false; return true; } /*------------------------------------------------------------------------- * Function: print_region_block * * Purpose: print start coordinates and opposite corner of a region block * * Return: void *------------------------------------------------------------------------- */ static void print_region_block(int i, hsize_t *ptdata, int ndims) { int j; parallel_print(" "); for (j = 0; j < ndims; j++) parallel_print("%s%lu", j ? "," : " (", (unsigned long)ptdata[i * 2 * ndims + j]); for (j = 0; j < ndims; j++) parallel_print("%s%lu", j ? "," : ")-(", (unsigned long)ptdata[i * 2 * ndims + j + ndims]); parallel_print(")"); } /*------------------------------------------------------------------------- * Function: print_points * * Purpose: print points of a region reference * * Return: void *------------------------------------------------------------------------- */ static void print_points(int i, hsize_t *ptdata, int ndims) { int j; parallel_print(" "); for (j = 0; j < ndims; j++) parallel_print("%s%lu", j ? "," : "(", (unsigned long)(ptdata[i * ndims + j])); parallel_print(")"); } /*------------------------------------------------------------------------- * Function: diff_region * * Purpose: diff a dataspace region * * Return: number of differences *------------------------------------------------------------------------- */ static hsize_t diff_region(hid_t obj1_id, hid_t obj2_id, hid_t region1_id, hid_t region2_id, diff_opt_t *opts) { hssize_t nblocks1, npoints1; hssize_t nblocks2, npoints2; hsize_t alloc_size; hsize_t *ptdata1 = NULL; hsize_t *ptdata2 = NULL; int ndims1; int ndims2; int i, j; hsize_t nfound_b = 0; /* block differences found */ hsize_t nfound_p = 0; /* point differences found */ hsize_t ret_value = 0; H5TOOLS_START_DEBUG(" "); ndims1 = H5Sget_simple_extent_ndims(region1_id); ndims2 = H5Sget_simple_extent_ndims(region2_id); /* * These two functions fail if the region does not have blocks or points, * respectively. They do not currently know how to translate from one to * the other. */ H5E_BEGIN_TRY { nblocks1 = H5Sget_select_hyper_nblocks(region1_id); nblocks2 = H5Sget_select_hyper_nblocks(region2_id); npoints1 = H5Sget_select_elem_npoints(region1_id); npoints2 = H5Sget_select_elem_npoints(region2_id); } H5E_END_TRY H5TOOLS_DEBUG("blocks: 1=%" PRIdHSIZE "-2=%" PRIdHSIZE, nblocks1, nblocks2); H5TOOLS_DEBUG("points: 1=%" PRIdHSIZE "-2=%" PRIdHSIZE, npoints1, npoints2); if (nblocks1 != nblocks2 || npoints1 != npoints2 || ndims1 != ndims2) { opts->not_cmp = 1; H5TOOLS_GOTO_DONE(0); } /*------------------------------------------------------------------------- * compare block information *------------------------------------------------------------------------- */ if (nblocks1 > 0) { H5TOOLS_DEBUG("region compare blocks"); assert(ndims1 > 0); alloc_size = (hsize_t)nblocks1 * (unsigned)ndims1 * 2 * sizeof(ptdata1[0]); assert(alloc_size == (hsize_t)((size_t)alloc_size)); /*check for overflow*/ if ((ptdata1 = (hsize_t *)malloc((size_t)alloc_size)) == NULL) { opts->err_stat = H5DIFF_ERR; H5TOOLS_INFO("Buffer allocation failed"); } else { H5_CHECK_OVERFLOW(nblocks1, hssize_t, hsize_t); H5Sget_select_hyper_blocklist(region1_id, (hsize_t)0, (hsize_t)nblocks1, ptdata1); if ((ptdata2 = (hsize_t *)malloc((size_t)alloc_size)) == NULL) { opts->err_stat = H5DIFF_ERR; H5TOOLS_INFO("Buffer allocation failed"); } else { H5_CHECK_OVERFLOW(nblocks2, hssize_t, hsize_t); H5Sget_select_hyper_blocklist(region2_id, (hsize_t)0, (hsize_t)nblocks2, ptdata2); for (i = 0; i < nblocks1; i++) { /* start coordinates and opposite corner */ for (j = 0; j < ndims1; j++) { hsize_t start1, start2, end1, end2; start1 = ptdata1[i * 2 * ndims1 + j]; start2 = ptdata2[i * 2 * ndims1 + j]; end1 = ptdata1[i * 2 * ndims1 + j + ndims1]; end2 = ptdata2[i * 2 * ndims1 + j + ndims1]; if (start1 != start2 || end1 != end2) nfound_b++; } } /* print differences if found */ if (nfound_b && opts->mode_verbose) { H5O_info2_t oi1, oi2; char *obj1_str = NULL, *obj2_str = NULL; H5Oget_info3(obj1_id, &oi1, H5O_INFO_BASIC); H5Oget_info3(obj2_id, &oi2, H5O_INFO_BASIC); /* Convert object tokens into printable output */ H5Otoken_to_str(obj1_id, &oi1.token, &obj1_str); H5Otoken_to_str(obj2_id, &oi2.token, &obj2_str); parallel_print("Referenced dataset %s %s\n", obj1_str, obj2_str); parallel_print("------------------------------------------------------------\n"); H5free_memory(obj1_str); H5free_memory(obj2_str); parallel_print("Region blocks\n"); for (i = 0; i < nblocks1; i++) { parallel_print("block #%d", i); print_region_block(i, ptdata1, ndims1); print_region_block(i, ptdata2, ndims1); parallel_print("\n"); } } free(ptdata2); } /* else ptdata2 */ free(ptdata1); } /* else ptdata1 */ } /*------------------------------------------------------------------------- * compare point information *------------------------------------------------------------------------- */ if (npoints1 > 0) { H5TOOLS_DEBUG("region compare points"); alloc_size = (hsize_t)npoints1 * (unsigned)ndims1 * sizeof(ptdata1[0]); assert(alloc_size == (hsize_t)((size_t)alloc_size)); /*check for overflow*/ if ((ptdata1 = (hsize_t *)malloc((size_t)alloc_size)) == NULL) { opts->err_stat = H5DIFF_ERR; H5TOOLS_INFO("Buffer allocation failed"); } else { H5_CHECK_OVERFLOW(npoints1, hssize_t, hsize_t); H5Sget_select_elem_pointlist(region1_id, (hsize_t)0, (hsize_t)npoints1, ptdata1); if ((ptdata2 = (hsize_t *)malloc((size_t)alloc_size)) == NULL) { opts->err_stat = H5DIFF_ERR; H5TOOLS_INFO("Buffer allocation failed"); } else { H5_CHECK_OVERFLOW(npoints1, hssize_t, hsize_t); H5Sget_select_elem_pointlist(region2_id, (hsize_t)0, (hsize_t)npoints2, ptdata2); for (i = 0; i < npoints1; i++) { hsize_t pt1, pt2; for (j = 0; j < ndims1; j++) { pt1 = ptdata1[i * ndims1 + j]; pt2 = ptdata2[i * ndims1 + j]; if (pt1 != pt2) nfound_p++; } } if (nfound_p && opts->mode_verbose) { parallel_print("Region points\n"); for (i = 0; i < npoints1; i++) { hsize_t pt1, pt2; int diff_data = 0; for (j = 0; j < ndims1; j++) { pt1 = ptdata1[i * ndims1 + j]; pt2 = ptdata2[i * ndims1 + j]; if (pt1 != pt2) { diff_data = 1; break; } } if (diff_data) { parallel_print("point #%d", i); print_points(i, ptdata1, ndims1); print_points(i, ptdata2, ndims1); parallel_print("\n"); } } } free(ptdata2); } /* else ptdata2 */ #if defined(H5DIFF_DEBUG) for (i = 0; i < npoints1; i++) { parallel_print("%sPt%d: ", i ? "," : "", i); for (j = 0; j < ndims1; j++) parallel_print("%s%" PRIuHSIZE, j ? "," : "(", ptdata1[i * ndims1 + j]); parallel_print(")"); } parallel_print("\n"); #endif free(ptdata1); } /* else ptdata1 */ } nfound_b = nfound_b / (unsigned)ndims1; nfound_p = nfound_p / (unsigned)ndims1; ret_value = nfound_p + nfound_b; done: H5TOOLS_ENDDEBUG(" with diffs:%" PRIuHSIZE, ret_value); return ret_value; } /*------------------------------------------------------------------------- * Function: character_compare * * Purpose: do a byte-by-byte comparison and print in char format * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t character_compare(char *mem1, char *mem2, hsize_t elemtno, size_t u, diff_opt_t *opts) { hsize_t nfound = 0; /* differences found */ char temp1_uchar; char temp2_uchar; memcpy(&temp1_uchar, mem1, sizeof(unsigned char)); memcpy(&temp2_uchar, mem2, sizeof(unsigned char)); H5TOOLS_START_DEBUG(" %d=%d", temp1_uchar, temp2_uchar); if (temp1_uchar != temp2_uchar) { if (print_data(opts)) { opts->print_percentage = 0; opts->print_dims = 1; print_pos(opts, elemtno, u); parallel_print(" "); h5diff_print_char(temp1_uchar); parallel_print(" "); h5diff_print_char(temp2_uchar); parallel_print("\n"); } nfound++; } H5TOOLS_ENDDEBUG(": %" PRIuHSIZE, nfound); return nfound; } /*------------------------------------------------------------------------- * Function: character_compare_opt * * Purpose: do a byte-by-byte comparison and print in numerical format * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t character_compare_opt(unsigned char *mem1, unsigned char *mem2, hsize_t elemtno, diff_opt_t *opts) { hsize_t nfound = 0; /* differences found */ unsigned char temp1_uchar; unsigned char temp2_uchar; bool both_zero = false; double per; /* both_zero is set in the PER_UNSIGN macro but not used in this function */ (void)both_zero; memcpy(&temp1_uchar, mem1, sizeof(unsigned char)); memcpy(&temp2_uchar, mem2, sizeof(unsigned char)); H5TOOLS_START_DEBUG(" %d=%d", temp1_uchar, temp2_uchar); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (PDIFF(temp1_uchar, temp2_uchar) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elemtno, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_uchar, temp2_uchar, PDIFF(temp1_uchar, temp2_uchar)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { PER_UNSIGN(signed char, temp1_uchar, temp2_uchar); if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elemtno, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_uchar, temp2_uchar, PDIFF(temp1_uchar, temp2_uchar), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { PER_UNSIGN(signed char, temp1_uchar, temp2_uchar); if (per > opts->percent && PDIFF(temp1_uchar, temp2_uchar) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elemtno, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_uchar, temp2_uchar, PDIFF(temp1_uchar, temp2_uchar), per); } nfound++; } } else if (temp1_uchar != temp2_uchar) { opts->print_percentage = 0; print_pos(opts, elemtno, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_uchar, temp2_uchar, PDIFF(temp1_uchar, temp2_uchar)); } nfound++; } H5TOOLS_ENDDEBUG(": %" PRIuHSIZE " zero:%d", nfound, both_zero); return nfound; } /*------------------------------------------------------------------------- * Function: diff_float_element * * Purpose: diff a single H5T_NATIVE_FLOAT type * * Return: number of differences found * *------------------------------------------------------------------------- */ static hsize_t diff_float_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ float temp1_float; float temp2_float; double per; bool both_zero = false; bool isnan1 = false; bool isnan2 = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_float, mem1, sizeof(float)); memcpy(&temp2_float, mem2, sizeof(float)); /* logic for detecting NaNs is different with opts -d, -p and no opts */ /*------------------------------------------------------------------------- * -d and !-p *------------------------------------------------------------------------- */ if (opts->delta_bool && !opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_float); isnan2 = isnan(temp2_float); } /* both not NaN, do the comparison */ if (!isnan1 && !isnan2) { if ((double)ABS(temp1_float - temp2_float) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, (double)temp1_float, (double)temp2_float, (double)ABS(temp1_float - temp2_float)); } nfound++; } } /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, (double)temp1_float, (double)temp2_float, (double)ABS(temp1_float - temp2_float)); } nfound++; } } /*------------------------------------------------------------------------- * !-d and -p *------------------------------------------------------------------------- */ else if (!opts->delta_bool && opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_float); isnan2 = isnan(temp2_float); } /* both not NaN, do the comparison */ if ((!isnan1 && !isnan2)) { PER(temp1_float, temp2_float); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P_NOTCOMP, (double)temp1_float, (double)temp2_float, (double)ABS(temp1_float - temp2_float)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P, (double)temp1_float, (double)temp2_float, (double)ABS(temp1_float - temp2_float), (double)ABS(1 - temp2_float / temp1_float)); } nfound++; } } /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, (double)temp1_float, (double)temp2_float, (double)ABS(temp1_float - temp2_float)); } nfound++; } } /*------------------------------------------------------------------------- * -d and -p *------------------------------------------------------------------------- */ else if (opts->delta_bool && opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_float); isnan2 = isnan(temp2_float); } /* both not NaN, do the comparison */ if (!isnan1 && !isnan2) { PER(temp1_float, temp2_float); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P_NOTCOMP, (double)temp1_float, (double)temp2_float, (double)ABS(temp1_float - temp2_float)); } nfound++; } else if (per > opts->percent && (double)ABS(temp1_float - temp2_float) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P, (double)temp1_float, (double)temp2_float, (double)ABS(temp1_float - temp2_float), (double)ABS(1 - temp2_float / temp1_float)); } nfound++; } } /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, (double)temp1_float, (double)temp2_float, (double)ABS(temp1_float - temp2_float)); } nfound++; } } /*------------------------------------------------------------------------- * no -d and -p *------------------------------------------------------------------------- */ else { if (equal_float(temp1_float, temp2_float, opts) == false) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, (double)temp1_float, (double)temp2_float, (double)ABS(temp1_float - temp2_float)); } nfound++; } } H5TOOLS_ENDDEBUG(": %" PRIuHSIZE " zero:%d", nfound, both_zero); return nfound; } /*------------------------------------------------------------------------- * Function: diff_double_element * * Purpose: diff a single H5T_NATIVE_DOUBLE type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_double_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ double temp1_double; double temp2_double; double per; bool both_zero = false; bool isnan1 = false; bool isnan2 = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_double, mem1, sizeof(double)); memcpy(&temp2_double, mem2, sizeof(double)); /*------------------------------------------------------------------------- * -d and !-p *------------------------------------------------------------------------- */ if (opts->delta_bool && !opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_double); isnan2 = isnan(temp2_double); } /* both not NaN, do the comparison */ if (!isnan1 && !isnan2) { if (ABS(temp1_double - temp2_double) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } } /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } } /*------------------------------------------------------------------------- * !-d and -p *------------------------------------------------------------------------- */ else if (!opts->delta_bool && opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_double); isnan2 = isnan(temp2_double); } /* both not NaN, do the comparison */ if (!isnan1 && !isnan2) { PER(temp1_double, temp2_double); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P_NOTCOMP, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P, temp1_double, temp2_double, ABS(temp1_double - temp2_double), ABS(1 - temp2_double / temp1_double)); } nfound++; } } /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } } /*------------------------------------------------------------------------- * -d and -p *------------------------------------------------------------------------- */ else if (opts->delta_bool && opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_double); isnan2 = isnan(temp2_double); } /* both not NaN, do the comparison */ if (!isnan1 && !isnan2) { PER(temp1_double, temp2_double); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P_NOTCOMP, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } else if (per > opts->percent && ABS(temp1_double - temp2_double) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P, temp1_double, temp2_double, ABS(temp1_double - temp2_double), ABS(1 - temp2_double / temp1_double)); } nfound++; } } /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } } /*------------------------------------------------------------------------- * no -d and -p *------------------------------------------------------------------------- */ else { if (equal_double(temp1_double, temp2_double, opts) == false) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_ldouble_element * * Purpose: diff a single H5T_NATIVE_LDOUBLE type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_ldouble_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ long double temp1_double; long double temp2_double; double per; bool both_zero = false; bool isnan1 = false; bool isnan2 = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_double, mem1, sizeof(long double)); memcpy(&temp2_double, mem2, sizeof(long double)); /* logic for detecting NaNs is different with options -d, -p and no options */ /*------------------------------------------------------------------------- * -d and !-p *------------------------------------------------------------------------- */ if (opts->delta_bool && !opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_double); isnan2 = isnan(temp2_double); } /* both not NaN, do the comparison */ if (!isnan1 && !isnan2) { if ((double)ABS(temp1_double - temp2_double) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LD_FORMAT, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } } /* NaN */ /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LD_FORMAT, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } } /*------------------------------------------------------------------------- * !-d and -p *------------------------------------------------------------------------- */ else if (!opts->delta_bool && opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_double); isnan2 = isnan(temp2_double); } /* both not NaN, do the comparison */ if (!isnan1 && !isnan2) { PER(temp1_double, temp2_double); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LD_FORMAT_P_NOTCOMP, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LD_FORMAT_P, temp1_double, temp2_double, ABS(temp1_double - temp2_double), ABS(1 - temp2_double / temp1_double)); } nfound++; } } /* NaN */ /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LD_FORMAT, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } } /*------------------------------------------------------------------------- * -d and -p *------------------------------------------------------------------------- */ else if (opts->delta_bool && opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_double); isnan2 = isnan(temp2_double); } /* both not NaN, do the comparison */ if (!isnan1 && !isnan2) { PER(temp1_double, temp2_double); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LD_FORMAT_P_NOTCOMP, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } else if (per > opts->percent && (double)ABS(temp1_double - temp2_double) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LD_FORMAT_P, temp1_double, temp2_double, ABS(temp1_double - temp2_double), ABS(1 - temp2_double / temp1_double)); } nfound++; } } /* NaN */ /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LD_FORMAT, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } } /*------------------------------------------------------------------------- * no -d and -p *------------------------------------------------------------------------- */ else if (equal_ldouble(temp1_double, temp2_double, opts) == false) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LD_FORMAT, temp1_double, temp2_double, ABS(temp1_double - temp2_double)); } nfound++; } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } #ifdef H5_HAVE__FLOAT16 /*------------------------------------------------------------------------- * Function: diff_float16_element * * Purpose: diff a single H5T_NATIVE_FLOAT16 type * * Return: number of differences found * *------------------------------------------------------------------------- */ static hsize_t diff_float16_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ H5__Float16 temp1_float16; H5__Float16 temp2_float16; double per; bool both_zero = false; bool isnan1 = false; bool isnan2 = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_float16, mem1, sizeof(H5__Float16)); memcpy(&temp2_float16, mem2, sizeof(H5__Float16)); /* logic for detecting NaNs is different with opts -d, -p and no opts */ /*------------------------------------------------------------------------- * -d and !-p *------------------------------------------------------------------------- */ if (opts->delta_bool && !opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_float16); isnan2 = isnan(temp2_float16); } /* both not NaN, do the comparison */ if (!isnan1 && !isnan2) { if ((double)ABS(temp1_float16 - temp2_float16) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, (double)temp1_float16, (double)temp2_float16, (double)ABS(temp1_float16 - temp2_float16)); } nfound++; } } /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, (double)temp1_float16, (double)temp2_float16, (double)ABS(temp1_float16 - temp2_float16)); } nfound++; } } /*------------------------------------------------------------------------- * !-d and -p *------------------------------------------------------------------------- */ else if (!opts->delta_bool && opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_float16); isnan2 = isnan(temp2_float16); } /* both not NaN, do the comparison */ if ((!isnan1 && !isnan2)) { PER(temp1_float16, temp2_float16); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P_NOTCOMP, (double)temp1_float16, (double)temp2_float16, (double)ABS(temp1_float16 - temp2_float16)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P, (double)temp1_float16, (double)temp2_float16, (double)ABS(temp1_float16 - temp2_float16), (double)ABS(1 - temp2_float16 / temp1_float16)); } nfound++; } } /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, (double)temp1_float16, (double)temp2_float16, (double)ABS(temp1_float16 - temp2_float16)); } nfound++; } } /*------------------------------------------------------------------------- * -d and -p *------------------------------------------------------------------------- */ else if (opts->delta_bool && opts->percent_bool) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ if (opts->do_nans) { isnan1 = isnan(temp1_float16); isnan2 = isnan(temp2_float16); } /* both not NaN, do the comparison */ if (!isnan1 && !isnan2) { PER(temp1_float16, temp2_float16); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P_NOTCOMP, (double)temp1_float16, (double)temp2_float16, (double)ABS(temp1_float16 - temp2_float16)); } nfound++; } else if (per > opts->percent && (double)ABS(temp1_float16 - temp2_float16) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT_P, (double)temp1_float16, (double)temp2_float16, (double)ABS(temp1_float16 - temp2_float16), (double)ABS(1 - temp2_float16 / temp1_float16)); } nfound++; } } /* only one is NaN, assume difference */ else if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, (double)temp1_float16, (double)temp2_float16, (double)ABS(temp1_float16 - temp2_float16)); } nfound++; } } /*------------------------------------------------------------------------- * no -d and -p *------------------------------------------------------------------------- */ else { if (equal_float((float)temp1_float16, (float)temp2_float16, opts) == false) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(F_FORMAT, (double)temp1_float16, (double)temp2_float16, (double)ABS(temp1_float16 - temp2_float16)); } nfound++; } } H5TOOLS_ENDDEBUG(": %" PRIuHSIZE " zero:%d", nfound, both_zero); return nfound; } #endif /*------------------------------------------------------------------------- * Function: diff_schar_element * * Purpose: diff a single H5T_NATIVE_SCHAR type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_schar_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ char temp1_char; char temp2_char; double per; bool both_zero = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_char, mem1, sizeof(char)); memcpy(&temp2_char, mem2, sizeof(char)); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (ABS(temp1_char - temp2_char) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_char, temp2_char, ABS(temp1_char - temp2_char)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { PER(temp1_char, temp2_char); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P_NOTCOMP, temp1_char, temp2_char, ABS(temp1_char - temp2_char)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_char, temp2_char, ABS(temp1_char - temp2_char), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { PER(temp1_char, temp2_char); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P_NOTCOMP, temp1_char, temp2_char, ABS(temp1_char - temp2_char)); } nfound++; } else if (per > opts->percent && ABS(temp1_char - temp2_char) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_char, temp2_char, ABS(temp1_char - temp2_char), per); } nfound++; } } else if (temp1_char != temp2_char) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_char, temp2_char, ABS(temp1_char - temp2_char)); } nfound++; } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_uchar_element * * Purpose: diff a single H5T_NATIVE_UCHAR type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_uchar_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ unsigned char temp1_uchar; unsigned char temp2_uchar; double per; bool both_zero = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_uchar, mem1, sizeof(unsigned char)); memcpy(&temp2_uchar, mem2, sizeof(unsigned char)); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (PDIFF(temp1_uchar, temp2_uchar) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_uchar, temp2_uchar, PDIFF(temp1_uchar, temp2_uchar)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { PER_UNSIGN(signed char, temp1_uchar, temp2_uchar); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P_NOTCOMP, temp1_uchar, temp2_uchar, PDIFF(temp1_uchar, temp2_uchar)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_uchar, temp2_uchar, PDIFF(temp1_uchar, temp2_uchar), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { PER_UNSIGN(signed char, temp1_uchar, temp2_uchar); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P_NOTCOMP, temp1_uchar, temp2_uchar, PDIFF(temp1_uchar, temp2_uchar)); } nfound++; } else if (per > opts->percent && PDIFF(temp1_uchar, temp2_uchar) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_uchar, temp2_uchar, PDIFF(temp1_uchar, temp2_uchar), per); } nfound++; } } else if (temp1_uchar != temp2_uchar) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_uchar, temp2_uchar, PDIFF(temp1_uchar, temp2_uchar)); } nfound++; } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_short_element * * Purpose: diff a H5T_NATIVE_SHORT type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_short_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ short temp1_short; short temp2_short; double per; bool both_zero = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_short, mem1, sizeof(short)); memcpy(&temp2_short, mem2, sizeof(short)); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (ABS(temp1_short - temp2_short) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_short, temp2_short, ABS(temp1_short - temp2_short)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { PER(temp1_short, temp2_short); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P_NOTCOMP, temp1_short, temp2_short, ABS(temp1_short - temp2_short)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_short, temp2_short, ABS(temp1_short - temp2_short), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { PER(temp1_short, temp2_short); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P_NOTCOMP, temp1_short, temp2_short, ABS(temp1_short - temp2_short)); } nfound++; } else if (per > opts->percent && ABS(temp1_short - temp2_short) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_short, temp2_short, ABS(temp1_short - temp2_short), per); } nfound++; } } else if (temp1_short != temp2_short) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_short, temp2_short, ABS(temp1_short - temp2_short)); } nfound++; } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_ushort_element * * Purpose: diff a single H5T_NATIVE_USHORT type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_ushort_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ unsigned short temp1_ushort; unsigned short temp2_ushort; double per; bool both_zero = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_ushort, mem1, sizeof(unsigned short)); memcpy(&temp2_ushort, mem2, sizeof(unsigned short)); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (PDIFF(temp1_ushort, temp2_ushort) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_ushort, temp2_ushort, PDIFF(temp1_ushort, temp2_ushort)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { PER_UNSIGN(signed short, temp1_ushort, temp2_ushort); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P_NOTCOMP, temp1_ushort, temp2_ushort, PDIFF(temp1_ushort, temp2_ushort)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_ushort, temp2_ushort, PDIFF(temp1_ushort, temp2_ushort), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { PER_UNSIGN(signed short, temp1_ushort, temp2_ushort); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P_NOTCOMP, temp1_ushort, temp2_ushort, PDIFF(temp1_ushort, temp2_ushort)); } nfound++; } else if (per > opts->percent && PDIFF(temp1_ushort, temp2_ushort) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_ushort, temp2_ushort, PDIFF(temp1_ushort, temp2_ushort), per); } nfound++; } } else if (temp1_ushort != temp2_ushort) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_ushort, temp2_ushort, PDIFF(temp1_ushort, temp2_ushort)); } nfound++; } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_int_element * * Purpose: diff a single H5T_NATIVE_INT type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_int_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ int temp1_int; int temp2_int; double per; bool both_zero = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_int, mem1, sizeof(int)); memcpy(&temp2_int, mem2, sizeof(int)); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (ABS(temp1_int - temp2_int) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_int, temp2_int, ABS(temp1_int - temp2_int)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { PER(temp1_int, temp2_int); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P_NOTCOMP, temp1_int, temp2_int, ABS(temp1_int - temp2_int)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_int, temp2_int, ABS(temp1_int - temp2_int), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { PER(temp1_int, temp2_int); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P_NOTCOMP, temp1_int, temp2_int, ABS(temp1_int - temp2_int)); } nfound++; } else if (per > opts->percent && ABS(temp1_int - temp2_int) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT_P, temp1_int, temp2_int, ABS(temp1_int - temp2_int), per); } nfound++; } } else if (temp1_int != temp2_int) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(I_FORMAT, temp1_int, temp2_int, ABS(temp1_int - temp2_int)); } nfound++; } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_uint_element * * Purpose: diff a single H5T_NATIVE_UINT type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_uint_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ unsigned int temp1_uint; unsigned int temp2_uint; double per; bool both_zero = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_uint, mem1, sizeof(unsigned int)); memcpy(&temp2_uint, mem2, sizeof(unsigned int)); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (PDIFF(temp1_uint, temp2_uint) > opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(UI_FORMAT, temp1_uint, temp2_uint, PDIFF(temp1_uint, temp2_uint)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { PER_UNSIGN(signed int, temp1_uint, temp2_uint); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(UI_FORMAT_P_NOTCOMP, temp1_uint, temp2_uint, PDIFF(temp1_uint, temp2_uint)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(UI_FORMAT_P, temp1_uint, temp2_uint, PDIFF(temp1_uint, temp2_uint), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { PER_UNSIGN(signed int, temp1_uint, temp2_uint); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(UI_FORMAT_P_NOTCOMP, temp1_uint, temp2_uint, PDIFF(temp1_uint, temp2_uint)); } nfound++; } else if (per > opts->percent && PDIFF(temp1_uint, temp2_uint) > opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(UI_FORMAT_P, temp1_uint, temp2_uint, PDIFF(temp1_uint, temp2_uint), per); } nfound++; } } else if (temp1_uint != temp2_uint) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(UI_FORMAT, temp1_uint, temp2_uint, PDIFF(temp1_uint, temp2_uint)); } nfound++; } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_long_element * * Purpose: diff a single H5T_NATIVE_LONG type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_long_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ long temp1_long; long temp2_long; double per; bool both_zero = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_long, mem1, sizeof(long)); memcpy(&temp2_long, mem2, sizeof(long)); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (ABS(temp1_long - temp2_long) > (long)opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LI_FORMAT, temp1_long, temp2_long, ABS(temp1_long - temp2_long)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { PER(temp1_long, temp2_long); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LI_FORMAT_P_NOTCOMP, temp1_long, temp2_long, ABS(temp1_long - temp2_long)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LI_FORMAT_P, temp1_long, temp2_long, ABS(temp1_long - temp2_long), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { PER(temp1_long, temp2_long); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LI_FORMAT_P_NOTCOMP, temp1_long, temp2_long, ABS(temp1_long - temp2_long)); } nfound++; } else if (per > opts->percent && ABS(temp1_long - temp2_long) > (long)opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LI_FORMAT_P, temp1_long, temp2_long, ABS(temp1_long - temp2_long), per); } nfound++; } } else if (temp1_long != temp2_long) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LI_FORMAT, temp1_long, temp2_long, ABS(temp1_long - temp2_long)); } nfound++; } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_ulong_element * * Purpose: diff a single H5T_NATIVE_ULONG type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_ulong_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ unsigned long temp1_ulong; unsigned long temp2_ulong; double per; bool both_zero = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_ulong, mem1, sizeof(unsigned long)); memcpy(&temp2_ulong, mem2, sizeof(unsigned long)); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (PDIFF(temp1_ulong, temp2_ulong) > (unsigned long)opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULI_FORMAT, temp1_ulong, temp2_ulong, PDIFF(temp1_ulong, temp2_ulong)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { PER_UNSIGN(signed long, temp1_ulong, temp2_ulong); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULI_FORMAT_P_NOTCOMP, temp1_ulong, temp2_ulong, PDIFF(temp1_ulong, temp2_ulong)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULI_FORMAT_P, temp1_ulong, temp2_ulong, PDIFF(temp1_ulong, temp2_ulong), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { PER_UNSIGN(signed long, temp1_ulong, temp2_ulong); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULI_FORMAT_P_NOTCOMP, temp1_ulong, temp2_ulong, PDIFF(temp1_ulong, temp2_ulong)); } nfound++; } else if (per > opts->percent && PDIFF(temp1_ulong, temp2_ulong) > (unsigned long)opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULI_FORMAT_P, temp1_ulong, temp2_ulong, PDIFF(temp1_ulong, temp2_ulong), per); } nfound++; } } else if (temp1_ulong != temp2_ulong) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULI_FORMAT, temp1_ulong, temp2_ulong, PDIFF(temp1_ulong, temp2_ulong)); } nfound++; } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_llong_element * * Purpose: diff a single H5T_NATIVE_LLONG type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_llong_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ long long temp1_llong; long long temp2_llong; double per; bool both_zero = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_llong, mem1, sizeof(long long)); memcpy(&temp2_llong, mem2, sizeof(long long)); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (ABS(temp1_llong - temp2_llong) > (long long)opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LLI_FORMAT, temp1_llong, temp2_llong, ABS(temp1_llong - temp2_llong)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { PER(temp1_llong, temp2_llong); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LLI_FORMAT_P_NOTCOMP, temp1_llong, temp2_llong, ABS(temp1_llong - temp2_llong)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LLI_FORMAT_P, temp1_llong, temp2_llong, ABS(temp1_llong - temp2_llong), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { PER(temp1_llong, temp2_llong); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LLI_FORMAT_P_NOTCOMP, temp1_llong, temp2_llong, ABS(temp1_llong - temp2_llong)); } nfound++; } else if (per > opts->percent && ABS(temp1_llong - temp2_llong) > (long long)opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LLI_FORMAT_P, temp1_llong, temp2_llong, ABS(temp1_llong - temp2_llong), per); } nfound++; } } else { if (temp1_llong != temp2_llong) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(LLI_FORMAT, temp1_llong, temp2_llong, ABS(temp1_llong - temp2_llong)); } nfound++; } } H5TOOLS_ENDDEBUG(":%" PRIuHSIZE " - errstat:%d", nfound, opts->err_stat); return nfound; } /*------------------------------------------------------------------------- * Function: diff_ullong_element * * Purpose: diff a single H5T_NATIVE_ULLONG type * * Return: number of differences found *------------------------------------------------------------------------- */ static hsize_t diff_ullong_element(unsigned char *mem1, unsigned char *mem2, hsize_t elem_idx, diff_opt_t *opts) { hsize_t nfound = 0; /* number of differences found */ unsigned long long temp1_ullong; unsigned long long temp2_ullong; float f1, f2; double per; bool both_zero = false; H5TOOLS_START_DEBUG("delta_bool:%d - percent_bool:%d", opts->delta_bool, opts->percent_bool); memcpy(&temp1_ullong, mem1, sizeof(unsigned long long)); memcpy(&temp2_ullong, mem2, sizeof(unsigned long long)); /* -d and !-p */ if (opts->delta_bool && !opts->percent_bool) { if (PDIFF(temp1_ullong, temp2_ullong) > (unsigned long long)opts->delta) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULLI_FORMAT, temp1_ullong, temp2_ullong, PDIFF(temp1_ullong, temp2_ullong)); } nfound++; } } /* !-d and -p */ else if (!opts->delta_bool && opts->percent_bool) { ull2float(temp1_ullong, &f1); ull2float(temp2_ullong, &f2); PER(f1, f2); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULLI_FORMAT_P_NOTCOMP, temp1_ullong, temp2_ullong, PDIFF(temp1_ullong, temp2_ullong)); } nfound++; } else if (per > opts->percent) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULLI_FORMAT_P, temp1_ullong, temp2_ullong, PDIFF(temp1_ullong, temp2_ullong), per); } nfound++; } } /* -d and -p */ else if (opts->delta_bool && opts->percent_bool) { ull2float(temp1_ullong, &f1); ull2float(temp2_ullong, &f2); PER(f1, f2); if (not_comparable && !both_zero) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULLI_FORMAT_P_NOTCOMP, temp1_ullong, temp2_ullong, PDIFF(temp1_ullong, temp2_ullong)); } nfound++; } else if (per > opts->percent && PDIFF(temp1_ullong, temp2_ullong) > (unsigned long long)opts->delta) { opts->print_percentage = 1; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULLI_FORMAT_P, temp1_ullong, temp2_ullong, PDIFF(temp1_ullong, temp2_ullong), per); } nfound++; } } else { if (temp1_ullong != temp2_ullong) { opts->print_percentage = 0; print_pos(opts, elem_idx, 0); if (print_data(opts)) { parallel_print(ULLI_FORMAT, temp1_ullong, temp2_ullong, PDIFF(temp1_ullong, temp2_ullong)); } nfound++; } } H5TOOLS_ENDDEBUG(": %" PRIuHSIZE " zero:%d", nfound, both_zero); return nfound; } /*------------------------------------------------------------------------- * Function: ull2float * * Purpose: convert unsigned long long to float *------------------------------------------------------------------------- */ static int ull2float(unsigned long long ull_value, float *f_value) { hid_t dxpl_id = H5I_INVALID_HID; unsigned char *buf = NULL; size_t src_size; size_t dst_size; int ret_value = 0; H5TOOLS_START_DEBUG(" "); if ((dxpl_id = H5Pcreate(H5P_DATASET_XFER)) < 0) H5TOOLS_GOTO_ERROR(FAIL, "H5Pcreate failed"); src_size = H5Tget_size(H5T_NATIVE_ULLONG); dst_size = H5Tget_size(H5T_NATIVE_FLOAT); if ((buf = (unsigned char *)calloc((size_t)1, MAX(src_size, dst_size))) == NULL) H5TOOLS_GOTO_ERROR(FAIL, "Could not allocate buffer for dims"); memcpy(buf, &ull_value, src_size); /* do conversion */ if (H5Tconvert(H5T_NATIVE_ULLONG, H5T_NATIVE_FLOAT, (size_t)1, buf, NULL, dxpl_id) < 0) H5TOOLS_GOTO_ERROR(FAIL, "H5Tconvert failed"); memcpy(f_value, buf, dst_size); done: H5E_BEGIN_TRY { H5Pclose(dxpl_id); } H5E_END_TRY if (buf) free(buf); H5TOOLS_ENDDEBUG(" "); return ret_value; } /*------------------------------------------------------------------------- * Function: equal_double * * Purpose: use a absolute error formula to deal with floating point uncertainty *------------------------------------------------------------------------- */ static bool equal_double(double value, double expected, diff_opt_t *opts) { if (opts->do_nans) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ bool isnan1 = isnan(value); bool isnan2 = isnan(expected); /*------------------------------------------------------------------------- * we consider NaN == NaN to be true *------------------------------------------------------------------------- */ if (isnan1 && isnan2) return true; /*------------------------------------------------------------------------- * one is a NaN, do not compare but assume difference *------------------------------------------------------------------------- */ if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) return false; } if (opts->use_system_epsilon) { /* Check equality within some epsilon */ if (H5_DBL_ABS_EQUAL(value, expected)) return true; } else { /* Check bits */ if (!memcmp(&value, &expected, sizeof(double))) return true; } return false; } /*------------------------------------------------------------------------- * Function: equal_ldouble * * Purpose: use a absolute error formula to deal with floating point uncertainty *------------------------------------------------------------------------- */ static bool equal_ldouble(long double value, long double expected, diff_opt_t *opts) { if (opts->do_nans) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ bool isnan1 = isnan(value); bool isnan2 = isnan(expected); /*------------------------------------------------------------------------- * we consider NaN == NaN to be true *------------------------------------------------------------------------- */ if (isnan1 && isnan2) return true; /*------------------------------------------------------------------------- * one is a NaN, do not compare but assume difference *------------------------------------------------------------------------- */ if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) return false; } if (opts->use_system_epsilon) { /* Check equality within some epsilon */ if (H5_LDBL_ABS_EQUAL(value, expected)) return true; } else { /* Check bits */ if (!memcmp(&value, &expected, sizeof(long double))) return true; } return false; } /*------------------------------------------------------------------------- * Function: equal_float * * Purpose: use a absolute error formula to deal with floating point uncertainty *------------------------------------------------------------------------- */ static bool equal_float(float value, float expected, diff_opt_t *opts) { if (opts->do_nans) { /*------------------------------------------------------------------------- * detect NaNs *------------------------------------------------------------------------- */ bool isnan1 = isnan(value); bool isnan2 = isnan(expected); /*------------------------------------------------------------------------- * we consider NaN == NaN to be true *------------------------------------------------------------------------- */ if (isnan1 && isnan2) return true; /*------------------------------------------------------------------------- * one is a NaN, do not compare but assume difference *------------------------------------------------------------------------- */ if ((isnan1 && !isnan2) || (!isnan1 && isnan2)) return false; } if (opts->use_system_epsilon) { /* Check equality within some epsilon */ if (H5_FLT_ABS_EQUAL(value, expected)) return true; } else { /* Check bits */ if (!memcmp(&value, &expected, sizeof(float))) return true; } return false; } /*------------------------------------------------------------------------- * * Local functions * *------------------------------------------------------------------------- */ /*------------------------------------------------------------------------- * Function: print_data * * Purpose: print data only in report or verbose modes, and do not print in quiet mode *------------------------------------------------------------------------- */ static int print_data(diff_opt_t *opts) { return ((opts->mode_report || opts->mode_verbose) && !opts->mode_quiet) ? 1 : 0; } /*------------------------------------------------------------------------- * Function: print_header * * Purpose: print header for difference *------------------------------------------------------------------------- */ static void print_header(diff_opt_t *opts) { /* print header */ parallel_print("%-16s", "size:"); print_dimensions(opts->rank, opts->dims); parallel_print("%-11s", ""); print_dimensions(opts->rank, opts->dims); parallel_print("\n"); if (opts->print_percentage) { parallel_print("%-15s %-15s %-15s %-15s %-15s\n", "position", opts->obj_name[0], opts->obj_name[1], "difference", "relative"); parallel_print("------------------------------------------------------------------------\n"); } else { parallel_print("%-15s %-15s %-15s %-20s\n", "position", opts->obj_name[0], opts->obj_name[1], "difference"); parallel_print("------------------------------------------------------------\n"); } } /*------------------------------------------------------------------------- * Function: print_pos * * Purpose: print in matrix notation, converting from an array index position *------------------------------------------------------------------------- */ static void print_pos(diff_opt_t *opts, hsize_t idx, size_t u) { H5TOOLS_START_DEBUG(" -- idx:%" PRIuHSIZE, idx); if (print_data(opts)) { hsize_t curr_pos = idx; /* print header */ if (opts->print_header == 1) { opts->print_header = 0; print_header(opts); } /* end print header */ H5TOOLS_DEBUG("rank=%d", opts->rank); if (opts->rank > 0) { parallel_print("[ "); H5TOOLS_DEBUG("do calc_acc_pos[%" PRIuHSIZE "] nelmts:%" PRIuHSIZE " - errstat:%d", idx, opts->hs_nelmts, opts->err_stat); if (opts->sset[0] != NULL) { /* Subsetting is used - calculate total position */ hsize_t curr_idx = 0; /* current pos in the selection space for each dimension */ curr_pos = 0; /* current position in full space */ if (curr_idx < idx) { int j; hsize_t count; hsize_t block; hsize_t stride = 0; hsize_t tmp = 0; hsize_t k0 = 0; /* whole location beyond current dimension */ hsize_t k1 = 0; /* partial location within dimension */ hsize_t dim_size = 0; /* previous dim size */ hsize_t prev_dim_size = 0; /* previous dim size */ hsize_t total_dim_size = 1; /* current dim size */ hsize_t prev_total_dim_size = 1; /* current dim size */ prev_dim_size = 1; total_dim_size = 1; curr_idx = idx; /* begin with fastest changing dimension */ for (int i = 0; i < opts->rank; i++) { j = opts->rank - i - 1; prev_total_dim_size *= prev_dim_size; dim_size = opts->dims[j]; H5TOOLS_DEBUG("j=%d, dim_size=%" PRIuHSIZE ", prev_dim_size=%" PRIuHSIZE ", total_dim_size=%" PRIuHSIZE ", " "prev_total_dim_size=%" PRIuHSIZE, j, dim_size, prev_dim_size, total_dim_size, prev_total_dim_size); count = opts->sset[0]->count.data[j]; block = opts->sset[0]->block.data[j]; stride = opts->sset[0]->stride.data[j]; H5TOOLS_DEBUG("stride=%" PRIuHSIZE ", count=%" PRIuHSIZE ", block=%" PRIuHSIZE, stride, count, block); tmp = count * block; k0 = curr_idx / tmp; k1 = curr_idx % tmp; curr_pos += k1 * stride * prev_total_dim_size; H5TOOLS_DEBUG("curr_idx=%" PRIuHSIZE ", k0=%" PRIuHSIZE ", k1=%" PRIuHSIZE ", curr_pos=%" PRIuHSIZE, curr_idx, k0, k1, curr_pos); if (k0 > 0) curr_idx = k0 * total_dim_size; H5TOOLS_DEBUG("curr_idx=%" PRIuHSIZE ", tmp=%" PRIuHSIZE, curr_idx, tmp); total_dim_size *= dim_size; /* if last calculation exists within in current dimension */ if (k0 == 0) break; H5TOOLS_DEBUG("j=%d, curr_pos=%" PRIuHSIZE, j, curr_pos); prev_dim_size = dim_size; } /* check if there is a final calculation needed for slowest changing dimension */ if (k0 > 0) curr_pos += k0 * stride * prev_total_dim_size; H5TOOLS_DEBUG("4:curr_idx=%" PRIuHSIZE ", curr_pos=%" PRIuHSIZE, curr_idx, curr_pos); } } /* * Calculate the number of elements represented by a unit change in a * certain index position. */ calc_acc_pos((unsigned)opts->rank, curr_pos, opts->acc, opts->pos); for (int i = 0; i < opts->rank; i++) { H5TOOLS_DEBUG("pos loop:%d with opts->pos=%" PRIuHSIZE " opts->sm_pos=%" PRIuHSIZE, i, opts->pos[i], opts->sm_pos[i]); opts->pos[i] += (unsigned long)opts->sm_pos[i]; H5TOOLS_DEBUG("pos loop:%d with opts->pos=%" PRIuHSIZE, i, opts->pos[i]); parallel_print("%" PRIuHSIZE, opts->pos[i]); parallel_print(" "); } parallel_print("]"); } else { if (opts->print_dims) { parallel_print("[ "); parallel_print("%zu", u); parallel_print("]"); opts->print_dims = 0; } else parallel_print(" "); } parallel_print(SPACES); } H5TOOLS_ENDDEBUG(" "); } /*------------------------------------------------------------------------- * Function: h5diff_print_char. Adapted from h5tools_print_char * * Purpose: Print a char *------------------------------------------------------------------------- */ static void h5diff_print_char(char ch) { switch (ch) { case '"': parallel_print("\\\""); break; case '\\': parallel_print("\\\\"); break; case '\b': parallel_print("\\b"); break; case '\f': parallel_print("\\f"); break; case '\n': parallel_print("\\n"); break; case '\r': parallel_print("\\r"); break; case '\t': parallel_print("\\t"); break; default: if (isprint(ch)) parallel_print("%c", ch); else parallel_print("\\%03o", ch); break; } } /*------------------------------------------------------------------------- * added to improve performance for compound datasets * set up compound datatype structures. *------------------------------------------------------------------------- */ static void get_member_types(hid_t tid, mcomp_t *members) { int tclass; unsigned u; if (tid <= 0 || !members) return; tclass = H5Tget_class(tid); if (tclass == H5T_ARRAY || tclass == H5T_VLEN) { hid_t base_tid = H5Tget_super(tid); get_member_types(base_tid, members); H5Tclose(base_tid); } else if (tclass == H5T_COMPOUND) { int nmembs; if ((nmembs = H5Tget_nmembers(tid)) <= 0) return; members->n = (unsigned)nmembs; members->ids = (hid_t *)calloc((size_t)members->n, sizeof(hid_t)); members->offsets = (size_t *)calloc((size_t)members->n, sizeof(size_t)); members->m = (mcomp_t **)calloc((size_t)members->n, sizeof(mcomp_t *)); for (u = 0; u < members->n; u++) { members->ids[u] = H5Tget_member_type(tid, u); members->offsets[u] = H5Tget_member_offset(tid, u); members->m[u] = (mcomp_t *)malloc(sizeof(mcomp_t)); memset(members->m[u], 0, sizeof(mcomp_t)); get_member_types(members->ids[u], members->m[u]); } } } /*------------------------------------------------------------------------- * added to improve performance for compound datasets * clean and close compound members. *------------------------------------------------------------------------- */ static void close_member_types(mcomp_t *members) { unsigned u; if (!members || members->n <= 0 || !members->ids) return; for (u = 0; u < members->n; u++) { if (members->m[u]) { close_member_types(members->m[u]); free(members->m[u]); } H5Tclose(members->ids[u]); } free(members->m); free(members->ids); free(members->offsets); }