Ejemplo n.º 1
0
Archivo: e5.c Proyecto: voidcycles/void
eid_t
e5_create_file(
    const char* filename)
{
    eid_t e5_file_id;
    eid_t e5_group_id;
    estatus_t status = E5_SUCCESS;

    e5_info(E5_DEFAULT, "Creating E5 file '%s'\n", filename);

    e5_file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
    if(e5_file_id < 0)
    {
        status = E5_WRITE_FAILURE;
        e5_error(e5_file_id, status, "Failed to create '%s' E5 data file\n", filename);
        return (eid_t)e5_file_id;
    }

    e5_group_id = e5_create_group(e5_file_id, E5_EMISSIVITY_GROUP_NAME_ABS);
    e5_close_group(e5_group_id);

    return (eid_t)e5_file_id;
}
Ejemplo n.º 2
0
Archivo: e5.c Proyecto: voidcycles/void
static estatus_t
e5_merge_flash_scalars(
    eid_t e5_file_id, hid_t f5_file_id,
    const char* f5_list_name, f5_scalar_list_type f5_list_type)
{
    size_t s;
    hsize_t dimens_1d;
    hsize_t maxdimens_1d;
    hid_t string_type;

    hsize_t f5_scalar_bytes;
    hid_t f5_dataspace;
    hid_t f5_memspace;
    hid_t f5_dataset;
    hid_t f5_type;
    void* f5_data;

    hid_t e5_em_group_id;
    int hstatus;
    size_t e5_scalar_bytes;

    estatus_t estatus = E5_SUCCESS;

    string_type = H5Tcopy(H5T_C_S1);
    H5Tset_size(string_type, F5_MAX_STRING_LENGTH);

    f5_dataset = H5Dopen(f5_file_id, f5_list_name);
    if (f5_dataset < 0)
    {
        estatus = E5_INVALID_DATASET;
        e5_error(f5_file_id, estatus, "Failed to open dataset '%s'\n", f5_list_name);
        return estatus;
    }

    f5_dataspace = H5Dget_space(f5_dataset);
    H5Sget_simple_extent_dims(f5_dataspace, &dimens_1d, &maxdimens_1d);

    e5_em_group_id = e5_open_group(e5_file_id, E5_EMISSIVITY_GROUP_NAME_ABS);

    switch(f5_list_type)
    {
    case F5_SCALAR_LIST_INTEGER:
    case F5_SCALAR_LIST_LOGICAL:
    {
        hid_t f5_int_list_type;
        f5_int_list_t *f5_int_list;

        f5_scalar_bytes = dimens_1d * sizeof(f5_int_list_t);
        f5_int_list = (f5_int_list_t *) e5_malloc(f5_scalar_bytes);
        if(!f5_int_list)
        {
            estatus = E5_OUT_OF_MEMORY;
            e5_error(f5_file_id, estatus, "Failed to allocate memory for reading '%s' from F5 data file\n", f5_list_name);
            break;
        }

        memset(f5_int_list, 0, f5_scalar_bytes);
        f5_int_list_type = H5Tcreate(H5T_COMPOUND, sizeof(f5_int_list_t));
        H5Tinsert(f5_int_list_type, "name",  HOFFSET(f5_int_list_t, name), string_type);
        H5Tinsert(f5_int_list_type, "value", HOFFSET(f5_int_list_t, value), H5T_NATIVE_INT);

        f5_memspace = H5Screate_simple(1, &dimens_1d, NULL);
        hstatus = H5Dread(f5_dataset, f5_int_list_type, f5_memspace, f5_dataspace, H5P_DEFAULT, f5_int_list);
        if (hstatus < 0)
        {
            estatus = E5_READ_FAILURE;
            e5_error(f5_file_id, estatus, "Failed to read '%s' dataset from data file\n", f5_list_name);
            break;
        }
        f5_data = f5_int_list;
        f5_type = f5_int_list_type;

        if(f5_data)
        {
            // Add the scalar list as attributes for the top-level Emissivity group
            e5_scalar_bytes = (dimens_1d + 1) * sizeof(e5_mutable_attr_int);
            e5_mutable_attr_int* e5_int_scalars = (e5_mutable_attr_int*) e5_malloc(e5_scalar_bytes);
            memset(e5_int_scalars, 0, e5_scalar_bytes);
            for(s = 0; s < dimens_1d; s++)
            {
                e5_int_scalars[s].value = f5_int_list[s].value;
                e5_int_scalars[s].name = e5_trim(f5_int_list[s].name, E5_TRUE, E5_TRUE, F5_MAX_STRING_LENGTH);
            }
            e5_write_attr_list_int(e5_em_group_id, (e5_attr_int*)e5_int_scalars);
            e5_free(e5_int_scalars);
        }
        break;
    }
    case F5_SCALAR_LIST_REAL:
    {
        hid_t f5_real_list_type;
        f5_real_list_t *f5_real_list;

        f5_scalar_bytes = dimens_1d * sizeof(f5_real_list_t);
        f5_real_list = (f5_real_list_t *) e5_malloc(f5_scalar_bytes);
        if(!f5_real_list)
        {
            estatus = E5_OUT_OF_MEMORY;
            e5_error(f5_file_id, estatus, "Failed to allocate memory for reading '%s' from F5 data file\n", f5_list_name);
            break;
        }

        memset(f5_real_list, 0, f5_scalar_bytes);
        f5_real_list_type = H5Tcreate(H5T_COMPOUND, sizeof(f5_real_list_t));
        H5Tinsert(f5_real_list_type, "name",  HOFFSET(f5_real_list_t, name), string_type);
        H5Tinsert(f5_real_list_type, "value", HOFFSET(f5_real_list_t, value), H5T_NATIVE_DOUBLE);

        f5_memspace = H5Screate_simple(1, &dimens_1d, NULL);
        hstatus = H5Dread(f5_dataset, f5_real_list_type, f5_memspace, f5_dataspace, H5P_DEFAULT, f5_real_list);
        if (hstatus < 0)
        {
            estatus = E5_READ_FAILURE;
            e5_error(f5_file_id, estatus, "Failed to read '%s' from F5 data file\n", f5_list_name);
            break;
        }

        f5_data = f5_real_list;
        f5_type = f5_real_list_type;

        if(f5_data)
        {
            // Add the scalar list as attributes for the top-level Emissivity group
            e5_scalar_bytes = (dimens_1d + 1) * sizeof(e5_mutable_attr_double);
            e5_mutable_attr_double* e5_double_scalars = (e5_mutable_attr_double*) e5_malloc(e5_scalar_bytes);
            memset(e5_double_scalars, 0, e5_scalar_bytes);

            for(s = 0; s < dimens_1d; s++)
            {
                e5_double_scalars[s].value = f5_real_list[s].value;
                e5_double_scalars[s].name = f5_real_list[s].name;
                e5_double_scalars[s].name = e5_trim(f5_real_list[s].name, E5_TRUE, E5_TRUE, F5_MAX_STRING_LENGTH);
            }

            e5_write_attr_list_double(e5_em_group_id, (e5_attr_double*)e5_double_scalars);
            e5_free(e5_double_scalars);
        }
        break;
    }
    case F5_SCALAR_LIST_STRING:
    {
        hid_t f5_str_list_type;
        f5_str_list_t *f5_str_list;

        f5_scalar_bytes = dimens_1d * sizeof(f5_str_list_t);
        f5_str_list = (f5_str_list_t *) e5_malloc(f5_scalar_bytes);
        if(!f5_str_list)
        {
            estatus = E5_OUT_OF_MEMORY;
            e5_error(f5_file_id, estatus, "Failed to allocate memory for reading '%s' from F5 data file\n", f5_list_name);
            break;
        }

        memset(f5_str_list, 0, f5_scalar_bytes);
        f5_str_list_type = H5Tcreate(H5T_COMPOUND, sizeof(f5_str_list_t));
        H5Tinsert(f5_str_list_type, "name",  HOFFSET(f5_str_list_t, name), string_type);
        H5Tinsert(f5_str_list_type, "value", HOFFSET(f5_str_list_t, value), string_type);

        f5_memspace = H5Screate_simple(1, &dimens_1d, NULL);
        hstatus = H5Dread(f5_dataset, f5_str_list_type, f5_memspace, f5_dataspace, H5P_DEFAULT, f5_str_list);
        if (hstatus < 0)
        {
            estatus = E5_READ_FAILURE;
            e5_error(f5_file_id, estatus, "Failed to read '%s' from F5 data file\n", f5_list_name);
            break;
        }

        f5_data = f5_str_list;
        f5_type = f5_str_list_type;

        if(f5_data)
        {
            // Add the scalar list as attributes for the top-level Emissivity group
            e5_scalar_bytes = (dimens_1d + 1) * sizeof(e5_mutable_attr_str);
            e5_mutable_attr_str* e5_str_scalars = (e5_mutable_attr_str*) e5_malloc(e5_scalar_bytes);
            memset(e5_str_scalars, 0, e5_scalar_bytes);

            for(s = 0; s < dimens_1d; s++)
            {
                char* trimmed = e5_trim(f5_str_list[s].value, E5_TRUE, E5_TRUE, E5_MAX_ATTR_STRING_LENGTH);
                strncpy( e5_str_scalars[s].value, trimmed, E5_MAX_ATTR_STRING_LENGTH);
                e5_str_scalars[s].name = e5_trim(f5_str_list[s].name, E5_TRUE, E5_TRUE, F5_MAX_STRING_LENGTH);
            }

            e5_write_attr_list_str(e5_em_group_id, (e5_attr_str*)e5_str_scalars);
            e5_free(e5_str_scalars);
        }
        break;
    }
    default:
    {
        estatus = E5_INVALID_DATASET;
        e5_error(f5_file_id, estatus, "Unknown scalar list requested '%s' from F5 data file\n", f5_list_name);
        break;
    }
    };

    H5Tclose(f5_type);
    H5Sclose(f5_memspace);
    H5Sclose(f5_dataspace);
    H5Dclose(f5_dataset);

    e5_free(f5_data);
    e5_close_group(e5_em_group_id);

    return estatus;
}
Ejemplo n.º 3
0
Archivo: e5.c Proyecto: voidcycles/void
estatus_t
e5_read_data_info_list(
    eid_t e5_group_id, const char* list_name, e5_data_info* info_list)
{
    int i;
    int d;
    int log_scale;
    int close_group;
    estatus_t status;

    hsize_t h5_min_dim[3];
    hsize_t h5_max_dim[3];

    eid_t e5_list_group_id;
    eid_t e5_type_id;
    eid_t e5_dataset_id;
    eid_t e5_dataspace_id;

    status = E5_SUCCESS;

    if(list_name && strlen(list_name))
    {
        e5_list_group_id = e5_create_group(e5_group_id, list_name);
        close_group = 1;
    }
    else
    {
        e5_list_group_id = e5_group_id;
        close_group = 0;
    }

    for(i = 0; info_list && info_list[i].name != 0; i++)
    {
        e5_data_info* info = &info_list[i];

        e5_dataset_id = H5Dopen(e5_list_group_id, info->name);
        if (e5_dataset_id < 0)
        {
            status = E5_INVALID_DATASET;
            e5_error(e5_list_group_id, status, "Failed to open info for dataset '%s'\n",  info->name);
            return status;
        }

        e5_dataspace_id = H5Dget_space(e5_dataset_id);
        e5_type_id = H5Dget_type(e5_dataset_id);
        H5Sget_simple_extent_dims(e5_dataspace_id, h5_min_dim, h5_max_dim);

        info->type = e5_convert_hdf_type(e5_type_id);

        for(d = 0; d < 3; d++)
        {
            info->dim[d] = h5_min_dim[d] >= h5_max_dim[d] ? h5_min_dim[d] : h5_max_dim[d];
            info->dim[d] = info->dim[d] < 1 ? 1 : info->dim[d];
        }

        log_scale = 0;
        if(e5_is_valid_attr(e5_group_id, "log10"))
            e5_read_attr_int(e5_dataset_id, "log10", &log_scale);
        info->scale = log_scale ? E5_VALUE_SCALE_LOG10 : E5_VALUE_SCALE_LINEAR;

        e5_info(e5_group_id, "Read data info [type='%s', name='%s', dim='%u %u %u']\n",
                e5_typename(info->type), info->name, info->dim[0], info->dim[1], info->dim[2]);

        H5Sclose(e5_dataspace_id);
        H5Dclose(e5_dataset_id);
        H5Tclose(e5_type_id);
    }

    if(close_group)
        e5_close_group(e5_list_group_id);

    return E5_SUCCESS;
}
Ejemplo n.º 4
0
Archivo: e5.c Proyecto: voidcycles/void
estatus_t
e5_write_grid_list(
    eid_t e5_group_id, const char* list_name, e5_grid_dataset* grid_list)
{
    int i;
    int close_group;
    estatus_t status;

    eid_t e5_list_group_id;
    eid_t e5_dataset_id;
    eid_t e5_dataspace_id;

    status = E5_SUCCESS;

    if(list_name && strlen(list_name))
    {
        e5_list_group_id = e5_create_group(e5_group_id, list_name);
        close_group = 1;
    }
    else
    {
        e5_list_group_id = e5_group_id;
        close_group = 0;
    }

    for(i = 0; grid_list && grid_list[i].name != 0 && strlen(grid_list[i].name); i++)
    {
        e5_grid_dataset* grid = &grid_list[i];
        e5_dataspace_id = H5Screate_simple(3, (hsize_t*)(grid->dim), NULL);

        switch(grid->type)
        {
        case E5_TYPE_INT:
        {
            e5_info(e5_group_id, "Writing grid [type='int', name='%s', dim='%u %u %u']\n",
                    grid->name, grid->dim[0], grid->dim[1], grid->dim[2]);

            e5_dataset_id = H5Dcreate(e5_list_group_id, grid->name, H5T_STD_I32LE, e5_dataspace_id, H5P_DEFAULT);
            status = H5Dwrite(e5_dataset_id, H5T_NATIVE_INT, H5S_ALL, e5_dataspace_id, H5P_DEFAULT, grid->data);
            if(status < 0)
            {
                status = E5_WRITE_FAILURE;
                e5_error(e5_dataset_id, status, "Failed to write '%s' E5 grid to file\n", grid->name);
            }
            break;
        }
        case E5_TYPE_FLOAT:
        {
            e5_info(e5_group_id, "Writing grid [type='float', name='%s', dim='%u %u %u']\n",
                    grid->name, grid->dim[0], grid->dim[1], grid->dim[2]);

            e5_dataset_id = H5Dcreate(e5_list_group_id, grid->name, H5T_IEEE_F32LE, e5_dataspace_id, H5P_DEFAULT);
            status = H5Dwrite(e5_dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, e5_dataspace_id, H5P_DEFAULT, grid->data);
            if(status < 0)
            {
                status = E5_WRITE_FAILURE;
                e5_error(e5_dataset_id, status, "Failed to write '%s' E5 grid to file\n", grid->name);
            }
            break;
        }
        case E5_TYPE_DOUBLE:
        {
            e5_info(e5_group_id, "Writing grid [type='float', name='%s', dim='%u %u %u']\n",
                    grid->name, grid->dim[0], grid->dim[1], grid->dim[2]);

            e5_dataset_id = H5Dcreate(e5_list_group_id, grid->name, H5T_IEEE_F64LE, e5_dataspace_id, H5P_DEFAULT);
            status = H5Dwrite(e5_dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, e5_dataspace_id, H5P_DEFAULT, grid->data);
            if(status < 0)
            {
                status = E5_WRITE_FAILURE;
                e5_error(e5_dataset_id, status, "Failed to write '%s' E5 grid to file\n", grid->name);
            }
            break;
        }
        case E5_TYPE_INVALID:
        default:
        {
            status = E5_INVALID_TYPE;
            e5_error(e5_dataset_id, status, "Invalid type for grid '%s' data\n", grid->name);
        }
        break;
        };

        if(grid->scale == E5_VALUE_SCALE_LOG10)
            e5_write_attr_int(e5_dataset_id, "log10", 1);

        H5Sclose(e5_dataspace_id);
        H5Dclose(e5_dataset_id);
    }

    if(close_group)
        e5_close_group(e5_list_group_id);

    return E5_SUCCESS;
}
Ejemplo n.º 5
0
Archivo: e5.c Proyecto: voidcycles/void
estatus_t
e5_read_grid_list(
    eid_t e5_group_id, const char* list_name, e5_grid_dataset* grid_list)
{
    int i;
    int d;
    int log_scale;
    int close_group;

    hsize_t h5_max_dim[3];
    hsize_t h5_min_dim[3];

    eid_t e5_list_group_id;
    eid_t e5_type_id;
    eid_t e5_dataset_id;
    eid_t e5_dataspace_id;
    eid_t e5_memspace_id;

    hid_t h5_status;

    estatus_t e5_status = E5_SUCCESS;

    if(list_name && strlen(list_name))
    {
        e5_list_group_id = e5_create_group(e5_group_id, list_name);
        close_group = 1;
    }
    else
    {
        e5_list_group_id = e5_group_id;
        close_group = 0;
    }

    for(i = 0; grid_list && grid_list[i].name != 0; i++)
    {
        e5_grid_dataset* grid = &grid_list[i];
        if(grid->name == 0 || strlen(grid->name) < 1)
            continue;

        e5_dataset_id = H5Dopen(e5_list_group_id, grid->name);
        if (e5_dataset_id < 0)
        {
            e5_status = E5_INVALID_DATASET;
            e5_error(e5_list_group_id, e5_status, "Failed to open grid dataset '%s'\n",  grid->name);
            return e5_status;
        }

        if(!grid->data)
        {
            e5_status = E5_INVALID_POINTER;
            e5_error(e5_dataspace_id, e5_status, "Failed to provide pointer for reading '%s' from E5 data file\n", grid->name);
            break;
        }

        e5_dataspace_id = H5Dget_space(e5_dataset_id);
        e5_type_id = H5Dget_type(e5_dataset_id);
        H5Sget_simple_extent_dims(e5_dataspace_id, h5_min_dim, h5_max_dim);

        for(d = 0; d < 3; d++)
        {
            grid->dim[d] = h5_min_dim[d] >= h5_max_dim[d] ? h5_min_dim[d] : h5_max_dim[d];
            grid->dim[d] = grid->dim[d] < 1 ? 1 : grid->dim[d];
        }

        grid->type = e5_convert_hdf_type(e5_type_id);

        switch(grid->type)
        {
        case E5_TYPE_FLOAT:
        {
            e5_info(e5_group_id, "Reading grid [type='float', name='%s', dim='%u %u %u']\n",
                    grid->name, grid->dim[0], grid->dim[1], grid->dim[2]);

            e5_memspace_id = H5Screate_simple(3, h5_min_dim, h5_max_dim);
            h5_status = H5Dread(e5_dataset_id, H5T_NATIVE_FLOAT, e5_memspace_id, e5_dataspace_id, H5P_DEFAULT, (grid->data));
            if (h5_status < 0)
            {
                e5_status = E5_READ_FAILURE;
                e5_error(e5_dataset_id, e5_status, "Failed to read '%s' from F5 data file\n", grid->name);
            }
            H5Sclose(e5_memspace_id);
            break;
        }
        case E5_TYPE_DOUBLE:
        {
            e5_info(e5_group_id, "Reading grid [type='double', name='%s', dim='%u %u %u']\n",
                    grid->name, grid->dim[0], grid->dim[1], grid->dim[2]);

            e5_memspace_id = H5Screate_simple(3, h5_min_dim, h5_max_dim);
            h5_status = H5Dread(e5_dataset_id, H5T_NATIVE_DOUBLE, e5_memspace_id, e5_dataspace_id, H5P_DEFAULT, (grid->data));
            if (h5_status < 0)
            {
                e5_status = E5_READ_FAILURE;
                e5_error(e5_dataset_id, e5_status, "Failed to read '%s' from F5 data file\n", grid->name);
            }
            H5Sclose(e5_memspace_id);
            break;
        }
        case E5_TYPE_INVALID:
        default:
        {
            e5_status = E5_INVALID_TYPE;
            e5_error(e5_dataset_id, e5_status, "Invalid type for grid '%s' data\n", grid->name);
            break;
        }
        };

        log_scale = 0;
        if(e5_is_valid_attr(e5_dataset_id, "log10"))
            e5_read_attr_int(e5_dataset_id, "log10", &log_scale);
        grid->scale = log_scale ? E5_VALUE_SCALE_LOG10 : E5_VALUE_SCALE_LINEAR;

        H5Sclose(e5_dataspace_id);
        H5Dclose(e5_dataset_id);
        H5Tclose(e5_type_id);
    }

    if(list_name)
        e5_close_group(e5_list_group_id);

    return e5_status;
}
Ejemplo n.º 6
0
int
main(int argc, char** argv)
{
    eid_t e5_file_id;
    eid_t e5_group_id;
    estatus_t status;
    
    /* Parse the command line options
     */
    options_t options = {0};
    ParseOptions(&options, argc, argv);

    /* Open the E5 file and main group
     */
    e5_set_notify_func(E5_DEFAULT, notify_func, E5_NOTIFY_LEVEL_MIN, E5_NOTIFY_LEVEL_MAX);
    e5_file_id = e5_open_file(options.filename);

    /* Read the grid dimensionality and type info
     */
    if(options.type == OPT_GRID)
    {
        e5_grid_dataset grid = { 0 };
        grid.name = options.location;
        status = e5_read_data_info(e5_file_id, grid.name, grid.dim, &grid.type, &grid.scale);
        E5_EXIT_ON_ERROR(status);
        
        /* Allocate memory and read the grid data
         */
        grid.data = malloc(e5_sizeof(grid.type) * grid.dim[0] * grid.dim[1] * grid.dim[2]);
        status = e5_read_grid(e5_file_id, grid.name, grid.data, grid.dim, &grid.type, &grid.scale);
        E5_EXIT_ON_ERROR(status);
        
        e5_dump_grid(&grid);
        free(grid.data);
    }
    else if (options.type == OPT_ATTR)
    {
        int* data = malloc(sizeof(int));

        const char* base_name = e5_basename(options.location);
        size_t offset = base_name - options.location;
        char* group_name = malloc(offset + 2);
        snprintf(group_name, offset, "%s", options.location);
    
        e5_group_id = e5_open_group(e5_file_id, group_name);           
        e5_attr attr[] = { {base_name, data, E5_TYPE_INT, 0}, {0} };
        status = e5_read_attr_list(e5_group_id, attr);
        E5_EXIT_ON_ERROR(status);
        
        printf("ATTR: '%s' -> '%d'\n", options.location, *data);

        free(data);
        free(group_name);
        e5_close_group(e5_group_id);
    }

    /* Close the group and the file 
     */
    status = e5_close_file(e5_file_id);
    E5_EXIT_ON_ERROR(status);
    
    /* Free the command line options
     */
    free(options.filename);
    free(options.location);
    return 0;
}
Ejemplo n.º 7
0
static void
e5_export_bov(
    const char* bov_file, 
    eid_t e5_file_id, 
    e5_grid_dataset* grid)
{
    static const int min_bricklet = 1;
    static const int max_bricklet = 32;
    
    int i;
    int d;
    
    bov_header_t header;
    e5_bov_attrs_t attrs;
    
    memset(&header, 0, sizeof(bov_header_t));
    memset(&attrs, 0, sizeof(e5_bov_attrs_t));
    
    size_t len = strlen(bov_file) + 8;
    char *data_file = malloc(len);
    snprintf(data_file, len, "%s.data", e5_basename(bov_file));
    
    eid_t e5_group_id = e5_open_group(e5_file_id, "/Emissivity/real scalars");           
    e5_attr real_scalars_attr[] = { {"time", &(attrs.time), E5_TYPE_DOUBLE, 0}, {0} };
    estatus_t status = e5_read_attr_list(e5_group_id, real_scalars_attr);
    E5_EXIT_ON_ERROR(status);
    e5_close_group(e5_group_id);
    
    e5_group_id = e5_open_group(e5_file_id, "/Emissivity/real runtime parameters");           
    e5_attr real_param_attr[] = { 
        {"xmin", &(attrs.xmin), E5_TYPE_DOUBLE, 0}, 
        {"xmax", &(attrs.xmax), E5_TYPE_DOUBLE, 0}, 
        {"ymin", &(attrs.ymin), E5_TYPE_DOUBLE, 0}, 
        {"ymax", &(attrs.ymax), E5_TYPE_DOUBLE, 0}, 
        {"zmin", &(attrs.zmin), E5_TYPE_DOUBLE, 0}, 
        {"zmax", &(attrs.zmax), E5_TYPE_DOUBLE, 0}, 
        {0} 
    };
    
    status = e5_read_attr_list(e5_group_id, real_param_attr);
    E5_EXIT_ON_ERROR(status);
    e5_close_group(e5_group_id);
    
    header.variable = grid->name;
    header.time = (float)attrs.time;
    header.data_file = data_file;
    header.data_size[0] = (int)grid->dim[0];
    header.data_size[1] = (int)grid->dim[1];
    header.data_size[2] = (int)grid->dim[2];
    header.centering = "zonal";
    header.data_components = 1;
    header.brick_origin[0] = (attrs.xmax + attrs.xmin) * 0.5;
    header.brick_origin[1] = (attrs.ymax + attrs.ymin) * 0.5;
    header.brick_origin[2] = (attrs.zmax + attrs.zmin) * 0.5;
    header.brick_size[0] = attrs.xmax - attrs.xmin;
    header.brick_size[1] = attrs.ymax - attrs.ymin;
    header.brick_size[2] = attrs.zmax - attrs.zmin;
    
    for(i=min_bricklet; i <= max_bricklet; i++)
    {
        for(d=0; d<3; d++)
            header.data_bricklets[d] = ((header.data_size[d] % i) == 0) ? i : header.data_bricklets[d];
    }

    if(grid->type == E5_TYPE_FLOAT)
        header.data_format = "FLOAT";
    else if(grid->type == E5_TYPE_DOUBLE)
        header.data_format = "DOUBLE";
    else if(grid->type == E5_TYPE_INT)
        header.data_format = "INT";        
        
    FILE* fd = CreateTextFile(bov_file); 
    if(!fd)
    {
        printf("Failed to create BOV header file '%s'! Exiting...\n", bov_file);
        exit(EXIT_FAILURE);
    }

    printf("Writing header to '%s'...\n", bov_file);
    fprintf(fd, "TIME: %f\n", header.time);
    fprintf(fd, "DATA_FILE: %s\n", header.data_file);
    fprintf(fd, "DATA_SIZE: %d %d %d\n", 
        header.data_size[0], header.data_size[1], header.data_size[2]);
    fprintf(fd, "DATA_FORMAT: %s\n", header.data_format);
    fprintf(fd, "VARIABLE: %s\n", header.variable);
    fprintf(fd, "DATA_ENDIAN: LITTLE\n");
    fprintf(fd, "CENTERING: %s\n", header.centering);
    fprintf(fd, "BRICK_ORIGIN: %f %f %f\n",
        header.brick_origin[0], header.brick_origin[1], header.brick_origin[2]);
    fprintf(fd, "BRICK_SIZE: %f %f %f\n",
        header.brick_size[0], header.brick_size[1], header.brick_size[2]);
    fprintf(fd, "DIVIDE_BRICK: true\n");
    fprintf(fd, "DATA_BRICKLETS: %d %d %d\n",
        header.data_bricklets[0], header.data_bricklets[1], header.data_bricklets[2]);
    fprintf(fd, "DATA_COMPONENTS: %d\n", 1);
    CloseTextFile(fd);

    snprintf(data_file, len, "%s.data", (bov_file));
    fd = CreateRawFile(header.data_file);
    if(!fd)
    {
        printf("Failed to create BOV data file '%s'! Exiting...\n", bov_file);
        exit(EXIT_FAILURE);
    }

    printf("Writing data to '%s'...\n", header.data_file);
    WriteRaw(fd, grid->data, e5_sizeof(grid->type), grid->dim[0] * grid->dim[1] * grid->dim[2]);
    CloseRawFile(fd);
    printf("DONE!\n");
}