From 837780443693fc562725f57e874312120cde32d8 Mon Sep 17 00:00:00 2001 From: Raymond Lu Date: Thu, 20 Dec 2007 16:09:58 -0500 Subject: [svn-r14354] Bug fix for #956 where the element coordinates went wrong for dataspace selection. Added a test for it, too. This round of checkin isn't well tarnished yet. I'll come back to work on Jan. 8. I'll revise it then. Tested it on kagiso, smirom, linew. --- MANIFEST | 1 + src/H5Shyper.c | 58 +++++++- src/H5Sprivate.h | 1 + src/H5Sselect.c | 3 + test/Makefile.am | 2 +- test/Makefile.in | 5 +- test/tcoords.c | 402 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/testhdf5.c | 1 + test/testhdf5.h | 2 + 9 files changed, 471 insertions(+), 4 deletions(-) create mode 100644 test/tcoords.c diff --git a/MANIFEST b/MANIFEST index e995e3e..7473603 100644 --- a/MANIFEST +++ b/MANIFEST @@ -804,6 +804,7 @@ ./test/tbogus.h5 ./test/tchecksum.c ./test/tconfig.c +./test/tcoords.c ./test/testerror.sh.in ./test/testframe.c ./test/testhdf5.c diff --git a/src/H5Shyper.c b/src/H5Shyper.c index 8c56056..7e3b30c 100644 --- a/src/H5Shyper.c +++ b/src/H5Shyper.c @@ -280,8 +280,10 @@ H5S_hyper_iter_init(H5S_sel_iter_t *iter, const H5S_t *space) if(iter->elmt_size>0) { /* Check for any "contiguous" blocks that can be flattened */ for(u=rank-1; u>0; u--) { - if(tdiminfo[u].count==1 && tdiminfo[u].block==mem_size[u]) + if(tdiminfo[u].count==1 && tdiminfo[u].block==mem_size[u]) { cont_dim++; + iter->dims_flatten[u] = TRUE; + } } /* end for */ } /* end if */ @@ -418,6 +420,7 @@ H5S_hyper_iter_init(H5S_sel_iter_t *iter, const H5S_t *space) * *------------------------------------------------------------------------- */ +#ifdef TMP static herr_t H5S_hyper_iter_coords (const H5S_sel_iter_t *iter, hsize_t *coords) { @@ -434,15 +437,25 @@ H5S_hyper_iter_coords (const H5S_sel_iter_t *iter, hsize_t *coords) /* Check if this is a "flattened" regular hyperslab selection */ if(iter->u.hyp.iter_rank!=0 && iter->u.hyp.iter_rankrank) { unsigned flat_dim; /* The rank of the flattened dimension */ + unsigned dim = iter->rank - iter->u.hyp.iter_rank; /* Get the rank of the flattened dimension */ flat_dim=iter->u.hyp.iter_rank-1; /* Copy the coordinates up to where things got flattened */ +#ifdef TMP HDmemcpy(coords,iter->u.hyp.off,sizeof(hsize_t)*flat_dim); /* Compute the coordinates for the flattened dimensions */ H5V_array_calc(iter->u.hyp.off[flat_dim],iter->rank-flat_dim,&(iter->dims[flat_dim]),&(coords[flat_dim])); +#else + /* Compute the coords for the flattened dimensions */ + H5V_array_calc(iter->u.hyp.off[0],dim+1,iter->dims,coords); + + /* Copy the coords for the unflattened dimensions */ + if(dim+1 < iter->rank) + HDmemcpy(&(coords[dim+1]),&(iter->u.hyp.off[1]),sizeof(hsize_t)*(iter->u.hyp.iter_rank -1)); +#endif } /* end if */ else HDmemcpy(coords,iter->u.hyp.off,sizeof(hsize_t)*iter->rank); @@ -452,6 +465,49 @@ H5S_hyper_iter_coords (const H5S_sel_iter_t *iter, hsize_t *coords) FUNC_LEAVE_NOAPI(SUCCEED); } /* H5S_hyper_iter_coords() */ +#else +static herr_t +H5S_hyper_iter_coords (const H5S_sel_iter_t *iter, hsize_t *coords) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5S_hyper_iter_coords); + + /* Check args */ + assert (iter); + assert (coords); + + /* Copy the offset of the current point */ + + /* Check for a single "regular" hyperslab */ + if(iter->u.hyp.diminfo_valid) { + /* Check if this is a "flattened" regular hyperslab selection */ + if(iter->u.hyp.iter_rank!=0 && iter->u.hyp.iter_rankrank) { + unsigned dim = iter->rank - iter->u.hyp.iter_rank; + int u, v; + int begin = -1; + + for(u=iter->rank-1, v=iter->u.hyp.iter_rank-1; u>=0, v>=0; u--) { + if(!iter->dims_flatten[u]) { + if(begin > 0) { + /* Compute the coords for the flattened dimensions */ + H5V_array_calc(iter->u.hyp.off[v],begin-u+1,&(iter->dims[u]),&(coords[u])); + begin = -1; + } else + HDmemcpy(&(coords[u]), &(iter->u.hyp.off[v]), sizeof(hsize_t)); + v--; + } + else if(iter->dims_flatten[u] && (begin == -1)) + begin = u; + } + } /* end if */ + else + HDmemcpy(coords,iter->u.hyp.off,sizeof(hsize_t)*iter->rank); + } /* end if */ + else + HDmemcpy(coords,iter->u.hyp.off,sizeof(hsize_t)*iter->rank); + + FUNC_LEAVE_NOAPI(SUCCEED); +} /* H5S_hyper_iter_coords() */ +#endif /*------------------------------------------------------------------------- diff --git a/src/H5Sprivate.h b/src/H5Sprivate.h index ace2559..64bf3a5 100644 --- a/src/H5Sprivate.h +++ b/src/H5Sprivate.h @@ -103,6 +103,7 @@ typedef struct H5S_sel_iter_t { /* Information common to all iterators */ unsigned rank; /* Rank of dataspace the selection iterator is operating on */ hsize_t *dims; /* Dimensions of dataspace the selection is operating on */ + hbool_t *dims_flatten; hsize_t elmt_left; /* Number of elements left to iterate over */ size_t elmt_size; /* Size of elements to iterate over */ diff --git a/src/H5Sselect.c b/src/H5Sselect.c index 41b565f..09083fa 100644 --- a/src/H5Sselect.c +++ b/src/H5Sselect.c @@ -804,6 +804,9 @@ H5S_select_iter_init(H5S_sel_iter_t *sel_iter, const H5S_t *space, size_t elmt_s if(sel_iter->rank>0) { /* Point to the dataspace dimensions */ sel_iter->dims=space->extent.size; + + /* Allocate space for the flags whether the dimension is flattened */ + sel_iter->dims_flatten = (hbool_t*)H5MM_calloc(sel_iter->rank*sizeof(hbool_t)); } /* end if */ else sel_iter->dims = NULL; diff --git a/test/Makefile.am b/test/Makefile.am index e5a1394..62b1f92 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -121,7 +121,7 @@ CHECK_CLEANFILES+=cmpd_dset.h5 compact_dataset.h5 dataset.h5 extend.h5 istore.h5 # Sources for testhdf5 executable testhdf5_SOURCES=testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \ - tgenprop.c th5o.c th5s.c theap.c tid.c titerate.c tmeta.c tmisc.c \ + tgenprop.c th5o.c th5s.c tcoords.c theap.c tid.c titerate.c tmeta.c tmisc.c \ trefer.c trefstr.c tselect.c tskiplist.c tsohm.c ttime.c ttst.c tunicode.c \ tvlstr.c tvltypes.c diff --git a/test/Makefile.in b/test/Makefile.in index add9df2..a7617b3 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -288,7 +288,7 @@ stab_DEPENDENCIES = libh5test.la $(LIBHDF5) am_testhdf5_OBJECTS = testhdf5.$(OBJEXT) tarray.$(OBJEXT) \ tattr.$(OBJEXT) tchecksum.$(OBJEXT) tconfig.$(OBJEXT) \ tfile.$(OBJEXT) tgenprop.$(OBJEXT) th5o.$(OBJEXT) \ - th5s.$(OBJEXT) theap.$(OBJEXT) tid.$(OBJEXT) \ + th5s.$(OBJEXT) tcoords.$(OBJEXT) theap.$(OBJEXT) tid.$(OBJEXT) \ titerate.$(OBJEXT) tmeta.$(OBJEXT) tmisc.$(OBJEXT) \ trefer.$(OBJEXT) trefstr.$(OBJEXT) tselect.$(OBJEXT) \ tskiplist.$(OBJEXT) tsohm.$(OBJEXT) ttime.$(OBJEXT) \ @@ -652,7 +652,7 @@ ttsafe_SOURCES = ttsafe.c ttsafe_dcreate.c ttsafe_error.c ttsafe_cancel.c # Sources for testhdf5 executable testhdf5_SOURCES = testhdf5.c tarray.c tattr.c tchecksum.c tconfig.c tfile.c \ - tgenprop.c th5o.c th5s.c theap.c tid.c titerate.c tmeta.c tmisc.c \ + tgenprop.c th5o.c th5s.c tcoords.c theap.c tid.c titerate.c tmeta.c tmisc.c \ trefer.c trefstr.c tselect.c tskiplist.c tsohm.c ttime.c ttst.c tunicode.c \ tvlstr.c tvltypes.c @@ -959,6 +959,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tattr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tchecksum.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tconfig.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcoords.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testframe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testhdf5.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testmeta.Po@am__quote@ diff --git a/test/tcoords.c b/test/tcoords.c new file mode 100644 index 0000000..67e7aa1 --- /dev/null +++ b/test/tcoords.c @@ -0,0 +1,402 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * 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 files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdfgroup.org/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/*********************************************************** +* +* Test program: th5s +* +* Test the element coordinates for dataspace selection. +* +*************************************************************/ + +#include "testhdf5.h" + +/* +** Data used to write the dataset. +*/ + +static int da_buffer[12][1][6][2]; + +static hsize_t da_dims[4] = { 12, 1, 6, 2 }; +static hsize_t da_maxdims[4] = { H5S_UNLIMITED, H5S_UNLIMITED, H5S_UNLIMITED, H5S_UNLIMITED }; +/*static hsize_t da_chunksize[4] = { 3, 1, 2, 1 };*/ +static hsize_t da_chunksize[4] = { 12, 1, 6, 2 }; + +/* +** The dataset end of the selection is done using element selection. +** These are the element locations. +*/ +#ifdef TMP +static hsize_t da_elements[12][4] = { { 11, 0, 0, 0 }, + { 11, 0, 0, 1 }, + { 11, 0, 5, 0 }, + { 11, 0, 5, 1 }, + { 11, 0, 1, 0 }, + { 11, 0, 1, 1 }, + { 11, 0, 2, 0 }, + { 11, 0, 2, 1 }, + { 11, 0, 3, 0 }, + { 11, 0, 3, 1 }, + { 11, 0, 4, 0 }, + { 11, 0, 4, 1 } }; +#else +static hsize_t da_elements[12][4] = { { 11, 0, 0, 0 }, + { 11, 0, 0, 1 }, + { 11, 0, 1, 0 }, + { 11, 0, 1, 1 }, + { 11, 0, 2, 0 }, + { 11, 0, 2, 1 }, + { 11, 0, 3, 0 }, + { 11, 0, 3, 1 }, + { 11, 0, 4, 0 }, + { 11, 0, 4, 1 }, + { 11, 0, 5, 0 }, + { 11, 0, 5, 1 } }; +#endif + +/* +** This is where it gets interesting. +** +** First experiment: the data being read is rank=2, so use two +** dimensions. However, the array is 6x3, while the transfer is 6x2. +** We use a hyperslab to select the subset. This case shows no +** problem. +*/ +static int mem1_buffer[6][3]; + +static hsize_t mem1_dims[2] = { 6, 3}; + +static hsize_t mem1_start[2] = { 0, 0 }; +static hsize_t mem1_count[2] = { 1, 1 }; +static hsize_t mem1_stride[2] = { 1, 1 }; +static hsize_t mem1_block[2] = { 6, 2 }; + + +/* +** Second experiment: the transfer is the same rank as above, but we +** add two dimensions of 1. I.e., the array is 1x1x6x2. In this +** case, the 6x2 selection is over the entire array, not a subset of +** the array. However, we still use hyperslab selection. This case +** shows no problem. +*/ +static int mem2_buffer[1][1][6][2]; + +static hsize_t mem2_dims[4] = { 1, 1, 6, 2 }; + +static hsize_t mem2_start[4] = { 0, 0, 0, 0 }; +static hsize_t mem2_count[4] = { 1, 1, 1, 1 }; +static hsize_t mem2_stride[4] = { 1, 1, 1, 1 }; +static hsize_t mem2_block[4] = { 1, 1, 6, 2 }; + + +/* +** Third experiment: the transfer is the same rank as above, and we +** add two dimensions of 1, but now the array is larger: 1x1x6x3. +** The selection is now over a subset of the array (1x1x6x2). This +** case demonstrates the problem. +*/ +/*static int mem3_buffer[1][1][6][3];*/ +static int mem3_buffer[1][1][6][3]; + +/*static hsize_t mem3_dims[4] = { 1, 1, 6, 3 };*/ +static hsize_t mem3_dims[4] = { 1, 1, 6, 3 }; + +static hsize_t mem3_start[4] = { 0, 0, 0, 0 }; +static hsize_t mem3_count[4] = { 1, 1, 1, 1 }; +static hsize_t mem3_stride[4] = { 1, 1, 1, 1 }; +static hsize_t mem3_block[4] = { 1, 1, 6, 2 }; + +/* +** Fourth experiment: the transfer is the same rank as above, but we +** add two dimensions of 1. I.e., the array is 1x6x3. In this +** case, the 6x2 selection is over the entire array, not a subset of +** the array. However, we still use hyperslab selection. This case +** shows the problem. +*/ +static int mem4_buffer[1][6][3]; + +static hsize_t mem4_dims[3] = { 1, 6, 3 }; + +static hsize_t mem4_start[3] = { 0, 0, 0 }; +static hsize_t mem4_count[3] = { 1, 1, 1 }; +static hsize_t mem4_stride[3] = { 1, 1, 1 }; +static hsize_t mem4_block[3] = { 1, 6, 2 }; + + +/* +** Subroutine to write the dataset. It's probably not important to +** this example, other than to know it's shape. +*/ +void write_dataset() +{ + int i; + hid_t fid, dsid, daid, msid, plid; + herr_t rv; + + fid = H5Fcreate("coord.hdf", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + if(fid < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + /*dsid = H5Screate_simple(4, da_dims, da_maxdims);*/ + dsid = H5Screate_simple(4, da_dims, da_dims); + if(dsid < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + plid = H5Pcreate(H5P_DATASET_CREATE); + if(plid < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + rv = H5Pset_layout(plid, H5D_CHUNKED); + if(rv < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + rv = H5Pset_chunk(plid, 4, da_chunksize); + if(rv < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + daid = H5Dcreate2(fid, "dataset", H5T_NATIVE_INT, dsid, H5P_DEFAULT, plid, H5P_DEFAULT); + if(daid < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + /* + ** We'll only be interested in the front plane ([0][0][0-5[0-1]) so + ** we only initialize that. + */ + for(i = 0; i < 12; i++) + { + int j; + for(j = 0; j < 6; j++) + { + da_buffer[i][0][j][0] = j * 10; + da_buffer[i][0][j][1] = j * 10 + 1; + } + } + + msid = H5Screate_simple(4, da_dims, da_dims); + if(msid < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + rv = H5Dwrite(daid, H5T_NATIVE_INT, msid, dsid, H5P_DEFAULT, da_buffer); + if(rv < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + rv = H5Dclose(daid); + if(rv < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + rv = H5Fclose(fid); + if(rv < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } +} + +/* +** Read a dataset using the provided parameters. +*/ +void read_dataset(int rank, + int* buffer, + hsize_t* mdims, + hsize_t* start, + hsize_t* count, + hsize_t* stride, + hsize_t* block) +{ + hid_t fid, dsid, daid, msid, plid; + herr_t rv; + + fid = H5Fopen("coord.hdf", H5F_ACC_RDONLY, H5P_DEFAULT); + if(fid < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + daid = H5Dopen2(fid, "dataset", H5P_DEFAULT); + if(daid < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + + dsid = H5Dget_space(daid); + if(dsid < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + /* + ** Element selection is used to select 18 elements from the dataset. + */ +#ifdef TMP + rv = H5Sselect_elements(dsid, H5S_SELECT_SET, 12, (const hsize_t**)da_elements); +#else + rv = H5Sselect_hyperslab(dsid, H5S_SELECT_SET, mem2_start, mem2_stride, mem2_count, mem2_block); +#endif + if(rv < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + msid = H5Screate_simple(rank, mdims, mdims); + if(dsid < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + /* + ** The element selection above is combined with hyperslab + ** selection. The selection is always be a contiguous block. (See + ** above.) + */ + rv = H5Sselect_hyperslab(msid, H5S_SELECT_SET, start, stride, count, block); + if(rv < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + rv = H5Dread(daid, H5T_NATIVE_INT, msid, dsid, H5P_DEFAULT, buffer); + if(rv < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + rv = H5Dclose(daid); + if(rv < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } + + rv = H5Fclose(fid); + if(rv < 0) + { + H5Eprint2(H5E_DEFAULT, stderr); + exit(1); + } +} + +void test_coords(void) +{ + int i, j; + + write_dataset(); + + /* 1. + ** Use a rank=2 in memory array. (See above) + */ + memset(mem1_buffer, 0, sizeof(mem1_buffer)); + read_dataset(2, (int*)mem1_buffer, mem1_dims, mem1_start, mem1_count, mem1_stride, mem1_block); + for(i = 0; i < 6; i++) + { + for(j=0; j<2; j++) + if(da_buffer[11][0][i][j] != mem1_buffer[i][j]) + TestErrPrintf(" %3d %3d\n", mem1_buffer[i][j], mem1_buffer[i][j]); + } + + /* 2. + ** Use a rank=4 in memory array. Make the array smaller and select + ** the whole array. (See above) + */ + memset(mem2_buffer, 0, sizeof(mem2_buffer)); + read_dataset(4, (int*)mem2_buffer, mem2_dims, mem2_start, mem2_count, mem2_stride, mem2_block); + for(i = 0; i < 6; i++) + { + for(j=0; j<2; j++) + if(da_buffer[11][0][i][j] != mem2_buffer[0][0][i][j]) + TestErrPrintf(" %3d %3d\n", mem2_buffer[0][0][i][j], mem2_buffer[0][0][i][j]); + } + + /* 3. + ** Use a rank=4 in memory array, but don't select the whole array. (See above) + */ + memset(mem3_buffer, 0, sizeof(mem3_buffer)); + read_dataset(4, (int*)mem3_buffer, mem3_dims, mem3_start, mem3_count, mem3_stride, mem3_block); + for(i = 0; i < 6; i++) + { + for(j=0; j<2; j++) + if(da_buffer[11][0][i][j] != mem3_buffer[0][0][i][j]) + TestErrPrintf(" %3d %3d\n", mem3_buffer[0][0][i][j], mem3_buffer[0][0][i][j]); + + } + + /* 4. + ** Use a rank=3 in memory array. (See above) + */ + memset(mem4_buffer, 0, sizeof(mem4_buffer)); + read_dataset(3, (int*)mem4_buffer, mem4_dims, mem4_start, mem4_count, mem4_stride, mem4_block); + for(i = 0; i < 6; i++) + { + for(j=0; j<2; j++) + if(da_buffer[11][0][i][j] != mem4_buffer[0][i][j]) + TestErrPrintf(" %3d %3d\n", mem4_buffer[0][i][j], mem4_buffer[0][i][j]); + } + +} + + +/*------------------------------------------------------------------------- + * Function: cleanup_coords + * + * Purpose: Cleanup temporary test files + * + * Return: none + * + * Programmer: Raymond Lu + * 20 Dec. 2007 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +void +cleanup_coords(void) +{ + remove("coord.hdf"); +} diff --git a/test/testhdf5.c b/test/testhdf5.c index 5b174be..4afbfe8 100644 --- a/test/testhdf5.c +++ b/test/testhdf5.c @@ -54,6 +54,7 @@ main(int argc, char *argv[]) AddTest("file", test_file, cleanup_file, "Low-Level File I/O", NULL); AddTest("objects", test_h5o, cleanup_h5o, "Generic Object Functions", NULL); AddTest("h5s", test_h5s, cleanup_h5s, "Dataspaces", NULL); + AddTest("coords", test_coords, cleanup_coords, "Dataspace coordinates", NULL); AddTest("sohm", test_sohm, cleanup_sohm, "Shared Object Header Messages", NULL); AddTest("attr", test_attr, cleanup_attr, "Attributes", NULL); AddTest("select", test_select, cleanup_select, "Selections", NULL); diff --git a/test/testhdf5.h b/test/testhdf5.h index 45ad476..ed8b049 100644 --- a/test/testhdf5.h +++ b/test/testhdf5.h @@ -133,6 +133,7 @@ void test_file(void); void test_h5o(void); void test_h5t(void); void test_h5s(void); +void test_coords(void); void test_h5d(void); void test_attr(void); void test_select(void); @@ -156,6 +157,7 @@ void cleanup_checksum(void); void cleanup_file(void); void cleanup_h5o(void); void cleanup_h5s(void); +void cleanup_coords(void); void cleanup_attr(void); void cleanup_select(void); void cleanup_time(void); -- cgit v0.12