Initial code commit.

Little to no error reporting, still fairly brittle and not very well
tested.
This commit is contained in:
Charles Mita
2018-03-26 18:03:12 +01:00
parent 9e08e01623
commit 3c4b00f12f
7 changed files with 963 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
*.swp
*.*~
*.bak
*.tmp
*.o
*.so
+24
View File
@@ -0,0 +1,24 @@
Copyright (c) 2018, Diamond Light Source
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+18
View File
@@ -0,0 +1,18 @@
BUILD_DIR ?= ./build
SRC_DIR = ./src
INC_DIR = $(SRC_DIR)
CC=h5cc
CFLAGS=-Wall -g -O2 -fpic -I$(INC_DIR)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) -c $< -o $@
plugin: $(BUILD_DIR)/plugin.o $(BUILD_DIR)/file.o
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) -shared $^ -o $(BUILD_DIR)/plugin.so
.PHONY: clean
clean:
rm -r $(BUILD_DIR)
+668
View File
@@ -0,0 +1,668 @@
/*
* Copyright (c) 2018 Diamond Light Source Ltd.
* Author: Charles Mita
*/
#include <hdf5.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "file.h"
hid_t h5_int_type_from_width(const int width) {
if (width == sizeof(char)) {
return H5T_NATIVE_SCHAR;
} else if (width == sizeof(short)) {
return H5T_NATIVE_SHORT;
} else if (width == sizeof(int)) {
return H5T_NATIVE_INT;
} else if (width == sizeof(long)) {
return H5T_NATIVE_LONG;
} else if (width == sizeof(long long)) {
return H5T_NATIVE_LLONG;
} else {
/* TODO: error */
return -1;
}
}
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_dataset_properties(struct dataset_properties_t *p) {
if (p->dims) {
free(p->dims);
p->dims = NULL;
}
p->ndims = 0;
}
void free_nxs_data_description(struct data_description_t *desc) {
if (desc->extra) free(desc->extra); /* should just be NULL */
desc->extra = NULL;
}
void free_eiger_data_description(struct data_description_t *desc) {
if (!desc->extra) return;
struct eiger_data_description_t *extra = desc->extra;
if (extra->block_sizes) free(extra->block_sizes);
free(extra);
desc->extra = NULL;
}
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(const struct data_description_t *desc, struct dataset_properties_t *properties) {
hid_t g_id, ds_id, s_id, t_id;
int retval = 0;
int ndims = 0;
int width = 0;
hsize_t *dims = NULL;
g_id = desc->data_group_id;;
ds_id = H5Dopen2(g_id, "data", H5P_DEFAULT);
if (ds_id <= 0) {
retval = -1;
return retval;
}
t_id = H5Dget_type(ds_id);
if (t_id <= 0) {
retval = -1;
goto close_dataset;
}
width = H5Tget_size(t_id);
if (width <= 0) {
retval = -1;
goto close_type;
}
s_id = H5Dget_space(ds_id);
if (s_id <= 0) {
retval = -1;
goto close_dataset;
}
ndims = H5Sget_simple_extent_ndims(s_id);
if (ndims <= 0) {
retval = -1;
goto close_space;
}
dims = malloc(ndims * sizeof(hsize_t));
if (!dims) {
retval = -1;
goto close_space;
}
if (H5Sget_simple_extent_dims(s_id, dims, NULL) < 0) {
retval = -1;
free(dims);
goto close_space;
}
properties->ndims = ndims;
properties->dims = dims;
properties->data_width = width;
close_space:
H5Sclose(s_id);
close_type:
H5Tclose(t_id);
close_dataset:
H5Dclose(ds_id);
return retval;
}
int get_frame(hid_t g_id, const char* name, hsize_t *frame_idx, hsize_t *frame_size, int data_width, void *buffer) {
int retval = 0;
herr_t err = 0;
hid_t ds_id, s_id, ms_id, t_id;
ds_id = H5Dopen2(g_id, name, H5P_DEFAULT);
if (ds_id <= 0) {
retval = -1;
return retval;
}
s_id = H5Dget_space(ds_id);
if (s_id <= 0) {
retval = -1;
goto close_dataset;
}
err = H5Sselect_hyperslab(s_id, H5S_SELECT_SET, frame_idx, NULL, frame_size, NULL);
if (err < 0) {
retval = -1;
goto close_space;
}
ms_id = H5Screate_simple(3, frame_size, frame_size);
if (ms_id < 0) {
retval = -1;
goto close_space;
}
t_id = h5_int_type_from_width(data_width);
if (t_id < 0) {
retval = -1;
goto close_mspace;
}
err = H5Dread(ds_id, t_id, ms_id, s_id, H5P_DEFAULT, buffer);
if (err < 0) {
retval = -1;
goto close_mspace;
}
close_mspace:
H5Sclose(ms_id);
close_space:
H5Sclose(s_id);
close_dataset:
H5Dclose(ds_id);
return retval;
}
int get_nxs_frame(
const struct data_description_t *desc,
const struct dataset_properties_t *ds_prop,
int n,
int data_width,
void *buffer) {
/* detector data are the two inner most indices */
/* n is indexed from one - hdf5 slices start at zero */
/* TODO: handle ndims > 3 and select appropriately */
int retval = 0;
hsize_t frame_idx[3] = {n - 1, 0, 0};
hsize_t frame_size[3] = {1, ds_prop->dims[1], ds_prop->dims[2]};
retval = get_frame(desc->data_group_id, "data", frame_idx, frame_size, data_width, buffer);
return retval;
}
int get_dectris_eiger_frame(
const struct data_description_t *desc,
const struct dataset_properties_t *ds_prop,
int n,
int data_width,
void *buffer) {
int retval = 0;
int block, frame_count, idx;
struct eiger_data_description_t *eiger_desc = desc->extra;
char data_name[16] = {0};
hsize_t frame_idx[3] = {0, 0, 0};
hsize_t frame_size[3] = {1, ds_prop->dims[1], ds_prop->dims[2]};
/* determine the relevant data block */
frame_count = 0;
block = 0;
while ((frame_count += eiger_desc->block_sizes[block]) < (n-1)) block++;
idx = n - (frame_count - eiger_desc->block_sizes[block]) - 1; /* index in current block */
printf("n: %d -> Block: %d, idx: %d\n", n, block, idx);
frame_idx[0] = idx;
sprintf(data_name, "data_%06d", block + 1);
retval = get_frame(desc->data_group_id, data_name, frame_idx, frame_size, data_width, buffer);
return retval;
}
int get_dectris_eiger_dataset_dims(const struct data_description_t *desc, struct dataset_properties_t *properties) {
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 = malloc(3 * sizeof(hsize_t));
if (!dims) {
retval = -1;
return retval;
}
memset(dims, 0, sizeof(hsize_t) * ndims);
/* 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_group_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_group_id, ds_name, H5P_DEFAULT);
if (ds_id < 0) {
retval = -1;
break;
}
t_id = H5Dget_type(ds_id);
if (t_id < 0) {
retval = -1;
goto close_dataset;
}
s_id = H5Dget_space(ds_id);
if (s_id < 0) {
retval = -1;
goto close_type;
}
data_width = H5Tget_size(t_id);
if (data_width <= 0) {
retval = -1;
goto close_space;
}
if (H5Sget_simple_extent_dims(s_id, block_dims, NULL) < 0) {
retval = -1;
goto close_space;
}
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);
}
if (retval < 0) {
free(dims);
free(frame_counts);
} else {
properties->ndims = ndims;
properties->dims = dims;
properties->data_width = data_width;
((struct eiger_data_description_t *) desc->extra)->n_data_blocks = n_datas;
((struct eiger_data_description_t *) desc->extra)->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) {
retval = -1;
return retval;;
}
err = H5Dread(ds_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, &value);
if (err < 0) {
retval = -1;
goto close_dataset;
}
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) {
retval = -1;
goto close_dataset;
}
t_id = H5Aget_type(a_id);
if (t_id < 0) {
retval = -1;
goto close_attribute;
}
/* 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) {
retval = -1;
goto close_datatype;
}
mt_id = H5Tcopy(H5T_C_S1);
if (mt_id < 0) {
retval = -1;
goto free_string;
}
err = H5Tset_size(mt_id, str_size == -1 ? H5T_VARIABLE : str_size);
if (err < 0) {
retval = -1;
goto close_mem_datatype;
}
err = H5Aread(a_id, mt_id, str_buffer);
if (err < 0) {
retval = -1;
goto close_mem_datatype;
}
/* 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);
}
*size = value;
close_dataset:
H5Dclose(ds_id);
return retval;
}
int get_nxs_pixel_info(const struct data_description_t *desc, double *x_size, double *y_size) {
if (read_pixel_info(desc->det_group_id, "x_pixel_size", x_size) < 0) {
return -1;
}
if (read_pixel_info(desc->det_group_id, "y_pixel_size", y_size) < 0) {
return -1;
}
return 0;
}
int get_dectris_eiger_pixel_info(const struct data_description_t *desc, double *x_size, double *y_size) {
if (read_pixel_info(desc->det_group_id, "detectorSpecific/x_pixel_size", x_size) < 0) {
return -1;
}
if (read_pixel_info(desc->det_group_id, "detectorSpecific/y_pixel_size", y_size) < 0) {
return -1;
}
return 0;
}
int get_nxs_pixel_mask(const struct data_description_t *desc, int *buffer) {
int retval = 0;
hid_t ds_id;
herr_t err = 0;
ds_id = H5Dopen2(desc->det_group_id, "pixel_mask", H5P_DEFAULT);
if (ds_id < 0) {
retval = -1;
return retval;
}
err = H5Dread(ds_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer);
if (err < 0) {
retval = -1;
goto close_dataset;
}
close_dataset:
H5Dclose(ds_id);
return retval;
}
int get_dectris_eiger_pixel_mask(const struct data_description_t *desc, int *buffer) {
int retval = 0;
hid_t ds_id;
herr_t err = 0;
ds_id = H5Dopen2(desc->det_group_id, "detectorSpecific/pixel_mask", H5P_DEFAULT);
if (ds_id < 0) {
retval = -1;
return retval;
}
err = H5Dread(ds_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, buffer);
if (err < 0) {
retval = -1;
goto close_dataset;
}
close_dataset:
H5Dclose(ds_id);
return retval;
}
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);
/* check for an "NX_class" attribute */
{
char* buffer = NULL;
hid_t a_id, t_id;
H5A_info_t a_info;
if (H5Aexists(g_id, "NX_class") <= 0) {
retval = 0;
goto close_group;
}
a_id = H5Aopen(g_id, "NX_class", H5P_DEFAULT);
if (a_id <= 0) {
/* TODO: error trace */
retval = -1;
goto close_group;
}
if (H5Aget_info(a_id, &a_info) < 0) {
/* TODO: handle error */
retval = -1;
goto close_attr;
}
t_id = H5Tcreate(H5T_STRING, a_info.data_size);
if (t_id <= 0) {
retval = -1;
goto close_attr;
}
buffer = malloc(a_info.data_size + 1);
if (buffer == NULL) {
/* TODO: OOM error */
retval =- 1;
goto close_type;
}
if (H5Aread(a_id, t_id, buffer) < 0) {
/*TODO: handle*/
retval = -1;
goto free_buffer;
}
/* 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
*/
buffer[a_info.data_size] = '\0';
if (strcmp("NXdata", buffer) == 0) {
hid_t out_id = H5Gopen(root_id, name, H5P_DEFAULT);
output_data->nxdata = out_id;
} else if (strcmp("NXdetector", buffer) == 0) {
hid_t out_id = H5Gopen(root_id, name, H5P_DEFAULT);
output_data->nxdetector = out_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;
}
return retval;
}
int fill_data_descriptor(struct data_description_t *data_desc, struct det_visit_objects_t *visit_result) {
int retval = 0;
data_desc->det_group_id = visit_result->nxdetector;
/* determine the pixel information location */
if (H5Lexists(data_desc->det_group_id, "x_pixel_size", H5P_DEFAULT) > 0 &&
H5Lexists(data_desc->det_group_id, "y_pixel_size", H5P_DEFAULT)) {
data_desc->get_pixel_properties = &get_nxs_pixel_info;
} else if (H5Lexists(data_desc->det_group_id, "detectorSpecific", H5P_DEFAULT) > 0 &&
H5Lexists(data_desc->det_group_id, "detectorSpecifc/x_pixel_size", H5P_DEFAULT) > 0 &&
H5Lexists(data_desc->det_group_id, "detectorSpecifc/y_pixel_size", H5P_DEFAULT) > 0) {
data_desc->get_pixel_properties = &get_dectris_eiger_pixel_info;
} else {
data_desc->get_pixel_properties = NULL;
retval = -1;
}
/* determine pixel mask location */
if (H5Lexists(data_desc->det_group_id, "pixel_mask", H5P_DEFAULT) > 0) {
data_desc->get_pixel_mask = &get_nxs_pixel_mask;
} else if (H5Lexists(data_desc->det_group_id, "detectorSpecific", H5P_DEFAULT) > 0 &&
H5Lexists(data_desc->det_group_id, "detectorSpecific/pixel_mask", H5P_DEFAULT) > 0) {
data_desc->get_pixel_mask = &get_dectris_eiger_pixel_mask;
} else {
data_desc->get_pixel_mask = NULL;
retval = -1;
}
/* 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 (and possible
* failure opening it if the library version is not up to date)
*/
if (H5Lexists(visit_result->nxdetector, "data_000001", H5P_DEFAULT) > 0) {
data_desc->data_group_id = visit_result->nxdetector;
data_desc->get_data_properties = &get_dectris_eiger_dataset_dims;
data_desc->get_data_frame = &get_dectris_eiger_frame;
} else if (H5Lexists(visit_result->nxdetector, "data", H5P_DEFAULT) > 0) {
data_desc->data_group_id = visit_result->nxdetector;
data_desc->get_data_properties = &get_nxs_dataset_dims;
data_desc->get_data_frame = &get_nxs_frame;
} else if (H5Lexists(visit_result->nxdata, "data_000001", H5P_DEFAULT) > 0) {
data_desc->data_group_id = visit_result->nxdata;
data_desc->get_data_properties = &get_dectris_eiger_dataset_dims;
data_desc->get_data_frame = &get_dectris_eiger_frame;
} else if (H5Lexists(visit_result->nxdata, "data", H5P_DEFAULT) > 0) {
data_desc->data_group_id = visit_result->nxdata;
data_desc->get_data_properties = &get_nxs_dataset_dims;
data_desc->get_data_frame = &get_nxs_frame;
} else {
data_desc->data_group_id = 0;
data_desc->get_data_properties = NULL;
data_desc->get_data_frame = NULL;
retval = -1;
}
if (data_desc->get_data_properties == &get_dectris_eiger_dataset_dims) {
/* setup the "extra eiger info" struct */
struct eiger_data_description_t *eiger_desc = malloc(sizeof(*eiger_desc));
memset(eiger_desc, 0, sizeof(*eiger_desc));
if (!eiger_desc) {
retval = -1;
return retval;
}
data_desc->extra = eiger_desc;
data_desc->free_extra = free_eiger_data_description;
} else {
data_desc->free_extra = free_nxs_data_description;
}
return retval;
}
int extract_detector_info(
const hid_t fid,
struct data_description_t *data_desc,
struct dataset_properties_t *dataset_prop) {
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);
return -1;
}
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");
}
fill_data_descriptor(data_desc, &objects);
data_desc->get_data_properties(data_desc, dataset_prop);
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2018 Diamond Light Source Ltd.
* Author: Charles Mita
*/
#ifndef NXS_XDS_FILE_H
#define NXS_XDS_FILE_H
#include <hdf5.h>
struct dataset_properties_t {
int ndims;
int data_width;
hsize_t *dims;
};
void free_dataset_properties(struct dataset_properties_t *p);
struct data_description_t {
hid_t det_group_id;
hid_t data_group_id;
int (*get_pixel_properties)(const struct data_description_t*, double*, double*);
int (*get_pixel_mask)(const struct data_description_t*, int*);
int (*get_data_properties)(const struct data_description_t*, struct dataset_properties_t*);
int (*get_data_frame)(const struct data_description_t*, const struct dataset_properties_t*, int, int, void*);
void *extra;
void (*free_extra)(struct data_description_t*);
};
void free_nxs_data_description(struct data_description_t *desc);
struct eiger_data_description_t {
int n_data_blocks;
int *block_sizes;
};
void free_eiger_data_description(struct data_description_t *desc);
struct det_visit_objects_t {
hid_t nxdata;
hid_t nxdetector;
};
void clear_det_visit_objects(struct det_visit_objects_t *objects);
int get_nxs_dataset_dims(const struct data_description_t *desc, struct dataset_properties_t *properties);
int fill_data_descriptor(struct data_description_t *data_desc, struct det_visit_objects_t *visit_result);
int extract_detector_info(const hid_t fid, struct data_description_t *data_desc, struct dataset_properties_t *ds_prop);
#endif /* NXS_XDS_FILE_H */
+138
View File
@@ -0,0 +1,138 @@
/*
* Copyright (c) 2018 Diamond Light Source Ltd.
* Author: Charles Mita
*/
#include <hdf5.h>
#include <stdlib.h>
#include "file.h"
#include "plugin.h"
static hid_t file_id = 0;
static struct data_description_t data_desc = {0};
static struct dataset_properties_t ds_prop = {0};
static int *mask_buffer = NULL;
void apply_mask(int *data, int *mask, int size) {
int *dptr, *mptr;
dptr = data;
mptr = mask;
while (dptr < data + size && mptr < mask + size) {
/* mask bits loosely based on what Neggia does and what NeXus says should be done */
/* basically - anything in the low byte (& 0xFF) means "ignore this" */
if (*mptr & 0x01) *dptr = -1;
if (*mptr & 0xFE) *dptr = -2;
dptr++;
mptr++;
}
}
#ifdef __cplusplus
extern "C" {
#endif
void plugin_open(
const char *filename,
int info[1024],
int *error_flag) {
int err = 0;
info[0] = DLS_CUSTOMER_ID;
info[1] = VERSION_MAJOR;
info[2] = VERSION_MINOR;
info[3] = VERSION_PATCH;
info[4] = VERSION_TIMESTAMP;
file_id = H5Fopen(filename, H5F_ACC_RDONLY, H5P_DEFAULT);
if (file_id < 0) {
/* TODO: backtrace */
*error_flag = -4;
return;
}
err = extract_detector_info(file_id, &data_desc, &ds_prop);
if (err < 0) {
*error_flag = -4;
return;
}
mask_buffer = malloc(ds_prop.dims[1] * ds_prop.dims[2] * sizeof(int));
if (mask_buffer) {
err = data_desc.get_pixel_mask(&data_desc, mask_buffer);
if (err < 0) {
fprintf(stderr, "WARNING: Could not read pixel mask - no masking will be applied\n");
free(mask_buffer);
mask_buffer = NULL;
}
}
*error_flag = 0;
}
void plugin_get_header(
int *nx, int *ny,
int *nbytes,
float *qx, float *qy,
int *number_of_frames,
int info[1024],
int *error_flag) {
int err = 0;
double x_pixel_size, y_pixel_size;
err = data_desc.get_pixel_properties(&data_desc, &x_pixel_size, &y_pixel_size);
if (err < 0) {
*error_flag = -4;
return;
}
*nx = ds_prop.dims[2];
*ny = ds_prop.dims[1];
*nbytes = ds_prop.dims[1] * ds_prop.dims[2] * ds_prop.data_width;
*number_of_frames = ds_prop.dims[0];
*qx = (float) x_pixel_size;
*qy = (float) y_pixel_size;
*error_flag = 0;
}
void plugin_get_data(
int *frame_number,
int *nx, int *ny,
int *data_array,
int info[1024],
int *error_flag) {
int err = 0;
err = data_desc.get_data_frame(&data_desc, &ds_prop, *frame_number, sizeof(int), data_array);
if (err < 0) {
*error_flag = -2;
return;
}
if (mask_buffer) {
apply_mask(data_array, mask_buffer, ds_prop.dims[1] * ds_prop.dims[2]);
}
*error_flag = 0;
return;
}
void plugin_close(int *error_flag) {
if (file_id) {
herr_t err = H5Fclose(file_id);
if (err) {
/* TODO: backtrace */
*error_flag = -1;
}
}
file_id = 0;
if (mask_buffer) free(mask_buffer);
if (data_desc.free_extra) data_desc.free_extra(&data_desc);
free_dataset_properties(&ds_prop);
}
#ifdef __cplusplus
} /* extern "C" */
#endif
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2018 Diamond Light Source Ltd.
* Author: Charles Mita
*/
/*
* External library interface for XDS.
* Ref: https://strucbio.biologie.uni-konstanz.de/xdswiki/index.php/LIB
*/
#ifndef NXS_XDS_PLUGIN_H
#define NXS_XDS_PLUGIN_H
#ifdef __cplusplus
extern "C" {
#endif
#define DLS_CUSTOMER_ID 0x01 /* pretend we're Dectris, otherwise XDS doesn't work */
#define VERSION_MAJOR 0
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define VERSION_TIMESTAMP -1 /* good enough for Dectris apparantely */
void plugin_open(
const char *filename,
int info[1024],
int *error_flag);
void plugin_get_header(
int *nx, int *ny,
int *nbytes,
float *qx, float *qy,
int *number_of_frames,
int info[1024],
int *error_flag);
void plugin_get_data(
int *frame_number,
int *nx, int *ny,
int *data_array,
int info[1024],
int *error_flag);
void plugin_close(int *error_flag);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* NXS_XDS_PLUGIN_H */