59 Commits
root6 ... nxs

Author SHA1 Message Date
6a41458310 start working on the deadtime correction. 2026-02-08 15:34:22 +01:00
d70fd34345 improved NeXus docu. 2026-02-08 09:11:36 +01:00
3858cc723a improved docu for HDF4/5. 2026-02-07 21:43:34 +01:00
a6f5b956bf adopt HDF4 support for proper hierarchical writing of the data. 2026-02-07 21:26:35 +01:00
86ecfc84af fixed a copy/paste error. 2026-02-07 21:24:14 +01:00
8cb4fc7221 clean up HDF4 in PNeXus. First implementation for HDF4 IDF1/2 write. Compiles, but still some issues. 2026-02-07 20:54:09 +01:00
95d087164d first full mandatory HDF5 IDF V2 writer. 2026-02-07 20:17:23 +01:00
8f3ad0c61d PNeXus now handles std::vector<> attributes new correctly. HDF4/5 now is using int. 2026-02-07 20:00:27 +01:00
49d42c93ba more work on HDF5 IDF V2. 2026-02-07 19:34:26 +01:00
df379b834e first full version for HDF5 IDF V1 write. 2026-02-07 17:25:52 +01:00
3bb004ea2d more work on the NeXus write routines. 2026-02-07 11:31:11 +01:00
fc478d27c7 make sure that the config.h is accessible for the PMusr lib. 2026-02-07 11:29:48 +01:00
c690965025 add a function in the NeXus lib which gives the time in ISO8601. 2026-02-07 11:28:38 +01:00
300c9200df start implementing the NeXus write routines, needed by any2many. 2026-02-07 08:05:42 +01:00
4dcef1a835 add HDF4/HDF5 library version information, needed for writing. 2026-02-07 08:05:09 +01:00
4519a0b76e add more complete dump info for NeXus. 2026-02-06 18:08:37 +01:00
3aecdbf0a8 added the missing sample information when reading NeXus IDF V2. 2026-02-06 15:15:10 +01:00
dfa8852cfe removed debug tag. 2026-02-06 15:14:25 +01:00
29fbb4a62b replace the NeXus IDF 2 example. 2026-02-06 14:03:55 +01:00
de8b02b94d more complete doxygen docu. 2026-02-06 12:43:55 +01:00
dd2f743b3a added docu by Claude for PNeXus. 2026-02-06 08:45:58 +01:00
d5dbc12175 NeXus HDF4/HDF5 IDF V1: read 'frames_good' 2026-02-05 13:29:27 +01:00
643be9738f fixed wrong path in NeXus IDF V2. 2026-02-05 12:59:10 +01:00
88b5e492dd NeXus IDF V2 detector_1 -> instrument/detector_1 where possible. 2026-02-05 12:08:40 +01:00
810306cb2a first full IDF V2 implementation. 2026-02-05 10:59:15 +01:00
43cb8b2460 start with the implementation of NeXus IDF V2. 2026-02-04 19:48:38 +01:00
ceb9673330 read deadtime parameters for IDF V1. 2026-02-04 17:57:48 +01:00
da0b356e3b more work on the deadtime correction on the msr-file side. 2026-02-04 13:29:07 +01:00
b262ee33c5 start implementing with the deadtime correction, if present 2026-02-04 13:20:10 +01:00
12888be4c9 add deadtime correction related params. 2026-02-04 11:06:56 +01:00
867ac4895b switched to HDF4/HDF5 template loading in order to simplify the code. 2026-02-04 09:26:49 +01:00
a6c9120d06 check for IDF 1/2. 2026-02-03 17:38:56 +01:00
417901e271 HDF4 handling completed. 2026-02-03 16:17:06 +01:00
8d1dcef2de add more HDF4 header info: counts. 2026-02-03 08:03:13 +01:00
30fbd8eb67 fixed typo, and added file pointer checks. 2026-02-02 19:14:14 +01:00
76dbd757e3 dump_header can now handle HDF4/HDF5 NeXus files, without the NeXus library. 2026-02-02 19:08:12 +01:00
c894c21bf3 add more HDF4 header info. 2026-02-02 08:02:41 +01:00
008ca7210a add more HDF4 header info. 2026-02-01 19:49:55 +01:00
60f11dfc0e add more HDF4 header info. 2026-02-01 18:55:49 +01:00
3aaca28c87 start populating HDF4 header info. 2026-02-01 17:54:02 +01:00
d4f0855b19 fix git-revision.h generation: output to build tree and add missing dependencies
Generate git-revision.h into CMAKE_BINARY_DIR/src/ (which is in the
include path) instead of the source tree. Remove the header from
add_executable() source lists, and add missing add_dependencies on
git_revision for all Qt5/Qt6 targets.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 19:59:47 +01:00
00c980af68 generate git-revision.h at build time instead of configure time
Replace execute_process with add_custom_target so the git revision
check runs on every build, not just on cmake configure.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 19:40:33 +01:00
fb9d6e917c proper TDirectory handling for the histos. 2026-01-29 19:40:20 +01:00
2eb0cf28d5 fixed missing TDirectory handling of RunSummary in dump_header.cpp 2026-01-29 19:40:10 +01:00
65efb389c3 first test to read hdf4/hdf5 directly. 2026-01-25 16:20:10 +01:00
83c8f6630c 2nd spot for cmake version check for policy setting. 2026-01-25 14:50:23 +01:00
3c02c6073a cmake version check for policy setting. 2026-01-25 14:43:49 +01:00
b3e4d247f0 add HDF4/HDF5 example programs. 2026-01-25 14:07:36 +01:00
6aaed94adf add doxygen file comment. 2026-01-25 12:05:04 +01:00
c3e9c03920 added HDF5 ISIS NeXus class handling. 2026-01-25 11:15:49 +01:00
909fa6519d added HDF4 ISIS NeXus class handling. 2026-01-25 10:51:23 +01:00
3eea73f07a stub for new NeXus file handling. Not much is working yet. 2026-01-25 08:26:43 +01:00
f66c832d56 updated the copyright info. 2026-01-25 07:45:44 +01:00
990e280c8f set cmake Boost find policy. Removed NeXus library find from cmake, since it will not be used anymore. 2026-01-25 07:28:47 +01:00
7615e791d3 version update of the doxygen config file. 2026-01-24 18:30:18 +01:00
394ea01d37 further playing with the Prefs dialog. 2026-01-24 18:30:06 +01:00
d19d7b59c8 further playing with the Prefs dialog. 2026-01-24 18:29:46 +01:00
7dc0a237dc further playing with the Prefs dialog. 2026-01-24 18:29:37 +01:00
1b4b9cc238 increased size of prefs dialog, since it seems too small for the newest qt6 version, especially on macOS. 2026-01-24 18:29:28 +01:00
35 changed files with 14021 additions and 6853 deletions

View File

@@ -6,7 +6,7 @@ if (CMAKE_VERSION GREATER_EQUAL "3.3")
cmake_policy(SET CMP0167 NEW) cmake_policy(SET CMP0167 NEW)
endif () endif ()
project(musrfit VERSION 1.9.10 LANGUAGES C CXX) project(musrfit VERSION 1.9.11 LANGUAGES C CXX)
#--- musrfit specific options ------------------------------------------------- #--- musrfit specific options -------------------------------------------------
option(nexus "build optional NeXus support. Needed for ISIS" OFF) option(nexus "build optional NeXus support. Needed for ISIS" OFF)
@@ -211,14 +211,41 @@ if (qt_based_tools)
endif (qt_version STREQUAL 3) endif (qt_version STREQUAL 3)
endif (qt_based_tools) endif (qt_based_tools)
#--- if NeXus check also for HDF4, HDF5, and MXML ----------------------------- #--- if NeXus check also for HDF4 (optional), HDF5 ----------------------------
if (nexus) if (nexus)
find_package(HDF5 COMPONENTS CXX REQUIRED) find_package(HDF5 COMPONENTS CXX REQUIRED)
if (HAVE_HDF4) 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) add_definitions(-DHAVE_HDF4)
endif (HAVE_HDF4) endif (HAVE_HDF4)
find_package(NEXUS REQUIRED)
add_definitions(-DPNEXUS_ENABLED) add_definitions(-DPNEXUS_ENABLED)
endif (nexus) endif (nexus)
@@ -323,7 +350,6 @@ if (nexus)
message(" HDF4 not present.") message(" HDF4 not present.")
endif (HAVE_HDF4) endif (HAVE_HDF4)
message(" HDF5 found in ${HDF5_INCLUDE_DIRS}, Version: ${HDF5_VERSION}") message(" HDF5 found in ${HDF5_INCLUDE_DIRS}, Version: ${HDF5_VERSION}")
message(" NeXus found in ${NEXUS_INCLUDE_DIR}, Version: ${NEXUS_VERSION_STRING}")
endif (nexus) endif (nexus)
message("") message("")

View File

@@ -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})

View File

@@ -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)

View File

@@ -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)

Binary file not shown.

Binary file not shown.

View File

@@ -1,33 +1,32 @@
nc-ZnO T=80 F=69 Ag_T=100_F=20
############################################################### ###############################################################
FITPARAMETER FITPARAMETER
# No Name Value Step Pos_Error Boundaries # No Name Value Step Pos_Error Boundaries
1 alpha 0.88008 -0.00063 0.00063 1 alpha 1.02825 -0.00097 0.00098
2 asym 0.1708 -0.0017 0.0017 0 0.3 2 asym 0.23163 -0.00083 0.00103 0 0.3
3 phase 3.90 -0.38 0.38 0 100 3 phase 0.000 -0.000 0.011 0 100
4 field 71.003 -0.036 0.036 0 none 4 field 20.310 -0.010 0.010 0 none
5 rate 0.1526 -0.0024 0.0024 0 100 5 rate 0.00031 -0.00031 0.00134 0 100
6 beta 1.231 -0.046 0.047
############################################################### ###############################################################
THEORY THEORY
asymmetry 2 asymmetry 2
TFieldCos 3 fun1 (phase frequency) TFieldCos 3 fun1 (phase frequency)
generExpo 5 6 (rate exponent) simplExpo 5 (rate)
############################################################### ###############################################################
FUNCTIONS FUNCTIONS
fun1 = gamma_mu * par4 fun1 = gamma_mu * par4
############################################################### ###############################################################
RUN data/EMU00005989_v2 EMU ISIS NEXUS (name beamline institute data-file-format) RUN data/emu00139040 EMU ISIS NEXUS (name beamline institute data-file-format)
fittype 2 (asymmetry fit) fittype 2 (asymmetry fit)
alpha 1 alpha 1
map 0 0 0 0 0 0 0 0 0 0 map 0 0 0 0 0 0 0 0 0 0
forward 1-16 forward 1-48
backward 17-32 backward 49-96
backgr.fix 0 0 backgr.fix 0 0
data 40 1500 40 1500 data 10 2048 10 2048
fit 0.2 14 fit 0.2 14
packing 1 packing 1
@@ -39,19 +38,19 @@ SAVE
############################################################### ###############################################################
FOURIER FOURIER
units Gauss # units either 'Gauss', 'MHz', or 'Mc/s' units Gauss # units either 'Gauss', 'Tesla', 'MHz', or 'Mc/s'
fourier_power 10 fourier_power 10
apodization STRONG # NONE, WEAK, MEDIUM, STRONG apodization STRONG # NONE, WEAK, MEDIUM, STRONG
plot REAL # REAL, IMAG, REAL_AND_IMAG, POWER, PHASE plot REAL # REAL, IMAG, REAL_AND_IMAG, POWER, PHASE, PHASE_OPT_REAL
range 0 100 range 0 100
phase par2 phase par2
############################################################### ###############################################################
PLOT 2 (asymmetry plot) PLOT 2 (asymmetry plot)
runs 1 runs 1
range 0 14 -0.22 0.22 range 0 14 -0.32 0.32
view_packing 5 view_packing 10
############################################################### ###############################################################
STATISTIC --- 2012-03-20 10:28:41 STATISTIC --- 2026-02-06 14:00:49
chisq = 796.7, NDF = 846, chisq/NDF = 0.941749 chisq = 1092.3, NDF = 858, chisq/NDF = 1.273055

View File

@@ -1,23 +1,22 @@
nc-ZnO T=80 F=69 Ag_T=100_F=20
############################################################### ###############################################################
FITPARAMETER FITPARAMETER
# No Name Value Step Pos_Error Boundaries # No Name Value Step Pos_Error Boundaries
1 zero 0 0 none 1 zero 0 0 none
2 phase 2.81 -0.30 0.30 0 100 2 phase 0.000000011 -0.000000011 0.005772888 0 100
3 field 70.998 -0.025 0.025 0 none 3 field 20.3391 -0.0085 0.0085 0 none
4 asym 0.1700 -0.0011 0.0012 0 0.3 4 asym 0.23461 -0.00051 0.00051 0 0.3
5 rate 0.1523 -0.0017 0.0017 0 100 5 rate 0.0239 -0.0040 0.0035 0 100
6 beta 1.255 -0.033 0.033 6 Norm_L 1151.24 -0.53 0.53
7 Norm_L 2410.44 -0.83 0.83 7 BG_L 0 0 none 0 none
8 BG_L 0 0 none 0 none 8 Norm_R 1178.60 -0.58 0.58 0 none
9 Norm_R 2121.43 -0.77 0.77 0 none 9 BG_R 0 0 none 0 none
10 BG_R 0 0 none 0 none 10 relPhase 178.49 -0.20 0.20 0 none
11 relPhase 182.29 -0.31 0.31 0 none
############################################################### ###############################################################
THEORY THEORY
asymmetry 4 asymmetry 4
generExpo 5 6 (rate exponent) simpleGss 5 (rate)
TFieldCos fun1 fun2 (phase frequency) TFieldCos fun1 fun2 (phase frequency)
############################################################### ###############################################################
@@ -28,22 +27,25 @@ fun2 = gamma_mu * par3
############################################################### ###############################################################
GLOBAL GLOBAL
fittype 0 (single histogram fit) fittype 0 (single histogram fit)
data 40 1500 data 5 2048
fit 0.2 14 t0 10.0
deadtime-cor file
fit 0.144 30
packing 1 packing 1
############################################################### ###############################################################
RUN data/EMU00005989_v2 XXXX ISIS NEXUS (name beamline institute data-file-format) RUN data/emu00139040 EMU ISIS NEXUS (name beamline institute data-file-format)
norm 7 norm 6
backgr.fit 8 backgr.fit 7
map 1 0 0 0 0 0 0 0 0 0 map 1 0 0 0 0 0 0 0 0 0
forward 1-16 forward 1-48
#deadtime-cor file
RUN data/EMU00005989_v2 XXXX ISIS NEXUS (name beamline institute data-file-format) RUN data/emu00139040 XXXX ISIS NEXUS (name beamline institute data-file-format)
norm 9 norm 8
backgr.fit 10 backgr.fit 9
map 11 0 0 0 0 0 0 0 0 0 map 10 0 0 0 0 0 0 0 0 0
forward 17-32 forward 49-96
############################################################### ###############################################################
COMMANDS COMMANDS
@@ -59,15 +61,15 @@ fourier_power 11
apodization STRONG # NONE, WEAK, MEDIUM, STRONG apodization STRONG # NONE, WEAK, MEDIUM, STRONG
plot REAL # REAL, IMAG, REAL_AND_IMAG, POWER, PHASE, PHASE_OPT_REAL plot REAL # REAL, IMAG, REAL_AND_IMAG, POWER, PHASE, PHASE_OPT_REAL
range 0 200 range 0 200
phase parR2 par11 phase parR2, par10
############################################################### ###############################################################
PLOT 0 (single histo plot) PLOT 0 (single histo plot)
lifetimecorrection lifetimecorrection
runs 1 2 runs 1 2
range 0 14 -0.22 0.22 range 0 20 -0.35 0.35
view_packing 2 #view_packing 10
############################################################### ###############################################################
STATISTIC --- 2019-03-12 18:08:05 STATISTIC --- 2026-02-08 15:32:12
maxLH = 2585.1, NDF = 1696, maxLH/NDF = 1.524236 maxLH = 4233.1, NDF = 3725, maxLH/NDF = 1.136412

