added HDF4 ISIS NeXus class handling.
This commit is contained in:
@@ -213,7 +213,35 @@ endif (qt_based_tools)
|
||||
if (nexus)
|
||||
find_package(HDF5 COMPONENTS CXX REQUIRED)
|
||||
if (HAVE_HDF4)
|
||||
find_package(HDF4 REQUIRED)
|
||||
#--- check for HDF4 -----------------------------------------------------------
|
||||
# Find HDF4 manually (pkg-config often doesn't have hdf4)
|
||||
find_path(HDF4_INCLUDE_DIR
|
||||
NAMES mfhdf.h
|
||||
PATHS /usr/include /usr/local/include
|
||||
PATH_SUFFIXES hdf
|
||||
)
|
||||
|
||||
find_library(HDF4_DF_LIBRARY
|
||||
NAMES df libdf
|
||||
PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib
|
||||
)
|
||||
|
||||
find_library(HDF4_MFHDF_LIBRARY
|
||||
NAMES mfhdf libmfhdf
|
||||
PATHS /usr/lib64 /usr/lib /usr/local/lib64 /usr/local/lib
|
||||
)
|
||||
|
||||
if (HDF4_INCLUDE_DIR AND HDF4_DF_LIBRARY AND HDF4_MFHDF_LIBRARY)
|
||||
set(HDF4_FOUND TRUE)
|
||||
set(HDF4_INCLUDE_DIRS ${HDF4_INCLUDE_DIR})
|
||||
set(HDF4_LIBRARIES ${HDF4_MFHDF_LIBRARY} ${HDF4_DF_LIBRARY})
|
||||
message(STATUS "Found HDF4: ${HDF4_INCLUDE_DIR}")
|
||||
message(STATUS " HDF4 libraries: ${HDF4_LIBRARIES}")
|
||||
else()
|
||||
message(FATAL_ERROR "HDF4 library not found. Please install libhdf4-dev or hdf-devel")
|
||||
endif()
|
||||
|
||||
include_directories(${HDF4_INCLUDE_DIRS})
|
||||
add_definitions(-DHAVE_HDF4)
|
||||
endif (HAVE_HDF4)
|
||||
add_definitions(-DPNEXUS_ENABLED)
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
## Process this file with cmake
|
||||
#=============================================================================
|
||||
# NeXus - Neutron & X-ray Common Data Format
|
||||
#
|
||||
# CMakeLists for building the NeXus library and applications.
|
||||
#
|
||||
# Copyright (C) 2011 Stephen Rankin
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by the
|
||||
# Free Software Foundation; either version 2 of the License, or (at your
|
||||
# option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this library; if not, write to the Free Software Foundation,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# For further information, see <http://www.nexusformat.org>
|
||||
#
|
||||
#
|
||||
#=============================================================================
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# find the runtime binaries of the HDF4 library
|
||||
#------------------------------------------------------------------------------
|
||||
find_library(HDF4_DF_LIBRARY NAMES df hdf
|
||||
HINTS ENV HDF4_ROOT
|
||||
PATH_SUFFIXES hdf)
|
||||
|
||||
|
||||
if(HDF4_DF_LIBRARY MATCHES HDF4_DF_LIBRARY-NOTFOUND)
|
||||
message(FATAL_ERROR "Could not find HDF4 DF library!")
|
||||
else()
|
||||
get_filename_component(HDF4_LIBRARY_DIRS ${HDF4_DF_LIBRARY} PATH)
|
||||
message(STATUS "Found HDF4 DF library: ${HDF4_DF_LIBRARY}")
|
||||
message(STATUS "HDF4 libary path: ${HDF4_LIBRARY_DIRS}")
|
||||
endif()
|
||||
|
||||
find_library(HDF4_MFHDF_LIBRARY NAMES mfhdf
|
||||
HINTS ENV HDF4_ROOT
|
||||
PATH_SUFFIXES hdf)
|
||||
|
||||
if(HDF4_MFHDF_LIBRARY MATCHES HDF4_MFHDF_LIBRARY-NOTFOUND)
|
||||
message(FATAL_ERROR "Could not find HDF5 MFHDF library!")
|
||||
else()
|
||||
message(STATUS "Found HDF4 MFHDF library: ${HDF4_MFHDF_LIBRARY}")
|
||||
endif()
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# find the HDF4 header file
|
||||
#------------------------------------------------------------------------------
|
||||
find_path(HDF4_INCLUDE_DIRS mfhdf.h
|
||||
HINTS ENV HDF4_ROOT
|
||||
PATH_SUFFIXES hdf)
|
||||
|
||||
if(HDF4_INCLUDE_DIRS MATCHES HDF4_INCLUDE_DIRS-NOTFOUND)
|
||||
message(FATAL_ERROR "Could not find HDF4 header files")
|
||||
else()
|
||||
message(STATUS "Found HDF4 header files in: ${HDF4_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# search for additional packages required to link against HDF4
|
||||
#------------------------------------------------------------------------------
|
||||
find_package(JPEG REQUIRED)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# add libraries to the link list for NAPI
|
||||
#------------------------------------------------------------------------------
|
||||
get_filename_component(LIB_EXT ${HDF4_DF_LIBRARY} EXT)
|
||||
if(LIB_EXT MATCHES .a)
|
||||
message(STATUS "HDF4 DF library is static")
|
||||
list(APPEND NAPI_LINK_LIBS "-Wl,-whole-archive" ${HDF4_DF_LIBRARY} "-Wl,-no-whole-archive")
|
||||
else()
|
||||
list(APPEND NAPI_LINK_LIBS ${HDF4_DF_LIBRARY})
|
||||
endif()
|
||||
|
||||
|
||||
get_filename_component(LIB_EXT ${HDF4_MFHDF_LIBRARY} EXT)
|
||||
if(LIB_EXT MATCHES .a)
|
||||
message(STATUS "HDF4 MFHDF library is static")
|
||||
list(APPEND NAPI_LINK_LIBS "-Wl,-whole-archive" ${HDF4_MFHDF_LIBRARY} "-Wl,-no-whole-archive")
|
||||
else()
|
||||
list(APPEND NAPI_LINK_LIBS ${HDF4_MFHDF_LIBRARY})
|
||||
endif()
|
||||
|
||||
list(APPEND NAPI_LINK_LIBS jpeg)
|
||||
|
||||
include_directories ( SYSTEM ${HDF4_INCLUDE_DIRS} )
|
||||
link_directories(${HDF4_LIBRARY_DIRS})
|
||||
@@ -1,34 +0,0 @@
|
||||
# - find MXML
|
||||
# find the MXML lib and includes
|
||||
# This module defines
|
||||
# LIBMXML_INCLUDE_DIR, where to find mxml.h
|
||||
# LIBMXML_LIBRARY, library to link against
|
||||
# LIBMXML_FOUND, if false, do not try to use the MXML lib
|
||||
|
||||
find_path(LIBMXML_INCLUDE_DIR mxml.h
|
||||
HINT "/usr/include"
|
||||
)
|
||||
# find position of mxml.h from the end
|
||||
string(FIND "${LIBMXML_INCLUDE_DIR}" "/mxml.h" pos REVERSE)
|
||||
# truncate the string
|
||||
string(SUBSTRING "${LIBMXML_INCLUDE_DIR}" 0 ${pos} substr)
|
||||
set(LIBMXML_INCLUDE_DIR ${substr})
|
||||
unset(substr)
|
||||
|
||||
find_library(LIBMXML_LIBRARY mxml)
|
||||
|
||||
# get version string
|
||||
# currently do not know from where to get it automatically
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set LIBMXML_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MXML
|
||||
REQUIRED_VARS LIBMXML_LIBRARY LIBMXML_INCLUDE_DIR)
|
||||
|
||||
if (NOT LIBMXML_FOUND)
|
||||
unset(LIBMXML_LIBRARY)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(LIBMXML_INCLUDE_DIR LIBMXML_LIBRARY)
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# - Find NeXus library
|
||||
# Find the native NEXUS includes and library
|
||||
# This module defines
|
||||
# NEXUS_INCLUDE_DIR, where to find NeXus.h, etc.
|
||||
# NEXUS_LIBRARY, library to link against to use NEXUS
|
||||
# NEXUS_FOUND, if false, do not try to use NEXUS.
|
||||
|
||||
find_path(NEXUS_INCLUDE_DIR napi.h
|
||||
HINTS "/usr/local/include" "/opt/nexus/include" "/usr/local/include/nexus"
|
||||
)
|
||||
# find position of napi.h from the end
|
||||
string(FIND "${NEXUS_INCLUDE_DIR}" "/napi.h" pos REVERSE)
|
||||
# truncate the string
|
||||
string(SUBSTRING "${NEXUS_INCLUDE_DIR}" 0 ${pos} substr)
|
||||
set(NEXUS_INCLUDE_DIR ${substr})
|
||||
unset(substr)
|
||||
|
||||
find_library(NEXUS_LIBRARY NeXus
|
||||
HINTS "/usr/lib" "/usr/lib64" "/usr/local/lib" "/usr/local/lib64" "/opt/nexus/lib")
|
||||
|
||||
# get version string
|
||||
if (NEXUS_INCLUDE_DIR AND EXISTS ${NEXUS_INCLUDE_DIR}/napi.h)
|
||||
file(STRINGS "${NEXUS_INCLUDE_DIR}/napi.h" NEXUS_version_str
|
||||
REGEX "^#define[\t ]+NEXUS_VERSION[\t ].*")
|
||||
|
||||
string(REGEX REPLACE "^#define[\t ]+NEXUS_VERSION[\t ]+\"([^\"]*).*"
|
||||
"\\1" NEXUS_VERSION_STRING "${NEXUS_version_str}")
|
||||
unset(NEXUS_version_str)
|
||||
endif()
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set NEXUS_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
include(${CMAKE_ROOT}/Modules/FindPackageHandleStandardArgs.cmake)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(NEXUS
|
||||
REQUIRED_VARS NEXUS_LIBRARY NEXUS_INCLUDE_DIR
|
||||
VERSION_VAR NEXUS_VERSION_STRING)
|
||||
|
||||
if (NOT NEXUS_FOUND)
|
||||
unset(NEXUS_LIBRARY)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(NEXUS_INCLUDE_DIR NEXUS_LIBRARY)
|
||||
|
||||
|
||||
|
||||
2
src/external/nexus/CMakeLists.txt
vendored
2
src/external/nexus/CMakeLists.txt
vendored
@@ -28,7 +28,7 @@ target_include_directories(
|
||||
)
|
||||
|
||||
#--- add library dependencies -------------------------------------------------
|
||||
target_link_libraries(PNeXus ${NEXUS_LIBRARY})
|
||||
target_link_libraries(PNeXus ${HDF4_LIBRARIES} ${ROOT_LIBRARIES})
|
||||
|
||||
#--- install PNeXus solib -----------------------------------------------------
|
||||
install(TARGETS PNeXus DESTINATION lib)
|
||||
|
||||
2193
src/external/nexus/PNeXus.cpp
vendored
2193
src/external/nexus/PNeXus.cpp
vendored
File diff suppressed because it is too large
Load Diff
848
src/external/nexus/PNeXus.h
vendored
848
src/external/nexus/PNeXus.h
vendored
@@ -31,6 +31,19 @@
|
||||
#define _PNEXUS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
#include <any>
|
||||
#include <cstdint>
|
||||
|
||||
#include "Minuit2/FCNBase.h"
|
||||
|
||||
#ifdef HAVE_HDF4
|
||||
#include <mfhdf.h>
|
||||
#include <hdf.h>
|
||||
#endif // HAVE_HDF4
|
||||
|
||||
namespace nxs {
|
||||
|
||||
@@ -44,4 +57,839 @@ HDFType checkHDFType(const std::string& filename);
|
||||
|
||||
} // end namespace nxs
|
||||
|
||||
#ifdef HAVE_HDF4
|
||||
namespace nxH4 {
|
||||
|
||||
class PNeXus;
|
||||
|
||||
/**
|
||||
* @class PNeXusDeadTime
|
||||
* @brief Dead time correction calculator for muon detector data
|
||||
*
|
||||
* The PNeXusDeadTime class calculates dead time corrections for muon detector
|
||||
* count data using ROOT Minuit2 minimization. It inherits from ROOT::Minuit2::FCNBase
|
||||
* to implement a chi-square minimization function.
|
||||
*
|
||||
* Dead time is the period after detecting an event during which the detector
|
||||
* cannot register another event. This class estimates the dead time parameter
|
||||
* for each detector spectrum by minimizing the deviation from expected count rates.
|
||||
*
|
||||
* **Typical Usage:**
|
||||
* @code
|
||||
* nxH4::PNeXus nexus("file.nxs");
|
||||
* nxH4::PNeXusDeadTime ndt(&nexus, false); // false = no debug output
|
||||
*
|
||||
* if (ndt.IsValid()) {
|
||||
* auto dims = ndt.GetDimensions();
|
||||
* // Minimize for each spectrum
|
||||
* for (unsigned int i = 0; i < dims[1]; i++) {
|
||||
* ndt.minimize(i);
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @note Requires a valid PNeXus object with count data
|
||||
* @note Uses ROOT Minuit2 for minimization
|
||||
*
|
||||
* @see ROOT::Minuit2::FCNBase
|
||||
* @see nxH4::PNeXus
|
||||
*/
|
||||
class PNeXusDeadTime : public ROOT::Minuit2::FCNBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor - initializes dead time calculator from NeXus data
|
||||
* * Reads count data, time resolution, and bin information from the NeXus file
|
||||
* to set up the dead time calculation.
|
||||
* * @param nxs Pointer to PNeXus object containing the detector data
|
||||
* @param debug If true, print additional debug information during calculations
|
||||
* * @note After construction, check IsValid() to ensure data was loaded successfully
|
||||
*/
|
||||
PNeXusDeadTime(const PNeXus *nxs, bool debug=false);
|
||||
|
||||
/**
|
||||
* @brief Check if the dead time calculator was initialized successfully
|
||||
* * @return true if required datasets were found and loaded, false otherwise
|
||||
*/
|
||||
bool IsValid() { return fValid; }
|
||||
|
||||
/**
|
||||
* @brief Get the error definition for the minimizer (FCNBase requirement)
|
||||
* * Returns the UP parameter which defines how the minimizer estimates errors.
|
||||
* For chi-square minimization, UP = 0.5 corresponds to 1-sigma errors.
|
||||
* * @return Error definition parameter (0.5 for chi-square)
|
||||
*/
|
||||
double Up() const { return fUp; }
|
||||
|
||||
/**
|
||||
* @brief Function call operator - calculates chi-square for given parameters
|
||||
* * This is the objective function that ROOT::Minuit2 minimizes. It calculates
|
||||
* the chi-square deviation between observed counts and expected counts
|
||||
* corrected for dead time.
|
||||
* * @param par Vector of parameters (dead time values in microseconds)
|
||||
* @return Chi-square value for the given parameters
|
||||
*/
|
||||
double operator()(const std::vector<double> &par) const;
|
||||
|
||||
/**
|
||||
* @brief Minimize dead time for a specific detector spectrum
|
||||
* * Performs Minuit2 minimization to find the optimal dead time parameter
|
||||
* for the specified spectrum index. Results are printed to stdout.
|
||||
* * @param i Spectrum index to minimize (0-based index into second dimension)
|
||||
* * @note Prints minimization results including dead time estimate and errors
|
||||
* @note The index i must be less than dims[1] (number of spectra)
|
||||
*/
|
||||
void minimize(const int i);
|
||||
|
||||
/**
|
||||
* @brief Get the dimensions of the count dataset
|
||||
* * Returns the dimensions [periods, spectra, bins] of the count data
|
||||
* being used for dead time calculation.
|
||||
* * @return Vector of dimension sizes (typically 3D: [periods, spectra, bins])
|
||||
*/
|
||||
const std::vector<uint32_t>& GetDimensions() const { return fDims; }
|
||||
|
||||
private:
|
||||
bool fDebug{false}; ///< Debug flag - if true, print additional diagnostic information
|
||||
bool fValid; ///< Validity flag - true if required data was loaded successfully
|
||||
int fGoodFrames{-1}; ///< Number of good time frames for analysis
|
||||
float fTimeResolution{0.0}; ///< Time resolution in picoseconds
|
||||
std::vector<uint32_t>fDims = {0, 0, 0}; ///< Dimensions of count data [periods, spectra, bins]
|
||||
int fT0Bin{-1}; ///< T0 bin number (time zero reference)
|
||||
int fFgbBin{-1}; ///< First good bin for analysis
|
||||
int fLgbBin{-1}; ///< Last good bin for analysis
|
||||
std::vector<float> fDeadTime; ///< Dead time values per detector (microseconds)
|
||||
std::vector<int> fCounts; ///< Count data for minimization
|
||||
double fUp{0.5}; ///< UP parameter for Minuit2 (0.5 for chi-square)
|
||||
unsigned int fIdx{0}; ///< Current spectrum index being minimized
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief HDF4 data type enumeration
|
||||
*
|
||||
* This enum maps to HDF4 numeric types (DFNT_*) for type-safe dataset handling
|
||||
*/
|
||||
enum class H4DataType {
|
||||
INT32, ///< 32-bit signed integer (DFNT_INT32)
|
||||
FLOAT32, ///< 32-bit floating point (DFNT_FLOAT32)
|
||||
FLOAT64, ///< 64-bit floating point (DFNT_FLOAT64)
|
||||
CHAR8, ///< 8-bit character (DFNT_CHAR8)
|
||||
UINT32, ///< 32-bit unsigned integer (DFNT_UINT32)
|
||||
INT16, ///< 16-bit signed integer (DFNT_INT16)
|
||||
UINT16, ///< 16-bit unsigned integer (DFNT_UINT16)
|
||||
INT8, ///< 8-bit signed integer (DFNT_INT8)
|
||||
UINT8 ///< 8-bit unsigned integer (DFNT_UINT8)
|
||||
};
|
||||
|
||||
/**
|
||||
* @class PNXdata
|
||||
* @brief Template class for storing HDF4 dataset content with attributes
|
||||
*
|
||||
* The PNXdata class stores data read from an HDF4 dataset along with metadata
|
||||
* such as dimensions, datatype, and attributes. It is designed to be stored in
|
||||
* std::map<std::string, std::any> where the key is the HDF4 path.
|
||||
*
|
||||
* @tparam T The element type of the dataset (int, float, std::string, etc.)
|
||||
*
|
||||
* Key features:
|
||||
* - Stores multi-dimensional data as flattened std::vector<T>
|
||||
* - Preserves dimension information (shape)
|
||||
* - Stores HDF4 DataType for type safety
|
||||
* - Supports attributes as nested PNXdata objects
|
||||
* - Compatible with std::any for type-erased storage
|
||||
*
|
||||
* @example
|
||||
* @code
|
||||
* // Create PNXdata for a 3D integer dataset (1 x 96 x 2048)
|
||||
* PNXdata<int> counts;
|
||||
* counts.SetDimensions({1, 96, 2048});
|
||||
* counts.SetData(dataVector);
|
||||
*
|
||||
* // Store in map
|
||||
* std::map<std::string, std::any> dataMap;
|
||||
* dataMap["/raw_data_1/detector_1/counts"] = counts;
|
||||
* @endcode
|
||||
*/
|
||||
template <typename T> class PNXdata {
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
PNXdata() : fDataType(H4DataType::INT32) {}
|
||||
|
||||
/**
|
||||
* @brief Constructor with datatype
|
||||
* @param dataType HDF4 datatype for this dataset
|
||||
*/
|
||||
PNXdata(const H4DataType& dataType) : fDataType(dataType) {}
|
||||
|
||||
/**
|
||||
* @brief Get the HDF4 DataType
|
||||
* @return The HDF4 DataType for this dataset
|
||||
*/
|
||||
H4DataType GetDataType() const { return fDataType; }
|
||||
|
||||
/**
|
||||
* @brief Set the HDF4 DataType
|
||||
* @param dataType The HDF4 DataType to set
|
||||
*/
|
||||
void SetDataType(const H4DataType& dataType) { fDataType = dataType; }
|
||||
|
||||
/**
|
||||
* @brief Get the data as a vector
|
||||
* @return Reference to the data vector
|
||||
*/
|
||||
const std::vector<T>& GetData() const { return fData; }
|
||||
|
||||
/**
|
||||
* @brief Get mutable reference to the data vector
|
||||
* @return Reference to the data vector
|
||||
*/
|
||||
std::vector<T>& GetData() { return fData; }
|
||||
|
||||
/**
|
||||
* @brief Set the data vector
|
||||
* @param data Vector of data to store
|
||||
*/
|
||||
void SetData(const std::vector<T>& data) { fData = data; }
|
||||
|
||||
/**
|
||||
* @brief Get the dimensions of the dataset
|
||||
* @return Vector of dimension sizes
|
||||
*/
|
||||
const std::vector<uint32_t>& GetDimensions() const { return fDimensions; }
|
||||
|
||||
/**
|
||||
* @brief Set the dimensions of the dataset
|
||||
* @param dims Vector of dimension sizes
|
||||
*/
|
||||
void SetDimensions(const std::vector<uint32_t>& dims) { fDimensions = dims; }
|
||||
|
||||
/**
|
||||
* @brief Get the number of dimensions
|
||||
* @return Number of dimensions (rank)
|
||||
*/
|
||||
size_t GetRank() const { return fDimensions.size(); }
|
||||
|
||||
/**
|
||||
* @brief Get total number of elements
|
||||
* @return Product of all dimensions
|
||||
*/
|
||||
size_t GetNumElements() const {
|
||||
if (fDimensions.empty()) return 0;
|
||||
size_t total = 1;
|
||||
for (auto dim : fDimensions) {
|
||||
total *= dim;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add an attribute to this dataset
|
||||
* @param name Attribute name
|
||||
* @param value Attribute value (stored as std::any to support different types)
|
||||
*/
|
||||
void AddAttribute(const std::string& name, const std::any& value) {
|
||||
fAttributes[name] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get an attribute by name
|
||||
* @param name Attribute name
|
||||
* @return The attribute value as std::any
|
||||
* @throws std::out_of_range if attribute doesn't exist
|
||||
*/
|
||||
std::any GetAttribute(const std::string& name) const {
|
||||
return fAttributes.at(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if an attribute exists
|
||||
* @param name Attribute name
|
||||
* @return true if attribute exists, false otherwise
|
||||
*/
|
||||
bool HasAttribute(const std::string& name) const {
|
||||
return fAttributes.find(name) != fAttributes.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get all attributes
|
||||
* @return Map of attribute names to values
|
||||
*/
|
||||
const std::map<std::string, std::any>& GetAttributes() const {
|
||||
return fAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get mutable reference to all attributes
|
||||
* @return Mutable map of attribute names to values
|
||||
*/
|
||||
std::map<std::string, std::any>& GetAttributes() {
|
||||
return fAttributes;
|
||||
}
|
||||
|
||||
private:
|
||||
H4DataType fDataType; ///< HDF4 datatype of the dataset
|
||||
std::vector<T> fData; ///< Data storage (flattened multi-dimensional array)
|
||||
std::vector<uint32_t> fDimensions; ///< Dimensions of the dataset
|
||||
std::map<std::string, std::any> fAttributes; ///< Attributes associated with this dataset
|
||||
};
|
||||
|
||||
/**
|
||||
* @class PNeXus
|
||||
* @brief NeXus HDF4 file reader with case-insensitive path lookup
|
||||
*
|
||||
* The PNeXus class provides functionality for reading ISIS muon NeXus HDF4 files
|
||||
* using the HDF4 C API. It implements case-insensitive path lookup for
|
||||
* datasets, groups, and attributes to handle files with varying path casings.
|
||||
*
|
||||
* Key features:
|
||||
* - Automatic file reading upon construction
|
||||
* - Case-insensitive path resolution for datasets and groups
|
||||
* - Case-insensitive attribute name matching
|
||||
* - Comprehensive exception handling
|
||||
*
|
||||
* @example
|
||||
* @code
|
||||
* PNeXus nexus("data/experiment.nxs");
|
||||
* // Case-insensitive paths work: "/RAW_DATA_1/IDF_version" -> "/raw_data_1/IDF_version"
|
||||
* @endcode
|
||||
*
|
||||
* @note All path lookups throw appropriate exceptions on failure
|
||||
*/
|
||||
class PNeXus {
|
||||
public:
|
||||
PNeXus();
|
||||
|
||||
/**
|
||||
* @brief Constructor - creates PNeXus object and reads the NeXus file
|
||||
* @param fln Filename of the NeXus HDF4 file to read
|
||||
* @param printDebug Enable debug output
|
||||
* @throws std::runtime_error if file cannot be opened or read
|
||||
*/
|
||||
PNeXus(const std::string fln, const bool printDebug=false);
|
||||
|
||||
/**
|
||||
* @brief Destructor - closes HDF4 file if open
|
||||
*/
|
||||
~PNeXus();
|
||||
|
||||
/**
|
||||
* @brief Get the filename of the NeXus file
|
||||
* @return The filename as a string
|
||||
*/
|
||||
std::string GetFileName() const { return fFileName; }
|
||||
|
||||
/**
|
||||
* @brief Get the hdf4 version of the NeXus file
|
||||
* @return The hdf4 version as a string
|
||||
*/
|
||||
std::string GetHdf4Version() const { return fHdf4Version; }
|
||||
|
||||
/**
|
||||
* @brief Get the NeXus version of the file
|
||||
* @return The NeXus version as a string
|
||||
*/
|
||||
std::string GetNeXusVersion() const { return fNeXusVersion; }
|
||||
|
||||
/**
|
||||
* @brief Get the Idf version of the file
|
||||
* @return The Idf version tag
|
||||
*/
|
||||
int GetIdfVersion() const { return fIdfVersion; }
|
||||
|
||||
/**
|
||||
* @brief Read and parse the NeXus HDF4 file
|
||||
* @return 0 on success, 1 on error
|
||||
* @throws std::runtime_error if file cannot be opened or read
|
||||
*/
|
||||
int ReadNexusFile();
|
||||
|
||||
/**
|
||||
* @brief Get the data map containing all datasets
|
||||
* @return Reference to the data map (path -> PNXdata stored in std::any)
|
||||
*/
|
||||
const std::map<std::string, std::any>& GetDataMap() const { return fDataMap; }
|
||||
|
||||
/**
|
||||
* @brief Get mutable reference to the data map
|
||||
* @return Reference to the data map
|
||||
*/
|
||||
std::map<std::string, std::any>& GetDataMap() { return fDataMap; }
|
||||
|
||||
/**
|
||||
* @brief Check if a dataset path exists in the data map
|
||||
* @param path HDF4 path to check
|
||||
* @return true if path exists, false otherwise
|
||||
*/
|
||||
bool HasDataset(const std::string& path) const { return fDataMap.find(path) != fDataMap.end(); }
|
||||
|
||||
/**
|
||||
* @brief Add or update a dataset in the data map
|
||||
* @tparam T Data type of the PNXdata object
|
||||
* @param path HDF4 path for the dataset
|
||||
* @param data PNXdata object to store
|
||||
*/
|
||||
template <typename T>
|
||||
void SetDataset(const std::string& path, const PNXdata<T>& data) {
|
||||
fDataMap[path] = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a dataset from the data map
|
||||
* @tparam T Data type of the PNXdata object
|
||||
* @param path HDF4 path of the dataset
|
||||
* @return PNXdata object
|
||||
* @throws std::out_of_range if path doesn't exist
|
||||
* @throws std::bad_any_cast if type T doesn't match stored type
|
||||
*/
|
||||
template <typename T>
|
||||
PNXdata<T> GetDataset(const std::string& path) const {
|
||||
return std::any_cast<PNXdata<T>>(fDataMap.at(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a mutable reference to a dataset in the data map
|
||||
* @tparam T Data type of the PNXdata object
|
||||
* @param path HDF4 path of the dataset
|
||||
* @return Reference to PNXdata object
|
||||
* @throws std::out_of_range if path doesn't exist
|
||||
* @throws std::bad_any_cast if type T doesn't match stored type
|
||||
*/
|
||||
template <typename T>
|
||||
PNXdata<T>& GetDatasetRef(const std::string& path) {
|
||||
return std::any_cast<PNXdata<T>&>(fDataMap.at(path));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove a dataset from the data map
|
||||
* @param path HDF4 path of the dataset to remove
|
||||
* @return true if dataset was removed, false if path didn't exist
|
||||
*/
|
||||
bool RemoveDataset(const std::string& path) {
|
||||
auto it = fDataMap.find(path);
|
||||
if (it != fDataMap.end()) {
|
||||
fDataMap.erase(it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear all datasets from the data map
|
||||
*/
|
||||
void ClearDataMap() { fDataMap.clear(); }
|
||||
|
||||
/**
|
||||
* @brief Get the number of datasets in the data map
|
||||
* @return Number of datasets stored
|
||||
*/
|
||||
size_t GetNumDatasets() const { return fDataMap.size(); }
|
||||
|
||||
/**
|
||||
* @brief Update the data of an existing dataset
|
||||
* @tparam T Data type of the PNXdata object
|
||||
* @param path HDF4 path of the dataset
|
||||
* @param newData New data vector to set
|
||||
* @return true if update succeeded, false if path doesn't exist
|
||||
*/
|
||||
template <typename T>
|
||||
bool UpdateDatasetData(const std::string& path, const std::vector<T>& newData) {
|
||||
if (!HasDataset(path)) return false;
|
||||
try {
|
||||
auto& dataset = std::any_cast<PNXdata<T>&>(fDataMap.at(path));
|
||||
dataset.SetData(newData);
|
||||
return true;
|
||||
} catch (const std::bad_any_cast&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Update the dimensions of an existing dataset
|
||||
* @tparam T Data type of the PNXdata object
|
||||
* @param path HDF4 path of the dataset
|
||||
* @param newDimensions New dimensions vector to set
|
||||
* @return true if update succeeded, false if path doesn't exist
|
||||
*/
|
||||
template <typename T>
|
||||
bool UpdateDatasetDimensions(const std::string& path, const std::vector<uint32_t>& newDimensions) {
|
||||
if (!HasDataset(path)) return false;
|
||||
try {
|
||||
auto& dataset = std::any_cast<PNXdata<T>&>(fDataMap.at(path));
|
||||
dataset.SetDimensions(newDimensions);
|
||||
return true;
|
||||
} catch (const std::bad_any_cast&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Add or update an attribute for a dataset
|
||||
* @tparam T Data type of the PNXdata object
|
||||
* @param path HDF4 path of the dataset
|
||||
* @param attrName Attribute name
|
||||
* @param attrValue Attribute value (stored as std::any)
|
||||
* @return true if attribute was added, false if dataset doesn't exist
|
||||
*/
|
||||
template <typename T>
|
||||
bool AddDatasetAttribute(const std::string& path, const std::string& attrName,
|
||||
const std::any& attrValue) {
|
||||
if (!HasDataset(path)) return false;
|
||||
try {
|
||||
auto& dataset = std::any_cast<PNXdata<T>&>(fDataMap.at(path));
|
||||
dataset.AddAttribute(attrName, attrValue);
|
||||
return true;
|
||||
} catch (const std::bad_any_cast&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove an attribute from a dataset
|
||||
* @tparam T Data type of the PNXdata object
|
||||
* @param path HDF4 path of the dataset
|
||||
* @param attrName Attribute name to remove
|
||||
* @return true if attribute was removed, false if dataset doesn't exist or attribute not found
|
||||
*/
|
||||
template <typename T>
|
||||
bool RemoveDatasetAttribute(const std::string& path, const std::string& attrName) {
|
||||
if (!HasDataset(path)) return false;
|
||||
try {
|
||||
auto& dataset = std::any_cast<PNXdata<T>&>(fDataMap.at(path));
|
||||
auto& attrs = dataset.GetAttributes();
|
||||
auto it = attrs.find(attrName);
|
||||
if (it != attrs.end()) {
|
||||
attrs.erase(it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (const std::bad_any_cast&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create and add a new dataset with data, dimensions, and optional attributes
|
||||
* @tparam T Data type of the PNXdata object
|
||||
* @param path HDF4 path for the new dataset
|
||||
* @param data Data vector
|
||||
* @param dimensions Dimensions vector
|
||||
* @param dataType HDF4 DataType (optional, uses default if not provided)
|
||||
* @return true if dataset was created, false if path already exists
|
||||
*/
|
||||
template <typename T>
|
||||
bool AddDataset(const std::string& path, const std::vector<T>& data,
|
||||
const std::vector<uint32_t>& dimensions,
|
||||
const H4DataType& dataType = H4DataType::INT32) {
|
||||
if (HasDataset(path)) return false;
|
||||
PNXdata<T> dataset(dataType);
|
||||
dataset.SetData(data);
|
||||
dataset.SetDimensions(dimensions);
|
||||
fDataMap[path] = dataset;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Modify an existing dataset's data and dimensions
|
||||
* @tparam T Data type of the PNXdata object
|
||||
* @param path HDF4 path of the dataset
|
||||
* @param newData New data vector
|
||||
* @param newDimensions New dimensions vector
|
||||
* @return true if modification succeeded, false if path doesn't exist
|
||||
*/
|
||||
template <typename T>
|
||||
bool ModifyDataset(const std::string& path, const std::vector<T>& newData,
|
||||
const std::vector<uint32_t>& newDimensions) {
|
||||
if (!HasDataset(path)) return false;
|
||||
try {
|
||||
auto& dataset = std::any_cast<PNXdata<T>&>(fDataMap.at(path));
|
||||
dataset.SetData(newData);
|
||||
dataset.SetDimensions(newDimensions);
|
||||
return true;
|
||||
} catch (const std::bad_any_cast&) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dump the read hdf4-NeXus file content which was read
|
||||
*/
|
||||
void Dump();
|
||||
|
||||
/**
|
||||
* @brief Write the data map contents to a NeXus HDF4 file
|
||||
* @param filename Path to the output NeXus HDF4 file
|
||||
* @param idfVersion IDF version to write (default: 2)
|
||||
* @return 0 on success, 1 on error
|
||||
* @throws std::runtime_error if file cannot be created or written
|
||||
*/
|
||||
int WriteNexusFile(const std::string& filename, int idfVersion = 2);
|
||||
|
||||
/**
|
||||
* @brief Add or update an attribute for a group
|
||||
* @param groupPath HDF4 path of the group (e.g., "/raw_data_1")
|
||||
* @param attrName Attribute name
|
||||
* @param attrValue Attribute value (stored as std::any)
|
||||
* @return true if attribute was added successfully
|
||||
* @example
|
||||
* @code
|
||||
* nexus.AddGroupAttribute("/raw_data_1", "NX_class", std::string("NXentry"));
|
||||
* @endcode
|
||||
*/
|
||||
bool AddGroupAttribute(const std::string& groupPath, const std::string& attrName,
|
||||
const std::any& attrValue);
|
||||
|
||||
/**
|
||||
* @brief Remove an attribute from a group
|
||||
* @param groupPath HDF4 path of the group
|
||||
* @param attrName Attribute name to remove
|
||||
* @return true if attribute was removed, false if group or attribute not found
|
||||
*/
|
||||
bool RemoveGroupAttribute(const std::string& groupPath, const std::string& attrName);
|
||||
|
||||
/**
|
||||
* @brief Check if a group has a specific attribute
|
||||
* @param groupPath HDF4 path of the group
|
||||
* @param attrName Attribute name to check
|
||||
* @return true if attribute exists, false otherwise
|
||||
*/
|
||||
bool HasGroupAttribute(const std::string& groupPath, const std::string& attrName) const;
|
||||
|
||||
/**
|
||||
* @brief Get an attribute value from a group
|
||||
* @param groupPath HDF4 path of the group
|
||||
* @param attrName Attribute name
|
||||
* @return The attribute value as std::any
|
||||
* @throws std::out_of_range if group or attribute doesn't exist
|
||||
*/
|
||||
std::any GetGroupAttribute(const std::string& groupPath, const std::string& attrName) const;
|
||||
|
||||
/**
|
||||
* @brief Get all attributes for a group
|
||||
* @param groupPath HDF4 path of the group
|
||||
* @return Map of attribute names to values
|
||||
*/
|
||||
const std::map<std::string, std::any>& GetGroupAttributes(const std::string& groupPath) const;
|
||||
|
||||
/**
|
||||
* @brief Clear all attributes from a group
|
||||
* @param groupPath HDF4 path of the group
|
||||
* @return true if group was found and attributes cleared, false otherwise
|
||||
*/
|
||||
bool ClearGroupAttributes(const std::string& groupPath);
|
||||
|
||||
/**
|
||||
* @brief Add or update an attribute at the root level "/"
|
||||
* @param attrName Attribute name
|
||||
* @param attrValue Attribute value (stored as std::any)
|
||||
* @return true if attribute was added successfully
|
||||
* @note This is a convenience method that calls AddGroupAttribute("/", attrName, attrValue)
|
||||
* @example
|
||||
* @code
|
||||
* nexus.AddRootAttribute("experiment_id", std::string("EXP-2024-001"));
|
||||
* nexus.AddRootAttribute("temperature", 293.15f);
|
||||
* nexus.AddRootAttribute("scan_number", static_cast<int32_t>(42));
|
||||
* @endcode
|
||||
*/
|
||||
bool AddRootAttribute(const std::string& attrName, const std::any& attrValue);
|
||||
|
||||
private:
|
||||
bool fPrintDebug{false}; ///< if true print additional debug information
|
||||
std::string fFileName{""}; ///< NeXus HDF4 filename
|
||||
int fIdfVersion{-1}; ///< IDF version of the NeXus file
|
||||
std::string fHdf4Version{""}; ///< HDF4 version of the file
|
||||
std::string fNeXusVersion{""}; ///< NeXus version of the file
|
||||
std::string fFileNameNxs{""};
|
||||
std::string fFileTimeNxs{""};
|
||||
std::string fCreatorNxs{""};
|
||||
std::string fUserV1{""};
|
||||
int32 fSdId{-1}; ///< HDF4 SD interface identifier
|
||||
int32 fFileId{-1}; ///< HDF4 file identifier
|
||||
std::map<std::string, std::any> fDataMap; ///< Map of HDF4 paths to PNXdata objects
|
||||
std::map<std::string, std::map<std::string, std::any>> fGroupAttributes; ///< Map of group paths to their attributes
|
||||
|
||||
/**
|
||||
* @brief HandleIdfV1
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
*/
|
||||
void HandleIdfV1(int32 sd_id);
|
||||
|
||||
/**
|
||||
* @brief HandleIdfV2
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
*/
|
||||
void HandleIdfV2(int32 sd_id);
|
||||
|
||||
// ========================================================================
|
||||
// Write methods for HDF4 file creation
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief Write dataset attributes from PNXdata object
|
||||
* @tparam T The data type of the PNXdata object
|
||||
* @param sds_id HDF4 dataset ID to write attributes to
|
||||
* @param data PNXdata object containing attributes
|
||||
*/
|
||||
template <typename T>
|
||||
void WriteDatasetAttributes(int32 sds_id, const PNXdata<T>& data);
|
||||
|
||||
/**
|
||||
* @brief Write attributes to a group
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @param groupPath Group path
|
||||
* @param attributes Map of attribute names to values
|
||||
*/
|
||||
void WriteGroupAttributes(int32 sd_id, const std::string& groupPath,
|
||||
const std::map<std::string, std::any>& attributes);
|
||||
|
||||
/**
|
||||
* @brief Write an integer dataset with attributes
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @param path Dataset path
|
||||
* @param data PNXdata object containing data, dimensions, and attributes
|
||||
* @throws std::runtime_error if writing fails
|
||||
*/
|
||||
void WriteIntDataset(int32 sd_id, const std::string& path,
|
||||
const PNXdata<int>& data);
|
||||
|
||||
/**
|
||||
* @brief Write a float dataset with attributes
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @param path Dataset path
|
||||
* @param data PNXdata object containing data, dimensions, and attributes
|
||||
* @throws std::runtime_error if writing fails
|
||||
*/
|
||||
void WriteFloatDataset(int32 sd_id, const std::string& path,
|
||||
const PNXdata<float>& data);
|
||||
|
||||
/**
|
||||
* @brief Write a string dataset with attributes
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @param path Dataset path
|
||||
* @param data PNXdata object containing data, dimensions, and attributes
|
||||
* @throws std::runtime_error if writing fails
|
||||
*/
|
||||
void WriteStringDataset(int32 sd_id, const std::string& path,
|
||||
const PNXdata<std::string>& data);
|
||||
|
||||
/**
|
||||
* @brief Write root-level file attributes
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @throws std::runtime_error if writing fails
|
||||
*/
|
||||
void WriteFileAttributes(int32 sd_id);
|
||||
|
||||
/**
|
||||
* @brief Write IDF version 2 structure
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @throws std::runtime_error if writing fails
|
||||
*/
|
||||
void WriteIdfV2(int32 sd_id);
|
||||
|
||||
// ========================================================================
|
||||
// Case-insensitive lookup helper methods
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief Compare two strings case-insensitively
|
||||
* @param a First string to compare
|
||||
* @param b Second string to compare
|
||||
* @return true if strings are equal (ignoring case), false otherwise
|
||||
* @note Uses std::tolower for character-by-character comparison
|
||||
*/
|
||||
static bool caseInsensitiveEquals(const std::string& a, const std::string& b);
|
||||
|
||||
/**
|
||||
* @brief Split an HDF4 path into components
|
||||
* @param path HDF4 path string (e.g., "/raw_data_1/IDF_version")
|
||||
* @return Vector of path components
|
||||
* @note Empty first component indicates absolute path
|
||||
* @example "/raw_data_1/IDF_version" -> ["", "raw_data_1", "IDF_version"]
|
||||
*/
|
||||
static std::vector<std::string> splitPath(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief Find attribute name with case-insensitive matching
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @param requestedName Requested attribute name (any case)
|
||||
* @return Correctly-cased attribute name as it exists in the file
|
||||
* @throws std::runtime_error if attribute not found
|
||||
* @example "nexus_version" might resolve to "NeXus_version"
|
||||
*/
|
||||
std::string findAttributeName(int32 sd_id, const std::string& requestedName);
|
||||
|
||||
/**
|
||||
* @brief Find dataset index with case-insensitive matching
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @param requestedName Requested dataset name (any case)
|
||||
* @return Dataset index
|
||||
* @throws std::runtime_error if dataset not found
|
||||
*/
|
||||
int32 findDatasetIndex(int32 sd_id, const std::string& requestedName);
|
||||
|
||||
/**
|
||||
* @brief Find dataset reference by navigating VGroup hierarchy
|
||||
* @param path Full hierarchical path (e.g., "/run/sample/name")
|
||||
* @return Dataset reference number, or -1 if not found
|
||||
* @note Uses VGroup navigation to resolve paths in HDF4 files with duplicate dataset names
|
||||
*/
|
||||
int32 findDatasetRefByPath(const std::string& path);
|
||||
|
||||
// ========================================================================
|
||||
// Dataset reading helper methods
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief Read an integer dataset and store in data map
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @param path Path to the dataset
|
||||
* @throws std::runtime_error if reading fails
|
||||
*/
|
||||
void ReadIntDataset(int32 sd_id, const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief Read a float dataset and store in data map
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @param path Path to the dataset
|
||||
* @throws std::runtime_error if reading fails
|
||||
*/
|
||||
void ReadFloatDataset(int32 sd_id, const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief Read a string dataset and store in data map
|
||||
* @param sd_id HDF4 SD interface ID
|
||||
* @param path Path to the dataset
|
||||
* @throws std::runtime_error if reading fails
|
||||
*/
|
||||
void ReadStringDataset(int32 sd_id, const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief Read dataset attributes and add to PNXdata object
|
||||
* @tparam T The data type of the PNXdata object
|
||||
* @param sds_id HDF4 dataset ID
|
||||
* @param data PNXdata object to add attributes to
|
||||
*/
|
||||
template <typename T>
|
||||
void ReadDatasetAttributes(int32 sds_id, PNXdata<T>& data);
|
||||
|
||||
/**
|
||||
* @brief Convert HDF4 data type to H4DataType enum
|
||||
* @param hdf4_type HDF4 numeric type constant (DFNT_*)
|
||||
* @return H4DataType enum value
|
||||
*/
|
||||
static H4DataType convertHdf4Type(int32 hdf4_type);
|
||||
|
||||
/**
|
||||
* @brief Convert H4DataType enum to HDF4 data type
|
||||
* @param dataType H4DataType enum value
|
||||
* @return HDF4 numeric type constant (DFNT_*)
|
||||
*/
|
||||
static int32 convertToHdf4Type(H4DataType dataType);
|
||||
};
|
||||
|
||||
}
|
||||
#endif // HAVE_HDF4
|
||||
|
||||
#endif // _PNEXUS_H_
|
||||
|
||||
Reference in New Issue
Block a user