|
*Chnage first 5 includes from "" to open and close tags* |
|
#include "stdlib.h" |
|
#include "stdio.h" |
|
#include "string.h" |
|
#include "hdf5.h" |
|
#include "hdf5_hl.h" |
|
|
|
#include "common.h" |
|
#include "hdf5_data.h" |
|
#include "metadata/simulation.h" |
|
#include "metadata/simulation_list.h" |
|
|
|
enum FileIntent |
|
{ |
|
READING, |
|
WRITING, |
|
NEITHER |
|
}; |
|
|
|
struct HDF5Data |
|
{ |
|
hid_t file; |
|
hid_t group; |
|
int ptCreated; |
|
hid_t pt; |
|
enum FileIntent intent; |
|
}; |
|
|
|
/* Iterator function for pulling out existing simulation data. |
|
* Currently assumes we are only dealing with our own files but could be |
|
* made smarter to find only groups that contain the required dataspace's. |
|
*/ |
|
static herr_t |
|
rootIterator(hid_t group,const char *name,void *_iter) |
|
{ |
|
struct SimulationList* list = (struct SimulationList*)_iter; |
|
if (list) |
|
{ |
|
struct Simulation* s = CreateSimulation(); |
|
simulationSetName(s,name); |
|
simulationListAppend(list,s); |
|
DestroySimulation(&s); |
|
return(0); |
|
} |
|
return(-1); |
|
} |
|
|
|
struct HDF5Data* CreateHDF5Data() |
|
{ |
|
struct HDF5Data* hdf5 = (struct HDF5Data*)malloc(sizeof(struct HDF5Data)); |
|
if (hdf5) |
|
{ |
|
hdf5->file = (hid_t)NULL; |
|
hdf5->group = (hid_t)NULL; |
|
hdf5->pt = (hid_t)NULL; |
|
hdf5->ptCreated = 0; |
|
hdf5->intent = NEITHER; |
|
} |
|
return(hdf5); |
|
} |
|
|
|
int DestroyHDF5Data(struct HDF5Data** hdf5) |
|
{ |
|
int code = ERR; |
|
struct HDF5Data* h5 = *hdf5; |
|
if (h5) |
|
{ |
|
if (h5->ptCreated) H5PTclose(h5->pt); |
|
if (h5->group > 0) H5Gclose(h5->group); |
|
if (h5->file > 0) H5Fclose(h5->file); |
|
free(h5); |
|
code = OK; |
|
} |
|
*hdf5 = (struct HDF5Data*)NULL; |
|
return(code); |
|
} |
|
|
|
int hdf5DataOpenFileForWriting(struct HDF5Data* hdf5,const char* filename) |
|
{ |
|
/* Open the hdf5 file for writing. */ |
|
int code = ERR; |
|
if (hdf5) |
|
{ |
|
hdf5->file = |
|
H5Fcreate(filename,H5F_ACC_TRUNC,H5P_DEFAULT,H5P_DEFAULT); |
|
if (hdf5->file < 0) code = ERR; |
|
else |
|
{ |
|
hdf5->intent = WRITING; |
|
code = OK; |
|
} |
|
} |
|
return(code); |
|
} |
|
|
|
int hdf5DataOpenFileForReading(struct HDF5Data* hdf5,const char* filename) |
|
{ |
|
/* Open the hdf5 file for writing. */ |
|
int code = ERR; |
|
if (hdf5) |
|
{ |
|
hdf5->file = H5Fopen(filename,H5F_ACC_RDONLY,H5P_DEFAULT); |
|
if (hdf5->file < 0) code = ERR; |
|
else |
|
{ |
|
hdf5->intent = READING; |
|
code = OK; |
|
} |
|
} |
|
return(code); |
|
} |
|
|
|
int hdf5DataSetGroup(struct HDF5Data* hdf5,const char* groupName) |
|
{ |
|
int code = ERR; |
|
if (hdf5 && (hdf5->file > 0)) |
|
{ |
|
if (hdf5->group > 0) H5Gclose(hdf5->group); |
|
if (hdf5->ptCreated) H5PTclose(hdf5->pt); |
|
hdf5->ptCreated = 0; |
|
if (groupName) |
|
{ |
|
if (hdf5->intent == WRITING) hdf5->group = |
|
H5Gcreate(hdf5->file,groupName,/*size_hint*/0); |
|
else hdf5->group = H5Gopen(hdf5->file,groupName); |
|
} |
|
code = OK; |
|
} |
|
return(code); |
|
} |
|
|
|
int hdf5WriteSimulationModelURI(struct HDF5Data* hdf5,const char* uri) |
|
{ |
|
herr_t status; |
|
hid_t datatype,dataspace,dataset; |
|
hsize_t dim[1]; |
|
|
|
if ((hdf5 == NULL) || (hdf5->intent != WRITING)) |
|
{ |
|
fprintf(stderr,"Attempting to write to a reading file.\n"); |
|
return(ERR); |
|
} |
|
if (hdf5->group <= 0) |
|
{ |
|
fprintf(stderr,"Missing HDF5 group.\n"); |
|
return(ERR); |
|
} |
|
if (uri == NULL) |
|
{ |
|
fprintf(stderr,"Attempting to write invalid URI to data file.\n"); |
|
return(ERR); |
|
} |
|
if (strlen(uri) > HDF5_STRING_LENGTH-1) |
|
{ |
|
fprintf(stderr, |
|
"URI too long - fix the hdf5WriteSimulationModelURI code.\n"); |
|
return(ERR); |
|
} |
|
char* localURI = (char*)calloc(HDF5_STRING_LENGTH,1); |
|
strcpy(localURI,uri); |
|
/* Make a string data type */ |
|
datatype = H5Tcopy(H5T_C_S1); |
|
/* set the fixed string length */ |
|
status = H5Tset_size(datatype,HDF5_STRING_LENGTH); |
|
/* and we're gonna use C-like null-terminated string */ |
|
status = H5Tset_strpad(datatype,H5T_STR_NULLTERM); |
|
/* Create a simple memory space of the correct size */ |
|
dim[0] = 1; |
|
dataspace = H5Screate_simple(1,dim,NULL); |
|
/* and create the dataset to write to */ |
|
dataset = H5Dcreate(hdf5->group,SIMULATION_MODEL_URI_NAME,datatype, |
|
dataspace,H5P_DEFAULT); |
|
/* Write the URI to the file */ |
|
status = H5Dwrite(dataset,datatype,H5S_ALL,H5S_ALL,H5P_DEFAULT,localURI); |
|
/* clean up */ |
|
H5Dclose(dataset); |
|
H5Sclose(dataspace); |
|
H5Tclose(datatype); |
|
/*H5Fflush(hdf5->file,H5F_SCOPE_GLOBAL);*/ |
|
free(localURI); |
|
return(OK); |
|
} |
|
|
|
int hdf5WriteFieldHeader(struct HDF5Data* hdf5,int N,char* names) |
|
{ |
|
herr_t status; |
|
hid_t datatype,dataspace,dataset; |
|
hsize_t dim[1]; |
|
|
|
if ((hdf5 == NULL) || (hdf5->intent != WRITING)) |
|
{ |
|
fprintf(stderr,"Attempting to write to a reading file.\n"); |
|
return(ERR); |
|
} |
|
if (hdf5->group <= 0) |
|
{ |
|
fprintf(stderr,"Missing HDF5 group.\n"); |
|
return(ERR); |
|
} |
|
/* Make a string data type */ |
|
datatype = H5Tcopy(H5T_C_S1); |
|
/* set the fixed string length */ |
|
status = H5Tset_size(datatype,HDF5_STRING_LENGTH); |
|
/* and we're gonna use C-like null-terminated strings */ |
|
status = H5Tset_strpad(datatype,H5T_STR_NULLTERM); |
|
/* Create a simple memory space of the correct size */ |
|
dim[0] = N; |
|
dataspace = H5Screate_simple(1,dim,NULL); |
|
/* and create the dataset to write to */ |
|
dataset = H5Dcreate(hdf5->group,FIELD_HEADER_DATA_NAME,datatype, |
|
dataspace,H5P_DEFAULT); |
|
/* Write the field names to the file */ |
|
status = H5Dwrite(dataset,datatype,H5S_ALL,H5S_ALL,H5P_DEFAULT,names); |
|
/* clean up */ |
|
H5Dclose(dataset); |
|
H5Sclose(dataspace); |
|
H5Tclose(datatype); |
|
/*H5Fflush(hdf5->file,H5F_SCOPE_GLOBAL);*/ |
|
return(OK); |
|
} |
|
|
|
int hdf5WriteData(struct HDF5Data* hdf5,int N,double* data) |
|
{ |
|
herr_t status = 0; |
|
|
|
if ((hdf5 == NULL) || (hdf5->intent != WRITING)) |
|
{ |
|
fprintf(stderr,"Attempting to write to a reading file.\n"); |
|
return(ERR); |
|
} |
|
if (hdf5->group <= 0) |
|
{ |
|
fprintf(stderr,"Missing HDF5 group.\n"); |
|
return(ERR); |
|
} |
|
if (!hdf5->ptCreated) |
|
{ |
|
/* create a fixed length packet table in the file */ |
|
hdf5->pt = H5PTcreate_fl(hdf5->group,DATA_NAME,H5T_NATIVE_DOUBLE, |
|
/*chunk size ??*/sizeof(double)*N); |
|
hdf5->ptCreated = 1; |
|
} |
|
if (hdf5->ptCreated) |
|
{ |
|
/* Write a packet to the packet table */ |
|
status = H5PTappend(hdf5->pt,N,(void*)data); |
|
} |
|
return(OK); |
|
} |
|
|
|
char* hdf5ReadSimulationModelURI(struct HDF5Data* hdf5) |
|
{ |
|
herr_t status; |
|
hid_t datatype,dataspace,dataset; |
|
char *uri = (char*)NULL; |
|
|
|
if ((hdf5 == NULL) || (hdf5->intent != READING)) |
|
{ |
|
fprintf(stderr,"Attempting to read from a writing file.\n"); |
|
return((char*)NULL); |
|
} |
|
if (hdf5->group <= 0) |
|
{ |
|
fprintf(stderr,"Missing HDF5 group.\n"); |
|
return(ERR); |
|
} |
|
/* open the dataset */ |
|
dataset = H5Dopen(hdf5->group,SIMULATION_MODEL_URI_NAME); |
|
dataspace = H5Dget_space(dataset); |
|
/* get the data type */ |
|
datatype = H5Dget_type(dataset); |
|
/* allocate memory */ |
|
uri = (char*)malloc(HDF5_STRING_LENGTH); |
|
/* read in the data */ |
|
status = H5Dread(dataset,datatype,H5S_ALL,H5S_ALL,H5P_DEFAULT,uri); |
|
if (status < 0) |
|
{ |
|
fprintf(stderr,"Error getting the dimension of the field header.\n"); |
|
free(uri); |
|
H5Sclose(dataspace); |
|
H5Tclose(datatype); |
|
H5Dclose(dataset); |
|
return((char*)NULL); |
|
} |
|
/* clean up */ |
|
H5Sclose(dataspace); |
|
H5Tclose(datatype); |
|
H5Dclose(dataset); |
|
return(uri); |
|
} |
|
|
|
char** hdf5ReadFieldHeader(struct HDF5Data* hdf5,int* N) |
|
{ |
|
herr_t status; |
|
hid_t datatype,dataspace,dataset; |
|
hsize_t dim[1]; |
|
char *tmp,*names = (char*)NULL; |
|
char** fields = (char**)NULL; |
|
int i; |
|
|
|
if ((hdf5 == NULL) || (hdf5->intent != READING)) |
|
{ |
|
fprintf(stderr,"Attempting to read from a writing file.\n"); |
|
return((char**)NULL); |
|
} |
|
if (hdf5->group <= 0) |
|
{ |
|
fprintf(stderr,"Missing HDF5 group.\n"); |
|
return(ERR); |
|
} |
|
/* open the dataset */ |
|
dataset = H5Dopen(hdf5->group,FIELD_HEADER_DATA_NAME); |
|
dataspace = H5Dget_space(dataset); |
|
/* get the data type */ |
|
datatype = H5Dget_type(dataset); |
|
/* get the size and allocate memory */ |
|
status = H5Sget_simple_extent_dims(dataspace,dim,NULL); |
|
if (status < 0) |
|
{ |
|
fprintf(stderr,"Error getting the dimension of the field header.\n"); |
|
H5Sclose(dataspace); |
|
H5Tclose(datatype); |
|
H5Dclose(dataset); |
|
return((char**)NULL); |
|
} |
|
names = (char*)malloc(HDF5_STRING_LENGTH*dim[0]); |
|
/* read in the data */ |
|
status = H5Dread(dataset,datatype,H5S_ALL,H5S_ALL,H5P_DEFAULT,names); |
|
if (status < 0) |
|
{ |
|
fprintf(stderr,"Error getting the dimension of the field header.\n"); |
|
free(names); |
|
H5Sclose(dataspace); |
|
H5Tclose(datatype); |
|
H5Dclose(dataset); |
|
return((char**)NULL); |
|
} |
|
/* clean up */ |
|
H5Sclose(dataspace); |
|
H5Tclose(datatype); |
|
H5Dclose(dataset); |
|
/* split up the names */ |
|
fields = (char**)malloc(sizeof(char*)*dim[0]); |
|
tmp = names; |
|
for (i=0;i<dim[0];i++) |
|
{ |
|
fields[i] = (char*)malloc(strlen(tmp)+1); |
|
strcpy(fields[i],tmp); |
|
tmp += HDF5_STRING_LENGTH; |
|
} |
|
free(names); |
|
*N = dim[0]; |
|
return(fields); |
|
} |
|
|
|
double* hdf5ReadData(struct HDF5Data* hdf5,int N) |
|
{ |
|
herr_t status = 0; |
|
double* data = (double*)malloc(sizeof(double)*N); |
|
|
|
if ((hdf5 == NULL) || (hdf5->intent != READING)) |
|
{ |
|
fprintf(stderr,"Attempting to read from a writing file.\n"); |
|
return((double*)NULL); |
|
} |
|
if (hdf5->group <= 0) |
|
{ |
|
fprintf(stderr,"Missing HDF5 group.\n"); |
|
return(ERR); |
|
} |
|
if (!hdf5->ptCreated) |
|
{ |
|
/* open the packet table */ |
|
hdf5->pt = H5PTopen(hdf5->group,DATA_NAME); |
|
/* and make sure we're at the start of the table */ |
|
H5PTcreate_index(hdf5->pt); |
|
hdf5->ptCreated = 1; |
|
} |
|
if (hdf5->ptCreated) |
|
{ |
|
/* get N packets from the packet table */ |
|
status = H5PTget_next(hdf5->pt,N,(void*)data); |
|
if (status<0) |
|
{ |
|
free(data); |
|
data = (double*)NULL; |
|
} |
|
} |
|
return(data); |
|
} |
|
|
|
struct SimulationList* hdf5ReadSimulations(struct HDF5Data* hdf5) |
|
{ |
|
struct SimulationList* simulations = (struct SimulationList*)NULL; |
|
|
|
if ((hdf5 == NULL) || (hdf5->intent != READING)) |
|
{ |
|
fprintf(stderr,"Attempting to read from a writing file.\n"); |
|
return(simulations); |
|
} |
|
/* look for any groups which are children of the root group */ |
|
hid_t rootGroup = H5Gopen(hdf5->file,"/"); |
|
if (rootGroup > 0) |
|
{ |
|
simulations = CreateSimulationList(); |
|
if (H5Giterate(rootGroup,"/",NULL,rootIterator,(void*)simulations) |
|
!= 0) DestroySimulationList(&simulations); |
|
H5Gclose(rootGroup); |
|
} |
|
return(simulations); |
|
} |
Thank you Abhishek !
In the light of 3.7 years of more experience (hmm hmm) this should be marked as the correct answer instead of the one describing netCDF. As one can easily see the APIs are quite different.