View File

@@ -38,7 +38,7 @@ PROJECT_NAME = musrfit
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 1.9.10 PROJECT_NUMBER = 1.9.11
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
@@ -923,6 +923,18 @@ INPUT = musrfit.dox \
../src/classes/PUserFcn.cpp \ ../src/classes/PUserFcn.cpp \
../src/external/MusrRoot/TMusrRunHeader.h \ ../src/external/MusrRoot/TMusrRunHeader.h \
../src/external/MusrRoot/TMusrRunHeader.cpp \ ../src/external/MusrRoot/TMusrRunHeader.cpp \
../src/external/nexus/PNeXus.h \
../src/external/nexus/PNeXus.cpp \
../src/external/MuSR_software/Class_MuSR_PSI/MuSR_td_PSI_bin.h \
../src/external/MuSR_software/Class_MuSR_PSI/MuSR_td_PSI_bin.cpp \
../src/external/mud/src/mud.h \
../src/external/mud/src/mud_all.c \
../src/external/mud/src/mud.c \
../src/external/mud/src/mud_encode.c \
../src/external/mud/src/mud_friendly.c \
../src/external/mud/src/mud_gen.c \
../src/external/mud/src/mud_new.c \
../src/external/mud/src/mud_tri_ti.c \
../src/addRun.cpp \ ../src/addRun.cpp \
../src/any2many.cpp \ ../src/any2many.cpp \
../src/dump_header.cpp \ ../src/dump_header.cpp \
@@ -2241,7 +2253,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator. # recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = PREDEFINED = HAVE_HDF4
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The # tag can be used to specify a list of macro names that should be expanded. The

View File

@@ -138,6 +138,7 @@ target_include_directories(
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src/external/MuSR_software/Class_MuSR_PSI> $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src/external/MuSR_software/Class_MuSR_PSI>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src/external/mud/src> $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src/external/mud/src>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src/external/nexus> $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src/external/nexus>
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
) )
add_library(PUserFcnBase SHARED add_library(PUserFcnBase SHARED
@@ -151,6 +152,7 @@ add_library(PRgeHandler SHARED
) )
#--- set target properties, e.g. version -------------------------------------- #--- set target properties, e.g. version --------------------------------------
target_compile_options(PMusr BEFORE PRIVATE "-DHAVE_CONFIG_H")
set_target_properties(PMusr set_target_properties(PMusr
PROPERTIES PROPERTIES
VERSION ${MUSR_VERSION} VERSION ${MUSR_VERSION}

View File

@@ -814,6 +814,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages)
fout.width(16); fout.width(16);
fout << std::left << "packing"; fout << std::left << "packing";
fout << fGlobal.GetPacking() << std::endl; fout << fGlobal.GetPacking() << std::endl;
} else if (sstr.BeginsWith("deadtime-cor")) {
fout.width(16);
fout << std::left << "deadtime-cor";
fout << fGlobal.GetDeadTimeCorrection() << std::endl;
} else { } else {
fout << str.Data() << std::endl; fout << str.Data() << std::endl;
} }
@@ -1157,6 +1161,10 @@ Int_t PMsrHandler::WriteMsrLogFile(const Bool_t messages)
fout.width(16); fout.width(16);
fout << std::left << "packing"; fout << std::left << "packing";
fout << fRuns[runNo].GetPacking() << std::endl; fout << fRuns[runNo].GetPacking() << std::endl;
} else if (sstr.BeginsWith("deadtime-cor")) {
fout.width(16);
fout << std::left << "deadtime-cor";
fout << fRuns[runNo].GetDeadTimeCorrection() << std::endl;
} else { } else {
fout << str.Data() << std::endl; fout << str.Data() << std::endl;
} }
@@ -3334,6 +3342,20 @@ Bool_t PMsrHandler::HandleGlobalEntry(PMsrLines &lines)
error = true; error = true;
} }
} }
} else if (iter->fLine.BeginsWith("deadtime-cor", TString::kIgnoreCase)) { // deadtime correction
if (tokens->GetEntries() < 2) {
error = true;
} else {
ostr = dynamic_cast<TObjString*>(tokens->At(1));
str = ostr->GetString();
if (!str.CompareTo("no", TString::kIgnoreCase) ||
!str.CompareTo("file", TString::kIgnoreCase) ||
!str.CompareTo("estimate", TString::kIgnoreCase)) {
global.SetDeadTimeCorrection(str);
} else {
error = true;
}
}
} }
// clean up // clean up
@@ -3931,6 +3953,27 @@ Bool_t PMsrHandler::HandleRunEntry(PMsrLines &lines)
} }
} }
// deadtime-correction -----------------------------------
if (iter->fLine.BeginsWith("deadtime-cor", TString::kIgnoreCase)) { // deadtime correction
runLinePresent = false; // this is needed to make sure that a run line is present before and ADDRUN is following
if (tokens->GetEntries() < 2) {
error = true;
} else {
ostr = dynamic_cast<TObjString*>(tokens->At(1));
str = ostr->GetString();
if (!str.CompareTo("no", TString::kIgnoreCase) ||
!str.CompareTo("file", TString::kIgnoreCase) ||
!str.CompareTo("estimate", TString::kIgnoreCase)) {
param.SetDeadTimeCorrection(str);
} else {
error = true;
}
}
}
// xy-data ----------------------------------------------- // xy-data -----------------------------------------------
if (line.BeginsWith("xy-data", TString::kIgnoreCase)) { if (line.BeginsWith("xy-data", TString::kIgnoreCase)) {

View File

@@ -721,6 +721,22 @@ PRawRunDataSet* PRawRunData::GetDataSet(const UInt_t idx, Bool_t wantHistoNo)
return fData.GetSet(idx); return fData.GetSet(idx);
} }
//--------------------------------------------------------------------------
// DeadTimeCorrectionReady (public)
//--------------------------------------------------------------------------
/**
* <p>Checks if deadtime correction information is sufficient to apply it.
* This means that fNumberOfGoodFrames must be present and the deadtime
* parameter vector.
*
* @return true if ready to apply deadtime correctio, false otherwise
*/
const Bool_t PRawRunData::DeadTimeCorrectionReady()
{
if ((fNumberOfGoodFrames > 0) && (fDeadTimeParam.size() > 0))
return true;
return false;
}
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// SetRingAnode (public) // SetRingAnode (public)

File diff suppressed because it is too large Load Diff

View File

