/* * Copyright (c) 2018 Diamond Light Source Ltd. * Author: Charles Mita */ #include #include #include #include #include #include #include "err.h" #include "file.h" #include "filters.h" void clear_det_visit_objects(struct det_visit_objects_t *objects) { if (objects->nxdata) { H5Oclose(objects->nxdata); objects->nxdata = 0; } if (objects->nxdetector) { H5Oclose(objects->nxdetector); objects->nxdetector = 0; } } void free_ds_desc(struct ds_desc_t *desc) { H5Gclose(desc->det_g_id); H5Gclose(desc->data_g_id); free(desc); } void free_nxs_desc(struct ds_desc_t *desc) { free_ds_desc(desc); } void free_eiger_desc(struct ds_desc_t *desc) { struct eiger_ds_desc_t *e_desc = (struct eiger_ds_desc_t *)desc; free(e_desc->block_sizes); free_ds_desc(desc); } void free_opt_eiger_desc(struct ds_desc_t *desc) { free_eiger_desc(desc); } double scale_from_units(const char *unit_string) { if (strcasecmp("m", unit_string) == 0 || strcasecmp("metres", unit_string) == 0 || strcasecmp("meters", unit_string) == 0) { return 1.; } else if (strcasecmp("cm", unit_string) == 0 || strcasecmp("centimetres", unit_string) == 0 || strcasecmp("centimeters", unit_string) == 0) { return 0.01; } else if (strcasecmp("mm", unit_string) == 0 || strcasecmp("millimetres", unit_string) == 0 || strcasecmp("millimeters", unit_string) == 0) { return 0.001; } else if (strcasecmp("um", unit_string) == 0 || strcasecmp("microns", unit_string) == 0 || strcasecmp("micrometres", unit_string) == 0 || strcasecmp("micrometers", unit_string) == 0) { return 0.000001; } else { fprintf(stderr, "Unrecognised unit string %s", unit_string); return 1; } } int get_nxs_dataset_dims(struct ds_desc_t *desc) { hid_t g_id, ds_id, s_id, t_id; int retval = 0; int ndims = 0; int width = 0; g_id = desc->data_g_id; ; ds_id = H5Dopen2(g_id, "data", H5P_DEFAULT); if (ds_id <= 0) { ERROR_JUMP(-1, done, "Unable to open 'data' dataset"); } t_id = H5Dget_type(ds_id); if (t_id <= 0) { ERROR_JUMP(-1, close_dataset, "Error getting datatype"); } width = H5Tget_size(t_id); if (width <= 0) { ERROR_JUMP(-1, close_type, "Error getting type size"); } s_id = H5Dget_space(ds_id); if (s_id <= 0) { ERROR_JUMP(-1, close_dataset, "Error getting dataspace"); } ndims = H5Sget_simple_extent_ndims(s_id); if (ndims != 3) { char message[64]; sprintf(message, "Dataset rank is %d, expected %d", ndims, 3); ERROR_JUMP(-1, close_space, message); } if (H5Sget_simple_extent_dims(s_id, desc->dims, NULL) < 0) { ERROR_JUMP(-1, close_space, "Error getting dataset dimensions"); } if ( H5Tequal(t_id,H5T_NATIVE_CHAR)>0 || H5Tequal(t_id,H5T_NATIVE_INT)>0 || H5Tequal(t_id,H5T_NATIVE_SHORT)>0 || H5Tequal(t_id,H5T_NATIVE_LONG)>0 || H5Tequal(t_id,H5T_NATIVE_LLONG)>0 ) { // signed desc->data_width = -width; } else { // unsigned desc->data_width = width; } close_space: H5Sclose(s_id); close_type: H5Tclose(t_id); close_dataset: H5Dclose(ds_id); done: return retval; } int get_frame_simple(const struct ds_desc_t *desc, const char *name, const hsize_t *frame_idx, const hsize_t *frame_size, void *buffer) { int retval = 0; herr_t err = 0; hid_t g_id, ds_id, s_id, ms_id, t_id; g_id = desc->data_g_id; ds_id = H5Dopen2(g_id, name, H5P_DEFAULT); if (ds_id <= 0) { char message[64]; sprintf(message, "Unable to open dataset %.32s", name); ERROR_JUMP(-1, done, message); } s_id = H5Dget_space(ds_id); if (s_id <= 0) { ERROR_JUMP(-1, close_dataset, "Error getting dataspace"); } t_id = H5Dget_type(ds_id); if (t_id <= 0) { ERROR_JUMP(-1, close_type, "Error retrieving datatype"); } err = H5Sselect_hyperslab(s_id, H5S_SELECT_SET, frame_idx, NULL, frame_size, NULL); if (err < 0) { ERROR_JUMP(-1, close_space, "Error seleting hyperslab"); } ms_id = H5Screate_simple(3, frame_size, frame_size); if (ms_id < 0) { ERROR_JUMP(-1, close_space, "Could not create dataspace"); } err = H5Dread(ds_id, t_id, ms_id, s_id, H5P_DEFAULT, buffer); if (err < 0) { ERROR_JUMP(-1, close_mspace, "Error reading dataset"); } close_mspace: H5Sclose(ms_id); close_space: H5Sclose(s_id); close_type: H5Tclose(t_id); close_dataset: H5Dclose(ds_id); done: return retval; } int get_frame_from_chunk(const struct ds_desc_t *desc, const char *ds_name, const hsize_t *frame_idx, const hsize_t *frame_size, void *buffer) { hid_t d_id = 0; hsize_t c_offset[3] = {frame_idx[0], 0, 0}; uint32_t c_filter_mask = 0; hsize_t c_bytes; void *c_buffer = NULL; const struct opt_eiger_ds_desc_t *o_eiger_desc = (struct opt_eiger_ds_desc_t *)desc; int retval = 0; if (frame_idx[1] != 0 || frame_idx[2] != 0) { char message[64]; sprintf(message, "Require frame selection starts at [n, 0, 0], not [n, %llu, %llu]", frame_idx[1], frame_idx[2]); ERROR_JUMP(-1, done, message); } d_id = H5Dopen(desc->data_g_id, ds_name, H5P_DEFAULT); if (d_id < 0) { char message[64]; sprintf(message, "Error opening dataset %.32s", ds_name); ERROR_JUMP(-1, done, message); } if (H5Dget_chunk_storage_size(d_id, c_offset, &c_bytes) < 0) { char message[96]; sprintf(message, "Error reading chunk size from %.32s for frame %llu", ds_name, frame_idx[0]); ERROR_JUMP(-1, done, message); } if (c_bytes == 0) { char message[96]; sprintf(message, "Target chunk %llu has zero size for dataset %.32s", frame_idx[0], ds_name); ERROR_JUMP(-1, done, message); } if (o_eiger_desc->bs_applied) { c_buffer = malloc(c_bytes); if (!c_buffer) { char message[128]; sprintf(message, "Unable to allocate chunk buffer for dataset %.32s - frame %llu, " "size %llu bytes", ds_name, frame_idx[0], c_bytes); ERROR_JUMP(-1, done, message); } } else { c_buffer = buffer; } if (H5DOread_chunk(d_id, H5P_DEFAULT, c_offset, &c_filter_mask, c_buffer) < 0) { char message[128]; sprintf(message, "Error reading chunk %llu from dataset %.32s - size %llu bytes", frame_idx[0], ds_name, c_bytes); ERROR_JUMP(-1, done, message); } if (o_eiger_desc->bs_applied) { if (bslz4_decompress(o_eiger_desc->bs_params, c_bytes, c_buffer, abs(desc->data_width) * frame_size[1] * frame_size[2], buffer) < 0) { char message[128]; sprintf(message, "Error processing chunk %llu from %.32s with bitshuffle_lz4", frame_idx[0], ds_name); ERROR_JUMP(-1, done, message); } } done: if (c_buffer && (c_buffer != buffer)) free(c_buffer); if (d_id) H5Dclose(d_id); return retval; } int get_nxs_frame(const struct ds_desc_t *desc, const int nin, void *buffer) { /* detector data are the two inner most indices */ /* TODO: handle ndims > 3 and select appropriately */ int retval = 0; int n = nin - desc->image_number_offset; hsize_t frame_idx[3] = {n, 0, 0}; hsize_t frame_size[3] = {1, desc->dims[1], desc->dims[2]}; if (n < 0 || n >= desc->dims[0]) { char message[64]; sprintf(message, "Selected frame %d is out of range valid range [0, %d]", n, (int)desc->dims[0] - 1); ERROR_JUMP(-1, done, message); } retval = get_frame_simple(desc, "data", frame_idx, frame_size, buffer); if (retval < 0) { ERROR_JUMP(retval, done, ""); } done: return retval; } int get_dectris_eiger_frame(const struct ds_desc_t *desc, int nin, void *buffer) { int retval = 0; int n = nin - desc->image_number_offset; int block, frame_count, idx; struct eiger_ds_desc_t *eiger_desc = (struct eiger_ds_desc_t *)desc; char data_name[16] = {0}; hsize_t frame_idx[3] = {0, 0, 0}; hsize_t frame_size[3] = {1, desc->dims[1], desc->dims[2]}; if (n < 0 || n >= desc->dims[0]) { char message[64]; sprintf(message, "Selected frame %d is out of range valid range [0, %d]", n, (int)desc->dims[0] - 1); ERROR_JUMP(-1, done, message); } /* determine the relevant data block */ frame_count = 0; block = 0; while ((frame_count += eiger_desc->block_sizes[block]) <= n) block++; idx = n - (frame_count - eiger_desc->block_sizes[block]); /* index in current block */ frame_idx[0] = idx; sprintf(data_name, "data_%06d", block + 1); retval = eiger_desc->frame_func(desc, data_name, frame_idx, frame_size, buffer); if (retval < 0) { ERROR_JUMP(retval, done, ""); } done: return retval; } int get_dectris_eiger_dataset_dims(struct ds_desc_t *desc) { int retval = 0; int n_datas = 0; int n = 0; int data_width = 0; int ndims = 3; char ds_name[16] = {0}; /* 12 chars in "data_xxxxxx\0" */ int *frame_counts = NULL; hsize_t dims[3] = {0}; struct eiger_ds_desc_t *eiger_desc = (struct eiger_ds_desc_t *)desc; /* datasets are "data_%06d % n" - need to determine how many of these there * are and what the ranges are */ sprintf(ds_name, "data_%06d", n_datas + 1); while (H5Lexists(desc->data_g_id, ds_name, H5P_DEFAULT) > 0) { sprintf(ds_name, "data_%06d", ++n_datas + 1); } frame_counts = malloc(n_datas * sizeof(*frame_counts)); for (n = 0; n < n_datas; n++) { hid_t ds_id, t_id, s_id; hsize_t block_dims[3] = {0}; sprintf(ds_name, "data_%06d", n + 1); ds_id = H5Dopen2(desc->data_g_id, ds_name, H5P_DEFAULT); if (ds_id < 0) { char message[64]; sprintf(message, "Unable to open dataset %.16s", ds_name); ERROR_JUMP(-1, loop_end, message); } t_id = H5Dget_type(ds_id); if (t_id < 0) { ERROR_JUMP(-1, close_dataset, "Unable to get datatype") } s_id = H5Dget_space(ds_id); if (s_id < 0) { ERROR_JUMP(-1, close_type, "Unable to get dataspace"); } data_width = H5Tget_size(t_id); if (data_width <= 0) { ERROR_JUMP(-1, close_space, "Unable to get type size"); } if ( H5Tequal(t_id,H5T_NATIVE_CHAR)>0 || H5Tequal(t_id,H5T_NATIVE_INT)>0 || H5Tequal(t_id,H5T_NATIVE_SHORT)>0 || H5Tequal(t_id,H5T_NATIVE_LONG)>0 || H5Tequal(t_id,H5T_NATIVE_LLONG)>0 ) { // signed data_width = -data_width; } ndims = H5Sget_simple_extent_ndims(s_id); if (ndims != 3) { char message[64]; sprintf(message, "Dataset %.16s has rank %d, expected %d", ds_name, ndims, 3); ERROR_JUMP(-1, close_space, message); } if (H5Sget_simple_extent_dims(s_id, block_dims, NULL) < 0) { ERROR_JUMP(-1, close_space, "Unable to read dataset dimensions"); } dims[1] = block_dims[1]; dims[2] = block_dims[2]; dims[0] += block_dims[0]; frame_counts[n] = block_dims[0]; close_space: H5Sclose(s_id); close_type: H5Tclose(t_id); close_dataset: H5Dclose(ds_id); loop_end: if (retval < 0) break; } if (retval < 0) { free(frame_counts); } else { memcpy(desc->dims, dims, 3 * sizeof(*dims)); desc->data_width = data_width; eiger_desc->n_data_blocks = n_datas; eiger_desc->block_sizes = frame_counts; } return retval; } int read_pixel_info(hid_t g_id, const char *path, double *size) { /* * NXdetector allows pixel size to be an array (for varied pixel size), * however XDS only allows for a single value. * TODO: handle array case (return first value maybe?) */ /* read the scalar dataset value and scale according to the unit in the * attribute */ /* returned value is in metres */ int retval = 0; herr_t err = 0; hid_t ds_id; double value = 0; ds_id = H5Dopen2(g_id, path, H5P_DEFAULT); if (ds_id < 0) { char message[64]; sprintf(message, "Error opening dataset %.32s", path); ERROR_JUMP(-1, done, message); } err = H5Dread(ds_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &value); if (err < 0) { char message[64]; sprintf(message, "Error reading dataset %.32s", path); ERROR_JUMP(-1, close_dataset, message); } if (H5Aexists(ds_id, "units") > 0) { /* string may be variable length */ hid_t a_id, t_id, mt_id; void *str_buffer = NULL; int str_size = -1; double scale = 1; a_id = H5Aopen(ds_id, "units", H5P_DEFAULT); if (a_id < 0) { char message[100]; sprintf(message, "Error openeing units attribute for %.32s after existence check", path); ERROR_JUMP(-1, close_dataset, message); } t_id = H5Aget_type(a_id); if (t_id < 0) { ERROR_JUMP(-1, close_attribute, "Error getting datatype"); } /* TODO: handle multiple strings in attribute (just detect and error) */ if (H5Tis_variable_str(t_id) > 0) { str_size = -1; str_buffer = malloc(sizeof(char *)); } else { str_size = H5Tget_size(t_id); /* do not assume room has been left for null-byte in fixed length string */ str_buffer = malloc(str_size + 1); } if (str_buffer == NULL) { ERROR_JUMP(-1, close_datatype, "Unable to allocate space for variable length string"); } mt_id = H5Tcopy(H5T_C_S1); if (mt_id < 0) { ERROR_JUMP(-1, free_string, "Error creating HDF5 String datatype"); } err = H5Tset_size(mt_id, str_size == -1 ? H5T_VARIABLE : str_size); if (err < 0) { char message[64]; sprintf(message, "Error setting datatype size to %d", str_size); ERROR_JUMP(-1, close_mem_datatype, message); } err = H5Aread(a_id, mt_id, str_buffer); if (err < 0) { ERROR_JUMP(-1, close_mem_datatype, "Error reading units attribute"); } /* ensure last byte is null */ if (str_size > 0) ((char *)str_buffer)[str_size] = '\0'; scale = scale_from_units(str_size == -1 ? *(char **)str_buffer : (char *)str_buffer); value *= scale; if (str_size == -1) { /* we have to create this dataspace just to indicate we want * to clear the entire vlen dataset (all 1 element - good job HDF5) */ hsize_t dims[1] = {1}; hid_t s_id = H5Screate_simple(1, dims, NULL); H5Sselect_all(s_id); H5Dvlen_reclaim(mt_id, s_id, H5P_DEFAULT, str_buffer); H5Sclose(s_id); } close_mem_datatype: H5Tclose(mt_id); free_string: free(str_buffer); close_datatype: H5Tclose(t_id); close_attribute: H5Aclose(a_id); } /* if H5Aexists(...) */ close_dataset: H5Dclose(ds_id); done: if (retval == 0) *size = value; return retval; } int get_nxs_pixel_info(const struct ds_desc_t *desc, double *x_size, double *y_size) { int retval = 0; if (read_pixel_info(desc->det_g_id, "x_pixel_size", x_size) < 0) { ERROR_JUMP(-1, done, ""); } if (read_pixel_info(desc->det_g_id, "y_pixel_size", y_size) < 0) { ERROR_JUMP(-1, done, ""); } done: return retval; } int get_dectris_eiger_pixel_info(const struct ds_desc_t *desc, double *x_size, double *y_size) { int retval = 0; if (read_pixel_info(desc->det_g_id, "detectorSpecific/x_pixel_size", x_size) < 0) { ERROR_JUMP(-1, done, ""); } if (read_pixel_info(desc->det_g_id, "detectorSpecific/y_pixel_size", y_size) < 0) { ERROR_JUMP(-1, done, ""); } done: return retval; } int get_nxs_pixel_mask(const struct ds_desc_t *desc, int *buffer) { int retval = 0; hid_t ds_id; herr_t err = 0; ds_id = H5Dopen2(desc->det_g_id, "pixel_mask", H5P_DEFAULT); if (ds_id < 0) { ERROR_JUMP(-1, done, "Error opening pixel_mask dataset"); } err = H5Dread(ds_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer); if (err < 0) { ERROR_JUMP(-1, close_dataset, "Error reading pixel_mask dataset"); } close_dataset: H5Dclose(ds_id); done: return retval; } int get_dectris_eiger_pixel_mask(const struct ds_desc_t *desc, int *buffer) { int retval = 0; hid_t ds_id; herr_t err = 0; ds_id = H5Dopen2(desc->det_g_id, "detectorSpecific/pixel_mask", H5P_DEFAULT); if (ds_id < 0) { ERROR_JUMP(-1, done, "Error opening detectorSpecific/pixel_mask"); } // what if this is compressed? hid_t dcpl = H5Dget_create_plist(ds_id); int n_filters = H5Pget_nfilters(dcpl); H5Z_filter_t filter_id; if (n_filters>0) { unsigned int flags; size_t nelmts = 1; unsigned int values_out[1] = {99}; char filter_name[80]; filter_id = H5Pget_filter(dcpl, (unsigned) 0, &flags, &nelmts, values_out, sizeof(filter_name), filter_name, NULL); if (filter_id>=0) { fprintf(stderr," filter name =\"%s\"\n",filter_name); } } err = H5Dread(ds_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer); if (err < 0) { if (n_filters>0) { ERROR_JUMP(-1, close_dataset, "Error reading detectorSpecific/pixel_mask with filter(s)"); } else { ERROR_JUMP(-1, close_dataset, "Error reading detectorSpecific/pixel_mask"); } } if (H5Zfilter_avail(BS_H5_FILTER_ID)) { fprintf(stderr," bitshuffle filter is available now since H5Dread (of pixel-mask) triggered loading of the filter.\n"); } close_dataset: H5Dclose(ds_id); done: return retval; } int get_null_pixel_mask(const struct ds_desc_t *desc, int *buffer) { hsize_t buffer_length = desc->dims[1] * desc->dims[2]; memset(buffer, 0, sizeof(*buffer) * buffer_length); return 0; } herr_t det_visit_callback(hid_t root_id, const char *name, const H5O_info_t *info, void *op_data) { struct det_visit_objects_t *output_data = op_data; hid_t g_id; herr_t retval = 0; if (info->type != H5O_TYPE_GROUP) return 0; g_id = H5Oopen(root_id, name, H5P_DEFAULT); if (g_id < 0) { char message[256]; sprintf(message, "H5OVisit callback: Unable to open group %.128s", name); ERROR_JUMP(-1, done, message); } /* check for an "NX_class" attribute */ { int str_size = 0; void *buffer = NULL; hid_t a_id, t_id, mt_id; if (H5Aexists(g_id, "NX_class") <= 0) { /* not an error - just close group and allow continuation */ retval = 0; goto close_group; } a_id = H5Aopen(g_id, "NX_class", H5P_DEFAULT); if (a_id <= 0) { char message[256]; sprintf(message, "H5OVisit callback: Error opening NX_class attribute on %.128s " "after existence check", name); ERROR_JUMP(-1, close_group, message); } t_id = H5Aget_type(a_id); if (t_id < 0) { ERROR_JUMP(-1, close_attr, "Error getting datatype"); } if (H5Tis_variable_str(t_id) > 0) { str_size = -1; buffer = malloc(sizeof(char *)); } else { str_size = H5Tget_size(t_id); buffer = malloc(str_size + 1); } if (!buffer) { ERROR_JUMP(-1, close_type, "Error allocating string buffer"); } mt_id = H5Tcopy(H5T_C_S1); if (mt_id < 0) { ERROR_JUMP(-1, free_buffer, "Error creating HDF5 String datatype"); } // set the target string type to be one longer than the recorded string // in keeping with the malloc'd buffer - if this is already a null // terminated string then we will just have two nulls, if it is not // then we won't clobber the last char in the buffer with a null in the // H5Aread call if (H5Tset_size(mt_id, str_size == -1 ? H5T_VARIABLE : str_size + 1) < 0) { char message[64]; sprintf(message, "Error setting string datatype to size %d", str_size); ERROR_JUMP(-1, close_mtype, message); } if (H5Aread(a_id, mt_id, buffer) < 0) { char message[256]; sprintf( message, "H5OVisit callback: Error reading NX_class attribute on group %.128s", name); ERROR_JUMP(-1, close_mtype, message); } /* at least one file has been seen where the NX_class attribute was not null * terminated and extraneous bytes where being read by strcmp - set the end * byte to null */ if (str_size > 0) ((char *)buffer)[str_size] = '\0'; /* test for NXdata or NXdetector */ { char *nxclass = str_size > 0 ? (char *)buffer : *((char **)buffer); if (strcmp("NXdata", nxclass) == 0) { hid_t out_id = H5Gopen(root_id, name, H5P_DEFAULT); output_data->nxdata = out_id; } else if (strcmp("NXdetector", nxclass) == 0) { hid_t out_id = H5Gopen(root_id, name, H5P_DEFAULT); output_data->nxdetector = out_id; } } if (str_size == -1) { hsize_t dims[1] = {1}; hid_t s_id = H5Screate_simple(1, dims, NULL); H5Sselect_all(s_id); H5Dvlen_reclaim(mt_id, s_id, H5P_DEFAULT, buffer); H5Sclose(s_id); } close_mtype: H5Tclose(mt_id); free_buffer: free(buffer); close_type: H5Tclose(t_id); close_attr: H5Aclose(a_id); } close_group: if (H5Gclose(g_id) < 0) { /* TODO: error trace */ retval = -1; } done: return retval; } int check_for_chunk_read(hid_t g_id, const char *ds_name, struct opt_eiger_ds_desc_t *desc) { int retval = 0; int n_filters; hsize_t cdims[3]; hid_t ds_id, dcpl, s_id; unsigned int filter_flags, filter_config; char filter_name[16]; size_t name_len = 16; size_t cd_nelems = BS_H5_N_PARAMS; hsize_t dims[3]; H5Z_filter_t filter; dcpl = 0; s_id = 0; ds_id = 0; ds_id = H5Dopen2(g_id, ds_name, H5P_DEFAULT); if (ds_id < 0) { char message[64]; sprintf(message, "Error opening dataset %.32s", ds_name); ERROR_JUMP(-1, done, message) } s_id = H5Dget_space(ds_id); if (s_id < 0) { char message[64]; sprintf(message, "Error opening dataspace for %.32s", ds_name); ERROR_JUMP(-1, done, message); } if (3 != H5Sget_simple_extent_ndims(s_id)) { goto done; } if (H5Sget_simple_extent_dims(s_id, dims, NULL) < 0) { char message[80]; sprintf(message, "Error retriving dataset dimensions for %.32s", ds_name); ERROR_JUMP(-1, done, message); } dcpl = H5Dget_create_plist(ds_id); if (dcpl < 0) { ERROR_JUMP(-1, done, "Error getting dataset creation property list"); } /* check the chunk layout matches the layout we expect of * [1, frame_size_y, frame_size_x] (1 frame == 1 chunk) */ int cndims = H5Pget_chunk(dcpl, 3, cdims); if (cndims != 3) { goto done; } if (cdims[0] != 1 || cdims[1] != dims[1] || cdims[2] != dims[2]) { goto done; } /* check for potential filters - only the bitshuffle filter is supported */ n_filters = H5Pget_nfilters(dcpl); if (n_filters < 0) { ERROR_JUMP(-1, done, "Error retrieving number of filters on dataset"); } else if (n_filters > 1) { goto done; } if (n_filters == 1) { filter = H5Pget_filter2(dcpl, 0, &filter_flags, &cd_nelems, desc->bs_params, name_len, filter_name, &filter_config); if (filter < 0) { ERROR_JUMP(-1, done, "Error retrieving filter information"); } if (filter != BS_H5_FILTER_ID) { goto done; } if (cd_nelems > BS_H5_N_PARAMS) { char message[128]; sprintf(message, "More than expected number of parameters to bitshuffle filter - " "expected %d, was %lu", BS_H5_N_PARAMS, cd_nelems); ERROR_JUMP(-1, done, message); } desc->bs_applied = 1; } else { desc->bs_applied = 0; } retval = 1; done: if (dcpl) H5Pclose(dcpl); if (s_id) H5Sclose(s_id); if (ds_id) H5Dclose(ds_id); return retval; } int create_dataset_descriptor(struct ds_desc_t **desc, struct det_visit_objects_t *visit_result) { int retval = 0; hid_t g_id, ds_id; int (*pxl_func)(const struct ds_desc_t *, double *, double *); int (*pxl_mask_func)(const struct ds_desc_t *, int *); int (*ds_prop_func)(struct ds_desc_t *); int (*frame_func)(const struct ds_desc_t *, int, void *); void (*free_func)(struct ds_desc_t *); struct ds_desc_t *output; g_id = visit_result->nxdetector; /* determine the pixel information location */ if (H5Lexists(g_id, "x_pixel_size", H5P_DEFAULT) > 0 && H5Lexists(g_id, "y_pixel_size", H5P_DEFAULT) > 0) { pxl_func = &get_nxs_pixel_info; } else if (H5Lexists(g_id, "detectorSpecific", H5P_DEFAULT) > 0 && H5Lexists(g_id, "detectorSpecific/x_pixel_size", H5P_DEFAULT) > 0 && H5Lexists(g_id, "detectorSpecific/y_pixel_size", H5P_DEFAULT) > 0) { pxl_func = &get_dectris_eiger_pixel_info; } else { ERROR_JUMP(-1, done, "Could not locate x_pixel_size and y_pixel_size"); } /* determine pixel mask location */ if (H5Lexists(g_id, "pixel_mask", H5P_DEFAULT) > 0) { pxl_mask_func = &get_nxs_pixel_mask; } else if (H5Lexists(g_id, "detectorSpecific", H5P_DEFAULT) > 0 && H5Lexists(g_id, "detectorSpecific/pixel_mask", H5P_DEFAULT) > 0) { pxl_mask_func = &get_dectris_eiger_pixel_mask; } else { pxl_mask_func = &get_null_pixel_mask; fprintf( stderr, "WARNING: Could not find pixel mask - no masking will be applied\n"); } /* determine where the data is stored and what strategy to use */ /* we select the "dectris-eiger" strategy if both are valid due to * potential confusion with the sizes of a virtual dataset, possible failure * opening if we're using an old library version, and the potential to use the * optimised chunk read strategy */ if (H5Lexists(visit_result->nxdetector, "data_000001", H5P_DEFAULT) > 0) { ds_id = visit_result->nxdetector; ds_prop_func = &get_dectris_eiger_dataset_dims; frame_func = &get_dectris_eiger_frame; } else if (H5Lexists(visit_result->nxdetector, "data", H5P_DEFAULT) > 0) { ds_id = visit_result->nxdetector; ds_prop_func = &get_nxs_dataset_dims; frame_func = &get_nxs_frame; } else if (H5Lexists(visit_result->nxdata, "data_000001", H5P_DEFAULT) > 0) { ds_id = visit_result->nxdata; ds_prop_func = &get_dectris_eiger_dataset_dims; frame_func = &get_dectris_eiger_frame; } else if (H5Lexists(visit_result->nxdata, "data", H5P_DEFAULT) > 0) { ds_id = visit_result->nxdata; ds_prop_func = &get_nxs_dataset_dims; frame_func = &get_nxs_frame; } else { ERROR_JUMP(-1, done, "Could not locate detector dataset"); } if (ds_prop_func == &get_dectris_eiger_dataset_dims) { /* setup the "extra info" structs */ struct eiger_ds_desc_t *eiger_desc; struct opt_eiger_ds_desc_t *o_eiger_desc; eiger_desc = malloc(sizeof(*eiger_desc)); if (!eiger_desc) { ERROR_JUMP(-1, done, "Memory error creating data description for Eiger"); } memset(eiger_desc, 0, sizeof(*eiger_desc)); eiger_desc->frame_func = &get_frame_simple; o_eiger_desc = malloc(sizeof(*o_eiger_desc)); if (!o_eiger_desc) { free(eiger_desc); ERROR_JUMP(-1, done, "Memory error creating data description for optimised Eiger"); } o_eiger_desc->base.frame_func = &get_frame_from_chunk; /* check if we can perform the optimised chunk read */ retval = check_for_chunk_read(ds_id, "data_000001", o_eiger_desc); if (retval < 0) { free(o_eiger_desc); free(eiger_desc); ERROR_JUMP(-1, done, ""); } if (retval) { free(eiger_desc); *(struct opt_eiger_ds_desc_t **)desc = o_eiger_desc; free_func = &free_opt_eiger_desc; } else { free(o_eiger_desc); *(struct eiger_ds_desc_t **)desc = eiger_desc; free_func = &free_eiger_desc; } } else { *desc = malloc(sizeof(struct nxs_ds_desc_t)); free_func = &free_nxs_desc; } output = *((struct ds_desc_t **)desc); output->det_g_id = g_id; output->data_g_id = ds_id; output->get_pixel_properties = pxl_func; output->get_pixel_mask = pxl_mask_func; output->get_data_frame = frame_func; output->free_desc = free_func; ds_prop_func(output); done: return retval; } int get_detector_info(const hid_t fid, struct ds_desc_t **desc) { int retval = 0; herr_t err = 0; struct det_visit_objects_t objects = {0}; err = H5Ovisit(fid, H5_INDEX_NAME, H5_ITER_INC, &det_visit_callback, &objects); if (err < 0) { clear_det_visit_objects(&objects); ERROR_JUMP(-1, done, "Error during H5Ovisit callback"); } if (objects.nxdata == 0) { fprintf(stderr, "WARNING: Could not locate an NXdata entry\n"); } if (objects.nxdetector == 0) { fprintf(stderr, "WARNING: Could not locate an NXdetector entry\n"); } if ((retval = create_dataset_descriptor(desc, &objects)) < 0) { ERROR_JUMP(retval, done, ""); }; done: return retval; }