Mercurial > hg > minc-tools
view libsrc2/hyper.c @ 2659:d49870395329
fixed error error: non-void function 'miget_real_value_hyperslab'
author | Vladimir S. FONOV <vladimir.fonov@gmail.com> |
---|---|
date | Thu, 29 Mar 2012 17:20:21 -0400 |
parents | b4584c9a2140 |
children |
line wrap: on
line source
/** \file hyper.c * \brief MINC 2.0 Hyperslab Functions * \author Bert Vincent * * Functions to manipulate hyperslabs of volume image data. ************************************************************************/ #include <stdlib.h> #include <hdf5.h> #include "minc2.h" #include "minc2_private.h" #define MIRW_OP_READ 1 #define MIRW_OP_WRITE 2 typedef unsigned long mioffset_t; /** In-place array dimension restructuring. * * Based on Chris H.Q. Ding, "An Optimal Index Reshuffle Algorithm for * Multidimensional Arrays and its Applications for Parallel Architectures" * IEEE Transactions on Parallel and Distributed Systems, Vol.12, No.3, * March 2001, pp.306-315. * * I rewrote the algorithm in "C" an generalized it to N dimensions. * * Guaranteed to do the minimum number of memory moves, but requires * that we allocate a bitmap of nelem/8 bytes. The paper suggests * ways to eliminate the bitmap - I'll work on it. */ /** * Map a set of array coordinates to a linear offset in the array memory. */ static mioffset_t index_to_offset(int ndims, const unsigned long sizes[], const unsigned long index[]) { mioffset_t offset = index[0]; int i; for (i = 1; i < ndims; i++) { offset *= sizes[i]; offset += index[i]; } return (offset); } /** * Map a linear offset to a set of coordinates in a multidimensional array. */ static void offset_to_index(int ndims, const unsigned long sizes[], mioffset_t offset, unsigned long index[]) { int i; for (i = ndims - 1; i > 0; i--) { index[i] = offset % sizes[i]; offset /= sizes[i]; } index[0] = offset; } /* Trivial bitmap test & set. */ #define BIT_TST(bm, i) (bm[(i) / 8] & (1 << ((i) % 8))) #define BIT_SET(bm, i) (bm[(i) / 8] |= (1 << ((i) % 8))) /** The main restructuring code. */ MNCAPI void restructure_array(int ndims, /* Dimension count */ unsigned char *array, /* Raw data */ const unsigned long *lengths_perm, /* Permuted lengths */ int el_size, /* Element size, in bytes */ const int *map, /* Mapping array */ const int *dir) /* Direction array, in permuted order */ { unsigned long index[MI2_MAX_VAR_DIMS]; /* Raw indices */ unsigned long index_perm[MI2_MAX_VAR_DIMS]; /* Permuted indices */ unsigned long lengths[MI2_MAX_VAR_DIMS]; /* Raw (unpermuted) lengths */ unsigned char *temp; mioffset_t offset_start; mioffset_t offset_next; mioffset_t offset; unsigned char *bitmap; size_t total; int i; if ((temp = malloc(el_size)) == NULL) { return; } /** * Permute the lengths from their "output" configuration back into * their "raw" or native order: **/ for (i = 0; i < ndims; i++) { //lengths[i] = lengths_perm[map[i]]; lengths[map[i]] = lengths_perm[i]; } /** * Calculate the total size of the array, in elements. **/ total = 1; for (i = 0; i < ndims; i++) { total *= lengths[i]; } /** * Allocate a bitmap with enough space to hold one bit for each * element in the array. **/ bitmap = calloc((total + 8 - 1) / 8, 1); /* bit array */ if (bitmap == NULL) { return; } for (offset_start = 0; offset_start < total; offset_start++) { /** * Look for an unset bit - that's where we start the next * cycle. **/ if (!BIT_TST(bitmap, offset_start)) { /** * Found a cycle we have not yet performed. **/ offset_next = -1; /* Initialize. */ #ifdef DEBUG printf("%ld", offset_start); #endif /* DEBUG */ /** * Save the first element in this cycle. **/ memcpy(temp, array + (offset_start * el_size), el_size); /** * We've touched this location. **/ BIT_SET(bitmap, offset_start); offset = offset_start; /** * Do until the cycle repeats. **/ while (offset_next != offset_start) { /** * Compute the index from the offset and permuted length. **/ offset_to_index(ndims, lengths_perm, offset, index_perm); /** * Permute the index into the alternate arrangement. **/ for (i = 0; i < ndims; i++) { if (dir[i] < 0) { // index[i] = lengths[i] - index_perm[map[i]] - 1; index[map[i]] = lengths[map[i]] - index_perm[i] - 1; } else { //index[i] = index_perm[map[i]]; index[map[i]] = index_perm[i]; } } /** * Calculate the next offset from the permuted index. **/ offset_next = index_to_offset(ndims, lengths, index); #ifdef DEBUG if (offset_next >= total) { printf("Fatal - offset %ld out of bounds!\n", offset_next); printf("lengths %ld,%ld,%ld\n", lengths[0],lengths[1],lengths[2]); printf("index %ld,%ld,%ld\n", index_perm[0], index_perm[0], index_perm[2]); exit(-1); } #endif /** * If we are not at the end of the cycle... **/ if (offset_next != offset_start) { /** * Note that we've touched a new location. **/ BIT_SET(bitmap, offset_next); #ifdef DEBUG printf(" - %ld", offset_next); #endif /* DEBUG */ /** * Move from old to new location. **/ memcpy(array + (offset * el_size), array + (offset_next * el_size), el_size); /** * Advance offset to the next location in the cycle. **/ offset = offset_next; } } /** * Store the first value in the cycle, which we saved in * 'tmp', into the last offset in the cycle. **/ memcpy(array + (offset * el_size), temp, el_size); #ifdef DEBUG printf("\n"); #endif /* DEBUG */ } } free(bitmap); /* Get rid of the bitmap. */ free(temp); } /** Calculates and returns the number of bytes required to store the * hyperslab specified by the \a n_dimensions and the * \a count parameters. */ int miget_hyperslab_size(mitype_t volume_data_type, /**< Data type of a voxel. */ int n_dimensions, /**< Dimensionality */ const unsigned long count[], /**< Dimension lengths */ misize_t *size_ptr) /**< Returned byte count */ { int voxel_size; misize_t temp; int i; hid_t type_id; type_id = mitype_to_hdftype(volume_data_type, TRUE); if (type_id < 0) { return (MI_ERROR); } voxel_size = H5Tget_size(type_id); temp = 1; for (i = 0; i < n_dimensions; i++) { temp *= count[i]; } *size_ptr = (temp * voxel_size); H5Tclose(type_id); return (MI_NOERROR); } /** "semiprivate" function for translating coordinates. */ int mitranslate_hyperslab_origin(mihandle_t volume, const unsigned long start[], const unsigned long count[], hssize_t hdf_start[], hsize_t hdf_count[], int dir[]) /* direction vector in file order */ { int n_different = 0; int file_i; int ndims = volume->number_of_dims; int j; for(j=0; j<ndims; j++) { hdf_count[j]=0; hdf_start[j]=0; } for (file_i = 0; file_i < ndims; file_i++) { midimhandle_t hdim; int user_i; /* Set up the basic translations of dimensions, for * flipping directions and swapping indices. */ if (volume->dim_indices != NULL) { /* Have to swap indices */ user_i = volume->dim_indices[file_i]; if (user_i != file_i) { n_different++; } } else { user_i = file_i; } hdim = volume->dim_handles[user_i]; //hdim = volume->dim_handles[file_i]; switch (hdim->flipping_order) { case MI_FILE_ORDER: //hdf_start[file_i] = start[user_i]; hdf_start[user_i] = start[file_i]; dir[file_i] = 1; /* Set direction positive */ break; case MI_COUNTER_FILE_ORDER: //hdf_start[file_i] = hdim->length - start[user_i] - count[user_i]; hdf_start[user_i] = hdim->length - start[file_i] - count[file_i]; dir[file_i] = -1; /* Set direction negative */ break; case MI_POSITIVE: if (hdim->step > 0) { /* Positive? */ //hdf_start[file_i] = start[user_i]; /* Use raw file order. */ hdf_start[user_i] = start[file_i]; dir[file_i] = 1; /* Set direction positive */ } else { //hdf_start[file_i] = hdim->length - start[user_i] - count[user_i]; hdf_start[user_i] = hdim->length - start[file_i] - count[file_i]; dir[file_i] = -1; /* Set direction negative */ } break; case MI_NEGATIVE: if (hdim->step < 0) { /* Negative? */ //hdf_start[file_i] = start[user_i]; /* Use raw file order */ hdf_start[user_i] = start[file_i]; dir[file_i] = 1; /* Set direction positive */ } else { //hdf_start[file_i] = hdim->length - start[user_i] - count[user_i]; hdf_start[user_i] = hdim->length - start[file_i] - count[file_i]; dir[file_i] = -1; /* Set direction negative */ } break; } //hdf_count[file_i] = count[user_i]; hdf_count[user_i] = count[file_i]; } return (n_different); } /** Read/write a hyperslab of data. This is the simplified function * which performs no value conversion. It is much more efficient than * mirw_hyperslab_icv() */ static int mirw_hyperslab_raw(int opcode, mihandle_t volume, mitype_t midatatype, const unsigned long start[], const unsigned long count[], void *buffer) { hid_t dset_id = -1; hid_t mspc_id = -1; hid_t fspc_id = -1; hid_t type_id = -1; int result = MI_ERROR; hsize_t hdf_start[MI2_MAX_VAR_DIMS]; hsize_t hdf_count[MI2_MAX_VAR_DIMS]; int dir[MI2_MAX_VAR_DIMS]; /* Direction vector in file order */ int ndims; int n_different = 0; /* Disallow write operations to anything but the highest resolution. */ if (opcode == MIRW_OP_WRITE && volume->selected_resolution != 0) { return (MI_ERROR); } dset_id = volume->image_id; if (dset_id < 0) { goto cleanup; } fspc_id = H5Dget_space(dset_id); if (fspc_id < 0) { goto cleanup; } if (midatatype == MI_TYPE_UNKNOWN) { type_id = H5Tcopy(volume->mtype_id); } else { type_id = mitype_to_hdftype(midatatype, TRUE); } ndims = volume->number_of_dims; if (ndims == 0) { /* A scalar volume is possible but extremely unlikely, not to * mention useless! */ mspc_id = H5Screate(H5S_SCALAR); } else { n_different = mitranslate_hyperslab_origin(volume, start, count, hdf_start, hdf_count, dir); mspc_id = H5Screate_simple(ndims, hdf_count, NULL); if (mspc_id < 0) { goto cleanup; } } result = H5Sselect_hyperslab(fspc_id, H5S_SELECT_SET, hdf_start, NULL, hdf_count, NULL); if (result < 0) { goto cleanup; } if (opcode == MIRW_OP_READ) { result = H5Dread(dset_id, type_id, mspc_id, fspc_id, H5P_DEFAULT, buffer); /* Restructure the array after reading the data in file orientation. */ if (n_different != 0) { restructure_array(ndims, buffer, count, H5Tget_size(type_id), volume->dim_indices, dir); } } else { volume->is_dirty = TRUE; /* Mark as modified. */ /* Restructure array before writing to file. */ if (n_different != 0) { unsigned long icount[MI2_MAX_VAR_DIMS]; int idir[MI2_MAX_VAR_DIMS]; int imap[MI2_MAX_VAR_DIMS]; int i; /* Invert before calling */ for (i = 0; i < ndims; i++) { //icount[i] = count[volume->dim_indices[i]]; icount[volume->dim_indices[i]] = count[i]; //idir[i] = dir[volume->dim_indices[i]]; idir[volume->dim_indices[i]] = dir[i]; // this one was correct the original way imap[volume->dim_indices[i]] = i; } restructure_array(ndims, buffer, icount, H5Tget_size(type_id), imap, idir); } result = H5Dwrite(dset_id, type_id, mspc_id, fspc_id, H5P_DEFAULT, buffer); } cleanup: if (type_id >= 0) { H5Tclose(type_id); } if (mspc_id >= 0) { H5Sclose(mspc_id); } if (fspc_id >= 0) { H5Sclose(fspc_id); } return (result); } /** Read/write a hyperslab of data, performing dimension remapping * and data rescaling as needed. */ static int mirw_hyperslab_icv(int opcode, mihandle_t volume, int icv, const unsigned long start[], const unsigned long count[], void *buffer) { int ndims; int nbytes; int nc_type; int result = MI_ERROR; long icv_start[MI2_MAX_VAR_DIMS]; long icv_count[MI2_MAX_VAR_DIMS]; int dir[MI2_MAX_VAR_DIMS]; /* Direction, 1 or -1, in file order */ int n_different = 0; /* Disallow write operations to anything but the highest resolution. */ if (opcode == MIRW_OP_WRITE && volume->selected_resolution != 0) { return (MI_ERROR); } miicv_inqint(icv, MI_ICV_TYPE, &nc_type); nbytes = MI2typelen(nc_type); ndims = volume->number_of_dims; if (ndims != 0) { int i; hssize_t hdf_start[MI2_MAX_VAR_DIMS]; hsize_t hdf_count[MI2_MAX_VAR_DIMS]; n_different = mitranslate_hyperslab_origin(volume, start, count, hdf_start, hdf_count, dir); for (i = 0; i < ndims; i++) { icv_start[i] = hdf_start[i]; icv_count[i] = hdf_count[i]; } } if (opcode == MIRW_OP_READ) { result = miicv_get(icv, icv_start, icv_count, buffer); /* Now we have to restructure the array. * Count must be in raw order here. */ if (result == MI_NOERROR && n_different != 0) { restructure_array(ndims, buffer, count, nbytes, volume->dim_indices, dir); } } else { volume->is_dirty = TRUE; /* Flag as modified */ /* Restructure the data before writing. * Count must be in raw order here. */ if (n_different != 0) { restructure_array(ndims, buffer, count, nbytes, volume->dim_indices, dir); } result = miicv_put(icv, icv_start, icv_count, buffer); } return (result); } /** Reads the real values in the volume from the interval min through * max, mapped to the maximum representable range for the requested * data type. Float type is NOT an allowed data type. */ int miget_hyperslab_normalized(mihandle_t volume, mitype_t buffer_data_type, const unsigned long start[], const unsigned long count[], double min, double max, void *buffer) { hid_t file_id; int var_id; int icv; int result; int is_signed; int nctype; if (min > max) { return (MI_ERROR); } file_id = volume->hdf_id; if (file_id < 0) { return (MI_ERROR); } var_id = ncvarid(file_id, MIimage); if (var_id < 0) { return (MI_ERROR); } nctype = mitype_to_nctype(buffer_data_type, &is_signed); if (nctype == NC_FLOAT || nctype == NC_DOUBLE) { return (MI_ERROR); } if ((icv = miicv_create()) < 0) { return (MI_ERROR); } result = miicv_setint(icv, MI_ICV_TYPE, nctype); result = miicv_setstr(icv, MI_ICV_SIGN, is_signed ? MI_SIGNED : MI_UNSIGNED); result = miicv_setdbl(icv, MI_ICV_IMAGE_MIN, min); result = miicv_setdbl(icv, MI_ICV_IMAGE_MAX, max); result = miicv_setint(icv, MI_ICV_USER_NORM, TRUE); result = miicv_setint(icv, MI_ICV_DO_NORM, TRUE); result = miicv_attach(icv, file_id, var_id); if (result == MI_NOERROR) { result = mirw_hyperslab_icv(MIRW_OP_READ, volume, icv, start, count, buffer); miicv_detach(icv); } miicv_free(icv); return (result); } /** Get a hyperslab from the file, with the assistance of a MINC image * conversion variable (ICV). */ int miget_hyperslab_with_icv(mihandle_t volume, /**< A MINC 2.0 volume handle */ int icv, /**< The ICV to use */ mitype_t buffer_data_type, /**< Output datatype */ const unsigned long start[], /**< Start coordinates */ const unsigned long count[], /**< Lengths of edges */ void *buffer) /**< Output memory buffer */ { hid_t file_id; int var_id; int result; int is_signed; int nctype; file_id = volume->hdf_id; var_id = ncvarid(file_id, MIimage); nctype = mitype_to_nctype(buffer_data_type, &is_signed); miicv_setint(icv, MI_ICV_TYPE, nctype); miicv_setstr(icv, MI_ICV_SIGN, is_signed ? MI_SIGNED : MI_UNSIGNED); result = miicv_attach(icv, file_id, var_id); if (result == MI_NOERROR) { result = mirw_hyperslab_icv(MIRW_OP_READ, volume, icv, start, count, buffer); miicv_detach(icv); } return (result); } /** Write a hyperslab to the file, with the assistance of a MINC image * conversion variable (ICV). */ int miset_hyperslab_with_icv(mihandle_t volume, /**< A MINC 2.0 volume handle */ int icv, /**< The ICV to use */ mitype_t buffer_data_type, /**< Output datatype */ const unsigned long start[], /**< Start coordinates */ const unsigned long count[], /**< Lengths of edges */ void *buffer) /**< Output memory buffer */ { hid_t file_id; int var_id; int result; int is_signed; int nctype; file_id = volume->hdf_id; var_id = ncvarid(file_id, MIimage); nctype = mitype_to_nctype(buffer_data_type, &is_signed); miicv_setint(icv, MI_ICV_TYPE, nctype); miicv_setstr(icv, MI_ICV_SIGN, is_signed ? MI_SIGNED : MI_UNSIGNED); result = miicv_attach(icv, file_id, var_id); if (result == MI_NOERROR) { result = mirw_hyperslab_icv(MIRW_OP_WRITE, volume, icv, start, count, (void *) buffer); miicv_detach(icv); } return (result); } /** Read a hyperslab from the file into the preallocated buffer, * converting from the stored "voxel" data range to the desired * "real" (float or double) data range. */ int miget_real_value_hyperslab(mihandle_t volume, mitype_t buffer_data_type, const unsigned long start[], const unsigned long count[], void *buffer) { hid_t file_id; int var_id; int icv; int result; int is_signed; int nctype; int i; int ndims = volume->number_of_dims; midimhandle_t hdim; file_id = volume->hdf_id; var_id = ncvarid(file_id, MIimage); nctype = mitype_to_nctype(buffer_data_type, &is_signed); if ((icv = miicv_create()) < 0) { return (MI_ERROR); } miicv_setint(icv, MI_ICV_TYPE, nctype); miicv_setstr(icv, MI_ICV_SIGN, is_signed ? MI_SIGNED : MI_UNSIGNED); miicv_setint(icv, MI_ICV_DO_RANGE, TRUE); miicv_setint(icv, MI_ICV_DO_NORM, TRUE); miicv_setint(icv, MI_ICV_DO_DIM_CONV, FALSE); //figure out whether we need to flip image L.B May 18/2011 for (i=0; i < volume->number_of_dims; i++) { midimhandle_t hdim; hdim = volume->dim_handles[i]; switch (hdim->flipping_order) { default: case MI_FILE_ORDER: miicv_setint(icv, MI_ICV_DO_DIM_CONV, FALSE); break; case MI_COUNTER_FILE_ORDER: case MI_POSITIVE: if (hdim->step < 0) miicv_setint(icv, MI_ICV_DO_DIM_CONV, TRUE); break; case MI_NEGATIVE: if (hdim->step > 0) miicv_setint(icv, MI_ICV_DO_DIM_CONV, TRUE); break; } } result = miicv_attach(icv, file_id, var_id); if (result == MI_NOERROR) { result = mirw_hyperslab_icv(MIRW_OP_READ, volume, icv, start, count, (void *) buffer); miicv_detach(icv); } miicv_free(icv); return (result); } /** Write a hyperslab to the file from the preallocated buffer, * converting from the stored "voxel" data range to the desired * "real" (float or double) data range. */ int miset_real_value_hyperslab(mihandle_t volume, mitype_t buffer_data_type, const unsigned long start[], const unsigned long count[], void *buffer) { hid_t file_id; int var_id; int icv; int result; int is_signed; int nctype; file_id = volume->hdf_id; var_id = ncvarid(file_id, MIimage); nctype = mitype_to_nctype(buffer_data_type, &is_signed); if ((icv = miicv_create()) < 0) { return (MI_ERROR); } miicv_setint(icv, MI_ICV_TYPE, nctype); miicv_setstr(icv, MI_ICV_SIGN, is_signed ? MI_SIGNED : MI_UNSIGNED); result = miicv_attach(icv, file_id, var_id); if (result == MI_NOERROR) { result = mirw_hyperslab_icv(MIRW_OP_WRITE, volume, icv, start, count, (void *) buffer); miicv_detach(icv); } miicv_free(icv); return (result); } /** Read a hyperslab from the file into the preallocated buffer, * with no range conversions or normalization. Type conversions will * be performed if necessary. */ int miget_voxel_value_hyperslab(mihandle_t volume, mitype_t buffer_data_type, const unsigned long start[], const unsigned long count[], void *buffer) { return mirw_hyperslab_raw(MIRW_OP_READ, volume, buffer_data_type, start, count, buffer); } /** Write a hyperslab to the file from the preallocated buffer, * with no range conversions or normalization. Type conversions will * be performed if necessary. */ int miset_voxel_value_hyperslab(mihandle_t volume, mitype_t buffer_data_type, const unsigned long start[], const unsigned long count[], void *buffer) { return mirw_hyperslab_raw(MIRW_OP_WRITE, volume, buffer_data_type, start, count, (void *) buffer); }