@@ -1069,6 +1069,38 @@ Bool_t PRunSingleHisto::PrepareData()
forward[i] = *runData->GetDataBin(histoNo[i]); forward[i] = *runData->GetDataBin(histoNo[i]);
} }
// check if a dead time correction has to be done
// first check the global block
TString dtcg = fMsrInfo->GetMsrGlobal()->GetDeadTimeCorrection();
Int_t dtcg_tag = 0; // 0=no, 1=file, 2=estimate
if (dtcg.Contains("file", TString::kIgnoreCase)) {
dtcg_tag = 1;
} else if (dtcg.Contains("estimate", TString::kIgnoreCase)) {
dtcg_tag = 2;
}
// now check each run
TString dtcr{"no"};
Bool_t needToCheck{true};
for (UInt_t i=0; i<histoNo.size(); i++) {
dtcr = fRunInfo->GetDeadTimeCorrection();
if (dtcr.Contains("file", TString::kIgnoreCase) || (dtcg_tag != 0)) {
if (runData->DeadTimeCorrectionReady()) {
needToCheck = false;
// Dead time correction: n_true = n_obs / (1 - n_obs * t_dt / (good_frames * dt))
Double_t n_true;
Int_t gf = runData->GetNumberOfGoodFrames();
std::vector<float> t_dt = runData->GetDeadTimeParam();
for (UInt_t j=0; j<forward[i].size(); j++) {
n_true = forward[i][j] / (1.0 - forward[i][j] * t_dt[histoNo[i]] / (gf * fTimeResolution));
forward[i][j] = n_true;
}
}
}
if ((dtcr.Contains("estimate", TString::kIgnoreCase) || (dtcg_tag != 0)) && needToCheck) {
std::cerr << "as35> run: deadtime correction: " << dtcr.Data() << ", global: " << dtcg_tag << std::endl;
}
}
// check if there are runs to be added to the current one // check if there are runs to be added to the current one
if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present if (fRunInfo->GetRunNameSize() > 1) { // runs to be added present
PRawRunData *addRunData; PRawRunData *addRunData;

View File

@@ -37,6 +37,7 @@
#include <cstring> #include <cstring>
#include <ctime> #include <ctime>
#include <cassert> #include <cassert>
#include <cstddef>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@@ -365,15 +366,39 @@ int dump_header_root(const std::string fileName, const bool summary, const bool
int dump_header_nexus(const std::string fileName, const bool counts) { int dump_header_nexus(const std::string fileName, const bool counts) {
#ifdef PNEXUS_ENABLED #ifdef PNEXUS_ENABLED
std::unique_ptr<PNeXus> nxs_file = std::make_unique<PNeXus>(fileName.c_str()); nxs::HDFType type = nxs::checkHDFType(fileName);
if (nxs_file->IsValid(false)) { // check for type errors, missing enabled HDF4
nxs_file->Dump(counts); switch (type) {
} else { case nxs::HDFType::HDF4:
std::cerr << std::endl; std::cout << std::endl << ">> PRunDataHandler::ReadNexusFile(): HDF4 file." << std::endl;
std::cerr << "**ERROR** found invalid NeXus file." << std::endl; #ifndef HAVE_HDF4
std::cerr << std::endl; std::cerr << std::endl << ">> PRunDataHandler::ReadNexusFile(): **ERROR**, HDF4 is not enabled." << std::endl;
return 1; return 1;
#endif
break;
case nxs::HDFType::HDF5:
std::cout << std::endl << ">> PRunDataHandler::ReadNexusFile(): HDF5 file." << std::endl;
break;
case nxs::HDFType::Unknown:
std::cerr << std::endl << ">> PRunDataHandler::ReadNexusFile(): Not a valid NeXus file." << std::endl;
return 1;
}
if (type == nxs::HDFType::HDF4) {
#ifdef HAVE_HDF4
std::unique_ptr<nxH4::PNeXus> nxs_file = std::make_unique<nxH4::PNeXus>(fileName);
if (nxs_file == nullptr) {
std::cerr << std::endl << "**ERROR** allocation of nxH4::PNeXus object failed." << std::endl;
}
nxs_file->Dump();
#endif
} else { // HDF5
std::unique_ptr<nxH5::PNeXus> nxs_file = std::make_unique<nxH5::PNeXus>(fileName);
if (nxs_file == nullptr) {
std::cerr << std::endl << "**ERROR** allocation of nxH5::PNeXus object failed." << std::endl;
}
nxs_file->Dump();
} }
#else #else
std::cout << std::endl << "NeXus not enabled, hence the header information cannot be dumped." << std::endl << std::endl; std::cout << std::endl << "NeXus not enabled, hence the header information cannot be dumped." << std::endl << std::endl;

View File

@@ -7,7 +7,7 @@ set(prefix "${CMAKE_INSTALL_PREFIX}")
set(exec_prefix "\$\{prefix\}") set(exec_prefix "\$\{prefix\}")
set(libdir "\$\{exec_prefix\}/lib") set(libdir "\$\{exec_prefix\}/lib")
set(includedir "\$\{prefix\}/include") set(includedir "\$\{prefix\}/include")
set(PNEXUS_VERSION "0.9.0") set(PNEXUS_VERSION "1.0.0")
set(PNEXUS_LIBRARY_NAME "PNeXus") set(PNEXUS_LIBRARY_NAME "PNeXus")
configure_file("PNeXus.pc.in" "PNeXus.pc" @ONLY) configure_file("PNeXus.pc.in" "PNeXus.pc" @ONLY)
@@ -28,7 +28,13 @@ target_include_directories(
) )
#--- add library dependencies ------------------------------------------------- #--- add library dependencies -------------------------------------------------
target_link_libraries(PNeXus ${NEXUS_LIBRARY}) if (HAVE_HDF4)
set(HDF_LIBS ${HDF4_LIBRARIES} ${HDF5_LIBRARIES})
else (HAVE_HDF4)
set(HDF_LIBS ${HDF5_LIBRARIES})
endif (HAVE_HDF4)
message(STATUS "++>> HDF_LIBS: ${HDF_LIBS}")
target_link_libraries(PNeXus ${HDF_LIBS} ${ROOT_LIBRARIES})
#--- install PNeXus solib ----------------------------------------------------- #--- install PNeXus solib -----------------------------------------------------
install(TARGETS PNeXus DESTINATION lib) install(TARGETS PNeXus DESTINATION lib)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,69 +0,0 @@
2011/04/13 -- BMW
Under Cygwin of all the required libraries for NeXus only HDF5 is available.
The packages <hdf5> and <libhdf5-devel> can be installed through the Cygwin setup.
One should also make sure that <bison>, <flex> and a package containing "/usr/lib/librpc.a" (e.g. <sunrpc> = 4.0-3) are installed.
All other libraries have to be built from the sources:
* JPEG-6b
URL: http://www.hdfgroup.org/ftp/lib-external/jpeg/src/jpegsrc.v6b.tar.gz
Configure options: --prefix=/usr/local --enable-static
* MXML 2.5
URL: http://ftp.easysw.com/pub/mxml/2.5/mxml-2.5.tar.gz
Configure options: --prefix=/usr/local --enable-static
* HDF 4.2.5
URL: http://www.hdfgroup.org/ftp/HDF/HDF_Current/src/hdf-4.2.5.tar.gz
Configure options: --prefix=/usr/local --enable-static --disable-fortran --with-jpeg=/usr/local
* NeXus 4.2.1
URL: http://download.nexusformat.org/kits/nexus-4.2.1.tar.gz
Configure options: --prefix=/usr/local --with-hdf4=/usr/local --with-hdf5=/usr --with-xml=/usr/local
The version numbers and source-code locations might of course change with time but should be easily adjustable.
If one is confident enough that all requirements to build the above packages are fullfilled, one could also try to run the following lines as a script.
However, there is absolutely no warranty that it works.
---
#!/bin/sh
cd
mkdir nexus
cd nexus
curl http://www.hdfgroup.org/ftp/lib-external/jpeg/src/jpegsrc.v6b.tar.gz -G | tar xz
cd jpeg-6b
./configure --prefix=/usr/local --enable-static
make
make install
cd ..
curl http://ftp.easysw.com/pub/mxml/2.5/mxml-2.5.tar.gz -G | tar xz
cd mxml-2.5
./configure --prefix=/usr/local --enable-static
make
make install
cd ..
curl http://www.hdfgroup.org/ftp/HDF/HDF_Current/src/hdf-4.2.5.tar.gz -G | tar xz
cd hdf-4.2.5
./configure --prefix=/usr/local --enable-static --disable-fortran --with-jpeg=/usr/local
make
make install
cd ..
curl http://download.nexusformat.org/kits/nexus-4.2.1.tar.gz -G | tar xz
./configure --prefix=/usr/local --with-hdf4=/usr/local --with-hdf5=/usr --with-xml=/usr/local
make
make install
---
In order to obtain NeXus support in musrfit after installing the above libraries, musrfit has to be configured with the options
"--enable-static --enable-NeXus"
Further information on how to set up musrfit under Cygwin can be found here:
https://intranet.psi.ch/MUSR/MusrFitSetup#A_4_MS_Windows
http://lmu.web.psi.ch/facilities/software/musrfit/user/intranet.psi.ch/MUSR/MusrFitSetup.html#A_4_MS_Windows
EOF

1206
src/external/nexus/Usage.md vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,149 @@
# - h4nexus
cmake_minimum_required(VERSION 3.26)
project(h4nexus VERSION 0.1.0 LANGUAGES CXX)
#--- set C++ standard ---------------------------------------------------------
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
#--- set a default build type if none was specified ---------------------------
set(default_build_type "Release")
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE
STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif ()
#--- check for pkg-config -----------------------------------------------------
find_package(PkgConfig REQUIRED)
#--- check for git ------------------------------------------------------------
find_package(Git 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})
#--- check for HDF5 -----------------------------------------------------------
find_package(HDF5 REQUIRED COMPONENTS CXX)
if(NOT HDF5_FOUND)
message(FATAL_ERROR "HDF5 C++ library not found")
endif()
include_directories(${HDF5_INCLUDE_DIRS})
#--- check for ROOT -----------------------------------------------------------
find_package(ROOT 6.36 REQUIRED COMPONENTS Minuit2)
if (ROOT_miniut2_FOUND)
execute_process(COMMAND root-config --bindir OUTPUT_VARIABLE ROOT_BINDIR)
string(STRIP ${ROOT_BINDIR} ROOT_BINDIR)
execute_process(COMMAND root-config --version OUTPUT_VARIABLE ROOT_VERSION)
string(STRIP ${ROOT_VERSION} ROOT_VERSION)
message("-- Found ROOT: ${ROOT_BINDIR} (found version: ${ROOT_VERSION})")
#---Define useful ROOT functions and macros (e.g. ROOT_GENERATE_DICTIONARY)
include(${ROOT_USE_FILE})
endif (ROOT_miniut2_FOUND)
#--- all checks done -> feed config.h -----------------------------------------
set(HAVE_CONFIG_H 1 CACHE INTERNAL "config.h is available")
configure_file(${CMAKE_SOURCE_DIR}/cmake/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
#--- check if project source is a git repo ------------------------------------
if (EXISTS "${CMAKE_SOURCE_DIR}/.git/HEAD")
message(STATUS "is a git repo")
set(IS_GIT_REPO 1)
else ()
message(STATUS "is NOT a git repo")
set(IS_GIT_REPO 0)
endif ()
#--- start create git-revision.h ----------------------------------------------
if (IS_GIT_REPO)
execute_process(COMMAND sh ${CMAKE_SOURCE_DIR}/git_revision.sh ${CMAKE_BINARY_DIR})
set(HAVE_GIT_REV_H "-DHAVE_GIT_REV_H")
set(GIT_REV_H "git-revision.h")
else (IS_GIT_REPO)
set(HAVE_GIT_REV_H "")
set(GIT_REV_H "")
endif (IS_GIT_REPO)
#--- end create git-revision.h ------------------------------------------------
#--- write summary of the installation
cmake_host_system_information(RESULT PROCESSOR QUERY PROCESSOR_DESCRIPTION)
message("")
message("|-----------------------------------------------------------------------|")
message("| |")
message("| Summary |")
message("| |")
message("|-----------------------------------------------------------------------|")
message("")
message(" System: ${CMAKE_HOST_SYSTEM_NAME} ${CMAKE_SYSTEM_PROCESSOR} - ${CMAKE_HOST_SYSTEM_VERSION}")
message(" Processor: ${PROCESSOR} (${CMAKE_SYSTEM_PROCESSOR})")
message(" ----------")
message("")
message(" h4nexus Version: ${h4nexus_VERSION}")
message(" ----------------")
message("")
message(" Build Type: ${CMAKE_BUILD_TYPE}")
message(" -----------")
message("")
message(" Requirements:")
message(" -------------")
message("")
message(" HDF4 found in ${HDF4_INCLUDE_DIRS}")
message(" ROOT found in ${ROOT_INCLUDE_DIRS}, Version: ${ROOT_VERSION}")
message("")
message(" Installation directories:")
message(" -------------------------")
message("")
message(" Programs : ${CMAKE_INSTALL_PREFIX}/bin")
message("")
message("-------------------------------------------------------------------------")
message("")
#--- h4nexus executable -------------------------------------------------------
add_executable(h4nexus
../../PNeXus.cpp
main.cpp)
target_compile_options(h4nexus BEFORE PRIVATE "-DHAVE_HDF4 -DHAVE_CONFIG_H" ${HAVE_GIT_REV_H})
target_include_directories(h4nexus
BEFORE PRIVATE
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/build>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/../..>
$<BUILD_INTERFACE:${ROOT_INCLUDE_DIRS}>
)
target_link_libraries(h4nexus ${HDF4_LIBRARIES} ${HDF5_LIBRARIES} ${ROOT_LIBRARIES})

View File

@@ -0,0 +1,7 @@
/* config.h.in. Generated from CMakeLists.txt */
/* Define to 1 if you have the <config.h> file. */
#cmakedefine HAVE_CONFIG_H @HAVE_CONFIG_H@
/* h4nexus version */
#define H4NEXUS_VERSION "@h4nexus_VERSION@"

View File

@@ -0,0 +1,155 @@
# h4nexus - handle muSR-NeXus files via HDF4 only
## Contents
Tests and classes to handle muSR-NeXus files directly via the HDF4 C API.
This project provides the same API as h5nexus but uses HDF4 instead of HDF5 for handling NeXus files.
## Features
- **Read and write NeXus HDF4 files** with a clean C++ API
- **Case-insensitive path lookup** for datasets and groups
- **Type-safe data handling** using template classes
- **Dead time correction calculation** for muon detector data using ROOT Minuit2
- **Compatible API with h5nexus** for easy migration
## Key Classes
- `nxH4::PNeXus` - Main class for reading/writing NeXus HDF4 files
- `nxH4::PNXdata<T>` - Template class for storing dataset content with attributes
- `nxH4::PNeXusDeadTime` - Dead time correction calculator for muon detector data
## Requirements
- CMake >= 3.26
- C++17 compatible compiler
- HDF4 library (libhdf4-dev or hdf-devel)
- ROOT >= 6.36 with Minuit2 component
- pkg-config
## Building
```bash
mkdir build
cd build
cmake ..
make
```
## Installation
```bash
make install
```
This will install:
- Library: `libh4nexus.so` in `${CMAKE_INSTALL_PREFIX}/lib`
- Executable: `h4nexus` in `${CMAKE_INSTALL_PREFIX}/bin`
- Header: `PNeXus.h` in `${CMAKE_INSTALL_PREFIX}/include/h4nexus`
## Usage
### Command Line
```bash
# Display help
h4nexus --help
# Read and display a NeXus HDF4 file
h4nexus --fn input.nxs
# Read with debug output
h4nexus --fn input.nxs --debug
# Calculate dead time corrections
h4nexus --fn input.nxs --dead_time_estimate
# Write output file
h4nexus --fn input.nxs --out output.nxs
```
### Programmatic Usage
```cpp
#include <h4nexus/PNeXus.h>
// Read a NeXus file
nxH4::PNeXus nexus("data.nxs");
// Access datasets
auto counts_data = nexus.GetDataset<int>("/raw_data_1/detector_1/counts");
const auto& counts = counts_data.GetData();
const auto& dims = counts_data.GetDimensions();
// Dump file contents
nexus.Dump();
// Write to new file
nexus.WriteNexusFile("output.nxs", 2); // IDF version 2
```
### Creating Files from Scratch
```cpp
nxH4::PNeXus nxs_out;
// Add datasets
std::vector<int> counts(16*66000, 0);
nxs_out.AddDataset<int>("/raw_data_1/detector_1/counts",
counts, {1, 16, 66000},
nxH4::H4DataType::INT32);
// Add attributes
nxs_out.AddDatasetAttribute<int>("/raw_data_1/detector_1/counts",
"units", std::string("counts"));
// Add group attributes
nxs_out.AddGroupAttribute("/raw_data_1", "NX_class", std::string("NXentry"));
// Write file
nxs_out.WriteNexusFile("output.nxs");
```
## API Compatibility with h5nexus
The h4nexus API is designed to be compatible with h5nexus. The main differences are:
- Namespace: `nxH4::` instead of `nxH5::`
- Data types: `H4DataType` enum instead of `H5::DataType`
- Dimensions: Uses `uint32_t` instead of `hsize_t`
Code migration typically requires only:
1. Changing namespace from `nxH5` to `nxH4`
2. Changing `H5::PredType::NATIVE_INT` to `nxH4::H4DataType::INT32` (etc.)
3. Changing dimension types from `hsize_t` to `uint32_t`
## Supported Data Types
- `H4DataType::INT32` - 32-bit signed integer
- `H4DataType::FLOAT32` - 32-bit floating point
- `H4DataType::FLOAT64` - 64-bit floating point
- `H4DataType::CHAR8` - 8-bit character/string
- `H4DataType::UINT32` - 32-bit unsigned integer
- `H4DataType::INT16` - 16-bit signed integer
- `H4DataType::UINT16` - 16-bit unsigned integer
- `H4DataType::INT8` - 8-bit signed integer
- `H4DataType::UINT8` - 8-bit unsigned integer
## Differences from HDF5
HDF4 has some limitations compared to HDF5:
- No true hierarchical groups (simulated using naming conventions)
- Less flexible attribute handling
- Different maximum name lengths
- C API instead of C++ API
The h4nexus library abstracts these differences to provide a similar interface to h5nexus.
## License
GNU General Public License v2 (GPLv2)
## Contacts
Andreas Suter <andreas.suter@psi.ch>

View File

@@ -0,0 +1,35 @@
#!/bin/bash
# Script to create git-revision.h with current git information
# Usage: git_revision.sh [output_directory]
output_dir="${1:-.}"
output_file="${output_dir}/git-revision.h"
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo "Not in a git repository, skipping git-revision.h generation"
exit 0
fi
# Get git information
git_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
git_hash=$(git rev-parse --short HEAD 2>/dev/null)
git_date=$(git log -1 --format=%cd --date=short 2>/dev/null)
# Create header file
cat > "$output_file" << EOF
// This file is auto-generated by git_revision.sh
// Do not edit manually
#ifndef GIT_REVISION_H
#define GIT_REVISION_H
#define GIT_BRANCH "$git_branch"
#define GIT_HASH "$git_hash"
#define GIT_DATE "$git_date"
#endif // GIT_REVISION_H
EOF
echo "Generated $output_file"

View File

@@ -0,0 +1,447 @@
/***************************************************************************
main.cpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
***************************************************************************/
/***************************************************************************
* Copyright (C) 2007-2026 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
/**
* @file main.cpp
* @brief Command-line interface for the h4nexus NeXus HDF4 file reader/writer
*
* This file contains the main() function and command-line interface for the
* h4nexus program. It provides functionality to:
* - Read and display NeXus HDF4 files
* - Write NeXus HDF4 files using the PNXdata approach
* - Calculate dead time corrections for muon detector data
*
* **Command-Line Options:**
* - --fn <file>: Input NeXus HDF4 file (required)
* - --out <file>: Output NeXus HDF4 file (optional)
* - --debug, -d: Enable debug output
* - --dead_time_estimate, -dt: Calculate dead time corrections
* - --help, -h: Display help message
* - --version, -v: Display version information
*
* @author Andreas Suter
* @date 2007-2026
* @copyright GNU General Public License v2
* @version 1.0
*
* @see nxH4::PNeXus
* @see nxH4::PNeXusDeadTime
*/
#include <cstring>
#include <iostream>
#include <string>
#include <memory>
#include <ctime>
#include <mfhdf.h>
#include "PNeXus.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_GIT_REV_H
#include "git-revision.h"
#endif
//-----------------------------------------------------------------------------
/**
* @brief Display command-line syntax and help information
*
* Prints the usage syntax and available command-line options for the h4nexus
* program to stdout and exits the program.
*/
void h4nexus_syntax() {
std::cout << std::endl;
std::cout << "usage: h4nexus [--help | -h] |" << std::endl;
std::cout << " [--version | -v] |" << std::endl;
std::cout << " --fn <fln> [--debug | -d]" << std::endl;
std::cout << " [--dead_time_estimate | -dt]]" << std::endl;
std::cout << " [--out <fout>]" << std::endl;
std::cout << std::endl;
std::cout << "options:" << std::endl;
std::cout << " --help, -h: this help." << std::endl;
std::cout << " --version, -v: version of h4nexus." << std::endl;
std::cout << " --fn <fln>: nexus hdf4 input file name <fn>." << std::endl;
std::cout << " --dead_time_estimate, -dt: dead time estimate for the read hdf4 nexus file." << std::endl;
std::cout << " --debug, -d: print additional debug information." << std::endl;
std::cout << " --out <fout>: write the required datasets of a nexus hdf4 file to file " << std::endl;
std::cout << " with name <fout>. Only makes sense together with the option --fn <fln>." << std::endl;
std::cout << std::endl;
exit(0);
}
//-----------------------------------------------------------------------------
/**
* @brief Calculate dead time corrections for muon detector data
*
* Estimates dead time corrections for each detector in the NeXus file using
* the PNeXusDeadTime class and ROOT Minuit2 minimization.
*
* @param nxs Pointer to the PNeXus object containing the data
* @param debug If true, print additional debug information
*
* @see nxH4::PNeXusDeadTime
*/
void h4nexus_deadTimeEstimate(const nxH4::PNeXus *nxs, bool debug)
{
if (debug) {
std::cout << std::endl;
std::cout << std::endl << "+++++++++++++++++++";
std::cout << std::endl << "in deadTimeEstimate";
std::cout << std::endl << "+++++++++++++++++++";
std::cout << std::endl;
}
nxH4::PNeXusDeadTime ndt(nxs, debug);
auto dims = ndt.GetDimensions();
for (unsigned int i=0; i<dims[1]; i++) {
ndt.minimize(i);
}
}
//-----------------------------------------------------------------------------
/**
* @brief Write NeXus HDF4 file using the PNXdata approach
*
* Writes all datasets from the PNeXus data map to a new NeXus HDF4 file.
* This function uses the WriteNexusFile() method to create a complete
* NeXus file with all groups, datasets, and attributes.
*
* @param nxs Pointer to the PNeXus object containing the data to write
* @param outFileName Output filename for the NeXus HDF4 file
* @param debug If true, print additional debug information
*
* @note Currently only supports IDF version 2 files
*
* @see nxH4::PNeXus::WriteNexusFile()
*/
void h4nexus_writeTest(const nxH4::PNeXus *nxs, const std::string& outFileName, bool debug)
{
if (debug) {
std::cout << std::endl;
std::cout << "++++++++++++++++++++" << std::endl;
std::cout << "Writing NeXus file" << std::endl;
std::cout << "++++++++++++++++++++" << std::endl;
std::cout << std::endl;
}
if (nxs->GetIdfVersion() == 1) {
std::cerr << "Error: IDF v1 write not yet implemented" << std::endl;
return;
}
// Write using the read object's data
int result = const_cast<nxH4::PNeXus*>(nxs)->WriteNexusFile(outFileName, nxs->GetIdfVersion());
if (result == 0) {
std::cout << "Successfully wrote: " << outFileName << std::endl;
} else {
std::cerr << "Failed to write file: " << outFileName << std::endl;
}
// write data from scratch
std::unique_ptr<nxH4::PNeXus> nxs_out = std::make_unique<nxH4::PNeXus>();
std::vector<int> ival;
std::vector<float> fval;
std::vector<std::string> sval;
// ----------
// raw_data_1
// ----------
// IDF version
ival.push_back(2);
nxs_out->AddDataset<int>("/raw_data_1/IDF_version", ival, {1}, nxH4::H4DataType::INT32);
ival.clear();
// add group attribute to '/raw_data_1'
nxs_out->AddGroupAttribute("/raw_data_1", "NX_class", std::string("NXentry"));
// beamline
sval.push_back("piE3");
nxs_out->AddDataset<std::string>("/raw_data_1/beamline", sval, {1}, nxH4::H4DataType::CHAR8);
sval.clear();
// definition
sval.push_back("muonTD");
nxs_out->AddDataset<std::string>("/raw_data_1/definition", sval, {1}, nxH4::H4DataType::CHAR8);
sval.clear();
// run_number
ival.push_back(1234);
nxs_out->AddDataset<int>("/raw_data_1/run_number", ival, {1}, nxH4::H4DataType::INT32);
ival.clear();
// title
sval.push_back("this is the run title.");
nxs_out->AddDataset<std::string>("/raw_data_1/title", sval, {1}, nxH4::H4DataType::CHAR8);
sval.clear();
// start time
sval.push_back("2026-01-01T01:02:03");
nxs_out->AddDataset<std::string>("/raw_data_1/start_time", sval, {1}, nxH4::H4DataType::CHAR8);
sval.clear();
// end time
sval.push_back("2026-01-01T02:03:42");
nxs_out->AddDataset<std::string>("/raw_data_1/end_time", sval, {1}, nxH4::H4DataType::CHAR8);
sval.clear();
// experiment_identifier - pgroup for PSI
sval.push_back("p18324");
nxs_out->AddDataset<std::string>("/raw_data_1/experiment_identifier", sval, {1}, nxH4::H4DataType::CHAR8);
sval.clear();
// -------------------
// detector_1 (NXdata)
// -------------------
// add group attribute to /raw_data_1/instrument
nxs_out->AddGroupAttribute("/raw_data_1/detector_1", "NX_class", std::string("NXdata"));
// counts
std::vector<int> counts(16*66000, 42); // data 16 histos with length 66000
nxs_out->AddDataset<int>("/raw_data_1/detector_1/counts", counts, {1, 16, 66000}, nxH4::H4DataType::INT32);
// attributes for counts
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "signal", 1);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "axes", std::string("period_index,spectrum_index,raw_time"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "long_name", std::string("positron_counts"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "t0_bin", 2741);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "first_good_bin", 2741);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "last_good_bin", 66000);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "units", std::string("counts"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "target", std::string("/raw_data_1/instrument/detector_1/counts"));
// raw_time
std::vector<float> raw_time(66000, 0.0);
for (unsigned int i=0; i<raw_time.size(); i++)
raw_time[i] = 0.1953125f*1.0e-3*((float)i-2741.0f+0.5f);
nxs_out->AddDataset<float>("/raw_data_1/detector_1/raw_time", raw_time, {66000}, nxH4::H4DataType::FLOAT32);
// attributes raw_time
nxs_out->AddDatasetAttribute<float>("/raw_data_1/detector_1/raw_time", "units", std::string("microseconds"));
nxs_out->AddDatasetAttribute<float>("/raw_data_1/detector_1/raw_time", "target", std::string("/raw_data_1/instrument/detector_1/raw_time"));
// ----------
// instrument
// ----------
// add group attribute to /raw_data_1/instrument
nxs_out->AddGroupAttribute("/raw_data_1/instrument", "NX_class", std::string("NXinstrument"));
// name
sval.push_back("LEM");
nxs_out->AddDataset<std::string>("/raw_data_1/instrument/name", sval, {1}, nxH4::H4DataType::CHAR8);
sval.clear();
// ------
// source
// ------
// add group attribute to /raw_data_1/instrument/source
nxs_out->AddGroupAttribute("/raw_data_1/instrument/source", "NX_class", std::string("NXsource"));
// name
sval.push_back("PSI");
nxs_out->AddDataset<std::string>("/raw_data_1/instrument/source/name", sval, {1}, nxH4::H4DataType::CHAR8);
sval.clear();
// type
sval.push_back("continuous muon source");
nxs_out->AddDataset<std::string>("/raw_data_1/instrument/source/types", sval, {1}, nxH4::H4DataType::CHAR8);
sval.clear();
// probe
sval.push_back("postive muons");
nxs_out->AddDataset<std::string>("/raw_data_1/instrument/source/probe", sval, {1}, nxH4::H4DataType::CHAR8);
sval.clear();
// -----------------------
// detector_1 (NXdetector)
// -----------------------
// add group attribute to /raw_data_1/instrument/detector_1
nxs_out->AddGroupAttribute("/raw_data_1/instrument/detector_1", "NX_class", std::string("NXdetector"));
// counts
nxs_out->AddDataset<int>("/raw_data_1/instrument/detector_1/counts", counts, {1, 16, 66000}, nxH4::H4DataType::INT32);
// attributes for counts
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "signal", 1);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "axes", std::string("period_index,spectrum_index,raw_time"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "long_name", std::string("positron_counts"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "t0_bin", 2741);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "first_good_bin", 2741);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "last_good_bin", 66000);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "units", std::string("counts"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "target", std::string("/raw_data_1/instrument/detector_1/counts"));
// raw_time
nxs_out->AddDataset<float>("/raw_data_1/instrument/detector_1/raw_time", raw_time, {66000}, nxH4::H4DataType::FLOAT32);
// attributes raw_time
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/raw_time", "units", std::string("microseconds"));
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/raw_time", "target", std::string("/raw_data_1/instrument/detector_1/raw_time"));
// resolution
fval.push_back(195.3125);
nxs_out->AddDataset<float>("/raw_data_1/instrument/detector_1/resolution", fval, {1}, nxH4::H4DataType::FLOAT32);
fval.clear();
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/resolution",
"units", std::string("picoseconds"));
// spectrum_index
for (unsigned int i=0; i<16; i++)
ival.push_back(i+1);
nxs_out->AddDataset<int>("/raw_data_1/instrument/detector_1/spectrum_index", ival, {16}, nxH4::H4DataType::INT32);
ival.clear();
// dead_time
std::vector<float> deadTime(16, 0.0);
nxs_out->AddDataset<float>("/raw_data_1/instrument/detector_1/dead_time", deadTime, {16}, nxH4::H4DataType::FLOAT32);
// attributes dead_time
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/dead_time", "available", 0);
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/dead_time", "units", std::string("microseconds"));
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/dead_time", "target", std::string("/raw_data_1/instrument/detector_1/dead_time"));
// add root attributes
// file name
nxs_out->AddRootAttribute("file_name", std::string("_test.nxs"));
// date-time
std::time_t time = std::time({});
char timeString[std::size("yyyy-mm-ddThh:mm:ssZ")];
std::strftime(std::data(timeString), std::size(timeString),
"%FT%TZ", std::gmtime(&time));
nxs_out->AddRootAttribute("file_time", std::string(timeString));
// NeXus version
nxs_out->AddRootAttribute("NeXus_Version", std::string("4.3.0"));
// hdf4 version
nxs_out->AddRootAttribute("HDF4_Version", std::string(nxs->GetHdf4Version()));
// creator
nxs_out->AddRootAttribute("creator", std::string("h4nexus - PSI"));
nxs_out->WriteNexusFile("_test.nxs");
}
//-----------------------------------------------------------------------------
/**
* @brief Main entry point for the h4nexus program
*
* Parses command-line arguments and performs the requested operations:
* - Read and display NeXus HDF4 file information
* - Write NeXus HDF4 files with modified data
* - Calculate dead time corrections
*
* @param argc Number of command-line arguments
* @param argv Array of command-line argument strings
*
* @return 0 on success, non-zero on error
*
* @see h4nexus_syntax() for available command-line options
*/
int main(int argc, char *argv[])
{
std::string fileName{""};
std::string fileNameOut{""};
bool printDebug{false};
bool deadTimeEstimate{false};
if (argc == 1)
h4nexus_syntax();
for (int i=1; i<argc; i++) {
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
h4nexus_syntax();
} else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
#ifdef HAVE_CONFIG_H
#ifdef HAVE_GIT_REV_H
std::cout << std::endl << "h4nexus version: " << H4NEXUS_VERSION << ", git-branch: " << GIT_BRANCH << ", git-hash: " << GIT_HASH << std::endl << std::endl;
#else
std::cout << std::endl << "h4nexus version: " << H4NEXUS_VERSION << std::endl << std::endl;
#endif
#else
#ifdef HAVE_GIT_REV_H
std::cout << std::endl << "h4nexus git-branch: " << GIT_BRANCH << ", git-hash: " << GIT_HASH << std::endl << std::endl;
#else
std::cout << std::endl << "h4nexus version: unknown." << std::endl << std::endl;
#endif
#endif
return 0;
} else if (!strcmp(argv[i], "--fn")) {
if (i+1 >= argc) {
std::cout << std::endl << "**ERROR** found --fn without <fln>." << std::endl;
h4nexus_syntax();
}
i++;
fileName = argv[i];
} else if (!strcmp(argv[i], "-dt") || !strcmp(argv[i], "--dead_time_estimate")) {
deadTimeEstimate = true;
} else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
printDebug = true;
} else if (!strcmp(argv[i], "--out")) {
if (i+1 >= argc) {
std::cout << std::endl << "**ERROR** found --out without <fout>." << std::endl;
h4nexus_syntax();
}
i++;
fileNameOut = argv[i];
} else {
h4nexus_syntax();
}
}
if (fileName.empty()) {
std::cerr << std::endl;
std::cerr << "**ERROR** <fln> is missing." << std::endl;
std::cerr << std::endl;
h4nexus_syntax();
}
std::unique_ptr<nxH4::PNeXus> nxs = std::make_unique<nxH4::PNeXus>(fileName, printDebug);
nxs->Dump();
if (deadTimeEstimate) {
h4nexus_deadTimeEstimate(nxs.get(), printDebug);
}
if (!fileNameOut.empty()) {
h4nexus_writeTest(nxs.get(), fileNameOut, printDebug);
}
return 0;
}

