Program Listing for File NuMagSANSlib_SANSData2hdf5.h#

↰ Return to documentation for file (src/OutputData/SANSData/NuMagSANSlib_SANSData2hdf5.h)

#pragma once

#include "NuMagSANSlib_SANSDataTable.h"

#ifdef NUMAGSANS_ENABLE_HDF5
#include <hdf5.h>
#endif

inline std::string build_SANSData_hdf5_group_path(int MagData_File_Index, int StructData_File_Index = 0,
                                                  int RotData_File_Index = 0) {
    std::string group_path = "/SANS_" + std::to_string(MagData_File_Index);

    if (StructData_File_Index > 0) {
        group_path += "/StructData_" + std::to_string(StructData_File_Index);
    }

    if (RotData_File_Index > 0) {
        group_path += "/RotData_" + std::to_string(RotData_File_Index);
    }

    return group_path;
}

#ifdef NUMAGSANS_ENABLE_HDF5
inline void ensureHDF5Group(hid_t file_id, const std::string& group_path) {
    std::string current_path;
    std::stringstream ss(group_path);
    std::string token;

    while (std::getline(ss, token, '/')) {
        if (token.empty()) {
            continue;
        }

        current_path += "/" + token;

        if (H5Lexists(file_id, current_path.c_str(), H5P_DEFAULT) <= 0) {
            hid_t group_id = H5Gcreate2(file_id, current_path.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
            if (group_id < 0) {
                throw std::runtime_error("Could not create HDF5 group: " + current_path);
            }
            H5Gclose(group_id);
        }
    }
}

inline void writeHDF5Dataset(hid_t file_id, const std::string& dataset_path, unsigned long length, const float* data) {
    hsize_t dims[1] = {static_cast<hsize_t>(length)};
    hid_t dataspace_id = H5Screate_simple(1, dims, NULL);
    if (dataspace_id < 0) {
        throw std::runtime_error("Could not create HDF5 dataspace for: " + dataset_path);
    }

    if (H5Lexists(file_id, dataset_path.c_str(), H5P_DEFAULT) > 0) {
        H5Ldelete(file_id, dataset_path.c_str(), H5P_DEFAULT);
    }

    hid_t dataset_id = H5Dcreate2(file_id, dataset_path.c_str(), H5T_NATIVE_FLOAT, dataspace_id, H5P_DEFAULT,
                                  H5P_DEFAULT, H5P_DEFAULT);
    if (dataset_id < 0) {
        H5Sclose(dataspace_id);
        throw std::runtime_error("Could not create HDF5 dataset: " + dataset_path);
    }

    if (H5Dwrite(dataset_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) {
        H5Dclose(dataset_id);
        H5Sclose(dataspace_id);
        throw std::runtime_error("Could not write HDF5 dataset: " + dataset_path);
    }

    H5Dclose(dataset_id);
    H5Sclose(dataspace_id);
}

inline void writeHDF5Table(hid_t file_id, const std::string& table_path, unsigned long length,
                           const std::vector<Column>& columns) {
    ensureHDF5Group(file_id, table_path);

    for (const auto& column : columns) {
        writeHDF5Dataset(file_id, table_path + "/" + column.name, length, column.data);
    }
}
#endif

inline void write2HDF5table_ScatteringData(InputFileData* InputData, ScatteringData* SANSData, int MagData_File_Index,
                                           int StructData_File_Index = 0, int RotData_File_Index = 0) {
#ifndef NUMAGSANS_ENABLE_HDF5
    LogSystem::write("Error: HDF5 output requested, but NuMagSANS was built without HDF5 support.");
    LogSystem::write("Reconfigure with -DNUMAGSANS_ENABLE_HDF5=ON and make sure HDF5 is available.");
    throw std::runtime_error("HDF5 output requested without HDF5 build support.");
#else
    LogSystem::write("");
    LogSystem::write("write scattering data to hdf5-file...");

    std::filesystem::create_directories(InputData->SANSDataFoldername);

    std::string filename = InputData->SANSDataFoldername + "/NuMagSANS_Output.h5";
    hid_t file_id = std::filesystem::exists(filename)
                        ? H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT)
                        : H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);

    if (file_id < 0) {
        throw std::runtime_error("Could not open HDF5 output file: " + filename);
    }

    std::string root_path =
        build_SANSData_hdf5_group_path(MagData_File_Index, StructData_File_Index, RotData_File_Index);

    if (InputData->output_fourier_correlation_matrix_flag || any_active(InputData->OutFlags.SANS2D)) {
        unsigned long L = (*SANSData->N_q) * (*SANSData->N_theta);
        writeHDF5Table(file_id, root_path + "/SANS2D", L, build_SANS2D_columns(InputData, SANSData));
        LogSystem::write("SANS2D hdf5 output finished...");
    }

    if (any_active(InputData->OutFlags.SANS1D)) {
        writeHDF5Table(file_id, root_path + "/SANS1D", (*SANSData->N_q), build_SANS1D_columns(InputData, SANSData));
        LogSystem::write("SANS1D hdf5 output finished...");
    }

    if (any_active(InputData->OutFlags.Corr1D) || any_active(InputData->OutFlags.PairDist1D)) {
        writeHDF5Table(file_id, root_path + "/Corr1D", (*SANSData->N_r), build_Corr1D_columns(InputData, SANSData));
        LogSystem::write("Corr1D hdf5 output finished...");
    }

    if (any_active(InputData->OutFlags.Corr2D)) {
        unsigned long L = (*SANSData->N_r) * (*SANSData->N_alpha);
        writeHDF5Table(file_id, root_path + "/Corr2D", L, build_Corr2D_columns(InputData, SANSData));
        LogSystem::write("Corr2D hdf5 output finished...");
    }

    H5Fclose(file_id);
#endif
}