View File

@@ -0,0 +1,119 @@
# - h5nexus
cmake_minimum_required(VERSION 3.26)
project(h5nexus VERSION 0.1.0 LANGUAGES CXX)
#--- set C++ standard ---------------------------------------------------------
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
#--- set a default build type if none was specified ---------------------------
set(default_build_type "Release")
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE
STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif ()
#--- check for pkg-config -----------------------------------------------------
find_package(PkgConfig REQUIRED)
#--- check for git ------------------------------------------------------------
find_package(Git REQUIRED)
#--- check for HDF5 -----------------------------------------------------------
find_package(HDF5 REQUIRED COMPONENTS CXX)
if(NOT HDF5_FOUND)
message(FATAL_ERROR "HDF5 C++ library not found")
endif()
include_directories(${HDF5_INCLUDE_DIRS})
#--- check for ROOT -----------------------------------------------------------
find_package(ROOT 6.36 REQUIRED COMPONENTS Minuit2)
if (ROOT_miniut2_FOUND)
execute_process(COMMAND root-config --bindir OUTPUT_VARIABLE ROOT_BINDIR)
string(STRIP ${ROOT_BINDIR} ROOT_BINDIR)
execute_process(COMMAND root-config --version OUTPUT_VARIABLE ROOT_VERSION)
string(STRIP ${ROOT_VERSION} ROOT_VERSION)
message("-- Found ROOT: ${ROOT_BINDIR} (found version: ${ROOT_VERSION})")
#---Define useful ROOT functions and macros (e.g. ROOT_GENERATE_DICTIONARY)
include(${ROOT_USE_FILE})
endif (ROOT_miniut2_FOUND)
#--- all checks done -> feed config.h -----------------------------------------
set(HAVE_CONFIG_H 1 CACHE INTERNAL "config.h is available")
configure_file(${CMAKE_SOURCE_DIR}/cmake/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
#--- check if project source is a git repo ------------------------------------
if (EXISTS "${CMAKE_SOURCE_DIR}/.git/HEAD")
message(STATUS "is a git repo")
set(IS_GIT_REPO 1)
else ()
message(STATUS "is NOT a git repo")
set(IS_GIT_REPO 0)
endif ()
#--- start create git-revision.h ----------------------------------------------
if (IS_GIT_REPO)
execute_process(COMMAND sh ${CMAKE_SOURCE_DIR}/src/git_revision.sh)
set(HAVE_GIT_REV_H "-DHAVE_GIT_REV_H")
set(GIT_REV_H "git-revision.h")
else (IS_GIT_REPO)
set(HAVE_GIT_REV_H "")
set(GIT_REV_H "")
endif (IS_GIT_REPO)
#--- end create git-revision.h ------------------------------------------------
#--- write summary of the installation
cmake_host_system_information(RESULT PROCESSOR QUERY PROCESSOR_DESCRIPTION)
message("")
message("|-----------------------------------------------------------------------|")
message("| |")
message("| Summary |")
message("| |")
message("|-----------------------------------------------------------------------|")
message("")
message(" System: ${CMAKE_HOST_SYSTEM_NAME} ${CMAKE_SYSTEM_PROCESSOR} - ${CMAKE_HOST_SYSTEM_VERSION}")
message(" Processor: ${PROCESSOR} (${CMAKE_SYSTEM_PROCESSOR})")
message(" ----------")
message("")
message(" h5nexus Version: ${musrfit_VERSION}")
message(" ----------------")
message("")
message(" Build Type: ${CMAKE_BUILD_TYPE}")
message(" -----------")
message("")
message(" Requirements:")
message(" -------------")
message("")
message(" HDF5 found in ${HDF5_INCLUDE_DIRS}, Version: ${HDF5_VERSION}")
message(" ROOT found in ${ROOT_INCLUDE_DIRS}, Version: ${ROOT_VERSION}")
message("")
message(" Installation directories:")
message(" -------------------------")
message("")
message(" Programs : ${CMAKE_INSTALL_PREFIX}/bin")
message("")
message("-------------------------------------------------------------------------")
message("")
#--- add executable -----------------------------------------------------------
add_executable(h5nexus
../../PNeXus.cpp
main.cpp)
target_compile_options(h5nexus BEFORE PRIVATE "-DHAVE_CONFIG_H" "${HAVE_GIT_REV_H}")
target_include_directories(h5nexus
BEFORE PRIVATE
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/build>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/../..>
$<BUILD_INTERFACE:${ROOT_INCLUDE_DIRS}>
)
target_link_libraries(h5nexus ${HDF5_CXX_LIBRARIES} ${ROOT_LIBRARIES})

View File

@@ -0,0 +1,5 @@
// config.h
#define PACKAGE_VERSION "@PROJECT_VERSION@"
#define BUILD_TYPE "@CMAKE_BUILD_TYPE@"

View File

@@ -0,0 +1,8 @@
#ifndef GIT_VERSION_H
#define GIT_VERSION_H
#define GIT_BRANCH "@GIT_BRANCH@"
#define GIT_CURRENT_SHA1 @GIT_CURRENT_SHA1@
#endif // GIT_VERSION_H

View File

@@ -0,0 +1,55 @@
# h5nexus Documentation
This directory contains documentation for the h5nexus project.
## Available Documentation
- **Usage.md** - Comprehensive usage guide with detailed examples and workflow patterns
## Project Structure
The h5nexus example project has the following structure:
```
h5nexus/
├── CMakeLists.txt - Build configuration
├── main.cpp - Main program source
├── git_revision.sh - Git revision header generator
├── cmake/
│ ├── config.h.in - CMake config template
│ └── git-revision.h.in - Git revision template
└── docu/
├── README.md - This file
└── Usage.md - Detailed usage documentation
```
## Building
```bash
mkdir build
cd build
cmake ..
make
```
### Prerequisites
- CMake >= 3.26
- C++17 compatible compiler
- HDF5 C++ library
- ROOT >= 6.36 with Minuit2
## Key Classes
The h5nexus example uses the PNeXus library which provides:
- `nxH5::PNeXus` - Main NeXus file reader/writer class
- `nxH5::PNXdata<T>` - Template class for dataset storage
- `nxH5::PNeXusDeadTime` - Dead time correction calculator
- `nxs::checkHDFType()` - File format detection
## Additional Resources
- [Doxygen Manual](https://www.doxygen.nl/manual/)
- [HDF5 Documentation](https://portal.hdfgroup.org/documentation/)
- [NeXus Format](https://www.nexusformat.org/)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
#!/bin/bash
echo "-- Generating header for git hash"
GIT_HEADER="git-revision.h"
[ -d src ] || mkdir src
GIT_BRANCH=`git rev-parse --abbrev-ref HEAD`
GIT_VERSION=`git log -n 1 --pretty=format:"%ad - %h"`
if [ "$(grep -ics "$GIT_VERSION" $GIT_HEADER)" = 1 ]
then
echo "-- No need to generate new $GIT_HEADER - git hash is unchanged"
exit 0;
fi
echo "-- git branch is : " $GIT_BRANCH
echo "-- git version is : " $GIT_VERSION
echo "#ifndef GIT_VERSION_H" > $GIT_HEADER
echo "#define GIT_VERSION_H" >> $GIT_HEADER
echo "" >> $GIT_HEADER
echo "#define GIT_BRANCH \"$GIT_BRANCH\"" >> $GIT_HEADER
echo "#define GIT_CURRENT_SHA1 \"$GIT_VERSION\"" >> $GIT_HEADER
echo "" >> $GIT_HEADER
echo "#endif //GIT_VERSION_H" >> $GIT_HEADER
echo "-- file is generated into" $GIT_HEADER

View File

@@ -0,0 +1,572 @@
/***************************************************************************
main.cpp
Author: Andreas Suter
e-mail: andreas.suter@psi.ch
***************************************************************************/
/***************************************************************************
* Copyright (C) 2007-2026 by Andreas Suter *
* andreas.suter@psi.ch *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
/**
* @file main.cpp
* @brief Command-line interface for the h5nexus NeXus HDF5 file reader/writer
*
* This file contains the main() function and command-line interface for the
* h5nexus program. It provides functionality to:
* - Read and display NeXus HDF5 files
* - Write NeXus HDF5 files using the PNXdata approach
* - Calculate dead time corrections for muon detector data
*
* **Command-Line Options:**
* - --fn <file>: Input NeXus HDF5 file (required)
* - --out <file>: Output NeXus HDF5 file (optional)
* - --debug, -d: Enable debug output
* - --dead_time_estimate, -dt: Calculate dead time corrections
* - --help, -h: Display help message
* - --version, -v: Display version information
*
* @author Andreas Suter
* @date 2007-2026
* @copyright GNU General Public License v2
* @version 1.0
*
* @see nxH5::PNeXus
* @see nxH5::PNeXusDeadTime
*/
#include <cstring>
#include <iostream>
#include <string>
#include <memory>
#include <ctime>
#include <fstream>
#include "hdf5.h"
#include "PNeXus.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_GIT_REV_H
#include "git-revision.h"
#endif
//-----------------------------------------------------------------------------
/**
* @brief Display command-line syntax and help information
*
* Prints the usage syntax and available command-line options for the h5nexus
* program to stdout and exits the program.
*/
void h5nexus_syntax() {
std::cout << std::endl;
std::cout << "usage: h5nexus [--help | -h] |" << std::endl;
std::cout << " [--version | -v] |" << std::endl;
std::cout << " --fn <fln> [--debug | -d]" << std::endl;
std::cout << " [--dead_time_estimate | -dt]]" << std::endl;
std::cout << " [--out <fout>]" << std::endl;
std::cout << " [--data idx <dout>]" << std::endl;
std::cout << std::endl;
std::cout << "options:" << std::endl;
std::cout << " --help, -h: this help." << std::endl;
std::cout << " --version, -v: version of h5nexus." << std::endl;
std::cout << " --fn <fln>: nexus hdf5 input file name <fn>." << std::endl;
std::cout << " --dead_time_estimate, -dt: dead time estimate for the read hdf5 nexus file." << std::endl;
std::cout << " --debug, -d: print additional debug information." << std::endl;
std::cout << " --out <fout>: write the required datasets of a nexus hdf5 file to file " << std::endl;
std::cout << " with name <fout>. Only makes sense together with the option --fn <fln>." << std::endl;
std::cout << " --data idx <dout>: write a single ascii data set with idx to <dout>." << std::endl;
std::cout << " Only makes sense together with the option --fn <fln>." << std::endl;
std::cout << std::endl;
exit(0);
}
//-----------------------------------------------------------------------------
/**
* @brief Calculate dead time corrections for muon detector data
*
* Estimates dead time corrections for each detector in the NeXus file using
* the PNeXusDeadTime class and ROOT Minuit2 minimization.
*
* @param nxs Pointer to the PNeXus object containing the data
* @param debug If true, print additional debug information
*
* @see nxH5::PNeXusDeadTime
*/
std::vector<float> h5nexus_deadTimeEstimate(const nxH5::PNeXus *nxs, bool debug)
{
if (debug) {
std::cout << std::endl;
std::cout << std::endl << "+++++++++++++++++++";
std::cout << std::endl << "in deadTimeEstimate";
std::cout << std::endl << "+++++++++++++++++++";
std::cout << std::endl;
}
nxH5::PNeXusDeadTime ndt(nxs, debug);
auto dims = ndt.GetDimensions();
for (unsigned int i=0; i<dims[1]; i++) {
ndt.minimize(i);
}
return ndt.GetDeadTimeEstimated();
}
//-----------------------------------------------------------------------------
void h5nexus_writeData(const nxH5::PNeXus *nxs, const std::string& fln, const std::string& dataOutFln, const int idx, const std::vector<float> dte)
{
std::cout << std::endl << "as35> in h5nexus_writeData: idf version: " << nxs->GetIdfVersion();
std::vector<int> counts;
std::vector<float> dt;
std::vector<long long unsigned int> dims;
float resolution{0.0};
int good_frames{0};
if (nxs->GetIdfVersion() == 1) {
if (nxs->HasDataset("/run/histogram_data_1/counts")) {
std::cout << std::endl << "as35> found counts in idf version 1";
}
} else {
auto dataMap = nxs->GetDataMap();
if (nxs->HasDataset("/raw_data_1/detector_1/counts")) {
std::cout << std::endl << "as35> found counts in idf version 2";
auto counts_data = std::any_cast<nxH5::PNXdata<int>>(dataMap["/raw_data_1/detector_1/counts"]);
counts = counts_data.GetData();
auto dd = counts_data.GetDimensions();
for (auto i=0; i<dd.size(); i++)
dims.push_back(dd[i]);
std::cout << std::endl << "as35> dims: " << dims.size() << ": ";
for (auto i=0; i<dims.size(); i++)
std::cout << dims[i] << ", ";
}
if (idx >= dims[1]) {
std::cerr << std::endl << "**ERROR** idx=" << idx << " is >= number of dataset=" << dims[1] << std::endl;
return;
}
if (nxs->HasDataset("/raw_data_1/detector_1/dead_time")) {
std::cout << std::endl << "as35> found dead_time in idf version 2";
auto dt_data = std::any_cast<nxH5::PNXdata<float>>(dataMap["/raw_data_1/detector_1/dead_time"]);
dt = dt_data.GetData();
}
if (nxs->HasDataset("/raw_data_1/instrument/detector_1/resolution")) {
std::cout << std::endl << "as35> found resolution in idf version 2";
auto r_data = std::any_cast<nxH5::PNXdata<int>>(dataMap["/raw_data_1/instrument/detector_1/resolution"]);
auto rr = r_data.GetData();
resolution = (float)rr[0];
if (r_data.HasAttribute("units")) {
std::string units = std::any_cast<std::string>(r_data.GetAttribute("units"));
if (units == "picoseconds")
resolution *= 1.0e-6;
else if (units == "nanoseconds")
resolution *= 1.0e-3;
}
}
if (nxs->HasDataset("/raw_data_1/good_frames")) {
std::cout << std::endl << "as35> found good_frames in idf version 2";
auto gf_data = std::any_cast<nxH5::PNXdata<int>>(dataMap["/raw_data_1/good_frames"]);
good_frames = gf_data.GetData()[0];
}
}
std::cout << std::endl;
float dtei;
if (dte.size() > idx)
dtei = dte[idx];
// write dataset
std::ofstream fout(dataOutFln);
fout << "# NeXus fln: " << fln << std::endl;
fout << "# idx=" << idx << std::endl;
fout << "# resolution : " << resolution << " (us)" << std::endl;
fout << "# good_frames : " << good_frames << std::endl;
fout << "# dead_time : " << dt[idx] << " (us) : from file" << std::endl;
fout << "# dead_time : " << dtei << " (us) : from estimater" << std::endl;
fout << "# ------" << std::endl;
fout << "# raw counts, dead time corrected counts (file), dead time corrected counts (estimated)" << std::endl;
int cc{0}, dtcc{0}, dtecc{0};
// see https://docs.mantidproject.org/v3.9.0/algorithms/ApplyDeadTimeCorr-v1.html#algm-applydeadtimecorr
for (auto i=0; i<dims[2]; i++) {
cc = counts[i + idx*dims[2]];
dtcc = (int)((float)cc / (1.0 - (float)cc * (dt[idx]/(resolution*(float)good_frames))));
dtecc = (int)((float)cc / (1.0 - (float)cc * (dtei/(resolution*(float)good_frames))));
fout << cc << ", " << dtcc << ", " << dtecc << std::endl;
}
fout.close();
}
//-----------------------------------------------------------------------------
/**
* @brief Write NeXus HDF5 file using the PNXdata approach
*
* Writes all datasets from the PNeXus data map to a new NeXus HDF5 file.
* This function uses the WriteNexusFile() method to create a complete
* NeXus file with all groups, datasets, and attributes.
*
* @param nxs Pointer to the PNeXus object containing the data to write
* @param outFileName Output filename for the NeXus HDF5 file
* @param debug If true, print additional debug information
*
* @note Currently only supports IDF version 2 files
*
* @see nxH5::PNeXus::WriteNexusFile()
*/
void h5nexus_writeTest(const nxH5::PNeXus *nxs, const std::string& outFileName, bool debug)
{
if (debug) {
std::cout << std::endl;
std::cout << "++++++++++++++++++++" << std::endl;
std::cout << "Writing NeXus file" << std::endl;
std::cout << "++++++++++++++++++++" << std::endl;
std::cout << std::endl;
}
if (nxs->GetIdfVersion() == 1) {
std::cerr << "Error: IDF v1 write not yet implemented" << std::endl;
return;
}
// Write using the read object's data
int result = const_cast<nxH5::PNeXus*>(nxs)->WriteNexusFile(outFileName, nxs->GetIdfVersion());
if (result == 0) {
std::cout << "Successfully wrote: " << outFileName << std::endl;
} else {
std::cerr << "Failed to write file: " << outFileName << std::endl;
}
// write data from scratch
std::unique_ptr<nxH5::PNeXus> nxs_out = std::make_unique<nxH5::PNeXus>();
std::vector<int> ival;
std::vector<float> fval;
std::vector<std::string> sval;
H5::StrType strType(H5::PredType::C_S1, H5T_VARIABLE);
// ----------
// raw_data_1
// ----------
// IDF version
ival.push_back(2);
nxs_out->AddDataset<int>("/raw_data_1/IDF_version", ival, {1}, H5::PredType::NATIVE_INT);
ival.clear();
// add group attribute to '/raw_data_1'
nxs_out->AddGroupAttribute("/raw_data_1", "NX_class", std::string("NXentry"));
// beamline
sval.push_back("piE3");
nxs_out->AddDataset<std::string>("/raw_data_1/beamline", sval, {1}, strType);
sval.clear();
// definition
sval.push_back("muonTD");
nxs_out->AddDataset<std::string>("/raw_data_1/definition", sval, {1}, strType);
sval.clear();
// run_number
ival.push_back(1234);
nxs_out->AddDataset<int>("/raw_data_1/run_number", ival, {1}, H5::PredType::NATIVE_INT);
ival.clear();
// title
sval.push_back("this is the run title.");
nxs_out->AddDataset<std::string>("/raw_data_1/title", sval, {1}, strType);
sval.clear();
// start time
sval.push_back("2026-01-01T01:02:03");
nxs_out->AddDataset<std::string>("/raw_data_1/start_time", sval, {1}, strType);
sval.clear();
// end time
sval.push_back("2026-01-01T02:03:42");
nxs_out->AddDataset<std::string>("/raw_data_1/end_time", sval, {1}, strType);
sval.clear();
// experiment_identifier - pgroup for PSI
sval.push_back("p18324");
nxs_out->AddDataset<std::string>("/raw_data_1/experiment_identifier", sval, {1}, strType);
sval.clear();
// -------------------
// detector_1 (NXdata)
// -------------------
// add group attribute to /raw_data_1/instrument
nxs_out->AddGroupAttribute("/raw_data_1/detector_1", "NX_class", std::string("NXdata"));
// counts
std::vector<int> counts(16*66000, 42); // data 16 histos with length 66000
nxs_out->AddDataset<int>("/raw_data_1/detector_1/counts", counts, {1, 16, 66000}, H5::PredType::NATIVE_INT);
// attributes for counts
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "signal", 1);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "axes", std::string("period_index,spectrum_index,raw_time"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "long_name", std::string("positron_counts"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "t0_bin", 2741);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "first_good_bin", 2741);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "last_good_bin", 66000);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "units", std::string("counts"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/detector_1/counts", "target", std::string("/raw_data_1/instrument/detector_1/counts"));
// raw_time
std::vector<float> raw_time(66000, 0.0);
for (unsigned int i=0; i<raw_time.size(); i++)
raw_time[i] = 0.1953125f*1.0e-3*((float)i-2741.0f+0.5f);
nxs_out->AddDataset<float>("/raw_data_1/detector_1/raw_time", raw_time, {66000}, H5::PredType::NATIVE_FLOAT);
// attributes raw_time
nxs_out->AddDatasetAttribute<float>("/raw_data_1/detector_1/raw_time", "units", std::string("microseconds"));
nxs_out->AddDatasetAttribute<float>("/raw_data_1/detector_1/raw_time", "target", std::string("/raw_data_1/instrument/detector_1/raw_time"));
// ----------
// instrument
// ----------
// add group attribute to /raw_data_1/instrument
nxs_out->AddGroupAttribute("/raw_data_1/instrument", "NX_class", std::string("NXinstrument"));
// name
sval.push_back("LEM");
nxs_out->AddDataset<std::string>("/raw_data_1/instrument/name", sval, {1}, strType);
sval.clear();
// ------
// source
// ------
// add group attribute to /raw_data_1/instrument/source
nxs_out->AddGroupAttribute("/raw_data_1/instrument/source", "NX_class", std::string("NXsource"));
// name
sval.push_back("PSI");
nxs_out->AddDataset<std::string>("/raw_data_1/instrument/source/name", sval, {1}, strType);
sval.clear();
// type
sval.push_back("continuous muon source");
nxs_out->AddDataset<std::string>("/raw_data_1/instrument/source/types", sval, {1}, strType);
sval.clear();
// probe
sval.push_back("postive muons");
nxs_out->AddDataset<std::string>("/raw_data_1/instrument/source/probe", sval, {1}, strType);
sval.clear();
// -----------------------
// detector_1 (NXdetector)
// -----------------------
// add group attribute to /raw_data_1/instrument/detector_1
nxs_out->AddGroupAttribute("/raw_data_1/instrument/detector_1", "NX_class", std::string("NXdetector"));
// counts
nxs_out->AddDataset<int>("/raw_data_1/instrument/detector_1/counts", counts, {1, 16, 66000}, H5::PredType::NATIVE_INT);
// attributes for counts
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "signal", 1);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "axes", std::string("period_index,spectrum_index,raw_time"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "long_name", std::string("positron_counts"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "t0_bin", 2741);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "first_good_bin", 2741);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "last_good_bin", 66000);
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "units", std::string("counts"));
nxs_out->AddDatasetAttribute<int>("/raw_data_1/instrument/detector_1/counts", "target", std::string("/raw_data_1/instrument/detector_1/counts"));
// raw_time
nxs_out->AddDataset<float>("/raw_data_1/instrument/detector_1/raw_time", raw_time, {66000}, H5::PredType::NATIVE_FLOAT);
// attributes raw_time
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/raw_time", "units", std::string("microseconds"));
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/raw_time", "target", std::string("/raw_data_1/instrument/detector_1/raw_time"));
// resolution
fval.push_back(195.3125);
nxs_out->AddDataset<float>("/raw_data_1/instrument/detector_1/resolution", fval, {1}, H5::PredType::NATIVE_FLOAT);
fval.clear();
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/resolution",
"units", std::string("picoseconds"));
// spectrum_index
for (unsigned int i=0; i<16; i++)
ival.push_back(i+1);
nxs_out->AddDataset<int>("/raw_data_1/instrument/detector_1/spectrum_index", ival, {16}, H5::PredType::NATIVE_INT);
ival.clear();
// dead_time
std::vector<float> deadTime(16, 0.0);
nxs_out->AddDataset<float>("/raw_data_1/instrument/detector_1/dead_time", deadTime, {16}, H5::PredType::NATIVE_FLOAT);
// attributes dead_time
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/dead_time", "available", 0);
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/dead_time", "units", std::string("microseconds"));
nxs_out->AddDatasetAttribute<float>("/raw_data_1/instrument/detector_1/dead_time", "target", std::string("/raw_data_1/instrument/detector_1/dead_time"));
// add root attributes
// file name
nxs_out->AddRootAttribute("file_name", std::string("_test.nxs"));
// date-time
std::time_t time = std::time({});
char timeString[std::size("yyyy-mm-ddThh:mm:ssZ")];
std::strftime(std::data(timeString), std::size(timeString),
"%FT%TZ", std::gmtime(&time));
nxs_out->AddRootAttribute("file_time", std::string(timeString));
// NeXus version
nxs_out->AddRootAttribute("NeXus_Version", std::string("4.3.0"));
// hdf5 version
nxs_out->AddRootAttribute("HDF5_Version", std::string(nxs->GetHdf5Version()));
// creator
nxs_out->AddRootAttribute("creator", std::string("h5nexus - PSI"));
nxs_out->WriteNexusFile("_test.nxs");
}
//-----------------------------------------------------------------------------
/**
* @brief Main entry point for the h5nexus program
*
* Parses command-line arguments and performs the requested operations:
* - Read and display NeXus HDF5 file information
* - Write NeXus HDF5 files with modified data
* - Calculate dead time corrections
*
* @param argc Number of command-line arguments
* @param argv Array of command-line argument strings
*
* @return 0 on success, non-zero on error
*
* @see h5nexus_syntax() for available command-line options
*/
int main(int argc, char *argv[])
{
std::string fileName{""};
std::string fileNameOut{""};
std::string dataNameOut{""};
int idx{-1};
bool printDebug{false};
bool deadTimeEstimate{false};
if (argc == 1)
h5nexus_syntax();
for (int i=1; i<argc; i++) {
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
h5nexus_syntax();
} else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
#ifdef HAVE_CONFIG_H
#ifdef HAVE_GIT_REV_H
std::cout << std::endl << "h5nexus version: " << PACKAGE_VERSION << ", git-branch: " << GIT_BRANCH << ", git-rev: " << GIT_CURRENT_SHA1 << " (" << BUILD_TYPE << ")" << std::endl << std::endl;
#else
std::cout << std::endl << "h5nexus version: " << PACKAGE_VERSION << " (" << BUILD_TYPE << ")" << std::endl << std::endl;
#endif
#else
#ifdef HAVE_GIT_REV_H
std::cout << std::endl << "h5nexus git-branch: " << GIT_BRANCH << ", git-rev: " << GIT_CURRENT_SHA1 << std::endl << std::endl;
#else
std::cout << std::endl << "h5nexus version: unkown." << std::endl << std::endl;
#endif
#endif
return 0;
} else if (!strcmp(argv[i], "--fn")) {
if (i+1 >= argc) {
std::cout << std::endl << "**ERROR** found --fn without <fln>." << std::endl;
h5nexus_syntax();
}
i++;
fileName = argv[i];
} else if (!strcmp(argv[i], "-dt") || !strcmp(argv[i], "--dead_time_estimate")) {
deadTimeEstimate = true;
} else if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
printDebug = true;
} else if (!strcmp(argv[i], "--data")) {
if (i+2 >= argc) {
std::cout << std::endl << "**ERROR** in --data idx <dout>." << std::endl;
h5nexus_syntax();
}
int ii;
try {
ii = std::stoi(argv[i+1]);
} catch (const std::invalid_argument& ia) {
std::cout << std::endl << "**ERROR** couldn't convert idx from arguments given." << std::endl;
h5nexus_syntax();
}
if (ii < 0) {
std::cout << std::endl << "**ERROR** found idx < 0, namely " << ii << std::endl;
h5nexus_syntax();
}
idx = ii;
dataNameOut = argv[i+2];
i += 2;
} else if (!strcmp(argv[i], "--out")) {
if (i+1 >= argc) {
std::cout << std::endl << "**ERROR** found --out without <fout>." << std::endl;
h5nexus_syntax();
}
i++;
fileNameOut = argv[i];
} else {
h5nexus_syntax();
}
}
if (fileName.empty()) {
std::cerr << std::endl;
std::cerr << "**ERROR** <fln> is missing." << std::endl;
std::cerr << std::endl;
h5nexus_syntax();
}
if (printDebug) {
std::cout << std::endl;
std::cout << ">> fln = '" << fileName << "'" << std::endl;
std::cout << ">> fout = '" << fileNameOut << "'" << std::endl;
std::cout << ">> dout = '" << dataNameOut << "', idx=" << idx << std::endl;
std::cout << std::endl;
}
std::unique_ptr<nxH5::PNeXus> nxs = std::make_unique<nxH5::PNeXus>(fileName, printDebug);
nxs->Dump();
std::vector<float> dte;
if (deadTimeEstimate) {
dte = h5nexus_deadTimeEstimate(nxs.get(), printDebug);
}
if (!fileNameOut.empty()) {
h5nexus_writeTest(nxs.get(), fileNameOut, printDebug);
}
if (!dataNameOut.empty()) {
h5nexus_writeData(nxs.get(), fileName, dataNameOut, idx, dte);
}
return 0;
}

Binary file not shown.

View File

@@ -872,6 +872,9 @@ class PRawRunData {
virtual const PIntPair GetBkgBin(const UInt_t histoNo) { return fData.GetBkgBin(histoNo); } virtual const PIntPair GetBkgBin(const UInt_t histoNo) { return fData.GetBkgBin(histoNo); }
virtual const PIntPair GetGoodDataBin(const UInt_t histoNo) { return fData.GetGoodDataBin(histoNo); } virtual const PIntPair GetGoodDataBin(const UInt_t histoNo) { return fData.GetGoodDataBin(histoNo); }
virtual const PIntVector GetRedGreenOffset() { return fRedGreenOffset; } virtual const PIntVector GetRedGreenOffset() { return fRedGreenOffset; }
virtual const Bool_t DeadTimeCorrectionReady();
virtual const Int_t GetNumberOfGoodFrames() { return fNumberOfGoodFrames; }
virtual const std::vector<float> GetDeadTimeParam() { return fDeadTimeParam; }
virtual const UInt_t GetNoOfHistos() { return fData.Size(); } virtual const UInt_t GetNoOfHistos() { return fData.Size(); }
virtual PRawRunDataSet* GetDataSet(const UInt_t idx, Bool_t wantHistoNo = true); virtual PRawRunDataSet* GetDataSet(const UInt_t idx, Bool_t wantHistoNo = true);
virtual const PDoubleVector* GetDataBin(const UInt_t histoNo) { return fData.GetData(histoNo); } virtual const PDoubleVector* GetDataBin(const UInt_t histoNo) { return fData.GetData(histoNo); }
@@ -913,45 +916,49 @@ class PRawRunData {
virtual void SetRingAnode(const UInt_t idx, const Double_t dval); virtual void SetRingAnode(const UInt_t idx, const Double_t dval);
virtual void SetTimeResolution(const Double_t dval) { fTimeResolution = dval; } virtual void SetTimeResolution(const Double_t dval) { fTimeResolution = dval; }
virtual void SetRedGreenOffset(PIntVector &ivec) { fRedGreenOffset = ivec; } virtual void SetRedGreenOffset(PIntVector &ivec) { fRedGreenOffset = ivec; }
virtual void SetNumberOfGoodFrames(Int_t ival) { fNumberOfGoodFrames = ival; }
virtual void SetDeadTimeParam(std::vector<float> dvec) { fDeadTimeParam = dvec; }
virtual void SetDataSet(PRawRunDataSet &dataSet, UInt_t idx=-1) { fData.Set(dataSet, idx); } virtual void SetDataSet(PRawRunDataSet &dataSet, UInt_t idx=-1) { fData.Set(dataSet, idx); }
PNonMusrRawRunData fDataNonMusr; ///< keeps all ascii- or db-file info in case of nonMusr fit PNonMusrRawRunData fDataNonMusr; ///< keeps all ascii- or db-file info in case of nonMusr fit
private: private:
TString fVersion; ///< keeps the version information of the data file TString fVersion{"n/a"}; ///< keeps the version information of the data file
TString fGenericValidatorURL; ///< keeps the generic validator MusrRoot URL TString fGenericValidatorURL{"n/a"}; ///< keeps the generic validator MusrRoot URL
TString fSpecificValidatorURL; ///< keeps the instrument specific validator MusrRoot URL TString fSpecificValidatorURL{"n/a"}; ///< keeps the instrument specific validator MusrRoot URL
TString fGenerator; ///< keeps the data file generator name TString fGenerator{"n/a"}; ///< keeps the data file generator name
TString fComment; ///< keeps the data file comment TString fComment{"n/a"}; ///< keeps the data file comment
TString fFileName; ///< keeps the name of the original data file TString fFileName{"n/a"}; ///< keeps the name of the original data file
TString fLaboratory; ///< keeps the name of the laboratory, e.g. PSI, ISIS, TRIUMF, JPARC TString fLaboratory{"n/a"}; ///< keeps the name of the laboratory, e.g. PSI, ISIS, TRIUMF, JPARC
TString fBeamline; ///< keeps the name of the be beamline, e.g. muE4, piM3.1, ... TString fBeamline{"n/a"}; ///< keeps the name of the be beamline, e.g. muE4, piM3.1, ...
TString fInstrument; ///< keeps the name of the instrument, e.g. LEM, GPS, MUSR, EMU, ... TString fInstrument{"n/a"}; ///< keeps the name of the instrument, e.g. LEM, GPS, MUSR, EMU, ...
TString fMuonSource; ///< keeps the type of muon source, e.g. continous surface beam, pulsed beam, low energy muon beam TString fMuonSource{"n/a"}; ///< keeps the type of muon source, e.g. continous surface beam, pulsed beam, low energy muon beam
TString fMuonSpecies; ///< positive muon or negative muon TString fMuonSpecies{"n/a"}; ///< positive muon or negative muon
Double_t fMuonBeamMomentum; ///< given in MeV/c, for LEM this is the momentum of the secondary beamline and NOT the momentum of the low energy beam Double_t fMuonBeamMomentum{PMUSR_UNDEFINED}; ///< given in MeV/c, for LEM this is the momentum of the secondary beamline and NOT the momentum of the low energy beam
Double_t fMuonSpinAngle; ///< gives the muon spin angle in degrees (reference frame depends on the instrument) Double_t fMuonSpinAngle{PMUSR_UNDEFINED}; ///< gives the muon spin angle in degrees (reference frame depends on the instrument)
TString fRunName; ///< name of the run as found in the msr-file TString fRunName{"n/a"}; ///< name of the run as found in the msr-file
Int_t fRunNumber; ///< run number Int_t fRunNumber{-1}; ///< run number
TString fRunTitle; ///< run title TString fRunTitle{"n/a"}; ///< run title
TString fSetup; ///< description of the setup of this run TString fSetup{"n/a"}; ///< description of the setup of this run
TString fStartTime; ///< start time of the run TString fStartTime{"n/a"}; ///< start time of the run
TString fStartDate; ///< start date of the run TString fStartDate{"n/a"}; ///< start date of the run
time_t fStartDateTimeSec; ///< start run given as time_t object time_t fStartDateTimeSec{0}; ///< start run given as time_t object
TString fStopTime; ///< stop time of the run TString fStopTime{"n/a"}; ///< stop time of the run
TString fStopDate; ///< stop date of the run TString fStopDate{"n/a"}; ///< stop date of the run
time_t fStopDateTimeSec; ///< stop run given as time_t object time_t fStopDateTimeSec{0}; ///< stop run given as time_t object
TString fCryo; ///< name of the cryo TString fCryo{"n/a"}; ///< name of the cryo
TString fSample; ///< description of the sample TString fSample{"n/a"}; ///< description of the sample
TString fOrientation; ///< description of the orientation TString fOrientation{"n/a"}; ///< description of the orientation
TString fMagnet; ///< name of the sample magnet TString fMagnet{"n/a"}; ///< name of the sample magnet
Double_t fField; ///< magnetic field value in (G) Double_t fField{PMUSR_UNDEFINED}; ///< magnetic field value in (G)
PDoublePairVector fTemp; ///< measured temperatures and standard deviations during the run PDoublePairVector fTemp; ///< measured temperatures and standard deviations during the run
Double_t fEnergy; ///< implantation energy of the muon Double_t fEnergy{PMUSR_UNDEFINED}; ///< implantation energy of the muon
Double_t fTransport; ///< LEM transport settings (Moderator HV) Double_t fTransport{PMUSR_UNDEFINED}; ///< LEM transport settings (Moderator HV)
PDoubleVector fRingAnode; ///< LEM ring anode HVs (L,R[,T,B]) PDoubleVector fRingAnode; ///< LEM ring anode HVs (L,R[,T,B])
Double_t fTimeResolution; ///< time resolution of the run in (ns) Double_t fTimeResolution{PMUSR_UNDEFINED}; ///< time resolution of the run in (ns)
PIntVector fRedGreenOffset; ///< keeps the Red/Green offsets PIntVector fRedGreenOffset; ///< keeps the Red/Green offsets
std::vector<float> fDeadTimeParam; ///< dead time parameter vector needed for pulsed sources
Int_t fNumberOfGoodFrames{0}; ///< needed to correct dead times at pulsed sources
PRawRunDataVector fData; ///< keeps the histos together with the histo related properties such as T0, first good bin, etc. PRawRunDataVector fData; ///< keeps the histos together with the histo related properties such as T0, first good bin, etc.
}; };
@@ -1050,6 +1057,7 @@ class PMsrGlobalBlock {
virtual Int_t GetFitRangeOffset(UInt_t idx); virtual Int_t GetFitRangeOffset(UInt_t idx);
virtual Int_t GetPacking() { return fPacking; } virtual Int_t GetPacking() { return fPacking; }
virtual Double_t GetEstimatedAlpha() { return fAlpha; } virtual Double_t GetEstimatedAlpha() { return fAlpha; }
virtual TString GetDeadTimeCorrection() { return fDeadTimeCorrection; }
virtual void SetGlobalPresent(Bool_t bval) { fGlobalPresent = bval; } virtual void SetGlobalPresent(Bool_t bval) { fGlobalPresent = bval; }
virtual void SetRRFFreq(Double_t freq, const char *unit); virtual void SetRRFFreq(Double_t freq, const char *unit);
@@ -1063,6 +1071,7 @@ class PMsrGlobalBlock {
virtual void SetFitRange(Double_t dval, UInt_t idx); virtual void SetFitRange(Double_t dval, UInt_t idx);
virtual void SetFitRangeOffset(Int_t ival, UInt_t idx); virtual void SetFitRangeOffset(Int_t ival, UInt_t idx);
virtual void SetPacking(Int_t ival) { fPacking = ival; } virtual void SetPacking(Int_t ival) { fPacking = ival; }
virtual void SetDeadTimeCorrection(TString str) { fDeadTimeCorrection = str; }
private: private:
Bool_t fGlobalPresent; ///< flag showing if a GLOBAL block is present at all. Bool_t fGlobalPresent; ///< flag showing if a GLOBAL block is present at all.
@@ -1079,6 +1088,7 @@ class PMsrGlobalBlock {
Int_t fFitRangeOffset[2]; ///< if fit range is given in bins it can have the form fit fgb+n0 lgb-n1. This variable holds the n0 and n1. Int_t fFitRangeOffset[2]; ///< if fit range is given in bins it can have the form fit fgb+n0 lgb-n1. This variable holds the n0 and n1.
Int_t fPacking; ///< packing/rebinning Int_t fPacking; ///< packing/rebinning
Double_t fAlpha; ///< estimated alpha value from F/B counts Double_t fAlpha; ///< estimated alpha value from F/B counts
TString fDeadTimeCorrection; ///< tells if deadtime correction (pulsed sources) should be applied. Possible value: 'no' (default), 'file', 'estimate'
}; };
//------------------------------------------------------------- //-------------------------------------------------------------
@@ -1144,6 +1154,7 @@ class PMsrRunBlock {
virtual Double_t GetFitRange(UInt_t idx); virtual Double_t GetFitRange(UInt_t idx);
virtual Int_t GetFitRangeOffset(UInt_t idx); virtual Int_t GetFitRangeOffset(UInt_t idx);
virtual Int_t GetPacking() { return fPacking; } virtual Int_t GetPacking() { return fPacking; }
virtual TString GetDeadTimeCorrection() { return fDeadTimeCorrection; }
virtual Double_t GetEstimatedAlpha() { return fAlpha; } virtual Double_t GetEstimatedAlpha() { return fAlpha; }
virtual Int_t GetXDataIndex() { return fXYDataIndex[0]; } virtual Int_t GetXDataIndex() { return fXYDataIndex[0]; }
virtual Int_t GetYDataIndex() { return fXYDataIndex[1]; } virtual Int_t GetYDataIndex() { return fXYDataIndex[1]; }
@@ -1177,6 +1188,7 @@ class PMsrRunBlock {
virtual void SetFitRange(Double_t dval, UInt_t idx); virtual void SetFitRange(Double_t dval, UInt_t idx);
virtual void SetFitRangeOffset(Int_t ival, UInt_t idx); virtual void SetFitRangeOffset(Int_t ival, UInt_t idx);
virtual void SetPacking(Int_t ival) { fPacking = ival; } virtual void SetPacking(Int_t ival) { fPacking = ival; }
virtual void SetDeadTimeCorrection(TString str) { fDeadTimeCorrection = str; }
virtual void SetXDataIndex(Int_t ival) { fXYDataIndex[0] = ival; } virtual void SetXDataIndex(Int_t ival) { fXYDataIndex[0] = ival; }
virtual void SetYDataIndex(Int_t ival) { fXYDataIndex[1] = ival; } virtual void SetYDataIndex(Int_t ival) { fXYDataIndex[1] = ival; }
virtual void SetXDataLabel(TString& str) { fXYDataLabel[0] = str; } virtual void SetXDataLabel(TString& str) { fXYDataLabel[0] = str; }
@@ -1210,6 +1222,7 @@ class PMsrRunBlock {
Int_t fFitRangeOffset[2]; ///< if fit range is given in bins it can have the form fit fgb+n0 lgb-n1. This variable holds the n0 and n1. Int_t fFitRangeOffset[2]; ///< if fit range is given in bins it can have the form fit fgb+n0 lgb-n1. This variable holds the n0 and n1.
Double_t fAlpha; ///< estimated alpha value from F/B counts Double_t fAlpha; ///< estimated alpha value from F/B counts
Int_t fPacking; ///< packing/rebinning Int_t fPacking; ///< packing/rebinning
TString fDeadTimeCorrection; ///< tells if deadtime correction (pulsed sources) should be applied. Possible value: 'no' (default), 'file', 'estimate'
Int_t fXYDataIndex[2]; ///< used to get the data indices when using db-files (fit type 8) Int_t fXYDataIndex[2]; ///< used to get the data indices when using db-files (fit type 8)
TString fXYDataLabel[2]; ///< used to get the indices via labels when using db-files (fit type 8) TString fXYDataLabel[2]; ///< used to get the indices via labels when using db-files (fit type 8)

View File

@@ -30,6 +30,10 @@
#ifndef _PRUNDATAHANDLER_H_ #ifndef _PRUNDATAHANDLER_H_
#define _PRUNDATAHANDLER_H_ #define _PRUNDATAHANDLER_H_
#include <any>
#include <iostream>
#include <string>
#include <TString.h> #include <TString.h>
#include "PMusr.h" #include "PMusr.h"
@@ -432,6 +436,8 @@ class PRunDataHandler
virtual Bool_t FileExistsCheck(const Bool_t fileName, const Int_t idx); virtual Bool_t FileExistsCheck(const Bool_t fileName, const Int_t idx);
virtual Bool_t FileExistsCheck(const TString fileName); virtual Bool_t FileExistsCheck(const TString fileName);
virtual Bool_t ReadRootFile(); virtual Bool_t ReadRootFile();
template <typename T> Bool_t ReadNexusFileIdf1(T& nxs_file);
template <typename T> Bool_t ReadNexusFileIdf2(T& nxs_file);
virtual Bool_t ReadNexusFile(); virtual Bool_t ReadNexusFile();
virtual Bool_t ReadWkmFile(); virtual Bool_t ReadWkmFile();
virtual Bool_t ReadPsiBinFile(); virtual Bool_t ReadPsiBinFile();
@@ -443,7 +449,7 @@ class PRunDataHandler
virtual Bool_t WriteMusrRootFile(Int_t tag=A2M_MUSR_ROOT_DIR, TString fln=""); virtual Bool_t WriteMusrRootFile(Int_t tag=A2M_MUSR_ROOT_DIR, TString fln="");
virtual Bool_t WriteRootFile(TString fln=""); virtual Bool_t WriteRootFile(TString fln="");
virtual Bool_t WriteNexusFile(TString fln=""); virtual Bool_t WriteNexusFile(TString format, TString fln="");
virtual Bool_t WriteWkmFile(TString fln=""); virtual Bool_t WriteWkmFile(TString fln="");
virtual Bool_t WritePsiBinFile(TString fln=""); virtual Bool_t WritePsiBinFile(TString fln="");
virtual Bool_t WriteMudFile(TString fln=""); virtual Bool_t WriteMudFile(TString fln="");
@@ -464,4 +470,417 @@ class PRunDataHandler
virtual TString GetYear(Int_t month); virtual TString GetYear(Int_t month);
}; };
//--------------------------------------------------------------------------
// ReadNexusFileIdf1 (private)
//--------------------------------------------------------------------------
/**
* <p>Reads a NeXus file with IDF version 1 format.
*
* <p>Extracts run metadata (laboratory, beamline, instrument, run title,
* run number, temperature, field, sample info, time resolution, start/stop
* times) and histogram data from the NeXus file structure.
*
* @tparam T NeXus file handler type (std::unique_ptr<nxH4::PNeXus> and std::unique_ptr<nxH5::PNeXus>)
* @param nxs_file reference to the NeXus file handler
*
* <b>return:</b>
* - true at successful reading,
* - otherwise false.
*/
template <typename T>
Bool_t PRunDataHandler::ReadNexusFileIdf1(T& nxs_file)
{
PRawRunData runData;
PRawRunDataSet dataSet;
TString str;
std::string sstr;
Int_t ival;
Double_t dval, factor;
bool ok;
// get header information
// get/set laboratory
sstr = "n/a";
if (nxs_file->HasDataset("/run/lab"))
sstr = nxs_file->template GetDataset<std::string>("/run/lab").GetData()[0];
runData.SetLaboratory(sstr);
// get/set beamline
sstr = "n/a";
if (nxs_file->HasDataset("/run/beamline"))
sstr = nxs_file->template GetDataset<std::string>("/run/beamline").GetData()[0];
runData.SetBeamline(sstr);
// get/set instrument
sstr = "n/a";
if (nxs_file->HasDataset("/run/instrument/name"))
sstr = nxs_file->template GetDataset<std::string>("/run/instrument/name").GetData()[0];
runData.SetInstrument(sstr);
// get/set run title
str = "n/a";
if (nxs_file->HasDataset("/run/title"))
sstr = nxs_file->template GetDataset<std::string>("/run/title").GetData()[0];
runData.SetRunTitle(sstr);
// get/set run number
ival = -1;
if (nxs_file->HasDataset("/run/number"))
ival = nxs_file->template GetDataset<int>("/run/number").GetData()[0];
runData.SetRunNumber(ival);
// get/set temperature
dval = PMUSR_UNDEFINED;
sstr = "n/a";
if (nxs_file->HasDataset("/run/sample/temperature")) {
auto tmp_ds = nxs_file->template GetDataset<float>("/run/sample/temperature");
dval = tmp_ds.GetData()[0];
if (tmp_ds.HasAttribute("units"))
sstr = std::any_cast<std::string>(tmp_ds.GetAttribute("units"));
if (sstr == "Celcius")
dval += 273.16;
}
runData.SetTemperature(0, dval, 0.0);
// get/set field
dval = PMUSR_UNDEFINED;
sstr = "n/a";
factor = 1.0;
if (nxs_file->HasDataset("/run/sample/magnetic_field")) {
auto mag_ds = nxs_file->template GetDataset<float>("/run/sample/magnetic_field");
dval = mag_ds.GetData()[0];
if (mag_ds.HasAttribute("units"))
sstr = std::any_cast<std::string>(mag_ds.GetAttribute("units"));
if (sstr == "Tesla")
factor = 1.0e4;
}
runData.SetField(dval*factor);
// get/set implantation energy
runData.SetEnergy(PMUSR_UNDEFINED);
// get/set moderator HV
runData.SetTransport(PMUSR_UNDEFINED);
// get/set RA HV's (LEM specific)
for (UInt_t i=0; i<4; i++)
runData.SetRingAnode(i, PMUSR_UNDEFINED);
// get/set setup
sstr = "n/a";
if (nxs_file->HasDataset("/run/notes"))
sstr = nxs_file->template GetDataset<std::string>("/run/notes").GetData()[0];
runData.SetSetup(sstr);
// get/set sample
sstr = "n/a";
if (nxs_file->HasDataset("/run/sample/name"))
sstr = nxs_file->template GetDataset<std::string>("/run/sample/name").GetData()[0];
runData.SetSample(sstr);
// get/set orientation
runData.SetOrientation("??");
// get/set time resolution (ns)
dval = PMUSR_UNDEFINED;
sstr = "n/a";
factor = 1.0;
if (nxs_file->HasDataset("/run/histogram_data_1/resolution")) {
auto res_ds = nxs_file->template GetDataset<int>("/run/histogram_data_1/resolution");
dval = res_ds.GetData()[0];
if (res_ds.HasAttribute("units"))
sstr = std::any_cast<std::string>(res_ds.GetAttribute("units"));
if ((sstr == "picoseconds") || (sstr == "pico.seconds"))
factor = 1.0e-3; // ps -> ns
}
runData.SetTimeResolution(dval*factor);
// get/set start/stop time
sstr = "n/a";
TString date{"n/a"}, time{"n/a"};
if (nxs_file->HasDataset("/run/start_time"))
sstr = nxs_file->template GetDataset<std::string>("/run/start_time").GetData()[0];
str = sstr;
SplitTimeDate(str, time, date, ok);
if (ok) {
runData.SetStartTime(time);
runData.SetStartDate(date);
}
sstr = "n/a";
date = "n/a";
time = "n/a";
if (nxs_file->HasDataset("/run/stop_time"))
sstr = nxs_file->template GetDataset<std::string>("/run/stop_time").GetData()[0];
str = sstr;
SplitTimeDate(str, time, date, ok);
if (ok) {
runData.SetStopTime(time);
runData.SetStopDate(date);
}
// get/set deadtime relevant parameters
if (nxs_file->HasDataset("/run/instrument/detector/deadtimes")) {
std::vector<float> dt;
dt = nxs_file->template GetDataset<float>("/run/instrument/detector/deadtimes").GetData();
runData.SetDeadTimeParam(dt);
}
if (nxs_file->HasDataset("/run/instrument/beam/frames_good")) {
ival = nxs_file->template GetDataset<float>("/run/instrument/beam/frames_good").GetData()[0];
runData.SetNumberOfGoodFrames(ival);
}
// data with its metadata
if (nxs_file->HasDataset("/run/histogram_data_1/counts")) {
int t0_bin{-1}, fgb{-1}, lgb{-1}, noOfHistos{-1}, histoLength{-1};
auto count_ds = nxs_file->template GetDataset<int>("/run/histogram_data_1/counts");
auto count = count_ds.GetData();
// get all necessary attributes
if (count_ds.HasAttribute("t0_bin"))
t0_bin = std::any_cast<int>(count_ds.GetAttribute("t0_bin"));
if (count_ds.HasAttribute("first_good_bin"))
fgb = std::any_cast<int>(count_ds.GetAttribute("first_good_bin"));
if (count_ds.HasAttribute("last_good_bin"))
lgb = std::any_cast<int>(count_ds.GetAttribute("last_good_bin"));
if (count_ds.HasAttribute("number"))
noOfHistos = std::any_cast<int>(count_ds.GetAttribute("number"));
if (count_ds.HasAttribute("length"))
histoLength = std::any_cast<int>(count_ds.GetAttribute("length"));
if (static_cast<int>(count.size()) != noOfHistos*histoLength) {
std::cerr << std::endl << "**ERROR** PNeXus data size error! count.size()=" << count.size() << ", #histos=" << noOfHistos << ", length=" << histoLength << "." << std::endl;
return false;
}
// fill dataSet
PDoubleVector data;
for (int i=0; i<noOfHistos; i++) {
dataSet.Clear();
dataSet.SetHistoNo(i+1); // i.e. histo numbers start with 1
dataSet.SetTimeZeroBin(t0_bin);
dataSet.SetFirstGoodBin(fgb);
dataSet.SetLastGoodBin(lgb);
for (int j=0; j<histoLength; j++)
data.push_back(count[i*histoLength+j]);
dataSet.SetData(data);
runData.SetDataSet(dataSet);
data.clear();
}
// keep run name from the msr-file
runData.SetRunName(fRunName);
// keep the information
fData.push_back(runData);
} else { // no data found
std::cerr << std::endl << "**ERROR** PNeXus couldn't obtain data: '/run/histogram_data_1/counts' is missing." << std::endl;
return false;
}
return true;
}
//--------------------------------------------------------------------------
// ReadNexusFileIdf2 (private)
//--------------------------------------------------------------------------
template <typename T>
Bool_t PRunDataHandler::ReadNexusFileIdf2(T& nxs_file)
{
PRawRunData runData;
PRawRunDataSet dataSet;
TString str;
std::string sstr;
Int_t ival;
Double_t dval, factor;
bool ok;
// get header information
// get/set laboratory
sstr = "n/a";
if (nxs_file->HasDataset("/raw_data_1/instrument/source/name"))
sstr = nxs_file->template GetDataset<std::string>("/raw_data_1/instrument/source/name").GetData()[0];
runData.SetLaboratory(sstr);
// get/set beamline
sstr = "n/a";
if (nxs_file->HasDataset("/raw_data_1/instrument/name"))
sstr = nxs_file->template GetDataset<std::string>("/raw_data_1/instrument/name").GetData()[0];
runData.SetBeamline(sstr);
runData.SetBeamline(sstr);
// get/set muon source
sstr = "n/a";
if (nxs_file->HasDataset("/raw_data_1/instrument/source/type"))
sstr = nxs_file->template GetDataset<std::string>("/raw_data_1/instrument/source/type").GetData()[0];
runData.SetMuonSource(sstr);
// get/set muon species
sstr = "n/a";
if (nxs_file->HasDataset("/raw_data_1/instrument/source/probe"))
sstr = nxs_file->template GetDataset<std::string>("/raw_data_1/instrument/source/probe").GetData()[0];
runData.SetMuonSpecies(sstr);
// get/set run title
sstr = "n/a";
if (nxs_file->HasDataset("/raw_data_1/title"))
sstr = nxs_file->template GetDataset<std::string>("/raw_data_1/title").GetData()[0];
runData.SetRunTitle(sstr);
// get/set run number
ival = -1;
if (nxs_file->HasDataset("/raw_data_1/run_number"))
ival = nxs_file->template GetDataset<int>("/raw_data_1/run_number").GetData()[0];
runData.SetRunNumber(ival);
// get/set temperature
dval = PMUSR_UNDEFINED;
sstr = "n/a";
if (nxs_file->HasDataset("/raw_data_1/sample/temperature")) {
auto tmp_ds = nxs_file->template GetDataset<float>("/raw_data_1/sample/temperature");
dval = tmp_ds.GetData()[0];
if (tmp_ds.HasAttribute("units"))
sstr = std::any_cast<std::string>(tmp_ds.GetAttribute("units"));
if (sstr == "Celcius")
dval += 273.16;
}
runData.SetTemperature(0, dval, 0.0);
// get/set field
dval = PMUSR_UNDEFINED;
sstr = "n/a";
factor = 1.0;
if (nxs_file->HasDataset("/raw_data_1/sample/magnetic_field")) {
auto mag_ds = nxs_file->template GetDataset<float>("/raw_data_1/sample/magnetic_field");
dval = mag_ds.GetData()[0];
if (mag_ds.HasAttribute("units"))
sstr = std::any_cast<std::string>(mag_ds.GetAttribute("units"));
if (sstr == "Tesla")
factor = 1.0e4;
}
runData.SetField(dval*factor);
// get/set implantation energy
runData.SetEnergy(PMUSR_UNDEFINED);
// get/set implantation energy
runData.SetEnergy(PMUSR_UNDEFINED);
// get/set moderator HV
runData.SetTransport(PMUSR_UNDEFINED);
// get/set RA HV's (LEM specific)
for (UInt_t i=0; i<4; i++)
runData.SetRingAnode(i, PMUSR_UNDEFINED);
// get/set setup
sstr = "n/a";
runData.SetSetup(str);
// get/set sample
sstr = "n/a";
if (nxs_file->HasDataset("/raw_data_1/sample/name"))
sstr = nxs_file->template GetDataset<std::string>("/raw_data_1/sample/name").GetData()[0];
runData.SetSample(sstr);
// get/set orientation
runData.SetOrientation("n/a");
// get/set time resolution (ns)
dval = PMUSR_UNDEFINED;
sstr = "n/a";
factor = 1.0;
if (nxs_file->HasDataset("/raw_data_1/instrument/detector_1/resolution")) {
auto res_ds = nxs_file->template GetDataset<int>("/raw_data_1/instrument/detector_1/resolution");
dval = res_ds.GetData()[0];
if (res_ds.HasAttribute("units"))
sstr = std::any_cast<std::string>(res_ds.GetAttribute("units"));
if ((sstr == "picoseconds") || (sstr == "pico.seconds"))
factor = 1.0e-3; // ps -> ns
}
runData.SetTimeResolution(dval*factor);
// get/set start/stop time
sstr = "n/a";
TString date{"n/a"}, time{"n/a"};
if (nxs_file->HasDataset("/raw_data_1/start_time"))
sstr = nxs_file->template GetDataset<std::string>("/raw_data_1/start_time").GetData()[0];
str = sstr;
SplitTimeDate(str, time, date, ok);
if (ok) {
runData.SetStartTime(time);
runData.SetStartDate(date);
}
sstr = "n/a";
date = "n/a";
time = "n/a";
if (nxs_file->HasDataset("/raw_data_1/end_time"))
sstr = nxs_file->template GetDataset<std::string>("/raw_data_1/end_time").GetData()[0];
str = sstr;
SplitTimeDate(str, time, date, ok);
if (ok) {
runData.SetStopTime(time);
runData.SetStopDate(date);
}
// get/set deadtime relevant parameters
if (nxs_file->HasDataset("/raw_data_1/instrument/detector_1/dead_time")) {
std::vector<float> dt;
dt = nxs_file->template GetDataset<float>("/raw_data_1/instrument/detector_1/dead_time").GetData();
runData.SetDeadTimeParam(dt);
}
if (nxs_file->HasDataset("/raw_data_1/good_frames")) {
ival = nxs_file->template GetDataset<int>("/raw_data_1/good_frames").GetData()[0];
runData.SetNumberOfGoodFrames(ival);
}
// data with its metadata
if (nxs_file->HasDataset("/raw_data_1/instrument/detector_1/counts")) {
int t0_bin{-1}, fgb{-1}, lgb{-1}, noOfHistos{-1}, histoLength{-1};
auto count_ds = nxs_file->template GetDataset<int>("/raw_data_1/instrument/detector_1/counts");
auto count = count_ds.GetData();
auto dims = count_ds.GetDimensions();
if (dims.size() < 3) {
std::cerr << std::endl << "**ERROR** PNeXus data dimension error! dims.size()=" << dims.size() << ", expecting == 3." << std::endl;
return false;
}
noOfHistos = dims[1];
histoLength = dims[2];
// get all necessary attributes
if (count_ds.HasAttribute("t0_bin"))
t0_bin = std::any_cast<int>(count_ds.GetAttribute("t0_bin"));
if (count_ds.HasAttribute("first_good_bin"))
fgb = std::any_cast<int>(count_ds.GetAttribute("first_good_bin"));
if (count_ds.HasAttribute("last_good_bin"))
lgb = std::any_cast<int>(count_ds.GetAttribute("last_good_bin"));
if (static_cast<int>(count.size()) != noOfHistos*histoLength) {
std::cerr << std::endl << "**ERROR** PNeXus data size error! count.size()=" << count.size() << ", #histos=" << noOfHistos << ", length=" << histoLength << "." << std::endl;
return false;
}
// fill dataSet
PDoubleVector data;
for (int i=0; i<noOfHistos; i++) {
dataSet.Clear();
dataSet.SetHistoNo(i+1); // i.e. histo numbers start with 1
dataSet.SetTimeZeroBin(t0_bin);
dataSet.SetFirstGoodBin(fgb);
dataSet.SetLastGoodBin(lgb);
for (int j=0; j<histoLength; j++)
data.push_back(count[i*histoLength+j]);
dataSet.SetData(data);
runData.SetDataSet(dataSet);
data.clear();
}
// keep run name from the msr-file
runData.SetRunName(fRunName);
// keep the information
fData.push_back(runData);
}
return true;
}
#endif // _PRUNDATAHANDLER_H_ #endif // _PRUNDATAHANDLER_H_