diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ca5145a..934674b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -26,7 +26,7 @@ If applicable, add screenshots to help explain your problem. **Environment (please complete the following information):** - OS: [e.g. Ubuntu] - - Version [e.g. 22] + - Version [e.g. 22] **Additional context** Add any other context about the problem here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2beb0c4..a465cc7 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -27,6 +27,6 @@ If instructions for replicating the fault are contained in the linked issue then --> Fixes #xxxx. - diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 6bd730f..c4f608f 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -36,7 +36,7 @@ jobs: ctest -V --output-on-failure # macos-latest: - # runs-on: macos-latest + # runs-on: macos-latest-xlarge # steps: # - uses: actions/checkout@v3 # - uses: conda-incubator/setup-miniconda@v2 @@ -56,4 +56,4 @@ jobs: # shell: bash -l {0} # run: | # cd sophiread/build - # ctest -V + # ctest -V --output-on-failure diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..acfc376 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,33 @@ +ci: + autofix_prs: true + +repos: + + # Run fast code improvement/checks before running PR specific helpers. + - repo: https://github.com/pre-commit/pre-commit-hooks.git + rev: v4.6.0 + hooks: + - id: trailing-whitespace + args: [--markdown-linebreak-ext=md] + exclude: .patch$ + - id: check-added-large-files + args: ['--maxkb=4096'] + - id: check-xml + - id: check-yaml + args: [--allow-multiple-documents] + exclude: conda/recipes/mantid/meta.yaml|conda/recipes/mantidqt/meta.yaml|conda/recipes/mantiddocs/meta.yaml|conda/recipes/mantidworkbench/meta.yaml + + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + + - repo: https://github.com/mantidproject/pre-commit-hooks.git + rev: 2f8a4f22629d0d23332f621df9de93751331161b + hooks: + - id: clang-format + + - repo: https://github.com/cheshirekow/cmake-format-precommit + rev: v0.6.13 + hooks: + - id: cmake-format diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 54708af..690a81c 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -5,7 +5,7 @@ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, +identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation. diff --git a/README.md b/README.md index af649af..de84be6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/ornlneutronimaging/mcpevent2hist/next.svg)](https://results.pre-commit.ci/latest/github/ornlneutronimaging/mcpevent2hist/next) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.8299343.svg)](https://doi.org/10.5281/zenodo.8299343) [![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7256/badge)](https://bestpractices.coreinfrastructure.org/projects/7256) @@ -14,14 +15,14 @@ neutron events. - `Sophiread` is the updated version of the application, which contains three main parts: - - `libSophireadLib.a` is the static libary containing the core functions of + - `libSophireadLib.a` is the static library containing the core functions of the application. - `Sophiread` is the main command line application, which can be used to process raw data into clustered hits and neutron events. - `SophireadGUI` is the Qt GUI application, which can be used to process raw data into neutron events and display it as a 2D histogram via super-pixeling. -- The input data, binary `tpx3` file must contain the global time stamp, GDC, which can be achieved by turning on GDC with GlobalTimestampInterval set to 1.0 in the detector settings. +- The input data, binary `tpx3` file must contain the global time stamp, GDC, which can be achieved by turning on GDC with GlobalTimestampInterval set to 1.0 in the detector settings. Developer Note -------------- diff --git a/sophiread/.clang-format b/sophiread/.clang-format index 97b0c10..0e6bbdf 100644 --- a/sophiread/.clang-format +++ b/sophiread/.clang-format @@ -1,248 +1,3 @@ --- Language: Cpp -# BasedOnStyle: Google -AccessModifierOffset: -1 -AlignAfterOpenBracket: Align -AlignArrayOfStructures: None -AlignConsecutiveAssignments: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - PadOperators: true -AlignConsecutiveBitFields: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - PadOperators: false -AlignConsecutiveDeclarations: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - PadOperators: false -AlignConsecutiveMacros: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - PadOperators: false -AlignEscapedNewlines: Left -AlignOperands: Align -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortEnumsOnASingleLine: true -AllowShortBlocksOnASingleLine: Never -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AllowShortLambdasOnASingleLine: All -AllowShortIfStatementsOnASingleLine: WithoutElse -AllowShortLoopsOnASingleLine: true -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: Yes -AttributeMacros: - - __capability -BinPackArguments: true -BinPackParameters: true -BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: Never - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - AfterExternBlock: false - BeforeCatch: false - BeforeElse: false - BeforeLambdaBody: false - BeforeWhile: false - IndentBraces: false - SplitEmptyFunction: true - SplitEmptyRecord: true - SplitEmptyNamespace: true -BreakBeforeBinaryOperators: None -BreakBeforeConceptDeclarations: Always -BreakBeforeBraces: Attach -BreakBeforeInheritanceComma: false -BreakInheritanceList: BeforeColon -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: BeforeColon -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true -ColumnLimit: 120 -CommentPragmas: '^ IWYU pragma:' -QualifierAlignment: Leave -CompactNamespaces: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true -DeriveLineEnding: true -DerivePointerAlignment: true -DisableFormat: false -EmptyLineAfterAccessModifier: Never -EmptyLineBeforeAccessModifier: LogicalBlock -ExperimentalAutoDetectBinPacking: false -PackConstructorInitializers: NextLine -BasedOnStyle: '' -ConstructorInitializerAllOnOneLineOrOnePerLine: false -AllowAllConstructorInitializersOnNextLine: true -FixNamespaceComments: true -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IfMacros: - - KJ_IF_MAYBE -IncludeBlocks: Regroup -IncludeCategories: - - Regex: '^' - Priority: 2 - SortPriority: 0 - CaseSensitive: false - - Regex: '^<.*\.h>' - Priority: 1 - SortPriority: 0 - CaseSensitive: false - - Regex: '^<.*' - Priority: 2 - SortPriority: 0 - CaseSensitive: false - - Regex: '.*' - Priority: 3 - SortPriority: 0 - CaseSensitive: false -IncludeIsMainRegex: '([-_](test|unittest))?$' -IncludeIsMainSourceRegex: '' -IndentAccessModifiers: false -IndentCaseLabels: true -IndentCaseBlocks: false -IndentGotoLabels: true -IndentPPDirectives: None -IndentExternBlock: AfterExternBlock -IndentRequiresClause: true -IndentWidth: 2 -IndentWrappedFunctionNames: false -InsertBraces: false -InsertTrailingCommas: None -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: false -LambdaBodyIndentation: Signature -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBinPackProtocolList: Never -ObjCBlockIndentWidth: 2 -ObjCBreakBeforeNestedBlockParam: true -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true -PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 1 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakOpenParenthesis: 0 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 200 -PenaltyIndentedWhitespace: 0 -PointerAlignment: Left -PPIndentWidth: -1 -RawStringFormats: - - Language: Cpp - Delimiters: - - cc - - CC - - cpp - - Cpp - - CPP - - 'c++' - - 'C++' - CanonicalDelimiter: '' - BasedOnStyle: google - - Language: TextProto - Delimiters: - - pb - - PB - - proto - - PROTO - EnclosingFunctions: - - EqualsProto - - EquivToProto - - PARSE_PARTIAL_TEXT_PROTO - - PARSE_TEST_PROTO - - PARSE_TEXT_PROTO - - ParseTextOrDie - - ParseTextProtoOrDie - - ParseTestProto - - ParsePartialTestProto - CanonicalDelimiter: pb - BasedOnStyle: google -ReferenceAlignment: Pointer -ReflowComments: true -RemoveBracesLLVM: false -RequiresClausePosition: OwnLine -SeparateDefinitionBlocks: Leave -ShortNamespaceLines: 1 -SortIncludes: CaseSensitive -SortJavaStaticImport: Before -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: true -SpaceBeforeAssignmentOperators: true -SpaceBeforeCaseColon: false -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements -SpaceBeforeParensOptions: - AfterControlStatements: true - AfterForeachMacros: true - AfterFunctionDefinitionName: false - AfterFunctionDeclarationName: false - AfterIfMacros: true - AfterOverloadedOperator: false - AfterRequiresInClause: false - AfterRequiresInExpression: false - BeforeNonEmptyParentheses: false -SpaceAroundPointerQualifiers: Default -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyBlock: false -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 2 -SpacesInAngles: Never -SpacesInConditionalStatement: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInLineCommentPrefix: - Minimum: 1 - Maximum: -1 -SpacesInParentheses: false -SpacesInSquareBrackets: false -SpaceBeforeSquareBrackets: false -BitFieldColonSpacing: Both -Standard: Auto -StatementAttributeLikeMacros: - - Q_EMIT -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION -TabWidth: 8 -UseCRLF: false -UseTab: Never -WhitespaceSensitiveMacros: - - STRINGIZE - - PP_STRINGIZE - - BOOST_PP_STRINGIZE - - NS_SWIFT_NAME - - CF_SWIFT_NAME +BasedOnStyle: Google diff --git a/sophiread/.pre-commit-config.yaml b/sophiread/.pre-commit-config.yaml new file mode 120000 index 0000000..da40622 --- /dev/null +++ b/sophiread/.pre-commit-config.yaml @@ -0,0 +1 @@ +../.pre-commit-config.yaml \ No newline at end of file diff --git a/sophiread/CMakeLists.txt b/sophiread/CMakeLists.txt index f101296..a4dfb92 100644 --- a/sophiread/CMakeLists.txt +++ b/sophiread/CMakeLists.txt @@ -1,19 +1,20 @@ # Sophiread CMakeLists.txt cmake_minimum_required(VERSION 3.20) -execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/scripts/version.sh -s print - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE SOPHIREAD_VERSION - RESULT_VARIABLE VERSION_RESULT - OUTPUT_STRIP_TRAILING_WHITESPACE -) +execute_process( + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/scripts/version.sh -s print + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE SOPHIREAD_VERSION + RESULT_VARIABLE VERSION_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT VERSION_RESULT EQUAL 0) message(FATAL_ERROR "Failed to determine version") endif() project("Sophiread" VERSION ${SOPHIREAD_VERSION}) -# This is to avoid accidentally using Homebrew header/lib instead of the one from micromamba +# This is to avoid accidentally using Homebrew header/lib instead of the one +# from micromamba if(DEFINED ENV{CONDA_PREFIX}) set(CMAKE_PREFIX_PATH $ENV{CONDA_PREFIX} ${CMAKE_PREFIX_PATH}) endif() @@ -43,26 +44,17 @@ include(GoogleTest) # Copy resources add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/data - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/resources/data + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/resources/data ${CMAKE_BINARY_DIR}/data - DEPENDS ${CMAKE_SOURCE_DIR}/resources/data -) + DEPENDS ${CMAKE_SOURCE_DIR}/resources/data) add_custom_target(copy_resources ALL DEPENDS ${CMAKE_BINARY_DIR}/data) # Add compiler flags if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - add_compile_options( - -march=native - -ffast-math - -pthread - -Wall - -Wextra - ) + add_compile_options(-march=native -ffast-math -pthread -Wall -Wextra) endif() -# Add Sophiread library -# NOTE: this will take care of the testing as well +# Add Sophiread library NOTE: this will take care of the testing as well # add_subdirectory(SophireadLib) # Add FastSophiread library @@ -74,19 +66,19 @@ add_subdirectory(SophireadCLI) # Add Sophiread stream command line interface # add_subdirectory(SophireadStreamCLI) -# Add Sophiread GUI application -# add_subdirectory(SophireadGUI) +# Add Sophiread GUI application add_subdirectory(SophireadGUI) # ----------------- DOXYGEN ----------------- # find_package(Doxygen) if(DOXYGEN_FOUND) - file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/docs") - add_custom_target(docs - COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile - COMMENT "Generating API documentation with Doxygen" - VERBATIM - ) + add_custom_target( + docs + COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + COMMENT "Generating API documentation with Doxygen" + VERBATIM) if(APPLE) set(OPEN_COMMAND open) elseif(UNIX) @@ -94,10 +86,9 @@ if(DOXYGEN_FOUND) elseif(WIN32) set(OPEN_COMMAND start) endif() - add_custom_command(TARGET docs POST_BUILD - COMMAND ${CMAKE_COMMAND} -E chdir - ${CMAKE_BINARY_DIR}/docs/html - open - index.html - ) + add_custom_command( + TARGET docs + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_BINARY_DIR}/docs/html open + index.html) endif(DOXYGEN_FOUND) diff --git a/sophiread/FastSophiread/CMakeLists.txt b/sophiread/FastSophiread/CMakeLists.txt index 57d5fe7..6205ecb 100644 --- a/sophiread/FastSophiread/CMakeLists.txt +++ b/sophiread/FastSophiread/CMakeLists.txt @@ -1,71 +1,55 @@ # Config FastSophireadLib -set(SRC_FAST_FILES - src/abs.cpp - src/centroid.cpp - src/disk_io.cpp - src/fastgaussian.cpp - src/hit.cpp - src/tpx3_fast.cpp -) +set(SRC_FAST_FILES src/abs.cpp src/centroid.cpp src/disk_io.cpp + src/fastgaussian.cpp src/hit.cpp src/tpx3_fast.cpp) # ------------- SophireadLibFast -------------- # add_library(FastSophiread ${SRC_FAST_FILES}) -target_include_directories(FastSophiread - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include - $ENV{CONDA_PREFIX}/include - ${EIGEN3_INCLUDE_DIR} - ${HDF5_INCLUDE_DIRS} -) -target_link_directories(FastSophiread - PRIVATE - $ENV{CONDA_PREFIX}/lib -) +target_include_directories( + FastSophiread + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include $ENV{CONDA_PREFIX}/include + ${EIGEN3_INCLUDE_DIR} ${HDF5_INCLUDE_DIRS}) +target_link_directories(FastSophiread PRIVATE $ENV{CONDA_PREFIX}/lib) # ----------------- TESTS ----------------- # function(add_sophiread_test test_name) add_executable(${test_name} tests/test_${test_name}.cpp) - target_link_libraries(${test_name} - PRIVATE - FastSophiread - pthread - TBB::tbb - spdlog::spdlog - GTest::GTest - GTest::Main - ${ARGN} - ) + target_link_libraries( + ${test_name} + PRIVATE FastSophiread + pthread + TBB::tbb + spdlog::spdlog + GTest::GTest + GTest::Main + ${ARGN}) gtest_discover_tests(${test_name}) endfunction() # Add tests add_sophiread_test(disk_io ${HDF5_LIBRARIES}) add_sophiread_test(hit) -add_sophiread_test(tpx3 ${HDF5_LIBRARIES}) +add_sophiread_test(tpx3 ${HDF5_LIBRARIES}) add_sophiread_test(abs) add_sophiread_test(centroid) add_sophiread_test(fastgaussian) - -# ------------------ Benchmarks ------------------ # -# Define a function to add benchmark targets +# ------------------ Benchmarks ------------------ # Define a function to add +# benchmark targets function(add_sophiread_benchmark NAME) - set(TARGET_NAME SophireadBenchmarks_${NAME}) - add_executable(${TARGET_NAME} benchmarks/benchmark_${NAME}.cpp) - - target_link_libraries(${TARGET_NAME} - PRIVATE - FastSophiread - pthread - TBB::tbb - spdlog::spdlog - ${ARGN} # Additional libraries passed as arguments - ) - - add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink - ${PROJECT_BINARY_DIR}/FastSophiread/${TARGET_NAME} - ${PROJECT_BINARY_DIR}/FastSophireadBenchmarks_${NAME}.app - ) + set(TARGET_NAME SophireadBenchmarks_${NAME}) + add_executable(${TARGET_NAME} benchmarks/benchmark_${NAME}.cpp) + + target_link_libraries( + ${TARGET_NAME} PRIVATE FastSophiread pthread TBB::tbb spdlog::spdlog + ${ARGN} # Additional libraries passed as arguments + ) + + add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E create_symlink + ${PROJECT_BINARY_DIR}/FastSophiread/${TARGET_NAME} + ${PROJECT_BINARY_DIR}/FastSophireadBenchmarks_${NAME}.app) endfunction() # Add benchmarks @@ -74,23 +58,18 @@ add_sophiread_benchmark(hits2events) add_sophiread_benchmark(raw2events ${HDF5_LIBRARIES}) # ----------------- CLI ----------------- # -add_executable(FastSophireadBenchmarksCLI - benchmarks/benchmark_mmap.cpp -) -target_link_libraries(FastSophireadBenchmarksCLI - PRIVATE - FastSophiread - pthread - TBB::tbb - spdlog::spdlog - ${HDF5_LIBRARIES} -) -add_custom_command(TARGET FastSophireadBenchmarksCLI POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink +add_executable(FastSophireadBenchmarksCLI benchmarks/benchmark_mmap.cpp) +target_link_libraries( + FastSophireadBenchmarksCLI PRIVATE FastSophiread pthread TBB::tbb + spdlog::spdlog ${HDF5_LIBRARIES}) +add_custom_command( + TARGET FastSophireadBenchmarksCLI + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E create_symlink ${PROJECT_BINARY_DIR}/FastSophiread/FastSophireadBenchmarksCLI ${PROJECT_BINARY_DIR}/FastSophireadBenchmarksCLI.app - - COMMAND ${CMAKE_COMMAND} -E create_symlink + COMMAND + ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/FastSophiread/benchmarks/benchmark.sh - ${PROJECT_BINARY_DIR}/FastSophiread_benchmark.sh -) + ${PROJECT_BINARY_DIR}/FastSophiread_benchmark.sh) diff --git a/sophiread/FastSophiread/benchmarks/benchmark_hits2events.cpp b/sophiread/FastSophiread/benchmarks/benchmark_hits2events.cpp index e5f7da9..660af05 100644 --- a/sophiread/FastSophiread/benchmarks/benchmark_hits2events.cpp +++ b/sophiread/FastSophiread/benchmarks/benchmark_hits2events.cpp @@ -6,18 +6,7 @@ * @date 2023-09-07 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include #include @@ -77,10 +66,14 @@ int main() { // -- gather statistics int n_events = events.size(); spdlog::info("Number of events: {}", n_events); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Single thread processing: {} s", elapsed / 1e6); auto speed = hits.size() / (elapsed / 1e6); spdlog::info("Single thread processing speed: {:. + * SPDX - License - Identifier: GPL - 3.0 + */ #include +#include // for std::numeric_limits<> #include #include -#include // for std::numeric_limits<> +#include "abs.h" #include "disk_io.h" #include "hit.h" #include "spdlog/spdlog.h" -#include "abs.h" #include "tbb/tbb.h" #include "tpx3_fast.h" // from SophireadLib/include/tpx3.cpp #include + #include "neutron.h" void saveEventsToHDF5(const std::string out_file_name, const std::vector& events); @@ -41,16 +32,19 @@ void saveEventsToHDF5(const std::string out_file_name, * @brief Save events to HDF5 file. * * NOTE: it does not appear that this function produces reliable output data. - * The files are not identical from run-to-run (despite the events being identical) - * The resulting .h5 file does not load correctly in hdfview (at least I don't know how to see the vectors in it). + * The files are not identical from run-to-run (despite the events being + * identical) The resulting .h5 file does not load correctly in hdfview (at + * least I don't know how to see the vectors in it). + * + * TODO: There is another program Sophiread that also writes out events. Make + * sure that those match up. Better still, use common output writing routines + * for both programs. * - * TODO: There is another program Sophiread that also writes out events. Make sure that those match up. - * Better still, use common output writing routines for both programs. - * * @param out_file_name: output file name. * @param events: neutron events to be saved. */ -void saveEventsToHDF5(const std::string out_file_name, const std::vector &events) { +void saveEventsToHDF5(const std::string out_file_name, + const std::vector& events) { // sanity check if (events.size() == 0) return; @@ -65,44 +59,49 @@ void saveEventsToHDF5(const std::string out_file_name, const std::vector x(events.size()); - std::transform(events.begin(), events.end(), x.begin(), [](const Neutron &event) { return event.getX(); }); + std::transform(events.begin(), events.end(), x.begin(), + [](const Neutron& event) { return event.getX(); }); H5::DataSet x_dataset = group.createDataSet("x", float_type, dataspace); x_dataset.write(x.data(), float_type); // -- write y std::vector y(events.size()); - std::transform(events.begin(), events.end(), y.begin(), [](const Neutron &event) { return event.getY(); }); + std::transform(events.begin(), events.end(), y.begin(), + [](const Neutron& event) { return event.getY(); }); H5::DataSet y_dataset = group.createDataSet("y", float_type, dataspace); y_dataset.write(y.data(), float_type); // -- write TOF_ns std::vector tof_ns(events.size()); std::transform(events.cbegin(), events.cend(), tof_ns.begin(), - [](const Neutron &event) { return event.getTOF_ns(); }); - H5::DataSet tof_ns_dataset = group.createDataSet("tof", float_type, dataspace); + [](const Neutron& event) { return event.getTOF_ns(); }); + H5::DataSet tof_ns_dataset = + group.createDataSet("tof", float_type, dataspace); tof_ns_dataset.write(tof_ns.data(), float_type); // -- write Nhits std::vector nhits(events.size()); std::transform(events.cbegin(), events.cend(), nhits.begin(), - [](const Neutron &event) { return event.getNHits(); }); + [](const Neutron& event) { return event.getNHits(); }); H5::DataSet nhits_dataset = group.createDataSet("nHits", int_type, dataspace); nhits_dataset.write(nhits.data(), int_type); // -- write TOT std::vector tot(events.size()); - std::transform(events.cbegin(), events.cend(), tot.begin(), [](const Neutron &event) { return event.getTOT(); }); + std::transform(events.cbegin(), events.cend(), tot.begin(), + [](const Neutron& event) { return event.getTOT(); }); H5::DataSet tot_dataset = group.createDataSet("tot", float_type, dataspace); tot_dataset.write(tot.data(), float_type); // -- close file out_file.close(); } -void saveEventsToCSV( const std::string out_file_name, - const std::vector& events); +void saveEventsToCSV(const std::string out_file_name, + const std::vector& events); /** * @brief Save events to CSV file. * * @param out_file_name: output file name. * @param events: neutron events to be saved. */ -void saveEventsToCSV(const std::string out_file_name, const std::vector &events) { +void saveEventsToCSV(const std::string out_file_name, + const std::vector& events) { // sanity check if (events.size() == 0) return; @@ -119,34 +118,32 @@ void saveEventsToCSV(const std::string out_file_name, const std::vector file << "X,Y,TOF (ns),Nhits, TOT\n"; // write events - for (auto & event : events) { - file << - event.getX() << "," << - event.getY() << "," << - event.getTOF_ns() << "," << - event.getNHits() << "," << - event.getTOT() << "\n"; + for (auto& event : events) { + file << event.getX() << "," << event.getY() << "," << event.getTOF_ns() + << "," << event.getNHits() << "," << event.getTOT() << "\n"; } // -- close file file.close(); } -void saveEventsToBIN( const std::string out_file_name, - const std::vector& events); +void saveEventsToBIN(const std::string out_file_name, + const std::vector& events); /** * @brief Save events to BIN file. * * @param out_file_name: output file name. * @param events: neutron events to be saved. */ -void saveEventsToBIN(const std::string out_file_name, const std::vector &events) { +void saveEventsToBIN(const std::string out_file_name, + const std::vector& events) { // sanity check if (events.size() == 0) return; // write to BIN file // -- preparation and header - std::ofstream file(out_file_name, std::ofstream::binary | std::ofstream::trunc); + std::ofstream file(out_file_name, + std::ofstream::binary | std::ofstream::trunc); // Check if file is open successfully if (!file.is_open()) { @@ -155,10 +152,11 @@ void saveEventsToBIN(const std::string out_file_name, const std::vector } // write events - for (auto & event : events) - { - std::uint16_t x = (std::uint16_t)(event.getX() * std::numeric_limits::max()/512.0); - std::uint16_t y = (std::uint16_t)(event.getY() * std::numeric_limits::max()/512.0); + for (auto& event : events) { + std::uint16_t x = (std::uint16_t)( + event.getX() * std::numeric_limits::max() / 512.0); + std::uint16_t y = (std::uint16_t)( + event.getY() * std::numeric_limits::max() / 512.0); std::uint64_t tof = (std::uint64_t)event.getTOF_ns(); std::uint16_t nhits = (std::uint16_t)event.getNHits(); std::uint16_t tot = (std::uint16_t)event.getTOT(); @@ -171,18 +169,19 @@ void saveEventsToBIN(const std::string out_file_name, const std::vector } // https://stackoverflow.com/questions/874134/find-out-if-string-ends-with-another-string-in-c -bool endsWith (std::string const &fullString, std::string const &ending) { - if (fullString.length() >= ending.length()) { - return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); - } else { - return false; - } +bool endsWith(std::string const& fullString, std::string const& ending) { + if (fullString.length() >= ending.length()) { + return (0 == fullString.compare(fullString.length() - ending.length(), + ending.length(), ending)); + } else { + return false; + } } -int main(int argc, char* argv[]) -{ +int main(int argc, char* argv[]) { if (argc < 2) { - spdlog::critical("Usage: {} [ [options]]", argv[0]); + spdlog::critical("Usage: {} [ [options]]", + argv[0]); return 1; } @@ -198,23 +197,22 @@ int main(int argc, char* argv[]) bool use_tgdc = false; bool debug = false; float pulse_rate = 0.0; - if( argc>3 ) - { - use_tbb = strstr(argv[3],"tbb")!=NULL; - use_mmap = strstr(argv[3],"mmap")!=NULL; - use_tgdc = strstr(argv[3],"tgdc")!=NULL; - debug = strstr(argv[3],"debug")!=NULL; - - // select pulse rate - pulse_rate = strstr(argv[3],"1hz") ? 1.0 : pulse_rate; - pulse_rate = strstr(argv[3],"10hz") ? 10.0 : pulse_rate; - pulse_rate = strstr(argv[3],"15hz") ? 15.0 : pulse_rate; - pulse_rate = strstr(argv[3],"30hz") ? 30.0 : pulse_rate; - pulse_rate = strstr(argv[3],"45hz") ? 45.0 : pulse_rate; - pulse_rate = strstr(argv[3],"60hz") ? 60.0 : pulse_rate; + if (argc > 3) { + use_tbb = strstr(argv[3], "tbb") != NULL; + use_mmap = strstr(argv[3], "mmap") != NULL; + use_tgdc = strstr(argv[3], "tgdc") != NULL; + debug = strstr(argv[3], "debug") != NULL; + + // select pulse rate + pulse_rate = strstr(argv[3], "1hz") ? 1.0 : pulse_rate; + pulse_rate = strstr(argv[3], "10hz") ? 10.0 : pulse_rate; + pulse_rate = strstr(argv[3], "15hz") ? 15.0 : pulse_rate; + pulse_rate = strstr(argv[3], "30hz") ? 30.0 : pulse_rate; + pulse_rate = strstr(argv[3], "45hz") ? 45.0 : pulse_rate; + pulse_rate = strstr(argv[3], "60hz") ? 60.0 : pulse_rate; } - if( debug ) spdlog::set_level(spdlog::level::debug); + if (debug) spdlog::set_level(spdlog::level::debug); // report statistics size_t n_hits = 0; @@ -222,16 +220,9 @@ int main(int argc, char* argv[]) size_t n_events = 0; // manage timers (for statistics) - // but see also NOTES section of https://en.cppreference.com/w/cpp/chrono/high_resolution_clock - enum { - TOTAL = 0, - RAW_DATA, - BATCHES, - EVENTS, - GATHER, - OUTPUT, - NUM_TIMERS - }; + // but see also NOTES section of + // https://en.cppreference.com/w/cpp/chrono/high_resolution_clock + enum { TOTAL = 0, RAW_DATA, BATCHES, EVENTS, GATHER, OUTPUT, NUM_TIMERS }; struct { std::chrono::time_point begin; std::chrono::time_point end; @@ -244,10 +235,15 @@ int main(int argc, char* argv[]) // obtain pointer to data std::string method_raw_data = use_mmap ? "Mapping" : "Reading"; spdlog::debug("{} input: {}", method_raw_data, in_tpx3); - timer[TOTAL].begin = timer[RAW_DATA].begin = std::chrono::high_resolution_clock::now(); - auto raw_data = use_mmap ? mmapTPX3RawToMapInfo(in_tpx3) : readTPX3RawToMapInfo(in_tpx3); + timer[TOTAL].begin = timer[RAW_DATA].begin = + std::chrono::high_resolution_clock::now(); + auto raw_data = + use_mmap ? mmapTPX3RawToMapInfo(in_tpx3) : readTPX3RawToMapInfo(in_tpx3); timer[RAW_DATA].end = std::chrono::high_resolution_clock::now(); - timer[RAW_DATA].accumulated = static_cast(std::chrono::duration_cast(timer[RAW_DATA].end - timer[RAW_DATA].begin).count()); + timer[RAW_DATA].accumulated = + static_cast(std::chrono::duration_cast( + timer[RAW_DATA].end - timer[RAW_DATA].begin) + .count()); size_t raw_data_consumed = 0; unsigned long tdc_timestamp = 0; @@ -260,17 +256,15 @@ int main(int argc, char* argv[]) spdlog::debug("@{:p}, {}", raw_data.map, raw_data.max); - if ( raw_data.map == nullptr ) - { + if (raw_data.map == nullptr) { spdlog::error("Insufficient memory: {}", in_tpx3); exit(EXIT_FAILURE); } -// NB: processing large memory-mapped files requires a restriction -// on the amount of raw data that is treated by the algorithm + // NB: processing large memory-mapped files requires a restriction + // on the amount of raw data that is treated by the algorithm - if( use_tbb ) - { + if (use_tbb) { spdlog::debug("Processing tbb..."); method_events = "TBB Parallel"; } else { @@ -281,120 +275,137 @@ int main(int argc, char* argv[]) std::cerr << std::endl; std::cerr.precision(2); -while (raw_data_consumed < raw_data.max) { - - // manage partial batches - size_t consumed = 0; - char *raw_data_ptr = raw_data.map + raw_data_consumed; - size_t raw_data_size = raw_data.max - raw_data_consumed; - - //spdlog::debug("raw_data: {}/{} ({:.2}%)", raw_data_consumed, raw_data.max, static_cast(raw_data_consumed)*100.0/static_cast(raw_data.max)); - std::cerr << "\rraw_data: " - << raw_data_consumed << "/" << raw_data.max - << " (" << static_cast(raw_data_consumed)*100.0/static_cast(raw_data.max) << "%)"; - - timer[BATCHES].begin = std::chrono::high_resolution_clock::now(); - auto batches = findTPX3H(raw_data_ptr, raw_data_size, consumed); - if (use_tgdc) - { - // extract tdc and gdc timestamps from the batches read so far - for (auto& tpx3 : batches) { - updateTimestamp(tpx3, raw_data_ptr, consumed, tdc_timestamp, gdc_timestamp, timer_lsb32); + while (raw_data_consumed < raw_data.max) { + // manage partial batches + size_t consumed = 0; + char* raw_data_ptr = raw_data.map + raw_data_consumed; + size_t raw_data_size = raw_data.max - raw_data_consumed; + + // spdlog::debug("raw_data: {}/{} ({:.2}%)", raw_data_consumed, + // raw_data.max, + // static_cast(raw_data_consumed)*100.0/static_cast(raw_data.max)); + std::cerr << "\rraw_data: " << raw_data_consumed << "/" << raw_data.max + << " (" + << static_cast(raw_data_consumed) * 100.0 / + static_cast(raw_data.max) + << "%)"; + + timer[BATCHES].begin = std::chrono::high_resolution_clock::now(); + auto batches = findTPX3H(raw_data_ptr, raw_data_size, consumed); + if (use_tgdc) { + // extract tdc and gdc timestamps from the batches read so far + for (auto& tpx3 : batches) { + updateTimestamp(tpx3, raw_data_ptr, consumed, tdc_timestamp, + gdc_timestamp, timer_lsb32); + } } - } - timer[BATCHES].end = timer[EVENTS].begin = std::chrono::high_resolution_clock::now(); - - if( use_tbb ) - { - // https://github.com/jjallaire/TBB/blob/master/inst/examples/parallel-vector-sum.cpp - struct ComputeEvents { - // source vector(s) - char *input; - std::size_t range; - std::vector& batch; - - // output vector-of-vector-of-events - tbb::concurrent_vector> output; - - // standard and splitting constructor - ComputeEvents(char *input, std::size_t range, std::vector& batch) : input(input), range(range), batch(batch), output() {} - ComputeEvents(ComputeEvents& body, tbb::split) : input(body.input), range(body.range), batch(body.batch), output() {} - - // generate just the range of hits - void operator()(const tbb::blocked_range& r) { - auto abs_alg_mt = std::make_unique(5.0, 1, 75); - for (size_t i = r.begin(); i != r.end(); ++i) { - TPX3& _tpx3 = batch[i]; - extractHits(_tpx3, input, range); - abs_alg_mt->reset(); - abs_alg_mt->fit(_tpx3.hits); - output.push_back(abs_alg_mt->get_events(_tpx3.hits)); + timer[BATCHES].end = timer[EVENTS].begin = + std::chrono::high_resolution_clock::now(); + + if (use_tbb) { + // https://github.com/jjallaire/TBB/blob/master/inst/examples/parallel-vector-sum.cpp + struct ComputeEvents { + // source vector(s) + char* input; + std::size_t range; + std::vector& batch; + + // output vector-of-vector-of-events + tbb::concurrent_vector> output; + + // standard and splitting constructor + ComputeEvents(char* input, std::size_t range, std::vector& batch) + : input(input), range(range), batch(batch), output() {} + ComputeEvents(ComputeEvents& body, tbb::split) + : input(body.input), + range(body.range), + batch(body.batch), + output() {} + + // generate just the range of hits + void operator()(const tbb::blocked_range& r) { + auto abs_alg_mt = std::make_unique(5.0, 1, 75); + for (size_t i = r.begin(); i != r.end(); ++i) { + TPX3& _tpx3 = batch[i]; + extractHits(_tpx3, input, range); + abs_alg_mt->reset(); + abs_alg_mt->fit(_tpx3.hits); + output.push_back(abs_alg_mt->get_events(_tpx3.hits)); + } } - } - // join vectors - void join(ComputeEvents& rhs) { - for (auto& a : rhs.output) { - output.push_back(a); + // join vectors + void join(ComputeEvents& rhs) { + for (auto& a : rhs.output) { + output.push_back(a); + } } + }; + + ComputeEvents compute(raw_data_ptr, consumed, batches); + tbb::parallel_reduce(tbb::blocked_range(0, batches.size()), + compute); + // transfer vectors + for (auto& a : compute.output) { + events.push_back(a); + } + } else { + auto abs_alg = std::make_unique(5.0, 1, 75); + for (auto& _tpx3 : batches) { + extractHits(_tpx3, raw_data_ptr, consumed); + abs_alg->reset(); + abs_alg->fit(_tpx3.hits); + events.push_back(abs_alg->get_events(_tpx3.hits)); } - }; - - ComputeEvents compute(raw_data_ptr, consumed, batches); - tbb::parallel_reduce(tbb::blocked_range(0, batches.size()), compute); - // transfer vectors - for (auto& a : compute.output) { - events.push_back(a); - } - } else { - auto abs_alg = std::make_unique(5.0, 1, 75); - for (auto& _tpx3 : batches) { - extractHits(_tpx3, raw_data_ptr, consumed); - abs_alg->reset(); - abs_alg->fit(_tpx3.hits); - events.push_back(abs_alg->get_events(_tpx3.hits)); } - } - timer[EVENTS].end = std::chrono::high_resolution_clock::now(); + timer[EVENTS].end = std::chrono::high_resolution_clock::now(); - // report statistics - for (const auto& tpx3 : batches) { - n_hits += tpx3.hits.size(); - } - // sanity check: hit.getTOF() should be smaller than 666,667 clock, which is - // equivalent to 16.67 ms - if ( pulse_rate > 0.0 ) { + // report statistics for (const auto& tpx3 : batches) { - for (const auto& hit : tpx3.hits) { - auto tof_ms = hit.getTOF_ns() * 1e-6; - if (tof_ms > (1.0/pulse_rate)+1e-6) { - spdlog::debug("TOF: {} ms", tof_ms); - n_bad_hits++; + n_hits += tpx3.hits.size(); + } + // sanity check: hit.getTOF() should be smaller than 666,667 clock, which is + // equivalent to 16.67 ms + if (pulse_rate > 0.0) { + for (const auto& tpx3 : batches) { + for (const auto& hit : tpx3.hits) { + auto tof_ms = hit.getTOF_ns() * 1e-6; + if (tof_ms > (1.0 / pulse_rate) + 1e-6) { + spdlog::debug("TOF: {} ms", tof_ms); + n_bad_hits++; + } } } } - } - for (const auto& e : events) { - n_events += e.size(); - } + for (const auto& e : events) { + n_events += e.size(); + } - // manage iterations on partial raw_data - raw_data_consumed += consumed; - timer[BATCHES].accumulated += static_cast(std::chrono::duration_cast(timer[BATCHES].end - timer[BATCHES].begin).count()); - timer[EVENTS].accumulated += static_cast(std::chrono::duration_cast(timer[EVENTS].end - timer[EVENTS].begin).count()); -} + // manage iterations on partial raw_data + raw_data_consumed += consumed; + timer[BATCHES].accumulated += static_cast( + std::chrono::duration_cast( + timer[BATCHES].end - timer[BATCHES].begin) + .count()); + timer[EVENTS].accumulated += static_cast( + std::chrono::duration_cast( + timer[EVENTS].end - timer[EVENTS].begin) + .count()); + } std::cerr << std::endl; timer[TOTAL].end = std::chrono::high_resolution_clock::now(); - timer[TOTAL].accumulated += static_cast(std::chrono::duration_cast(timer[TOTAL].end - timer[TOTAL].begin).count()); + timer[TOTAL].accumulated += + static_cast(std::chrono::duration_cast( + timer[TOTAL].end - timer[TOTAL].begin) + .count()); spdlog::info("Number of hits: {}", n_hits); spdlog::info("Number of events: {}", n_events); - if (n_hits > 0) - { - spdlog::info("bad/total hit ratio: {:.2f}%", (n_bad_hits*100.0)/n_hits); + if (n_hits > 0) { + spdlog::info("bad/total hit ratio: {:.2f}%", (n_bad_hits * 100.0) / n_hits); auto speed_raw_data = n_hits / (timer[RAW_DATA].accumulated / 1e6); auto speed_batches = n_hits / (timer[BATCHES].accumulated / 1e6); @@ -408,11 +419,11 @@ while (raw_data_consumed < raw_data.max) { // write output // save events to file - if( !no_output && n_events > 0 ) - { + if (!no_output && n_events > 0) { spdlog::debug("Writing output: {}", out_dat); - // NB: events is a vector-of-vectors-of-events that we transfrom into a vector-of-events + // NB: events is a vector-of-vectors-of-events that we transform into a + // vector-of-events timer[GATHER].begin = std::chrono::high_resolution_clock::now(); std::vector v; for (auto& a : events) { @@ -422,23 +433,39 @@ while (raw_data_consumed < raw_data.max) { v.push_back(n); } } - timer[GATHER].end = timer[OUTPUT].begin = std::chrono::high_resolution_clock::now(); + timer[GATHER].end = timer[OUTPUT].begin = + std::chrono::high_resolution_clock::now(); std::string csv_ext = ".csv"; std::string bin_ext = ".bin"; std::string h5_ext = ".h5"; - if (endsWith(out_dat, csv_ext)) saveEventsToCSV(out_dat, v); - else if (endsWith(out_dat, bin_ext)) saveEventsToBIN(out_dat, v); - else if (endsWith(out_dat, h5_ext)) saveEventsToHDF5(out_dat, v); - else { spdlog::debug("Unhanded extention (.bin, .csv or .h5 are known)"); no_output = true; } + if (endsWith(out_dat, csv_ext)) + saveEventsToCSV(out_dat, v); + else if (endsWith(out_dat, bin_ext)) + saveEventsToBIN(out_dat, v); + else if (endsWith(out_dat, h5_ext)) + saveEventsToHDF5(out_dat, v); + else { + spdlog::debug("Unhanded extension (.bin, .csv or .h5 are known)"); + no_output = true; + } timer[OUTPUT].end = std::chrono::high_resolution_clock::now(); - timer[GATHER].accumulated += static_cast(std::chrono::duration_cast(timer[GATHER].end - timer[GATHER].begin).count()); - timer[OUTPUT].accumulated += static_cast(std::chrono::duration_cast(timer[OUTPUT].end - timer[OUTPUT].begin).count()); + timer[GATHER].accumulated += static_cast( + std::chrono::duration_cast( + timer[GATHER].end - timer[GATHER].begin) + .count()); + timer[OUTPUT].accumulated += static_cast( + std::chrono::duration_cast( + timer[OUTPUT].end - timer[OUTPUT].begin) + .count()); auto speed_gather = n_events / (timer[GATHER].accumulated / 1e6); auto speed_output = n_events / (timer[OUTPUT].accumulated / 1e6); - spdlog::info("{:s} speed: {:. + * SPDX - License - Identifier: GPL - 3.0 + */ #include #include @@ -56,7 +45,8 @@ void check_bad_tof(const std::vector batches) { } /** - * @brief benchmark converting raw data to neutron events performance, single thread. + * @brief benchmark converting raw data to neutron events performance, single + * thread. * * @param raw_data */ @@ -67,7 +57,9 @@ void run_single_thread(std::vector raw_data, bool check_tof = false) { auto start = std::chrono::high_resolution_clock::now(); auto batches = findTPX3H(raw_data); auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Locate all headers: {} s", elapsed / 1e6); total_time += elapsed / 1e6; // locate all gdc timestamps @@ -79,7 +71,8 @@ void run_single_thread(std::vector raw_data, bool check_tof = false) { updateTimestamp(tpx3, raw_data, tdc_timestamp, gdc_timestamp, timer_lsb32); } end = std::chrono::high_resolution_clock::now(); - elapsed = std::chrono::duration_cast(end - start).count(); + elapsed = std::chrono::duration_cast(end - start) + .count(); spdlog::info("Locate all gdc timestamps: {} s", elapsed / 1e6); total_time += elapsed / 1e6; /* @@ -117,7 +110,8 @@ void run_single_thread(std::vector raw_data, bool check_tof = false) { auto events = abs_alg->get_events(tpx3.hits); } end = std::chrono::high_resolution_clock::now(); - elapsed = std::chrono::duration_cast(end - start).count(); + elapsed = std::chrono::duration_cast(end - start) + .count(); spdlog::info("Get all hits: {} s", elapsed / 1e6); total_time += elapsed / 1e6; // find out total number of hits @@ -173,7 +167,8 @@ void run_single_thread(std::vector raw_data, bool check_tof = false) { max_spidertime_ns_from_file = spi_time_ns; } } - spdlog::info("Max spidertime_ns from file: {} / s", max_spidertime_ns_from_file / 1e9); + spdlog::info("Max spidertime_ns from file: {} / s", + max_spidertime_ns_from_file / 1e9); } void run_multi_thread(std::vector raw_data, bool check_tof = false) { @@ -189,19 +184,20 @@ void run_multi_thread(std::vector raw_data, bool check_tof = false) { updateTimestamp(tpx3, raw_data, tdc_timestamp, gdc_timestamp, timer_lsb32); } // use tbb parallel_for to process batches - tbb::parallel_for(tbb::blocked_range(0, batches_mt.size()), [&](const tbb::blocked_range& r) { - auto abs_alg_mt = std::make_unique(5.0, 1, 75); - for (size_t i = r.begin(); i != r.end(); ++i) { - auto& tpx3 = batches_mt[i]; - extractHits(tpx3, raw_data); - - abs_alg_mt->reset(); - // fit hits into clusters - abs_alg_mt->fit(tpx3.hits); - // get neutron events - auto events = abs_alg_mt->get_events(tpx3.hits); - } - }); + tbb::parallel_for(tbb::blocked_range(0, batches_mt.size()), + [&](const tbb::blocked_range& r) { + auto abs_alg_mt = std::make_unique(5.0, 1, 75); + for (size_t i = r.begin(); i != r.end(); ++i) { + auto& tpx3 = batches_mt[i]; + extractHits(tpx3, raw_data); + + abs_alg_mt->reset(); + // fit hits into clusters + abs_alg_mt->fit(tpx3.hits); + // get neutron events + auto events = abs_alg_mt->get_events(tpx3.hits); + } + }); auto end = std::chrono::high_resolution_clock::now(); // -- gather statistics auto n_hits = 0; @@ -210,7 +206,9 @@ void run_multi_thread(std::vector raw_data, bool check_tof = false) { n_hits += hits.size(); } spdlog::info("Number of hits: {}", n_hits); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Multi-thread processing: {} s", elapsed / 1e6); auto speed = n_hits / (elapsed / 1e6); spdlog::info("Multi-thread processing speed: {:(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Read raw data: {} s", elapsed / 1e6); // single thread processing diff --git a/sophiread/FastSophiread/benchmarks/benchmark_raw2hits.cpp b/sophiread/FastSophiread/benchmarks/benchmark_raw2hits.cpp index cff18fe..a4b2706 100644 --- a/sophiread/FastSophiread/benchmarks/benchmark_raw2hits.cpp +++ b/sophiread/FastSophiread/benchmarks/benchmark_raw2hits.cpp @@ -6,18 +6,7 @@ * @date 2023-08-30 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include @@ -46,7 +35,9 @@ void run_single_thread(const std::vector& raw_data) { n_hits += hits.size(); } spdlog::info("Number of hits: {}", n_hits); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Single thread processing: {} s", elapsed / 1e6); auto speed = n_hits / (elapsed / 1e6); spdlog::info("Single thread processing speed: {:& raw_data) { auto start = std::chrono::high_resolution_clock::now(); auto batches_mt = findTPX3H(raw_data); // use tbb parallel_for to process batches - tbb::parallel_for(tbb::blocked_range(0, batches_mt.size()), [&](const tbb::blocked_range& r) { - for (size_t i = r.begin(); i != r.end(); ++i) { - auto& tpx3 = batches_mt[i]; - extractHits(tpx3, raw_data); - } - }); + tbb::parallel_for(tbb::blocked_range(0, batches_mt.size()), + [&](const tbb::blocked_range& r) { + for (size_t i = r.begin(); i != r.end(); ++i) { + auto& tpx3 = batches_mt[i]; + extractHits(tpx3, raw_data); + } + }); auto end = std::chrono::high_resolution_clock::now(); // -- gather statistics auto n_hits = 0; @@ -72,7 +64,9 @@ void run_multi_thread(const std::vector& raw_data) { n_hits += hits.size(); } spdlog::info("Number of hits: {}", n_hits); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Multi-thread processing: {} s", elapsed / 1e6); auto speed = n_hits / (elapsed / 1e6); spdlog::info("Multi-thread processing speed: {:(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); // logging spdlog::info("Read raw data: {} s", elapsed / 1e6); diff --git a/sophiread/FastSophiread/include/abs.h b/sophiread/FastSophiread/include/abs.h index 151a14f..ff849d1 100644 --- a/sophiread/FastSophiread/include/abs.h +++ b/sophiread/FastSophiread/include/abs.h @@ -7,18 +7,7 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once @@ -43,8 +32,11 @@ struct Cluster { */ class ABS : public ClusteringAlgorithm { public: - ABS(double r, unsigned long int min_cluster_size, unsigned long int spider_time_range) - : m_feature(r), m_min_cluster_size(min_cluster_size), spiderTimeRange_(spider_time_range){}; + ABS(double r, unsigned long int min_cluster_size, + unsigned long int spider_time_range) + : m_feature(r), + m_min_cluster_size(min_cluster_size), + spiderTimeRange_(spider_time_range){}; void fit(const std::vector& data); void set_method(std::string method) { m_method = method; } void reset() { clusterLabels_.clear(); } @@ -53,13 +45,13 @@ class ABS : public ClusteringAlgorithm { ~ABS() = default; private: - double m_feature; // feather range - std::string m_method{"centroid"}; // method for centroid - std::vector clusterLabels_; // The cluster labels for each hit + double m_feature; // feather range + std::string m_method{"centroid"}; // method for centroid + std::vector clusterLabels_; // The cluster labels for each hit std::vector> clusterIndices_; // The cluster indices for // each cluster - const int numClusters_ = 8; // The number of clusters use in runtime - unsigned long int m_min_cluster_size = 1; // The maximum cluster size - unsigned long int spiderTimeRange_ = 75; // The spider time range (in ns) - std::unique_ptr m_alg; // The clustering algorithm + const int numClusters_ = 8; // The number of clusters use in runtime + unsigned long int m_min_cluster_size = 1; // The maximum cluster size + unsigned long int spiderTimeRange_ = 75; // The spider time range (in ns) + std::unique_ptr m_alg; // The clustering algorithm }; diff --git a/sophiread/FastSophiread/include/centroid.h b/sophiread/FastSophiread/include/centroid.h index 331c287..4a1ac40 100644 --- a/sophiread/FastSophiread/include/centroid.h +++ b/sophiread/FastSophiread/include/centroid.h @@ -7,18 +7,7 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once @@ -38,9 +27,12 @@ class Centroid : public PeakFittingAlgorithm { public: Centroid(bool weighted_by_tot = true) : m_weighted_by_tot(weighted_by_tot){}; Centroid(bool weighted_by_tot, double super_resolution_factor) - : m_weighted_by_tot(weighted_by_tot), m_super_resolution_factor(super_resolution_factor){}; + : m_weighted_by_tot(weighted_by_tot), + m_super_resolution_factor(super_resolution_factor){}; - void set_weighted_by_tot(bool weighted_by_tot) { m_weighted_by_tot = weighted_by_tot; } + void set_weighted_by_tot(bool weighted_by_tot) { + m_weighted_by_tot = weighted_by_tot; + } void set_super_resolution_factor(double super_resolution_factor) { m_super_resolution_factor = super_resolution_factor; @@ -52,6 +44,7 @@ class Centroid : public PeakFittingAlgorithm { private: bool m_weighted_by_tot = true; - double m_super_resolution_factor = 1.0; // it is better to perform super resolution during post processing, but it - // can also be part of the fitting algorithm + double m_super_resolution_factor = + 1.0; // it is better to perform super resolution during post processing, + // but it can also be part of the fitting algorithm }; diff --git a/sophiread/FastSophiread/include/clustering.h b/sophiread/FastSophiread/include/clustering.h index 0937260..01229df 100644 --- a/sophiread/FastSophiread/include/clustering.h +++ b/sophiread/FastSophiread/include/clustering.h @@ -6,18 +6,7 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once diff --git a/sophiread/FastSophiread/include/disk_io.h b/sophiread/FastSophiread/include/disk_io.h index 8c3f889..e9ea995 100644 --- a/sophiread/FastSophiread/include/disk_io.h +++ b/sophiread/FastSophiread/include/disk_io.h @@ -6,18 +6,7 @@ * @date 2023-09-01 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once @@ -34,44 +23,62 @@ std::vector readTPX3RawToCharVec(const std::string& tpx3file); typedef struct mapinfo { - int fd; - char *map; - size_t max; + int fd; + char* map; + size_t max; } mapinfo_t; mapinfo_t readTPX3RawToMapInfo(const std::string& tpx3file); mapinfo_t mmapTPX3RawToMapInfo(const std::string& tpx3file); -std::string generateFileNameWithMicroTimestamp(const std::string& originalFileName); +std::string generateFileNameWithMicroTimestamp( + const std::string& originalFileName); template -void writeDatasetToGroup(H5::Group& group, const std::string& dataset_name, ForwardIterator begin, ForwardIterator end, +void writeDatasetToGroup(H5::Group& group, const std::string& dataset_name, + ForwardIterator begin, ForwardIterator end, const H5::DataType& data_type); std::string generateGroupName(H5::H5File& file, const std::string& baseName); template void saveOrAppendToHDF5( - const std::string& out_file_name, ForwardIterator data_begin, ForwardIterator data_end, - const std::string& baseGroupName, - const std::vector>>& attributes, bool append); + const std::string& out_file_name, ForwardIterator data_begin, + ForwardIterator data_end, const std::string& baseGroupName, + const std::vector< + std::pair>>& + attributes, + bool append); template -void saveOrAppendHitsToHDF5(const std::string& out_file_name, ForwardIterator hits_begin, ForwardIterator hits_end, - bool appendMode = false); +void saveOrAppendHitsToHDF5(const std::string& out_file_name, + ForwardIterator hits_begin, + ForwardIterator hits_end, bool appendMode = false); template -void saveHitsToHDF5(const std::string& out_file_path, ForwardIterator hits_begin, ForwardIterator hits_end); -void saveHitsToHDF5(const std::string& out_file_path, const std::vector& hits); +void saveHitsToHDF5(const std::string& out_file_path, + ForwardIterator hits_begin, ForwardIterator hits_end); +void saveHitsToHDF5(const std::string& out_file_path, + const std::vector& hits); template -void appendHitsToHDF5(const std::string& out_file_name, ForwardIterator hits_begin, ForwardIterator hits_end); -void appendHitsToHDF5(const std::string& out_file_name, const std::vector& hits); +void appendHitsToHDF5(const std::string& out_file_name, + ForwardIterator hits_begin, ForwardIterator hits_end); +void appendHitsToHDF5(const std::string& out_file_name, + const std::vector& hits); template -void saveOrAppendNeutronToHDF5(const std::string& out_file_name, ForwardIterator neutron_begin, - ForwardIterator neutron_end, bool append = false); +void saveOrAppendNeutronToHDF5(const std::string& out_file_name, + ForwardIterator neutron_begin, + ForwardIterator neutron_end, + bool append = false); template -void saveNeutronToHDF5(const std::string& out_file_name, ForwardIterator neutron_begin, ForwardIterator neutron_end); -void saveNeutronToHDF5(const std::string& out_file_name, const std::vector& neutrons); +void saveNeutronToHDF5(const std::string& out_file_name, + ForwardIterator neutron_begin, + ForwardIterator neutron_end); +void saveNeutronToHDF5(const std::string& out_file_name, + const std::vector& neutrons); template -void appendNeutronToHDF5(const std::string& out_file_name, ForwardIterator neutron_begin, ForwardIterator neutron_end); -void appendNeutronToHDF5(const std::string& out_file_name, const std::vector& neutrons); +void appendNeutronToHDF5(const std::string& out_file_name, + ForwardIterator neutron_begin, + ForwardIterator neutron_end); +void appendNeutronToHDF5(const std::string& out_file_name, + const std::vector& neutrons); diff --git a/sophiread/FastSophiread/include/fastgaussian.h b/sophiread/FastSophiread/include/fastgaussian.h index fd477d9..298b71d 100644 --- a/sophiread/FastSophiread/include/fastgaussian.h +++ b/sophiread/FastSophiread/include/fastgaussian.h @@ -6,18 +6,7 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once @@ -30,7 +19,8 @@ class FastGaussian : public PeakFittingAlgorithm { public: FastGaussian(){}; - FastGaussian(double super_resolution_factor) : m_super_resolution_factor(super_resolution_factor){}; + FastGaussian(double super_resolution_factor) + : m_super_resolution_factor(super_resolution_factor){}; void set_super_resolution_factor(double super_resolution_factor) { m_super_resolution_factor = super_resolution_factor; diff --git a/sophiread/FastSophiread/include/hit.h b/sophiread/FastSophiread/include/hit.h index af8fa9e..3d0a449 100644 --- a/sophiread/FastSophiread/include/hit.h +++ b/sophiread/FastSophiread/include/hit.h @@ -6,18 +6,7 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once @@ -29,7 +18,14 @@ class Hit : public IPositionTOF { public: // default constructor - Hit() : m_x(0), m_y(0), m_tot(0), m_toa(0), m_ftoa(0), m_tof(0), m_spidertime(0){}; + Hit() + : m_x(0), + m_y(0), + m_tot(0), + m_toa(0), + m_ftoa(0), + m_tof(0), + m_spidertime(0){}; // copy constructor Hit(const Hit& hit) : m_x(hit.m_x), @@ -40,12 +36,20 @@ class Hit : public IPositionTOF { m_tof(hit.m_tof), m_spidertime(hit.m_spidertime){}; - Hit(int x, int y, int tot, int toa, int ftoa, unsigned int tof, unsigned long long spidertime) - : m_x(x), m_y(y), m_tot(tot), m_toa(toa), m_ftoa(ftoa), m_tof(tof), m_spidertime(spidertime){}; + Hit(int x, int y, int tot, int toa, int ftoa, unsigned int tof, + unsigned long long spidertime) + : m_x(x), + m_y(y), + m_tot(tot), + m_toa(toa), + m_ftoa(ftoa), + m_tof(tof), + m_spidertime(spidertime){}; // special constructor that directly parse the raw packet from tpx3 // into a hit - Hit(const char* packet, const unsigned long long tdc, const unsigned long long gdc, const int chip_layout_type); + Hit(const char* packet, const unsigned long long tdc, + const unsigned long long gdc, const int chip_layout_type); Hit& operator=(const Hit& hit) { m_x = hit.m_x; @@ -69,13 +73,16 @@ class Hit : public IPositionTOF { double getTOF_ns() const { return m_tof * m_scale_to_ns_40mhz; }; double getTOA_ns() const { return m_toa * m_scale_to_ns_40mhz; }; double getTOT_ns() const { return m_tot * m_scale_to_ns_40mhz; }; - double getSPIDERTIME_ns() const { return m_spidertime * m_scale_to_ns_40mhz; }; + double getSPIDERTIME_ns() const { + return m_spidertime * m_scale_to_ns_40mhz; + }; double getFTOA_ns() const { return m_ftoa * m_scale_to_ns_640mhz; }; std::string toString() const { std::stringstream ss; - ss << "Hit: x=" << m_x << ", y=" << m_y << ", tot=" << m_tot << ", toa=" << m_toa << ", ftoa=" << m_ftoa - << ", tof=" << m_tof << ", spidertime=" << m_spidertime; + ss << "Hit: x=" << m_x << ", y=" << m_y << ", tot=" << m_tot + << ", toa=" << m_toa << ", ftoa=" << m_ftoa << ", tof=" << m_tof + << ", spidertime=" << m_spidertime; return ss.str(); }; @@ -91,9 +98,12 @@ class Hit : public IPositionTOF { int m_toa; // time of arrival (40MHz clock, 14 bit) int m_ftoa; // fine time of arrival (640MHz clock, 4 bit) unsigned int m_tof; - unsigned long long m_spidertime; // time from the spider board (in the unit of 25ns) + unsigned long long + m_spidertime; // time from the spider board (in the unit of 25ns) // scale factor that converts time to ns - const double m_scale_to_ns_40mhz = 25.0; // 40 MHz clock is used for the coarse time of arrival. - const double m_scale_to_ns_640mhz = 25.0 / 16.0; // 640 MHz clock is used for the fine time of arrival. + const double m_scale_to_ns_40mhz = + 25.0; // 40 MHz clock is used for the coarse time of arrival. + const double m_scale_to_ns_640mhz = + 25.0 / 16.0; // 640 MHz clock is used for the fine time of arrival. }; \ No newline at end of file diff --git a/sophiread/FastSophiread/include/iposition_tof.h b/sophiread/FastSophiread/include/iposition_tof.h index 6f09783..7bb5a8c 100644 --- a/sophiread/FastSophiread/include/iposition_tof.h +++ b/sophiread/FastSophiread/include/iposition_tof.h @@ -4,27 +4,16 @@ * @brief Interface for neutron and hit * @version 0.1 * @date 2024-08-20 - * - * @copyright Copyright (c) 2024 - * 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 3 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, see . + * @copyright Copyright (c) 2024 + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once class IPositionTOF { -public: - virtual ~IPositionTOF() = default; - virtual double iGetX() const = 0; - virtual double iGetY() const = 0; - virtual double iGetTOF_ns() const = 0; + public: + virtual ~IPositionTOF() = default; + virtual double iGetX() const = 0; + virtual double iGetY() const = 0; + virtual double iGetTOF_ns() const = 0; }; diff --git a/sophiread/FastSophiread/include/neutron.h b/sophiread/FastSophiread/include/neutron.h index f39e43f..807494f 100644 --- a/sophiread/FastSophiread/include/neutron.h +++ b/sophiread/FastSophiread/include/neutron.h @@ -6,18 +6,7 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once @@ -28,7 +17,8 @@ class Neutron : public IPositionTOF { public: - Neutron(const double x, const double y, const double tof, const double tot, const int nHits) + Neutron(const double x, const double y, const double tof, const double tot, + const int nHits) : m_x(x), m_y(y), m_tof(tof), m_tot(tot), m_nHits(nHits){}; double getX() const { return m_x; }; @@ -41,7 +31,8 @@ class Neutron : public IPositionTOF { std::string toString() const { std::stringstream ss; - ss << "Neutron: x= " << m_x << ", y= " << m_y << ", tof= " << m_tof << ", nHits= " << m_nHits; + ss << "Neutron: x= " << m_x << ", y= " << m_y << ", tof= " << m_tof + << ", nHits= " << m_nHits; return ss.str(); }; @@ -51,9 +42,10 @@ class Neutron : public IPositionTOF { double iGetTOF_ns() const override { return getTOF_ns(); } private: - double m_x, m_y; // pixel coordinates - double m_tof; // time of flight - double m_tot; // time-over-threshold - int m_nHits; // number of hits in the event (cluster size) - double m_scale_to_ns_40mhz = 25.0; // 40 MHz clock is used for the coarse time of arrival. + double m_x, m_y; // pixel coordinates + double m_tof; // time of flight + double m_tot; // time-over-threshold + int m_nHits; // number of hits in the event (cluster size) + double m_scale_to_ns_40mhz = + 25.0; // 40 MHz clock is used for the coarse time of arrival. }; \ No newline at end of file diff --git a/sophiread/FastSophiread/include/peakfitting.h b/sophiread/FastSophiread/include/peakfitting.h index 1946931..d6a9ed8 100644 --- a/sophiread/FastSophiread/include/peakfitting.h +++ b/sophiread/FastSophiread/include/peakfitting.h @@ -6,18 +6,7 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once diff --git a/sophiread/FastSophiread/include/tpx3_fast.h b/sophiread/FastSophiread/include/tpx3_fast.h index 47734b7..a08d326 100644 --- a/sophiread/FastSophiread/include/tpx3_fast.h +++ b/sophiread/FastSophiread/include/tpx3_fast.h @@ -6,18 +6,7 @@ * @date 2023-08-31 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once @@ -29,26 +18,31 @@ /** * @brief Special struct to hold the information about chip dataset position in - * the raw charater array. + * the raw character array. * @note Each TPX3 dataset batch comes from a single sub-chip */ struct TPX3 { - std::size_t index; // index of the dataset batch in the raw charater array - const int num_packets; // number of packets in the dataset batch (time packet and data packet) - const int chip_layout_type; // data source (sub-chip ID) - std::vector hits; // hits extracted from the dataset batch + std::size_t index; // index of the dataset batch in the raw character array + const int num_packets; // number of packets in the dataset batch (time packet + // and data packet) + const int chip_layout_type; // data source (sub-chip ID) + std::vector hits; // hits extracted from the dataset batch std::vector neutrons; // neutrons from clustering hits - unsigned long tdc_timestamp; // starting tdc timestamp of the dataset batch - unsigned long long gdc_timestamp; // starting gdc timestamp of the dataset batch - unsigned long timer_lsb32; // starting Timer_LSB32 of the dataset batch + unsigned long tdc_timestamp; // starting tdc timestamp of the dataset batch + unsigned long long + gdc_timestamp; // starting gdc timestamp of the dataset batch + unsigned long timer_lsb32; // starting Timer_LSB32 of the dataset batch TPX3(std::size_t index, int num_packets, int chip_layout_type) - : index(index), num_packets(num_packets), chip_layout_type(chip_layout_type) { + : index(index), + num_packets(num_packets), + chip_layout_type(chip_layout_type) { hits.reserve(num_packets); // assuming 1 hit per data packet }; - void emplace_back(const char* packet, const unsigned long long tdc, const unsigned long long gdc) { + void emplace_back(const char* packet, const unsigned long long tdc, + const unsigned long long gdc) { hits.emplace_back(packet, tdc, gdc, chip_layout_type); }; }; @@ -58,29 +52,42 @@ std::vector findTPX3H(ForwardIter first, ForwardIter last); std::vector findTPX3H(const std::vector& raw_bytes); std::vector findTPX3H(char* raw_bytes, std::size_t size); template -std::vector findTPX3H(ForwardIter first, ForwardIter last, std::size_t& consumed); -std::vector findTPX3H(const std::vector& raw_bytes, std::size_t& consumed); -std::vector findTPX3H(char* raw_bytes, std::size_t size, std::size_t& consumed); +std::vector findTPX3H(ForwardIter first, ForwardIter last, + std::size_t& consumed); +std::vector findTPX3H(const std::vector& raw_bytes, + std::size_t& consumed); +std::vector findTPX3H(char* raw_bytes, std::size_t size, + std::size_t& consumed); template -void updateTimestamp(TPX3& tpx3h, ForwardIter bytes_begin, ForwardIter bytes_end, unsigned long& tdc_timestamp, - unsigned long long int& gdc_timestamp, unsigned long& timer_lsb32); -void updateTimestamp(TPX3& tpx3h, const std::vector& raw_bytes, unsigned long& tdc_timestamp, - unsigned long long int& gdc_timestamp, unsigned long& timer_lsb32); -void updateTimestamp(TPX3& tpx3h, char* raw_bytes, std::size_t size, unsigned long& tdc_timestamp, - unsigned long long int& gdc_timestamp, unsigned long& timer_lsb32); +void updateTimestamp(TPX3& tpx3h, ForwardIter bytes_begin, + ForwardIter bytes_end, unsigned long& tdc_timestamp, + unsigned long long int& gdc_timestamp, + unsigned long& timer_lsb32); +void updateTimestamp(TPX3& tpx3h, const std::vector& raw_bytes, + unsigned long& tdc_timestamp, + unsigned long long int& gdc_timestamp, + unsigned long& timer_lsb32); +void updateTimestamp(TPX3& tpx3h, char* raw_bytes, std::size_t size, + unsigned long& tdc_timestamp, + unsigned long long int& gdc_timestamp, + unsigned long& timer_lsb32); template void extractHits(TPX3& tpx3h, ForwardIter bytes_begin, ForwardIter bytes_end); void extractHits(TPX3& tpx3h, const std::vector& raw_bytes); void extractHits(TPX3& tpx3h, char* raw_bytes, std::size_t size); -void update_tdc_timestamp(const char* char_array, const unsigned long long& gdc_timestamp, +void update_tdc_timestamp(const char* char_array, + const unsigned long long& gdc_timestamp, unsigned long& tdc_timestamp); -void update_gdc_timestamp_and_timer_lsb32(const char* char_array, unsigned long& timer_lsb32, +void update_gdc_timestamp_and_timer_lsb32(const char* char_array, + unsigned long& timer_lsb32, unsigned long long& gdc_timestamp); template -void process_tpx3_packets(TPX3& tpx3h, ForwardIter bytes_begin, ForwardIter bytes_end, unsigned long& tdc_timestamp, - unsigned long long int& gdc_timestamp, unsigned long& timer_lsb32, bool extract_hits = true); +void process_tpx3_packets(TPX3& tpx3h, ForwardIter bytes_begin, + ForwardIter bytes_end, unsigned long& tdc_timestamp, + unsigned long long int& gdc_timestamp, + unsigned long& timer_lsb32, bool extract_hits = true); diff --git a/sophiread/FastSophiread/src/abs.cpp b/sophiread/FastSophiread/src/abs.cpp index 613c55f..4267ce0 100644 --- a/sophiread/FastSophiread/src/abs.cpp +++ b/sophiread/FastSophiread/src/abs.cpp @@ -7,18 +7,7 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include "abs.h" @@ -71,9 +60,12 @@ void ABS::fit(const std::vector& data) { // case_1: cluster is not full, check if hit is within the feather range // of the cluster, if yes, add hit to cluster and update cluster bounds, // if not, id as noise - else if (std::abs(hit.getSPIDERTIME_ns() - cluster.spidertime) <= spiderTimeRange_) { - if (hit.getX() >= cluster.x_min - m_feature && hit.getX() <= cluster.x_max + m_feature && - hit.getY() >= cluster.y_min - m_feature && hit.getY() <= cluster.y_max + m_feature) { + else if (std::abs(hit.getSPIDERTIME_ns() - cluster.spidertime) <= + spiderTimeRange_) { + if (hit.getX() >= cluster.x_min - m_feature && + hit.getX() <= cluster.x_max + m_feature && + hit.getY() >= cluster.y_min - m_feature && + hit.getY() <= cluster.y_max + m_feature) { cluster.size++; cluster.x_min = std::min(cluster.x_min, hit.getX()); cluster.x_max = std::max(cluster.x_max, hit.getX()); @@ -146,7 +138,8 @@ std::vector ABS::get_events(const std::vector& data) { if (clusterLabels_.empty()) { return events; } else { - auto max_label_it = std::max_element(clusterLabels_.begin(), clusterLabels_.end()); + auto max_label_it = + std::max_element(clusterLabels_.begin(), clusterLabels_.end()); max_label = *max_label_it; } diff --git a/sophiread/FastSophiread/src/centroid.cpp b/sophiread/FastSophiread/src/centroid.cpp index ccc288b..d9448e7 100644 --- a/sophiread/FastSophiread/src/centroid.cpp +++ b/sophiread/FastSophiread/src/centroid.cpp @@ -7,18 +7,7 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include "centroid.h" diff --git a/sophiread/FastSophiread/src/disk_io.cpp b/sophiread/FastSophiread/src/disk_io.cpp index bb9a475..0b65665 100644 --- a/sophiread/FastSophiread/src/disk_io.cpp +++ b/sophiread/FastSophiread/src/disk_io.cpp @@ -6,18 +6,7 @@ * @date 2023-09-01 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include "disk_io.h" @@ -26,12 +15,13 @@ #include "spdlog/spdlog.h" /** - * @brief Read Timepix3 raw data from file into memory as a vector of char for subsequent analysis. + * @brief Read Timepix3 raw data from file into memory as a vector of char for + * subsequent analysis. * * @param[in] tpx3file * @return std::vector */ -std::vector readTPX3RawToCharVec(const std::string& tpx3file) { +std::vector readTPX3RawToCharVec(const std::string &tpx3file) { // Open the file std::ifstream file(tpx3file, std::ios::binary | std::ios::ate); @@ -64,9 +54,8 @@ std::vector readTPX3RawToCharVec(const std::string& tpx3file) { * @param tpx3file * @return mapinfo_t that defines { char *, and size_t } */ -mapinfo_t readTPX3RawToMapInfo(const std::string& tpx3file) -{ - mapinfo_t info = { -1, NULL, 0 }; +mapinfo_t readTPX3RawToMapInfo(const std::string &tpx3file) { + mapinfo_t info = {-1, NULL, 0}; // Open the file std::ifstream file(tpx3file, std::ios::binary | std::ios::ate); @@ -87,8 +76,10 @@ mapinfo_t readTPX3RawToMapInfo(const std::string& tpx3file) info.map = reinterpret_cast(malloc(info.max)); // Read the data from file and store it in the vector - if (info.map == NULL) info.max = 0; - else file.read(info.map, info.max); + if (info.map == NULL) + info.max = 0; + else + file.read(info.map, info.max); // Close the file file.close(); @@ -97,10 +88,10 @@ mapinfo_t readTPX3RawToMapInfo(const std::string& tpx3file) } // for mmap support +#include #include -#include #include -#include +#include #include /** @@ -109,9 +100,8 @@ mapinfo_t readTPX3RawToMapInfo(const std::string& tpx3file) * @param tpx3file * @return mapinfo_t that defines { char *, and size_t } */ -mapinfo_t mmapTPX3RawToMapInfo(const std::string& tpx3file) -{ - mapinfo_t info = { -1, NULL, 0 }; +mapinfo_t mmapTPX3RawToMapInfo(const std::string &tpx3file) { + mapinfo_t info = {-1, NULL, 0}; std::ifstream file(tpx3file, std::ios::binary); if (!file.is_open()) { @@ -119,17 +109,22 @@ mapinfo_t mmapTPX3RawToMapInfo(const std::string& tpx3file) exit(EXIT_FAILURE); } - info.fd = open(tpx3file.c_str(),O_RDWR,0666); + info.fd = open(tpx3file.c_str(), O_RDWR, 0666); - if( info.fd == -1 ) { perror(tpx3file.c_str()); exit(EXIT_FAILURE); } - info.max = lseek(info.fd,0,SEEK_END); // determine the sizeof the file - info.map = reinterpret_cast(mmap(0, info.max, PROT_READ|PROT_WRITE, MAP_SHARED, info.fd, 0)); + if (info.fd == -1) { + perror(tpx3file.c_str()); + exit(EXIT_FAILURE); + } + info.max = lseek(info.fd, 0, SEEK_END); // determine the sizeof the file + info.map = reinterpret_cast( + mmap(0, info.max, PROT_READ | PROT_WRITE, MAP_SHARED, info.fd, 0)); // https://lemire.me/blog/2012/06/26/which-is-fastest-read-fread-ifstream-or-mmap/ // says to add MAP_POPULATE to make it mmap() faster... // TODO: Test this return info; - // https://stackoverflow.com/questions/26569217/do-i-have-to-munmap-a-mmap-file ( consensus is that you do not need to do it ) + // https://stackoverflow.com/questions/26569217/do-i-have-to-munmap-a-mmap-file + // ( consensus is that you do not need to do it ) } /** @@ -138,23 +133,26 @@ mapinfo_t mmapTPX3RawToMapInfo(const std::string& tpx3file) * @param[in] originalFileName * @return std::string */ -std::string generateFileNameWithMicroTimestamp(const std::string& originalFileName) { +std::string generateFileNameWithMicroTimestamp( + const std::string &originalFileName) { auto now = std::chrono::high_resolution_clock::now(); auto seconds = std::chrono::time_point_cast(now); - auto micros = std::chrono::duration_cast(now - seconds); + auto micros = + std::chrono::duration_cast(now - seconds); std::filesystem::path filePath(originalFileName); std::string baseName = filePath.stem().string(); std::string extension = filePath.extension().string(); std::filesystem::path parentPath = filePath.parent_path(); - // use h5 as extention if not specified + // use h5 as extension if not specified if (extension.empty()) { extension = ".h5"; } std::stringstream newFileName; - newFileName << baseName << "_" << std::setfill('0') << std::setw(6) << micros.count() << extension; + newFileName << baseName << "_" << std::setfill('0') << std::setw(6) + << micros.count() << extension; if (!parentPath.empty()) { return (parentPath / newFileName.str()).string(); @@ -177,7 +175,8 @@ std::string generateFileNameWithMicroTimestamp(const std::string& originalFileNa * @param[in] data_type */ template -void writeDatasetToGroup(H5::Group &group, const std::string &dataset_name, ForwardIterator begin, ForwardIterator end, +void writeDatasetToGroup(H5::Group &group, const std::string &dataset_name, + ForwardIterator begin, ForwardIterator end, Func transform_func, const H5::DataType &data_type) { std::vector data; data.reserve(std::distance(begin, end)); @@ -220,9 +219,11 @@ std::string generateGroupName(H5::H5File &file, const std::string &baseName) { */ template void saveOrAppendToHDF5( - const std::string &out_file_name, ForwardIterator data_begin, ForwardIterator data_end, - const std::string &baseGroupName, - const std::vector>> &attributes, + const std::string &out_file_name, ForwardIterator data_begin, + ForwardIterator data_end, const std::string &baseGroupName, + const std::vector< + std::pair>> + &attributes, bool append) { const size_t num_data = std::distance(data_begin, data_end); @@ -238,14 +239,17 @@ void saveOrAppendToHDF5( out_file = H5::H5File(out_file_name, H5F_ACC_RDWR); } - std::string groupName = append ? generateGroupName(out_file, baseGroupName) : baseGroupName; + std::string groupName = + append ? generateGroupName(out_file, baseGroupName) : baseGroupName; H5::Group group = out_file.createGroup(groupName); for (const auto &[dataset_name, func] : attributes) { if constexpr (std::is_same_v) { - writeDatasetToGroup(group, dataset_name, data_begin, data_end, func, H5::IntType(H5::PredType::NATIVE_INT)); + writeDatasetToGroup(group, dataset_name, data_begin, data_end, func, + H5::IntType(H5::PredType::NATIVE_INT)); } else if constexpr (std::is_same_v) { - writeDatasetToGroup(group, dataset_name, data_begin, data_end, func, + writeDatasetToGroup(group, dataset_name, data_begin, data_end, + func, H5::FloatType(H5::PredType::NATIVE_DOUBLE)); } } @@ -264,24 +268,29 @@ void saveOrAppendToHDF5( * @param[in] append */ template -void saveOrAppendHitsToHDF5(const std::string &out_file_name, ForwardIterator hits_begin, ForwardIterator hits_end, - bool append) { - saveOrAppendToHDF5(out_file_name, hits_begin, hits_end, "hits", - { - {"x", [](const auto &hit) { return static_cast(hit.getX()); }}, - {"y", [](const auto &hit) { return static_cast(hit.getY()); }}, - {"tot_ns", [](const auto &hit) { return hit.getTOT_ns(); }}, - {"toa_ns", [](const auto &hit) { return hit.getTOA_ns(); }}, - {"ftoa_ns", [](const auto &hit) { return hit.getFTOA_ns(); }}, - {"tof_ns", [](const auto &hit) { return hit.getTOF_ns(); }}, - {"spidertime_ns", [](const auto &hit) { return hit.getSPIDERTIME_ns(); }}, - }, - append); +void saveOrAppendHitsToHDF5(const std::string &out_file_name, + ForwardIterator hits_begin, + ForwardIterator hits_end, bool append) { + saveOrAppendToHDF5( + out_file_name, hits_begin, hits_end, "hits", + { + {"x", + [](const auto &hit) { return static_cast(hit.getX()); }}, + {"y", + [](const auto &hit) { return static_cast(hit.getY()); }}, + {"tot_ns", [](const auto &hit) { return hit.getTOT_ns(); }}, + {"toa_ns", [](const auto &hit) { return hit.getTOA_ns(); }}, + {"ftoa_ns", [](const auto &hit) { return hit.getFTOA_ns(); }}, + {"tof_ns", [](const auto &hit) { return hit.getTOF_ns(); }}, + {"spidertime_ns", + [](const auto &hit) { return hit.getSPIDERTIME_ns(); }}, + }, + append); } /** - * @brief Save a hit vector to a HDF5 file. If the file already exists, rename the file with a microsecond timestamp - as suffix. + * @brief Save a hit vector to a HDF5 file. If the file already exists, rename + the file with a microsecond timestamp as suffix. * * @tparam ForwardIterator * @param[in] out_file_name @@ -289,10 +298,12 @@ void saveOrAppendHitsToHDF5(const std::string &out_file_name, ForwardIterator hi * @param[in] hits_end */ template -void saveHitsToHDF5(const std::string &out_file_name, ForwardIterator hits_begin, ForwardIterator hits_end) { +void saveHitsToHDF5(const std::string &out_file_name, + ForwardIterator hits_begin, ForwardIterator hits_end) { std::string finalFileName = out_file_name; if (std::filesystem::exists(out_file_name)) { - spdlog::warn("File '{}' already exists. Renaming the output file.", out_file_name); + spdlog::warn("File '{}' already exists. Renaming the output file.", + out_file_name); finalFileName = generateFileNameWithMicroTimestamp(out_file_name); spdlog::info("New output file: '{}'", finalFileName); } @@ -305,12 +316,14 @@ void saveHitsToHDF5(const std::string &out_file_name, ForwardIterator hits_begin * @param[in] out_file_name * @param[in] hits */ -void saveHitsToHDF5(const std::string &out_file_name, const std::vector &hits) { +void saveHitsToHDF5(const std::string &out_file_name, + const std::vector &hits) { saveHitsToHDF5(out_file_name, hits.cbegin(), hits.cend()); } /** - * @brief Append a hit vector to a HDF5 file. If the file already exists, append the hits to the existing file. + * @brief Append a hit vector to a HDF5 file. If the file already exists, append + * the hits to the existing file. * * @tparam ForwardIterator * @param[in] out_file_name @@ -318,7 +331,8 @@ void saveHitsToHDF5(const std::string &out_file_name, const std::vector &hi * @param[in] hits_end */ template -void appendHitsToHDF5(const std::string &out_file_name, ForwardIterator hits_begin, ForwardIterator hits_end) { +void appendHitsToHDF5(const std::string &out_file_name, + ForwardIterator hits_begin, ForwardIterator hits_end) { saveOrAppendHitsToHDF5(out_file_name, hits_begin, hits_end, true); } @@ -328,7 +342,8 @@ void appendHitsToHDF5(const std::string &out_file_name, ForwardIterator hits_beg * @param[in] out_file_name * @param[in] hits */ -void appendHitsToHDF5(const std::string &out_file_name, const std::vector &hits) { +void appendHitsToHDF5(const std::string &out_file_name, + const std::vector &hits) { appendHitsToHDF5(out_file_name, hits.cbegin(), hits.cend()); } @@ -342,22 +357,26 @@ void appendHitsToHDF5(const std::string &out_file_name, const std::vector & * @param[in] append */ template -void saveOrAppendNeutronToHDF5(const std::string &out_file_name, ForwardIterator neutron_begin, +void saveOrAppendNeutronToHDF5(const std::string &out_file_name, + ForwardIterator neutron_begin, ForwardIterator neutron_end, bool append) { - saveOrAppendToHDF5(out_file_name, neutron_begin, neutron_end, "neutrons", - { - {"x", [](const Neutron &neutron) { return neutron.getX(); }}, - {"y", [](const Neutron &neutron) { return neutron.getY(); }}, - {"tof_ns", [](const Neutron &neutron) { return neutron.getTOF_ns(); }}, - {"tot_ns", [](const Neutron &neutron) { return neutron.getTOT_ns(); }}, - {"nHits", [](const Neutron &neutron) { return neutron.getNHits(); }}, - }, - append); + saveOrAppendToHDF5( + out_file_name, neutron_begin, neutron_end, "neutrons", + { + {"x", [](const Neutron &neutron) { return neutron.getX(); }}, + {"y", [](const Neutron &neutron) { return neutron.getY(); }}, + {"tof_ns", + [](const Neutron &neutron) { return neutron.getTOF_ns(); }}, + {"tot_ns", + [](const Neutron &neutron) { return neutron.getTOT_ns(); }}, + {"nHits", [](const Neutron &neutron) { return neutron.getNHits(); }}, + }, + append); } /** - * @brief Save a neutron vector to a HDF5 file. If the file already exists, rename the file with a microsecond - timestamp + * @brief Save a neutron vector to a HDF5 file. If the file already exists, + rename the file with a microsecond timestamp * as suffix. * * @tparam ForwardIterator @@ -366,10 +385,13 @@ void saveOrAppendNeutronToHDF5(const std::string &out_file_name, ForwardIterator * @param[in] neutron_end */ template -void saveNeutronToHDF5(const std::string &out_file_name, ForwardIterator neutron_begin, ForwardIterator neutron_end) { +void saveNeutronToHDF5(const std::string &out_file_name, + ForwardIterator neutron_begin, + ForwardIterator neutron_end) { std::string finalFileName = out_file_name; if (std::filesystem::exists(out_file_name)) { - spdlog::warn("File '{}' already exists. Renaming the output file.", out_file_name); + spdlog::warn("File '{}' already exists. Renaming the output file.", + out_file_name); finalFileName = generateFileNameWithMicroTimestamp(out_file_name); spdlog::info("New output file: '{}'", finalFileName); } @@ -382,13 +404,14 @@ void saveNeutronToHDF5(const std::string &out_file_name, ForwardIterator neutron * @param[in] out_file_name * @param[in] neutrons */ -void saveNeutronToHDF5(const std::string &out_file_name, const std::vector &neutrons) { +void saveNeutronToHDF5(const std::string &out_file_name, + const std::vector &neutrons) { saveNeutronToHDF5(out_file_name, neutrons.cbegin(), neutrons.cend()); } /** - * @brief Append a neutron vector to a HDF5 file. If group "neutrons" already exists, append the neutrons as a new - * group. + * @brief Append a neutron vector to a HDF5 file. If group "neutrons" already + * exists, append the neutrons as a new group. * * @tparam ForwardIterator * @param[in] out_file_name @@ -396,7 +419,9 @@ void saveNeutronToHDF5(const std::string &out_file_name, const std::vector -void appendNeutronToHDF5(const std::string &out_file_name, ForwardIterator neutron_begin, ForwardIterator neutron_end) { +void appendNeutronToHDF5(const std::string &out_file_name, + ForwardIterator neutron_begin, + ForwardIterator neutron_end) { saveOrAppendNeutronToHDF5(out_file_name, neutron_begin, neutron_end, true); } @@ -406,6 +431,7 @@ void appendNeutronToHDF5(const std::string &out_file_name, ForwardIterator neutr * @param[in] out_file_name * @param[in] neutrons */ -void appendNeutronToHDF5(const std::string &out_file_name, const std::vector &neutrons) { +void appendNeutronToHDF5(const std::string &out_file_name, + const std::vector &neutrons) { appendNeutronToHDF5(out_file_name, neutrons.cbegin(), neutrons.cend()); } diff --git a/sophiread/FastSophiread/src/fastgaussian.cpp b/sophiread/FastSophiread/src/fastgaussian.cpp index 5b90fdf..df9d95a 100644 --- a/sophiread/FastSophiread/src/fastgaussian.cpp +++ b/sophiread/FastSophiread/src/fastgaussian.cpp @@ -6,18 +6,7 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + * * @note Fast Gaussian peak fitting method works better when the number of hits * is large. It is not suitable for fitting tiny clsuters as it will throw away @@ -39,7 +28,9 @@ double getMedian(const std::vector& data) { std::vector sorted_data = data; std::sort(sorted_data.begin(), sorted_data.end()); if (sorted_data.size() % 2 == 0) { - return (sorted_data[sorted_data.size() / 2 - 1] + sorted_data[sorted_data.size() / 2]) / 2; + return (sorted_data[sorted_data.size() / 2 - 1] + + sorted_data[sorted_data.size() / 2]) / + 2; } else { return sorted_data[sorted_data.size() / 2]; } @@ -122,10 +113,13 @@ Neutron FastGaussian::fit(const std::vector& data) { double y_event = x_sol(1) / 2.0; // calculate the tof as the average of the tof of the filtered hits - double tof_event = std::accumulate(tof_filtered.begin(), tof_filtered.end(), 0.0) / tof_filtered.size(); + double tof_event = + std::accumulate(tof_filtered.begin(), tof_filtered.end(), 0.0) / + tof_filtered.size(); // calculate the tot - double tot_event = std::accumulate(tot_filtered.begin(), tot_filtered.end(), 0.0); + double tot_event = + std::accumulate(tot_filtered.begin(), tot_filtered.end(), 0.0); // even if we are throwing away to bottom half, we still need to return the // pre-filtered number of hits diff --git a/sophiread/FastSophiread/src/hit.cpp b/sophiread/FastSophiread/src/hit.cpp index aad67a3..c736ec1 100644 --- a/sophiread/FastSophiread/src/hit.cpp +++ b/sophiread/FastSophiread/src/hit.cpp @@ -7,20 +7,10 @@ * @date 2023-09-04 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include "hit.h" + #include /** @@ -31,8 +21,8 @@ * @param[in] gdc * @param[in] chip_layout_type */ -Hit::Hit(const char *packet, const unsigned long long TDC_timestamp, const unsigned long long GDC_timestamp, - const int chip_layout_type) { +Hit::Hit(const char *packet, const unsigned long long TDC_timestamp, + const unsigned long long GDC_timestamp, const int chip_layout_type) { // local variables unsigned short pixaddr, dcol, spix, pix; unsigned short *spider_time; @@ -62,16 +52,16 @@ Hit::Hit(const char *packet, const unsigned long long TDC_timestamp, const unsig m_spidertime = (SPDR_MSB18 << 30) & 0xFFFFC0000000; m_spidertime = m_spidertime | spidertime; - // additional check to make sure rollover of spidertime is correct + // additional check to make sure rollover of spidertime is correct // 4e7 is roughly 1 second in the units of 25 ns // 1073741824 is 2^30 (in units of 25 ns) - if ((m_spidertime-GDC_timestamp)>=4e7){ + if ((m_spidertime - GDC_timestamp) >= 4e7) { m_spidertime -= 1073741824; } // tof calculation m_tof = m_spidertime - TDC_timestamp; - while (m_tof*25E-6 > 16.67){ + while (m_tof * 25E-6 > 16.67) { m_tof -= 666667; } diff --git a/sophiread/FastSophiread/src/tpx3_fast.cpp b/sophiread/FastSophiread/src/tpx3_fast.cpp index cfa8188..4b6879e 100644 --- a/sophiread/FastSophiread/src/tpx3_fast.cpp +++ b/sophiread/FastSophiread/src/tpx3_fast.cpp @@ -7,38 +7,28 @@ * @date 2023-08-31 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include "tpx3_fast.h" #include #include -#define MAX_BATCH_LEN 100000 // enough to process suann_socket_background_serval32.tpx3 without rollover +#define MAX_BATCH_LEN \ + 100000 // enough to process suann_socket_background_serval32.tpx3 without + // rollover #ifdef MAX_BATCH_LEN -#include #include +#include // allow MAX_BATCH_LEN to come from the environment long unsigned int _get_max_batch_len(void) { - if (const char* env_p = std::getenv("MAX_BATCH_LEN")) { - auto max_batch_len = std::strtoul(env_p, NULL, 0); - // no conversion produce 0 - if (max_batch_len != 0 ) - return max_batch_len; - } - return MAX_BATCH_LEN; + if (const char *env_p = std::getenv("MAX_BATCH_LEN")) { + auto max_batch_len = std::strtoul(env_p, NULL, 0); + // no conversion produce 0 + if (max_batch_len != 0) return max_batch_len; + } + return MAX_BATCH_LEN; } #endif @@ -54,7 +44,8 @@ long unsigned int _get_max_batch_len(void) { template std::vector findTPX3H(ForwardIter begin, ForwardIter end) { std::vector batches; - batches.reserve(std::distance(begin, end) / 64); // just a guess here, need more work + batches.reserve(std::distance(begin, end) / + 64); // just a guess here, need more work // local variables int chip_layout_type = 0; @@ -62,15 +53,18 @@ std::vector findTPX3H(ForwardIter begin, ForwardIter end) { int data_packet_num = 0; // find all batches - for (auto iter = begin; std::distance(iter, end) >= 8; std::advance(iter, 8)) { + for (auto iter = begin; std::distance(iter, end) >= 8; + std::advance(iter, 8)) { const char *char_array = &(*iter); // locate the data packet header if (char_array[0] == 'T' && char_array[1] == 'P' && char_array[2] == 'X') { data_packet_size = ((0xff & char_array[7]) << 8) | (0xff & char_array[6]); - data_packet_num = data_packet_size >> 3; // every 8 (2^3) bytes is a data packet + data_packet_num = + data_packet_size >> 3; // every 8 (2^3) bytes is a data packet chip_layout_type = static_cast(char_array[4]); - batches.emplace_back(static_cast(std::distance(begin, iter)), data_packet_num, chip_layout_type); + batches.emplace_back(static_cast(std::distance(begin, iter)), + data_packet_num, chip_layout_type); } } @@ -85,17 +79,19 @@ std::vector findTPX3H(ForwardIter begin, ForwardIter end) { * @param[in] end * @param[out] consumed * @return std::vector - * @note will limit the batch size to 100000, will update the number of elements consumed + * @note will limit the batch size to 100000, will update the number of elements + * consumed */ template -std::vector findTPX3H(ForwardIter begin, ForwardIter end, std::size_t &consumed) { +std::vector findTPX3H(ForwardIter begin, ForwardIter end, + std::size_t &consumed) { std::vector batches; #ifdef MAX_BATCH_LEN auto len = _get_max_batch_len(); std::size_t batch_number = 0; #else - // prior code that estimates appropriate batch size to contain the entire input - // NOTE: this can grow without bound based on the input file size + // prior code that estimates appropriate batch size to contain the entire + // input NOTE: this can grow without bound based on the input file size auto len = std::distance(begin, end) / 64; #endif // MAX_BATCH_LEN batches.reserve(len); @@ -107,15 +103,18 @@ std::vector findTPX3H(ForwardIter begin, ForwardIter end, std::size_t &con int data_packet_num = 0; // find all batches - for (auto iter = begin; std::distance(iter, end) >= 8; std::advance(iter, 8), consumed += 8) { + for (auto iter = begin; std::distance(iter, end) >= 8; + std::advance(iter, 8), consumed += 8) { const char *char_array = &(*iter); // locate the data packet header if (char_array[0] == 'T' && char_array[1] == 'P' && char_array[2] == 'X') { data_packet_size = ((0xff & char_array[7]) << 8) | (0xff & char_array[6]); - data_packet_num = data_packet_size >> 3; // every 8 (2^3) bytes is a data packet + data_packet_num = + data_packet_size >> 3; // every 8 (2^3) bytes is a data packet chip_layout_type = static_cast(char_array[4]); - batches.emplace_back(static_cast(std::distance(begin, iter)), data_packet_num, chip_layout_type); + batches.emplace_back(static_cast(std::distance(begin, iter)), + data_packet_num, chip_layout_type); #ifdef MAX_BATCH_LEN if (++batch_number >= len) break; @@ -154,7 +153,8 @@ std::vector findTPX3H(char *raw_bytes, std::size_t size) { * @param[out] consumed * @return std::vector */ -std::vector findTPX3H(const std::vector &raw_bytes, std::size_t& consumed) { +std::vector findTPX3H(const std::vector &raw_bytes, + std::size_t &consumed) { return findTPX3H(raw_bytes.cbegin(), raw_bytes.cend(), consumed); } @@ -166,13 +166,14 @@ std::vector findTPX3H(const std::vector &raw_bytes, std::size_t& con * @param[out] consumed * @return std::vector */ -std::vector findTPX3H(char *raw_bytes, std::size_t size, std::size_t& consumed) { +std::vector findTPX3H(char *raw_bytes, std::size_t size, + std::size_t &consumed) { return findTPX3H(raw_bytes, raw_bytes + size, consumed); } /** - * @brief record the given timestamp as starting timestamp of the dataset batch, and evolve the timestamp till the end - * of the dataset batch. + * @brief record the given timestamp as starting timestamp of the dataset batch, + * and evolve the timestamp till the end of the dataset batch. * * @tparam ForwardIter * @param[in, out] tpx3h @@ -183,19 +184,22 @@ std::vector findTPX3H(char *raw_bytes, std::size_t size, std::size_t& cons * @param[in, out] timer_lsb32 */ template -void updateTimestamp(TPX3 &tpx3h, ForwardIter bytes_begin, ForwardIter bytes_end, unsigned long &tdc_timestamp, - unsigned long long int &gdc_timestamp, unsigned long &timer_lsb32) { +void updateTimestamp(TPX3 &tpx3h, ForwardIter bytes_begin, + ForwardIter bytes_end, unsigned long &tdc_timestamp, + unsigned long long int &gdc_timestamp, + unsigned long &timer_lsb32) { // record the starting timestamp tpx3h.tdc_timestamp = tdc_timestamp; tpx3h.gdc_timestamp = gdc_timestamp; tpx3h.timer_lsb32 = timer_lsb32; - process_tpx3_packets(tpx3h, bytes_begin, bytes_end, tdc_timestamp, gdc_timestamp, timer_lsb32, false); + process_tpx3_packets(tpx3h, bytes_begin, bytes_end, tdc_timestamp, + gdc_timestamp, timer_lsb32, false); } /** - * @brief record the given timestamp as starting timestamp of the dataset batch, and evolve the timestamp till the end - * of the dataset batch. + * @brief record the given timestamp as starting timestamp of the dataset batch, + * and evolve the timestamp till the end of the dataset batch. * * @param[in, out] tpx3h * @param[in] raw_bytes @@ -203,14 +207,17 @@ void updateTimestamp(TPX3 &tpx3h, ForwardIter bytes_begin, ForwardIter bytes_end * @param[in, out] gdc_timestamp * @param[in, out] timer_lsb32 */ -void updateTimestamp(TPX3 &tpx3h, const std::vector &raw_bytes, unsigned long &tdc_timestamp, - unsigned long long int &gdc_timestamp, unsigned long &timer_lsb32) { - updateTimestamp(tpx3h, raw_bytes.cbegin(), raw_bytes.cend(), tdc_timestamp, gdc_timestamp, timer_lsb32); +void updateTimestamp(TPX3 &tpx3h, const std::vector &raw_bytes, + unsigned long &tdc_timestamp, + unsigned long long int &gdc_timestamp, + unsigned long &timer_lsb32) { + updateTimestamp(tpx3h, raw_bytes.cbegin(), raw_bytes.cend(), tdc_timestamp, + gdc_timestamp, timer_lsb32); } /** - * @brief record the given timestamp as starting timestamp of the dataset batch, and evolve the timestamp till the end - * of the dataset batch. + * @brief record the given timestamp as starting timestamp of the dataset batch, + * and evolve the timestamp till the end of the dataset batch. * * @param[in, out] tpx3h * @param[in] raw_bytes @@ -219,9 +226,12 @@ void updateTimestamp(TPX3 &tpx3h, const std::vector &raw_bytes, unsigned l * @param[in, out] gdc_timestamp * @param[in, out] timer_lsb32 */ -void updateTimestamp(TPX3 &tpx3h, char *raw_bytes, std::size_t size, unsigned long &tdc_timestamp, - unsigned long long int &gdc_timestamp, unsigned long &timer_lsb32) { - updateTimestamp(tpx3h, raw_bytes, raw_bytes + size, tdc_timestamp, gdc_timestamp, timer_lsb32); +void updateTimestamp(TPX3 &tpx3h, char *raw_bytes, std::size_t size, + unsigned long &tdc_timestamp, + unsigned long long int &gdc_timestamp, + unsigned long &timer_lsb32) { + updateTimestamp(tpx3h, raw_bytes, raw_bytes + size, tdc_timestamp, + gdc_timestamp, timer_lsb32); } /** @@ -234,8 +244,8 @@ void updateTimestamp(TPX3 &tpx3h, char *raw_bytes, std::size_t size, unsigned lo */ template void extractHits(TPX3 &tpx3h, ForwardIter bytes_begin, ForwardIter bytes_end) { - process_tpx3_packets(tpx3h, bytes_begin, bytes_end, tpx3h.tdc_timestamp, tpx3h.gdc_timestamp, tpx3h.timer_lsb32, - true); + process_tpx3_packets(tpx3h, bytes_begin, bytes_end, tpx3h.tdc_timestamp, + tpx3h.gdc_timestamp, tpx3h.timer_lsb32, true); } /** @@ -255,7 +265,9 @@ void extractHits(TPX3 &tpx3h, const std::vector &raw_bytes) { * @param[in] raw_bytes * @param[in] size */ -void extractHits(TPX3 &tpx3h, char *raw_bytes, std::size_t size) { extractHits(tpx3h, raw_bytes, raw_bytes + size); } +void extractHits(TPX3 &tpx3h, char *raw_bytes, std::size_t size) { + extractHits(tpx3h, raw_bytes, raw_bytes + size); +} /** * @brief Update the tdc_timestamp with given char_array and gdc_timestamp @@ -264,7 +276,8 @@ void extractHits(TPX3 &tpx3h, char *raw_bytes, std::size_t size) { extractHits(t * @param[in] gdc_timestamp: the reference gdc_timestamp * @param[out] tdc_timestamp: the target to update */ -void update_tdc_timestamp(const char *char_array, const unsigned long long &gdc_timestamp, +void update_tdc_timestamp(const char *char_array, + const unsigned long long &gdc_timestamp, unsigned long &tdc_timestamp) { // local var for updating tdc_timestamp unsigned long *tdclast; @@ -274,7 +287,8 @@ void update_tdc_timestamp(const char *char_array, const unsigned long long &gdc_ // extract the data from the data packet tdclast = (unsigned long *)(&char_array[0]); - mytdc = (((*tdclast) >> 12) & 0xFFFFFFFF); // rick: 0x3fffffff, get 32-bit tdc + mytdc = + (((*tdclast) >> 12) & 0xFFFFFFFF); // rick: 0x3fffffff, get 32-bit tdc TDC_LSB32 = gdc_timestamp & 0xFFFFFFFF; TDC_MSB16 = (gdc_timestamp >> 32) & 0xFFFF; if (mytdc < TDC_LSB32) { @@ -291,7 +305,8 @@ void update_tdc_timestamp(const char *char_array, const unsigned long long &gdc_ * @param[in, out] timer_lsb32 * @param[out] gdc_timestamp */ -void update_gdc_timestamp_and_timer_lsb32(const char *char_array, unsigned long &timer_lsb32, +void update_gdc_timestamp_and_timer_lsb32(const char *char_array, + unsigned long &timer_lsb32, unsigned long long &gdc_timestamp) { // local var for updating gdc_timestamp and timer_lsb32 unsigned long *gdclast; @@ -330,11 +345,14 @@ void update_gdc_timestamp_and_timer_lsb32(const char *char_array, unsigned long * @param[in, out] tdc_timestamp * @param[in, out] gdc_timestamp * @param[in, out] timer_lsb32 - * @param[in] extract_hits: whether to extract hits from the data packets, or just scan&update the timestamp + * @param[in] extract_hits: whether to extract hits from the data packets, or + * just scan&update the timestamp */ template -void process_tpx3_packets(TPX3 &tpx3h, ForwardIter bytes_begin, ForwardIter bytes_end, unsigned long &tdc_timestamp, - unsigned long long int &gdc_timestamp, unsigned long &timer_lsb32, bool extract_hits) { +void process_tpx3_packets(TPX3 &tpx3h, ForwardIter bytes_begin, + ForwardIter bytes_end, unsigned long &tdc_timestamp, + unsigned long long int &gdc_timestamp, + unsigned long &timer_lsb32, bool extract_hits) { // Move to the first packet auto bytes_iter = bytes_begin; std::advance(bytes_iter, tpx3h.index); @@ -354,7 +372,8 @@ void process_tpx3_packets(TPX3 &tpx3h, ForwardIter bytes_begin, ForwardIter byte update_tdc_timestamp(char_array, gdc_timestamp, tdc_timestamp); } else if ((char_array[7] & 0xF0) == 0x40) { // GDC data packet - update_gdc_timestamp_and_timer_lsb32(char_array, timer_lsb32, gdc_timestamp); + update_gdc_timestamp_and_timer_lsb32(char_array, timer_lsb32, + gdc_timestamp); } else if ((char_array[7] & 0xF0) == 0xb0) { if (extract_hits) { // Data packet diff --git a/sophiread/FastSophiread/tests/test_abs.cpp b/sophiread/FastSophiread/tests/test_abs.cpp index 4df5a23..23348e6 100644 --- a/sophiread/FastSophiread/tests/test_abs.cpp +++ b/sophiread/FastSophiread/tests/test_abs.cpp @@ -90,7 +90,8 @@ class ABSTest : public ::testing::Test { } }; -// Test the constructor and the methods set_method, get_cluster_labels, and reset +// Test the constructor and the methods set_method, get_cluster_labels, and +// reset TEST_F(ABSTest, ConstructorAndMethods) { ABS abs(5.0, 1, 75); diff --git a/sophiread/FastSophiread/tests/test_centroid.cpp b/sophiread/FastSophiread/tests/test_centroid.cpp index 2414726..93abbad 100644 --- a/sophiread/FastSophiread/tests/test_centroid.cpp +++ b/sophiread/FastSophiread/tests/test_centroid.cpp @@ -69,8 +69,10 @@ TEST_F(CentroidTest, CentroidWeightedWithScale) { auto event = alg->fit(data); // Check the centroid - EXPECT_NEAR(event.getX(), 1863.66 * super_resolution_factor, absolution_tolerance); - EXPECT_NEAR(event.getY(), 2718.74 * super_resolution_factor, absolution_tolerance); + EXPECT_NEAR(event.getX(), 1863.66 * super_resolution_factor, + absolution_tolerance); + EXPECT_NEAR(event.getY(), 2718.74 * super_resolution_factor, + absolution_tolerance); EXPECT_NEAR(event.getTOF(), 2262.67, absolution_tolerance); } diff --git a/sophiread/FastSophiread/tests/test_disk_io.cpp b/sophiread/FastSophiread/tests/test_disk_io.cpp index 1bec939..41ad7b8 100644 --- a/sophiread/FastSophiread/tests/test_disk_io.cpp +++ b/sophiread/FastSophiread/tests/test_disk_io.cpp @@ -88,7 +88,8 @@ class FileNameGeneratorTest : public ::testing::Test { extension = resultPath.extension().string(); expectedPattern = std::regex(R"(.*_\d{6}\..*)"); - ASSERT_TRUE(std::regex_match(generatedBaseName + extension, expectedPattern)); + ASSERT_TRUE( + std::regex_match(generatedBaseName + extension, expectedPattern)); // Check that the timestamp is recent (within the last second). auto position = generatedBaseName.find_last_of('_'); @@ -143,8 +144,10 @@ class SaveHitsTest : public ::testing::Test { std::uniform_int_distribution distribution(1, 100); for (size_t i = 0; i < numHits; ++i) { - Hit hit(distribution(generator), distribution(generator), distribution(generator), distribution(generator), - distribution(generator), distribution(generator), distribution(generator)); + Hit hit(distribution(generator), distribution(generator), + distribution(generator), distribution(generator), + distribution(generator), distribution(generator), + distribution(generator)); hits.push_back(hit); } return hits; @@ -197,8 +200,9 @@ class SaveNeutronTest : public ::testing::Test { std::uniform_int_distribution distribution(1, 100); for (size_t i = 0; i < numNeutrons; ++i) { - Neutron neutron(distribution(generator), distribution(generator), distribution(generator), - distribution(generator), distribution(generator)); + Neutron neutron(distribution(generator), distribution(generator), + distribution(generator), distribution(generator), + distribution(generator)); neutrons.push_back(neutron); } return neutrons; @@ -230,7 +234,8 @@ TEST_F(SaveNeutronTest, TestSaveAndAppendToHDF5) { std::vector appendedNeutrons = generateRandomNeutrons(5); appendNeutronToHDF5(testFileName, appendedNeutrons); - // Ensure file still exists and now has a new group "neutrons_1" with 5 neutrons + // Ensure file still exists and now has a new group "neutrons_1" with 5 + // neutrons file.openFile(testFileName, H5F_ACC_RDONLY); group = file.openGroup("neutrons_1"); x_dataset = group.openDataSet("x"); diff --git a/sophiread/FastSophiread/tests/test_fastgaussian.cpp b/sophiread/FastSophiread/tests/test_fastgaussian.cpp index bebffba..abf7c6e 100644 --- a/sophiread/FastSophiread/tests/test_fastgaussian.cpp +++ b/sophiread/FastSophiread/tests/test_fastgaussian.cpp @@ -60,7 +60,8 @@ class FastGaussianTest : public ::testing::Test { data.reserve(num_hit); for (int i = 0; i < num_hit; i++) { - data.emplace_back(Hit(pos(gen), pos(gen), tot(gen), toa(gen), ftoa(gen), tof(gen), spidertime(gen))); + data.emplace_back(Hit(pos(gen), pos(gen), tot(gen), toa(gen), ftoa(gen), + tof(gen), spidertime(gen))); } } }; diff --git a/sophiread/FastSophiread/tests/test_tpx3.cpp b/sophiread/FastSophiread/tests/test_tpx3.cpp index 86900dc..477a156 100644 --- a/sophiread/FastSophiread/tests/test_tpx3.cpp +++ b/sophiread/FastSophiread/tests/test_tpx3.cpp @@ -64,13 +64,18 @@ TEST_F(TPX3Test, CheckIndex) { ASSERT_EQ(index, tpx3.index); } TEST_F(TPX3Test, CheckNumPackets) { ASSERT_EQ(num_packets, tpx3.num_packets); } -TEST_F(TPX3Test, CheckChipLayoutType) { ASSERT_EQ(chip_layout_type, tpx3.chip_layout_type); } +TEST_F(TPX3Test, CheckChipLayoutType) { + ASSERT_EQ(chip_layout_type, tpx3.chip_layout_type); +} -TEST_F(TPX3Test, CheckHitsSize) { ASSERT_EQ(num_packets, static_cast(tpx3.hits.size())); } +TEST_F(TPX3Test, CheckHitsSize) { + ASSERT_EQ(num_packets, static_cast(tpx3.hits.size())); +} TEST(TPX3FuncTest, TestFindTPX3H) { // read the testing raw data - auto rawdata = readTPX3RawToCharVec("../data/suann_socket_background_serval32.tpx3"); + auto rawdata = + readTPX3RawToCharVec("../data/suann_socket_background_serval32.tpx3"); // auto batches = findTPX3H(rawdata); @@ -82,7 +87,8 @@ TEST(TPX3FuncTest, TestFindTPX3H) { TEST(TPX3FuncTest, TestFindTPX3H_read) { // read the testing raw data - auto mapdata = readTPX3RawToMapInfo("../data/suann_socket_background_serval32.tpx3"); + auto mapdata = + readTPX3RawToMapInfo("../data/suann_socket_background_serval32.tpx3"); // auto batches = findTPX3H(mapdata.map, mapdata.max); @@ -94,7 +100,8 @@ TEST(TPX3FuncTest, TestFindTPX3H_read) { TEST(TPX3FuncTest, TestFindTPX3H_mmap) { // memory map the testing raw data - auto mapdata = mmapTPX3RawToMapInfo("../data/suann_socket_background_serval32.tpx3"); + auto mapdata = + mmapTPX3RawToMapInfo("../data/suann_socket_background_serval32.tpx3"); // auto batches = findTPX3H(mapdata.map, mapdata.max); @@ -106,7 +113,8 @@ TEST(TPX3FuncTest, TestFindTPX3H_mmap) { TEST(TPX3FuncTest, TestExtractHits) { // read the testing raw data - auto rawdata = readTPX3RawToCharVec("../data/suann_socket_background_serval32.tpx3"); + auto rawdata = + readTPX3RawToCharVec("../data/suann_socket_background_serval32.tpx3"); // locate all headers auto batches = findTPX3H(rawdata); @@ -145,7 +153,8 @@ TEST(TPX3FuncTest, TestExtractHits) { TEST(TPX3FuncTest, TestExtractHits_read) { // read the testing raw data - auto mapdata = readTPX3RawToMapInfo("../data/suann_socket_background_serval32.tpx3"); + auto mapdata = + readTPX3RawToMapInfo("../data/suann_socket_background_serval32.tpx3"); // locate all headers auto batches = findTPX3H(mapdata.map, mapdata.max); @@ -155,7 +164,8 @@ TEST(TPX3FuncTest, TestExtractHits_read) { unsigned long long int gdc_timestamp = 0; unsigned long timer_lsb32 = 0; for (auto& tpx3 : batches) { - updateTimestamp(tpx3, mapdata.map, mapdata.max, tdc_timestamp, gdc_timestamp, timer_lsb32); + updateTimestamp(tpx3, mapdata.map, mapdata.max, tdc_timestamp, + gdc_timestamp, timer_lsb32); } // extract hits @@ -184,7 +194,8 @@ TEST(TPX3FuncTest, TestExtractHits_read) { TEST(TPX3FuncTest, TestExtractHits_mmap) { // memory map the testing raw data - auto mapdata = mmapTPX3RawToMapInfo("../data/suann_socket_background_serval32.tpx3"); + auto mapdata = + mmapTPX3RawToMapInfo("../data/suann_socket_background_serval32.tpx3"); // locate all headers auto batches = findTPX3H(mapdata.map, mapdata.max); @@ -194,7 +205,8 @@ TEST(TPX3FuncTest, TestExtractHits_mmap) { unsigned long long int gdc_timestamp = 0; unsigned long timer_lsb32 = 0; for (auto& tpx3 : batches) { - updateTimestamp(tpx3, mapdata.map, mapdata.max, tdc_timestamp, gdc_timestamp, timer_lsb32); + updateTimestamp(tpx3, mapdata.map, mapdata.max, tdc_timestamp, + gdc_timestamp, timer_lsb32); } // extract hits @@ -223,61 +235,67 @@ TEST(TPX3FuncTest, TestExtractHits_mmap) { TEST(TPX3FuncTest, TestExtractHits_large) { // memory map the testing raw data - auto mapdata = mmapTPX3RawToMapInfo("../data/HV2700_1500_500_THLrel_274_sophy_chopper_60Hz_4.1mm_aperture_siemen_star_120s_000000.tpx3"); - const int n_hits_reference = 5303344; // HV2700_1500_500_THLrel_274_sophy_chopper_60Hz_4.1mm_aperture_siemen_star_120s_000000.tpx3 - //auto mapdata = mmapTPX3RawToMapInfo("../data/suann_socket_background_serval32.tpx3"); - //const int n_hits_reference = 98533; // suann_socket_background_serval32.tpx3 + auto mapdata = mmapTPX3RawToMapInfo( + "../data/" + "HV2700_1500_500_THLrel_274_sophy_chopper_60Hz_4.1mm_aperture_siemen_" + "star_120s_000000.tpx3"); + const int n_hits_reference = + 5303344; // HV2700_1500_500_THLrel_274_sophy_chopper_60Hz_4.1mm_aperture_siemen_star_120s_000000.tpx3 + // auto mapdata = + // mmapTPX3RawToMapInfo("../data/suann_socket_background_serval32.tpx3"); + // const int n_hits_reference = 98533; // + // suann_socket_background_serval32.tpx3 size_t raw_data_consumed = 0; size_t n_hits = 0; - // NB: these track timestamps; if they are reset improperly, the system keeps searching and gets the wrong answers! + // NB: these track timestamps; if they are reset improperly, the system keeps + // searching and gets the wrong answers! unsigned long tdc_timestamp = 0; unsigned long long int gdc_timestamp = 0; unsigned long timer_lsb32 = 0; - while (raw_data_consumed < mapdata.max) { + while (raw_data_consumed < mapdata.max) { + // manage partial batches + size_t consumed = 0; + char* raw_data_ptr = mapdata.map + raw_data_consumed; + size_t raw_data_size = mapdata.max - raw_data_consumed; - // manage partial batches - size_t consumed = 0; - char *raw_data_ptr = mapdata.map + raw_data_consumed; - size_t raw_data_size = mapdata.max - raw_data_consumed; - - // locate all headers - auto batches = findTPX3H(raw_data_ptr, raw_data_size, consumed); + // locate all headers + auto batches = findTPX3H(raw_data_ptr, raw_data_size, consumed); - // locate gdc and tdc - for (auto& tpx3 : batches) { - updateTimestamp(tpx3, raw_data_ptr, consumed, tdc_timestamp, gdc_timestamp, timer_lsb32); - } + // locate gdc and tdc + for (auto& tpx3 : batches) { + updateTimestamp(tpx3, raw_data_ptr, consumed, tdc_timestamp, + gdc_timestamp, timer_lsb32); + } - // extract hits - for (auto& tpx3 : batches) { - extractHits(tpx3, raw_data_ptr, consumed); - } + // extract hits + for (auto& tpx3 : batches) { + extractHits(tpx3, raw_data_ptr, consumed); + } - // count all hits - for (const auto& tpx3 : batches) { - auto hits = tpx3.hits; - n_hits += hits.size(); - } + // count all hits + for (const auto& tpx3 : batches) { + auto hits = tpx3.hits; + n_hits += hits.size(); + } - // make sure no tof is above 16.67 ms - for (const auto& tpx3 : batches) { - auto hits = tpx3.hits; - for (const auto& hit : hits) { - auto tof_ms = hit.getTOF_ns() * 1e-6; - EXPECT_LT(tof_ms, 16670); + // make sure no tof is above 16.67 ms + for (const auto& tpx3 : batches) { + auto hits = tpx3.hits; + for (const auto& hit : hits) { + auto tof_ms = hit.getTOF_ns() * 1e-6; + EXPECT_LT(tof_ms, 16670); + } } - } - // manage iterations on partial raw_data - raw_data_consumed += consumed; - } + // manage iterations on partial raw_data + raw_data_consumed += consumed; + } EXPECT_EQ(n_hits, n_hits_reference); - } -int main(int argc, char **argv) { +int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } diff --git a/sophiread/README.md b/sophiread/README.md index 49c678a..af09bc3 100644 --- a/sophiread/README.md +++ b/sophiread/README.md @@ -10,7 +10,7 @@ It provides both command line (CLI) and graphical user interface (GUI) interface Sophiread is built using `cmake` and `make` under a sandboxed environment with `conda` (see [conda](https://conda.io/docs/)). The following steps have been tested under MaxOS and Linux, and it is in theory possible to build it under Windows. -- Install `conda` or equivalent pacakge manager such as `miniconda`, `mamba`, `micromamba`, etc. +- Install `conda` or equivalent package manager such as `miniconda`, `mamba`, `micromamba`, etc. - Create a new development environment with `conda` (assuming we are on linux): ```bash diff --git a/sophiread/SophireadCLI/CMakeLists.txt b/sophiread/SophireadCLI/CMakeLists.txt index cd23498..149fc48 100644 --- a/sophiread/SophireadCLI/CMakeLists.txt +++ b/sophiread/SophireadCLI/CMakeLists.txt @@ -1,117 +1,86 @@ # Include the headers -include_directories( - include - ${PROJECT_SOURCE_DIR}/FastSophiread/include - ${TIFF_INCLUDE_DIRS} -) +include_directories(include ${PROJECT_SOURCE_DIR}/FastSophiread/include + ${TIFF_INCLUDE_DIRS}) # Configure the commandline application -set(SRC_FILES - src/user_config.cpp - src/json_config_parser.cpp - src/sophiread_core.cpp -) +set(SRC_FILES src/user_config.cpp src/json_config_parser.cpp + src/sophiread_core.cpp) # ----------------- CLI APPLICATION ----------------- # -add_executable(Sophiread - ${SRC_FILES} - src/sophiread.cpp -) +add_executable(Sophiread ${SRC_FILES} src/sophiread.cpp) set_target_properties(Sophiread PROPERTIES VERSION ${PROJECT_VERSION}) -target_link_libraries(Sophiread - PRIVATE - FastSophiread - TBB::tbb - spdlog::spdlog - fmt::fmt - nlohmann_json::nlohmann_json - ${HDF5_LIBRARIES} - ${TIFF_LIBRARIES} -) +target_link_libraries( + Sophiread + PRIVATE FastSophiread + TBB::tbb + spdlog::spdlog + fmt::fmt + nlohmann_json::nlohmann_json + ${HDF5_LIBRARIES} + ${TIFF_LIBRARIES}) # -add_executable(venus_auto_reducer -${SRC_FILES} - src/venus_auto_reducer.cpp -) -target_link_libraries(venus_auto_reducer - PRIVATE - FastSophiread - TBB::tbb - spdlog::spdlog - fmt::fmt - nlohmann_json::nlohmann_json - ${HDF5_LIBRARIES} - ${TIFF_LIBRARIES} -) +add_executable(venus_auto_reducer ${SRC_FILES} src/venus_auto_reducer.cpp) +target_link_libraries( + venus_auto_reducer + PRIVATE FastSophiread + TBB::tbb + spdlog::spdlog + fmt::fmt + nlohmann_json::nlohmann_json + ${HDF5_LIBRARIES} + ${TIFF_LIBRARIES}) -# ----------------- TESTS ----------------- # -# UserConfig tests -add_executable( - UserConfigTest - tests/test_user_config.cpp - src/user_config.cpp -) -target_link_libraries(UserConfigTest - PRIVATE - FastSophiread - spdlog::spdlog - GTest::GTest - GTest::Main -) +# ----------------- TESTS ----------------- # UserConfig tests +add_executable(UserConfigTest tests/test_user_config.cpp src/user_config.cpp) +target_link_libraries(UserConfigTest PRIVATE FastSophiread spdlog::spdlog + GTest::GTest GTest::Main) gtest_discover_tests(UserConfigTest) # Json config test -add_executable( - JsonConfigParserTest - tests/test_json_config_parser.cpp - src/json_config_parser.cpp -) -target_link_libraries(JsonConfigParserTest - PRIVATE - FastSophiread - spdlog::spdlog - GTest::GTest - GTest::Main - nlohmann_json::nlohmann_json -) +add_executable(JsonConfigParserTest tests/test_json_config_parser.cpp + src/json_config_parser.cpp) +target_link_libraries( + JsonConfigParserTest PRIVATE FastSophiread spdlog::spdlog GTest::GTest + GTest::Main nlohmann_json::nlohmann_json) gtest_discover_tests(JsonConfigParserTest) # core test add_executable( - SophireadCoreTest - tests/test_sophiread_core.cpp - src/sophiread_core.cpp - src/json_config_parser.cpp -) -target_link_libraries(SophireadCoreTest - PRIVATE - FastSophiread - spdlog::spdlog - GTest::GTest - GTest::Main - nlohmann_json::nlohmann_json - ${HDF5_LIBRARIES} - ${TIFF_LIBRARIES} - TBB::tbb -) + SophireadCoreTest tests/test_sophiread_core.cpp src/sophiread_core.cpp + src/json_config_parser.cpp) +target_link_libraries( + SophireadCoreTest + PRIVATE FastSophiread + spdlog::spdlog + GTest::GTest + GTest::Main + nlohmann_json::nlohmann_json + ${HDF5_LIBRARIES} + ${TIFF_LIBRARIES} + TBB::tbb) gtest_discover_tests(SophireadCoreTest) -# ----------------- SYMLINK ----------------- # -# symlink the executable to the build directory -add_custom_command(TARGET Sophiread POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink +# ----------------- SYMLINK ----------------- # symlink the executable to the +# build directory +add_custom_command( + TARGET Sophiread + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E create_symlink ${PROJECT_BINARY_DIR}/SophireadCLI/Sophiread - ${PROJECT_BINARY_DIR}/Sophiread -) -add_custom_command(TARGET venus_auto_reducer POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink + ${PROJECT_BINARY_DIR}/Sophiread) +add_custom_command( + TARGET venus_auto_reducer + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E create_symlink ${PROJECT_BINARY_DIR}/SophireadCLI/venus_auto_reducer - ${PROJECT_BINARY_DIR}/venus_auto_reducer -) + ${PROJECT_BINARY_DIR}/venus_auto_reducer) # ----------------- INSTALL ----------------- # if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Default install prefix" FORCE) + set(CMAKE_INSTALL_PREFIX + "/usr/local" + CACHE PATH "Default install prefix" FORCE) endif() -install(TARGETS Sophiread - RUNTIME DESTINATION bin) +install(TARGETS Sophiread RUNTIME DESTINATION bin) set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") include(CPack) diff --git a/sophiread/SophireadCLI/include/iconfig.h b/sophiread/SophireadCLI/include/iconfig.h index a9b4120..1ea78f1 100644 --- a/sophiread/SophireadCLI/include/iconfig.h +++ b/sophiread/SophireadCLI/include/iconfig.h @@ -6,18 +6,7 @@ * @date 2024-08-16 * * @copyright Copyright (c) 2024 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once @@ -25,14 +14,14 @@ #include class IConfig { -public: - virtual ~IConfig() = default; + public: + virtual ~IConfig() = default; - virtual double getABSRadius() const = 0; - virtual unsigned long int getABSMinClusterSize() const = 0; - virtual unsigned long int getABSSpiderTimeRange() const = 0; - virtual std::vector getTOFBinEdges() const = 0; - virtual double getSuperResolution() const = 0; + virtual double getABSRadius() const = 0; + virtual unsigned long int getABSMinClusterSize() const = 0; + virtual unsigned long int getABSSpiderTimeRange() const = 0; + virtual std::vector getTOFBinEdges() const = 0; + virtual double getSuperResolution() const = 0; - virtual std::string toString() const = 0; + virtual std::string toString() const = 0; }; \ No newline at end of file diff --git a/sophiread/SophireadCLI/include/json_config_parser.h b/sophiread/SophireadCLI/include/json_config_parser.h index f1e1dd2..fd11bff 100644 --- a/sophiread/SophireadCLI/include/json_config_parser.h +++ b/sophiread/SophireadCLI/include/json_config_parser.h @@ -1,57 +1,48 @@ /** * @file json_config_parser.h * @author Chen Zhang (zhangc@orn.gov) - * @brief Class to store user-defined configuration (JSON) for clustering algorithms. + * @brief Class to store user-defined configuration (JSON) for clustering + * algorithms. * @version 0.1 * @date 2024-08-16 * * @copyright Copyright (c) 2024 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once +#include #include #include -#include + #include "iconfig.h" #include "tof_binning.h" class JSONConfigParser : public IConfig { -public: - static JSONConfigParser createDefault(); - static JSONConfigParser fromFile(const std::string& filepath); - - double getABSRadius() const override; - unsigned long int getABSMinClusterSize() const override; - unsigned long int getABSSpiderTimeRange() const override; - std::vector getTOFBinEdges() const override; - double getSuperResolution() const override; - - std::string toString() const override; - -private: - JSONConfigParser(const nlohmann::json& config); - nlohmann::json m_config; - TOFBinning m_tof_binning; - - void parseTOFBinning(); - - // Default values - static constexpr double DEFAULT_ABS_RADIUS = 5.0; - static constexpr unsigned long int DEFAULT_ABS_MIN_CLUSTER_SIZE = 1; - static constexpr unsigned long int DEFAULT_ABS_SPIDER_TIME_RANGE = 75; - static constexpr int DEFAULT_TOF_BINS = 1500; - static constexpr double DEFAULT_TOF_MAX = 16.7e-3; // 16.7 milliseconds - static constexpr double DEFAULT_SUPER_RESOLUTION = 1.0; + public: + static JSONConfigParser createDefault(); + static JSONConfigParser fromFile(const std::string& filepath); + + double getABSRadius() const override; + unsigned long int getABSMinClusterSize() const override; + unsigned long int getABSSpiderTimeRange() const override; + std::vector getTOFBinEdges() const override; + double getSuperResolution() const override; + + std::string toString() const override; + + private: + JSONConfigParser(const nlohmann::json& config); + nlohmann::json m_config; + TOFBinning m_tof_binning; + + void parseTOFBinning(); + + // Default values + static constexpr double DEFAULT_ABS_RADIUS = 5.0; + static constexpr unsigned long int DEFAULT_ABS_MIN_CLUSTER_SIZE = 1; + static constexpr unsigned long int DEFAULT_ABS_SPIDER_TIME_RANGE = 75; + static constexpr int DEFAULT_TOF_BINS = 1500; + static constexpr double DEFAULT_TOF_MAX = 16.7e-3; // 16.7 milliseconds + static constexpr double DEFAULT_SUPER_RESOLUTION = 1.0; }; diff --git a/sophiread/SophireadCLI/include/sophiread_core.h b/sophiread/SophireadCLI/include/sophiread_core.h index b90c991..70951a6 100644 --- a/sophiread/SophireadCLI/include/sophiread_core.h +++ b/sophiread/SophireadCLI/include/sophiread_core.h @@ -6,43 +6,35 @@ * @date 2024-08-21 * * @copyright Copyright (c) 2024 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once #include #include + #include "abs.h" -#include "tpx3_fast.h" #include "iconfig.h" +#include "tpx3_fast.h" namespace sophiread { std::vector timedReadDataToCharVec(const std::string& in_tpx3); std::vector timedFindTPX3H(const std::vector& rawdata); -void timedLocateTimeStamp(std::vector& batches, const std::vector& rawdata); -void timedProcessing(std::vector& batches, const std::vector& raw_data, const IConfig& config); -void timedSaveHitsToHDF5(const std::string& out_hits, std::vector& batches); -void timedSaveEventsToHDF5(const std::string& out_events, std::vector& batches); +void timedLocateTimeStamp(std::vector& batches, + const std::vector& rawdata); +void timedProcessing(std::vector& batches, + const std::vector& raw_data, const IConfig& config); +void timedSaveHitsToHDF5(const std::string& out_hits, + std::vector& batches); +void timedSaveEventsToHDF5(const std::string& out_events, + std::vector& batches); std::vector>> timedCreateTOFImages( - const std::vector& batches, - double super_resolution, - const std::vector& tof_bin_edges, - const std::string& mode); + const std::vector& batches, double super_resolution, + const std::vector& tof_bin_edges, const std::string& mode); void timedSaveTOFImagingToTIFF( const std::string& out_tof_imaging, const std::vector>>& tof_images, const std::vector& tof_bin_edges, const std::string& tof_filename_base); -} // namespace sophiread +} // namespace sophiread diff --git a/sophiread/SophireadCLI/include/tiff_types.h b/sophiread/SophireadCLI/include/tiff_types.h index f85a4ab..dc9662c 100644 --- a/sophiread/SophireadCLI/include/tiff_types.h +++ b/sophiread/SophireadCLI/include/tiff_types.h @@ -13,6 +13,6 @@ #include // Define bit-depth types for TIFF images -using TIFF8Bit = uint8_t; // 8-bit -using TIFF16Bit = uint16_t; // 16-bit -using TIFF32Bit = uint32_t; // 32-bit \ No newline at end of file +using TIFF8Bit = uint8_t; // 8-bit +using TIFF16Bit = uint16_t; // 16-bit +using TIFF32Bit = uint32_t; // 32-bit \ No newline at end of file diff --git a/sophiread/SophireadCLI/include/tof_binning.h b/sophiread/SophireadCLI/include/tof_binning.h index b79167e..a4e10e9 100644 --- a/sophiread/SophireadCLI/include/tof_binning.h +++ b/sophiread/SophireadCLI/include/tof_binning.h @@ -4,53 +4,40 @@ * @brief TOF binning * @version 0.1 * @date 2024-08-16 - * - * @copyright Copyright (c) 2024 - * 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 3 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, see . + * @copyright Copyright (c) 2024 + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once -#include #include +#include struct TOFBinning { - std::optional num_bins; - std::optional tof_max; - std::vector custom_edges; + std::optional num_bins; + std::optional tof_max; + std::vector custom_edges; - // Default constructor - TOFBinning() : num_bins(1500), tof_max(1.0/60) {} + // Default constructor + TOFBinning() : num_bins(1500), tof_max(1.0 / 60) {} - bool isUniform() const { - return num_bins.has_value() && tof_max.has_value() && custom_edges.empty(); - } + bool isUniform() const { + return num_bins.has_value() && tof_max.has_value() && custom_edges.empty(); + } + + bool isCustom() const { return !custom_edges.empty(); } - bool isCustom() const { - return !custom_edges.empty(); + std::vector getBinEdges() const { + if (isCustom()) { + return custom_edges; } - std::vector getBinEdges() const { - if (isCustom()) { - return custom_edges; - } - - int bins = num_bins.value_or(1500); - double max = tof_max.value_or(1.0/60); - std::vector edges(bins + 1); - for (int i = 0; i <= bins; ++i) { - edges[i] = max * i / bins; - } - return edges; + int bins = num_bins.value_or(1500); + double max = tof_max.value_or(1.0 / 60); + std::vector edges(bins + 1); + for (int i = 0; i <= bins; ++i) { + edges[i] = max * i / bins; } + return edges; + } }; \ No newline at end of file diff --git a/sophiread/SophireadCLI/include/user_config.h b/sophiread/SophireadCLI/include/user_config.h index 5e8238e..841987b 100644 --- a/sophiread/SophireadCLI/include/user_config.h +++ b/sophiread/SophireadCLI/include/user_config.h @@ -7,46 +7,53 @@ * @date 2023-09-18 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #pragma once #include + #include "iconfig.h" #include "tof_binning.h" class UserConfig : public IConfig { public: UserConfig(); - UserConfig(double abs_radius, unsigned long int abs_min_cluster_size, unsigned long int abs_spider_time_range); + UserConfig(double abs_radius, unsigned long int abs_min_cluster_size, + unsigned long int abs_spider_time_range); double getABSRadius() const override { return m_abs_radius; } void setABSRadius(double abs_radius) { m_abs_radius = abs_radius; } - unsigned long int getABSMinClusterSize() const override { return m_abs_min_cluster_size; } - void setABSMinClusterSize(unsigned long int abs_min_cluster_size) { m_abs_min_cluster_size = abs_min_cluster_size; } + unsigned long int getABSMinClusterSize() const override { + return m_abs_min_cluster_size; + } + void setABSMinClusterSize(unsigned long int abs_min_cluster_size) { + m_abs_min_cluster_size = abs_min_cluster_size; + } - unsigned long int getABSSpiderTimeRange() const override { return m_abs_spider_time_range; } - void setABSSpiderTimeRange(unsigned long int abs_spider_time_range) { m_abs_spider_time_range = abs_spider_time_range; } + unsigned long int getABSSpiderTimeRange() const override { + return m_abs_spider_time_range; + } + void setABSSpiderTimeRange(unsigned long int abs_spider_time_range) { + m_abs_spider_time_range = abs_spider_time_range; + } - std::vector getTOFBinEdges() const override { return m_tof_binning.getBinEdges(); } - void setTOFBinning(const TOFBinning& tof_binning) { m_tof_binning = tof_binning; } - void setCustomTOFBinEdges(const std::vector& edges) { m_tof_binning.custom_edges = edges; } + std::vector getTOFBinEdges() const override { + return m_tof_binning.getBinEdges(); + } + void setTOFBinning(const TOFBinning& tof_binning) { + m_tof_binning = tof_binning; + } + void setCustomTOFBinEdges(const std::vector& edges) { + m_tof_binning.custom_edges = edges; + } // no super resolution for old config format - double getSuperResolution() const override {return m_super_resolution; } - void setSuperResolution(double super_resolution) {m_super_resolution = super_resolution; } + double getSuperResolution() const override { return m_super_resolution; } + void setSuperResolution(double super_resolution) { + m_super_resolution = super_resolution; + } std::string toString() const override; diff --git a/sophiread/SophireadCLI/src/json_config_parser.cpp b/sophiread/SophireadCLI/src/json_config_parser.cpp index e2bef14..f45e44f 100644 --- a/sophiread/SophireadCLI/src/json_config_parser.cpp +++ b/sophiread/SophireadCLI/src/json_config_parser.cpp @@ -1,76 +1,63 @@ /** * @file json_config_parser.cpp * @author Chen Zhang (zhangc@orn.gov) - * @brief Class to store user-defined configuration (JSON) for clustering algorithms. + * @brief Class to store user-defined configuration (JSON) for clustering + * algorithms. * @version 0.1 * @date 2024-08-16 * * @copyright Copyright (c) 2024 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include "json_config_parser.h" -#include + #include +#include JSONConfigParser JSONConfigParser::createDefault() { - nlohmann::json default_config = { - {"abs", { - {"radius", DEFAULT_ABS_RADIUS}, - {"min_cluster_size", DEFAULT_ABS_MIN_CLUSTER_SIZE}, - {"spider_time_range", DEFAULT_ABS_SPIDER_TIME_RANGE} - }}, - {"tof_imaging", { - {"uniform_bins", { - {"num_bins", DEFAULT_TOF_BINS}, - {"end", DEFAULT_TOF_MAX} - }}, - {"super_resolution", DEFAULT_SUPER_RESOLUTION} - }} - }; - - return JSONConfigParser(default_config); + nlohmann::json default_config = { + {"abs", + {{"radius", DEFAULT_ABS_RADIUS}, + {"min_cluster_size", DEFAULT_ABS_MIN_CLUSTER_SIZE}, + {"spider_time_range", DEFAULT_ABS_SPIDER_TIME_RANGE}}}, + {"tof_imaging", + {{"uniform_bins", + {{"num_bins", DEFAULT_TOF_BINS}, {"end", DEFAULT_TOF_MAX}}}, + {"super_resolution", DEFAULT_SUPER_RESOLUTION}}}}; + + return JSONConfigParser(default_config); } - /** * @brief Build JSONConfigParser from a given file * @param filepath Path to the JSON configuration file * @return JSONConfigParser */ JSONConfigParser JSONConfigParser::fromFile(const std::string& filepath) { - std::ifstream file(filepath); - if (!file.is_open()) { - throw std::runtime_error("Failed to open configuration file: " + filepath); - } - - nlohmann::json config; - try { - file >> config; - } catch (const nlohmann::json::exception& e) { - throw std::runtime_error("Error parsing JSON file: " + std::string(e.what())); - } - - return JSONConfigParser(config); + std::ifstream file(filepath); + if (!file.is_open()) { + throw std::runtime_error("Failed to open configuration file: " + filepath); + } + + nlohmann::json config; + try { + file >> config; + } catch (const nlohmann::json::exception& e) { + throw std::runtime_error("Error parsing JSON file: " + + std::string(e.what())); + } + + return JSONConfigParser(config); } /** * @brief Construct a new JSONConfigParser::JSONConfigParser object * @param config JSON configuration object */ -JSONConfigParser::JSONConfigParser(const nlohmann::json& config) : m_config(config) { - parseTOFBinning(); +JSONConfigParser::JSONConfigParser(const nlohmann::json& config) + : m_config(config) { + parseTOFBinning(); } /** @@ -78,7 +65,7 @@ JSONConfigParser::JSONConfigParser(const nlohmann::json& config) : m_config(conf * @return double */ double JSONConfigParser::getABSRadius() const { - return m_config.value("/abs/radius"_json_pointer, DEFAULT_ABS_RADIUS); + return m_config.value("/abs/radius"_json_pointer, DEFAULT_ABS_RADIUS); } /** @@ -86,7 +73,8 @@ double JSONConfigParser::getABSRadius() const { * @return unsigned long int */ unsigned long int JSONConfigParser::getABSMinClusterSize() const { - return m_config.value("/abs/min_cluster_size"_json_pointer, DEFAULT_ABS_MIN_CLUSTER_SIZE); + return m_config.value("/abs/min_cluster_size"_json_pointer, + DEFAULT_ABS_MIN_CLUSTER_SIZE); } /** @@ -94,7 +82,8 @@ unsigned long int JSONConfigParser::getABSMinClusterSize() const { * @return unsigned long int */ unsigned long int JSONConfigParser::getABSSpiderTimeRange() const { - return m_config.value("/abs/spider_time_range"_json_pointer, DEFAULT_ABS_SPIDER_TIME_RANGE); + return m_config.value("/abs/spider_time_range"_json_pointer, + DEFAULT_ABS_SPIDER_TIME_RANGE); } /** @@ -102,28 +91,30 @@ unsigned long int JSONConfigParser::getABSSpiderTimeRange() const { * @return std::vector */ std::vector JSONConfigParser::getTOFBinEdges() const { - return m_tof_binning.getBinEdges(); + return m_tof_binning.getBinEdges(); } double JSONConfigParser::getSuperResolution() const { - return m_config.value("/tof_imaging/super_resolution"_json_pointer, DEFAULT_SUPER_RESOLUTION); + return m_config.value("/tof_imaging/super_resolution"_json_pointer, + DEFAULT_SUPER_RESOLUTION); } /** * @brief Parse the TOF binning configuration */ void JSONConfigParser::parseTOFBinning() { - if (m_config.contains("/tof_imaging/bin_edges"_json_pointer)) { - m_tof_binning.custom_edges = m_config["/tof_imaging/bin_edges"_json_pointer].get>(); - } else if (m_config.contains("/tof_imaging/uniform_bins"_json_pointer)) { - const auto& uniform = m_config["/tof_imaging/uniform_bins"_json_pointer]; - m_tof_binning.num_bins = uniform.value("num_bins", DEFAULT_TOF_BINS); - m_tof_binning.tof_max = uniform.value("end", DEFAULT_TOF_MAX); - } else { - // Use default values - m_tof_binning.num_bins = DEFAULT_TOF_BINS; - m_tof_binning.tof_max = DEFAULT_TOF_MAX; - } + if (m_config.contains("/tof_imaging/bin_edges"_json_pointer)) { + m_tof_binning.custom_edges = m_config["/tof_imaging/bin_edges"_json_pointer] + .get>(); + } else if (m_config.contains("/tof_imaging/uniform_bins"_json_pointer)) { + const auto& uniform = m_config["/tof_imaging/uniform_bins"_json_pointer]; + m_tof_binning.num_bins = uniform.value("num_bins", DEFAULT_TOF_BINS); + m_tof_binning.tof_max = uniform.value("end", DEFAULT_TOF_MAX); + } else { + // Use default values + m_tof_binning.num_bins = DEFAULT_TOF_BINS; + m_tof_binning.tof_max = DEFAULT_TOF_MAX; + } } /** @@ -131,19 +122,21 @@ void JSONConfigParser::parseTOFBinning() { * @return std::string */ std::string JSONConfigParser::toString() const { - std::stringstream ss; - ss << "ABS: radius=" << getABSRadius() - << ", min_cluster_size=" << getABSMinClusterSize() - << ", spider_time_range=" << getABSSpiderTimeRange(); - - if (m_tof_binning.isCustom()) { - ss << ", Custom TOF binning with " << m_tof_binning.custom_edges.size() - 1 << " bins"; - } else { - ss << ", TOF bins=" << m_tof_binning.num_bins.value_or(DEFAULT_TOF_BINS) - << ", TOF max=" << (m_tof_binning.tof_max.value_or(DEFAULT_TOF_MAX) * 1000) << " ms"; - } - - ss << ", Super Resolution=" << getSuperResolution(); - - return ss.str(); + std::stringstream ss; + ss << "ABS: radius=" << getABSRadius() + << ", min_cluster_size=" << getABSMinClusterSize() + << ", spider_time_range=" << getABSSpiderTimeRange(); + + if (m_tof_binning.isCustom()) { + ss << ", Custom TOF binning with " << m_tof_binning.custom_edges.size() - 1 + << " bins"; + } else { + ss << ", TOF bins=" << m_tof_binning.num_bins.value_or(DEFAULT_TOF_BINS) + << ", TOF max=" + << (m_tof_binning.tof_max.value_or(DEFAULT_TOF_MAX) * 1000) << " ms"; + } + + ss << ", Super Resolution=" << getSuperResolution(); + + return ss.str(); } diff --git a/sophiread/SophireadCLI/src/sophiread.cpp b/sophiread/SophireadCLI/src/sophiread.cpp index b2b4f0a..3e3f436 100644 --- a/sophiread/SophireadCLI/src/sophiread.cpp +++ b/sophiread/SophireadCLI/src/sophiread.cpp @@ -7,114 +7,115 @@ * @date 2024-08-19 * * @copyright Copyright (c) 2024 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include #include +#include #include -#include #include +#include #include #include #include -#include #include "abs.h" #include "disk_io.h" -#include "tpx3_fast.h" -#include "user_config.h" #include "json_config_parser.h" #include "sophiread_core.h" +#include "tpx3_fast.h" +#include "user_config.h" struct ProgramOptions { - std::string input_tpx3; - std::string output_hits; - std::string output_events; - std::string config_file; - std::string output_tof_imaging; - std::string tof_filename_base = "tof_image"; - std::string tof_mode = "neutron"; - bool debug_logging = false; - bool verbose = false; + std::string input_tpx3; + std::string output_hits; + std::string output_events; + std::string config_file; + std::string output_tof_imaging; + std::string tof_filename_base = "tof_image"; + std::string tof_mode = "neutron"; + bool debug_logging = false; + bool verbose = false; }; void print_usage(const char* program_name) { - spdlog::info("Usage: {} -i -H -E [-u ] [-T ] [-f ] [-m ] [-d] [-v]", program_name); - spdlog::info("Options:"); - spdlog::info(" -i Input TPX3 file"); - spdlog::info(" -H Output hits HDF5 file"); - spdlog::info(" -E Output events HDF5 file"); - spdlog::info(" -u User configuration JSON file (optional)"); - spdlog::info(" -T Output folder for TIFF TOF images (optional)"); - spdlog::info(" -f Base name for TIFF files (default: tof_image)"); - spdlog::info(" -m TOF mode: 'hit' or 'neutron' (default: neutron)"); - spdlog::info(" -d Enable debug logging"); - spdlog::info(" -v Enable verbose logging"); + spdlog::info( + "Usage: {} -i -H -E [-u " + "] [-T ] [-f ] [-m " + "] [-d] [-v]", + program_name); + spdlog::info("Options:"); + spdlog::info(" -i Input TPX3 file"); + spdlog::info(" -H Output hits HDF5 file"); + spdlog::info(" -E Output events HDF5 file"); + spdlog::info( + " -u User configuration JSON file (optional)"); + spdlog::info( + " -T Output folder for TIFF TOF images " + "(optional)"); + spdlog::info( + " -f Base name for TIFF files (default: " + "tof_image)"); + spdlog::info( + " -m TOF mode: 'hit' or 'neutron' (default: " + "neutron)"); + spdlog::info(" -d Enable debug logging"); + spdlog::info(" -v Enable verbose logging"); } ProgramOptions parse_arguments(int argc, char* argv[]) { - ProgramOptions options; - int opt; - - while ((opt = getopt(argc, argv, "i:H:E:u:T:f:m:dv")) != -1) { - switch (opt) { - case 'i': - options.input_tpx3 = optarg; - break; - case 'H': - options.output_hits = optarg; - break; - case 'E': - options.output_events = optarg; - break; - case 'u': - options.config_file = optarg; - break; - case 'T': - options.output_tof_imaging = optarg; - break; - case 'f': - options.tof_filename_base = optarg; - break; - case 'm': - options.tof_mode = optarg; - break; - case 'd': - options.debug_logging = true; - break; - case 'v': - options.verbose = true; - break; - default: - print_usage(argv[0]); - throw std::runtime_error(std::string("Invalid argument: ") + static_cast(optopt)); - } - } - - // Validate required arguments - if (options.input_tpx3.empty()) { + ProgramOptions options; + int opt; + + while ((opt = getopt(argc, argv, "i:H:E:u:T:f:m:dv")) != -1) { + switch (opt) { + case 'i': + options.input_tpx3 = optarg; + break; + case 'H': + options.output_hits = optarg; + break; + case 'E': + options.output_events = optarg; + break; + case 'u': + options.config_file = optarg; + break; + case 'T': + options.output_tof_imaging = optarg; + break; + case 'f': + options.tof_filename_base = optarg; + break; + case 'm': + options.tof_mode = optarg; + break; + case 'd': + options.debug_logging = true; + break; + case 'v': + options.verbose = true; + break; + default: print_usage(argv[0]); - throw std::runtime_error("Missing required arguments"); + throw std::runtime_error(std::string("Invalid argument: ") + + static_cast(optopt)); } + } - // Validate TOF mode - if (options.tof_mode != "hit" && options.tof_mode != "neutron") { - throw std::runtime_error("Invalid TOF mode. Use 'hit' or 'neutron'."); - } + // Validate required arguments + if (options.input_tpx3.empty()) { + print_usage(argv[0]); + throw std::runtime_error("Missing required arguments"); + } + + // Validate TOF mode + if (options.tof_mode != "hit" && options.tof_mode != "neutron") { + throw std::runtime_error("Invalid TOF mode. Use 'hit' or 'neutron'."); + } - return options; + return options; } /** @@ -124,77 +125,90 @@ ProgramOptions parse_arguments(int argc, char* argv[]) { * @param[in] argv * @return int */ -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { try { - ProgramOptions options = parse_arguments(argc, argv); - - // Set logging level based on debug and verbose flags - if (options.debug_logging) { - spdlog::set_level(spdlog::level::debug); - spdlog::debug("Debug logging enabled"); - } else if (options.verbose) { - spdlog::set_level(spdlog::level::info); - } else { - spdlog::set_level(spdlog::level::warn); - } - - spdlog::info("Input file: {}", options.input_tpx3); - spdlog::info("Output hits file: {}", options.output_hits); - spdlog::info("Output events file: {}", options.output_events); - spdlog::info("Configuration file: {}", options.config_file); - spdlog::info("TOF imaging folder: {}", options.output_tof_imaging); - spdlog::info("TOF filename base: {}", options.tof_filename_base); - spdlog::info("TOF mode: {}", options.tof_mode); - - // Load configuration - std::unique_ptr config; - if (!options.config_file.empty()) { - std::string extension = std::filesystem::path(options.config_file).extension().string(); - if (extension == ".json") { - config = std::make_unique(JSONConfigParser::fromFile(options.config_file)); - } else { - spdlog::warn("Deprecated configuration format detected. Please switch to JSON format."); - config = std::make_unique(parseUserDefinedConfigurationFile(options.config_file)); - } - } else { - spdlog::info("No configuration file provided. Using default JSON configuration."); - config = std::make_unique(JSONConfigParser::createDefault()); - } - - spdlog::info("Configuration: {}", config->toString()); - - // Process raw data - auto start = std::chrono::high_resolution_clock::now(); - auto raw_data = sophiread::timedReadDataToCharVec(options.input_tpx3); - auto batches = sophiread::timedFindTPX3H(raw_data); - sophiread::timedLocateTimeStamp(batches, raw_data); - sophiread::timedProcessing(batches, raw_data, *config); - auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start).count(); - spdlog::info("Total processing time: {} s", elapsed / 1e6); - - // Release memory of raw data - std::vector().swap(raw_data); - - // Generate and save TOF images - if (!options.output_tof_imaging.empty()) { - auto tof_images = sophiread::timedCreateTOFImages(batches, config->getSuperResolution(), config->getTOFBinEdges(), options.tof_mode); - sophiread::timedSaveTOFImagingToTIFF(options.output_tof_imaging, tof_images, config->getTOFBinEdges(), options.tof_filename_base); - } - - // Save hits and events - if (!options.output_hits.empty()) { - sophiread::timedSaveHitsToHDF5(options.output_hits, batches); - } - - if (!options.output_events.empty()) { - sophiread::timedSaveEventsToHDF5(options.output_events, batches); - } - - } catch (const std::exception& e) { - spdlog::error("Error: {}", e.what()); - return 1; + ProgramOptions options = parse_arguments(argc, argv); + + // Set logging level based on debug and verbose flags + if (options.debug_logging) { + spdlog::set_level(spdlog::level::debug); + spdlog::debug("Debug logging enabled"); + } else if (options.verbose) { + spdlog::set_level(spdlog::level::info); + } else { + spdlog::set_level(spdlog::level::warn); + } + + spdlog::info("Input file: {}", options.input_tpx3); + spdlog::info("Output hits file: {}", options.output_hits); + spdlog::info("Output events file: {}", options.output_events); + spdlog::info("Configuration file: {}", options.config_file); + spdlog::info("TOF imaging folder: {}", options.output_tof_imaging); + spdlog::info("TOF filename base: {}", options.tof_filename_base); + spdlog::info("TOF mode: {}", options.tof_mode); + + // Load configuration + std::unique_ptr config; + if (!options.config_file.empty()) { + std::string extension = + std::filesystem::path(options.config_file).extension().string(); + if (extension == ".json") { + config = std::make_unique( + JSONConfigParser::fromFile(options.config_file)); + } else { + spdlog::warn( + "Deprecated configuration format detected. Please switch to JSON " + "format."); + config = std::make_unique( + parseUserDefinedConfigurationFile(options.config_file)); + } + } else { + spdlog::info( + "No configuration file provided. Using default JSON configuration."); + config = + std::make_unique(JSONConfigParser::createDefault()); + } + + spdlog::info("Configuration: {}", config->toString()); + + // Process raw data + auto start = std::chrono::high_resolution_clock::now(); + auto raw_data = sophiread::timedReadDataToCharVec(options.input_tpx3); + auto batches = sophiread::timedFindTPX3H(raw_data); + sophiread::timedLocateTimeStamp(batches, raw_data); + sophiread::timedProcessing(batches, raw_data, *config); + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); + spdlog::info("Total processing time: {} s", elapsed / 1e6); + + // Release memory of raw data + std::vector().swap(raw_data); + + // Generate and save TOF images + if (!options.output_tof_imaging.empty()) { + auto tof_images = sophiread::timedCreateTOFImages( + batches, config->getSuperResolution(), config->getTOFBinEdges(), + options.tof_mode); + sophiread::timedSaveTOFImagingToTIFF(options.output_tof_imaging, + tof_images, config->getTOFBinEdges(), + options.tof_filename_base); } - return 0; + // Save hits and events + if (!options.output_hits.empty()) { + sophiread::timedSaveHitsToHDF5(options.output_hits, batches); + } + + if (!options.output_events.empty()) { + sophiread::timedSaveEventsToHDF5(options.output_events, batches); + } + + } catch (const std::exception& e) { + spdlog::error("Error: {}", e.what()); + return 1; + } + + return 0; } diff --git a/sophiread/SophireadCLI/src/sophiread_core.cpp b/sophiread/SophireadCLI/src/sophiread_core.cpp index 41cb203..ea5ad6a 100644 --- a/sophiread/SophireadCLI/src/sophiread_core.cpp +++ b/sophiread/SophireadCLI/src/sophiread_core.cpp @@ -7,27 +7,19 @@ * @date 2024-08-21 * * @copyright Copyright (c) 2024 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ +#include "sophiread_core.h" + +#include #include +#include + #include -#include #include -#include -#include +#include + #include "disk_io.h" -#include "sophiread_core.h" #include "tiff_types.h" namespace sophiread { @@ -42,7 +34,9 @@ std::vector timedReadDataToCharVec(const std::string &in_tpx3) { auto start = std::chrono::high_resolution_clock::now(); auto raw_data = readTPX3RawToCharVec(in_tpx3); auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Read raw data: {} s", elapsed / 1e6); return raw_data; @@ -58,7 +52,9 @@ std::vector timedFindTPX3H(const std::vector &rawdata) { auto start = std::chrono::high_resolution_clock::now(); auto batches = findTPX3H(rawdata); auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Locate all headers: {} s", elapsed / 1e6); return batches; @@ -70,7 +66,8 @@ std::vector timedFindTPX3H(const std::vector &rawdata) { * @param[in, out] batches * @param[in] rawdata */ -void timedLocateTimeStamp(std::vector &batches, const std::vector &rawdata) { +void timedLocateTimeStamp(std::vector &batches, + const std::vector &rawdata) { auto start = std::chrono::high_resolution_clock::now(); unsigned long tdc_timestamp = 0; unsigned long long gdc_timestamp = 0; @@ -79,7 +76,9 @@ void timedLocateTimeStamp(std::vector &batches, const std::vector &r updateTimestamp(tpx3, rawdata, tdc_timestamp, gdc_timestamp, timer_lsb32); } auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Locate all timestamps: {} s", elapsed / 1e6); } @@ -90,26 +89,32 @@ void timedLocateTimeStamp(std::vector &batches, const std::vector &r * @param[in] rawdata * @param[in] config */ -void timedProcessing(std::vector &batches, const std::vector &raw_data, const IConfig &config) { +void timedProcessing(std::vector &batches, + const std::vector &raw_data, const IConfig &config) { auto start = std::chrono::high_resolution_clock::now(); - tbb::parallel_for(tbb::blocked_range(0, batches.size()), [&](const tbb::blocked_range &r) { - // Define ABS algorithm with user-defined parameters for each thread - auto abs_alg_mt = - std::make_unique(config.getABSRadius(), config.getABSMinClusterSize(), config.getABSSpiderTimeRange()); - - for (size_t i = r.begin(); i != r.end(); ++i) { - auto &tpx3 = batches[i]; - extractHits(tpx3, raw_data); - - abs_alg_mt->reset(); - abs_alg_mt->set_method("centroid"); - abs_alg_mt->fit(tpx3.hits); - - tpx3.neutrons = abs_alg_mt->get_events(tpx3.hits); - } - }); + tbb::parallel_for(tbb::blocked_range(0, batches.size()), + [&](const tbb::blocked_range &r) { + // Define ABS algorithm with user-defined parameters for + // each thread + auto abs_alg_mt = std::make_unique( + config.getABSRadius(), config.getABSMinClusterSize(), + config.getABSSpiderTimeRange()); + + for (size_t i = r.begin(); i != r.end(); ++i) { + auto &tpx3 = batches[i]; + extractHits(tpx3, raw_data); + + abs_alg_mt->reset(); + abs_alg_mt->set_method("centroid"); + abs_alg_mt->fit(tpx3.hits); + + tpx3.neutrons = abs_alg_mt->get_events(tpx3.hits); + } + }); auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Process all hits -> neutrons: {} s", elapsed / 1e6); } @@ -119,7 +124,8 @@ void timedProcessing(std::vector &batches, const std::vector &raw_da * @param[in] out_hits * @param[in] hits */ -void timedSaveHitsToHDF5(const std::string &out_hits, std::vector &batches) { +void timedSaveHitsToHDF5(const std::string &out_hits, + std::vector &batches) { auto start = std::chrono::high_resolution_clock::now(); // move all hits into a single vector std::vector hits; @@ -130,7 +136,9 @@ void timedSaveHitsToHDF5(const std::string &out_hits, std::vector &batches // save hits to HDF5 file saveHitsToHDF5(out_hits, hits); auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Save hits to HDF5: {} s", elapsed / 1e6); } @@ -140,7 +148,8 @@ void timedSaveHitsToHDF5(const std::string &out_hits, std::vector &batches * @param[in] out_events * @param[in] batches */ -void timedSaveEventsToHDF5(const std::string &out_events, std::vector &batches) { +void timedSaveEventsToHDF5(const std::string &out_events, + std::vector &batches) { auto start = std::chrono::high_resolution_clock::now(); // move all events into a single vector std::vector events; @@ -151,118 +160,133 @@ void timedSaveEventsToHDF5(const std::string &out_events, std::vector &bat // save events to HDF5 file saveNeutronToHDF5(out_events, events); auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start).count(); + auto elapsed = + std::chrono::duration_cast(end - start) + .count(); spdlog::info("Save events to HDF5: {} s", elapsed / 1e6); } /** * @brief Timed create TOF images. * - * This function creates time-of-flight (TOF) images based on the provided batches of TPX3 data. The TOF images are 2D histograms that represent the distribution of neutron events in space for different TOF bins. The function takes into account the super resolution, TOF bin edges, and the mode of operation (hit or neutron) to generate the TOF images. + * This function creates time-of-flight (TOF) images based on the provided + * batches of TPX3 data. The TOF images are 2D histograms that represent the + * distribution of neutron events in space for different TOF bins. The function + * takes into account the super resolution, TOF bin edges, and the mode of + * operation (hit or neutron) to generate the TOF images. * * @param[in] batches The vector of TPX3 batches containing the neutron events. - * @param[in] super_resolution The super resolution factor used to calculate the dimensions of each 2D histogram. - * @param[in] tof_bin_edges The vector of TOF bin edges used to determine the TOF bin for each neutron event. - * @param[in] mode The mode of operation, either "hit" or "neutron", which determines the type of events to process. - * @return std::vector>> The vector of TOF images, where each TOF image is a 2D histogram representing the distribution of neutron events in space for a specific TOF bin. + * @param[in] super_resolution The super resolution factor used to calculate the + * dimensions of each 2D histogram. + * @param[in] tof_bin_edges The vector of TOF bin edges used to determine the + * TOF bin for each neutron event. + * @param[in] mode The mode of operation, either "hit" or "neutron", which + * determines the type of events to process. + * @return std::vector>> The vector of TOF + * images, where each TOF image is a 2D histogram representing the distribution + * of neutron events in space for a specific TOF bin. */ std::vector>> timedCreateTOFImages( - const std::vector& batches, - double super_resolution, - const std::vector& tof_bin_edges, - const std::string& mode) { - - auto start = std::chrono::high_resolution_clock::now(); - - // Initialize the TOF images container - std::vector>> tof_images(tof_bin_edges.size() - 1); - - // Sanity checks - if (tof_bin_edges.size() < 2) { - spdlog::error("Invalid TOF bin edges: at least 2 edges are required"); - return {}; - } - if (batches.empty()) { - spdlog::error("No batches to process"); - return tof_images; - } - - // Calculate the dimensions of each 2D histogram based on super_resolution - // one chip: 0-255 pixel pos - // gap: 5 - // total: 0-255 + 5 + 0-255 -> 517 (TPX3@VENUS only) - int dim_x = static_cast(517 * super_resolution); - int dim_y = static_cast(517 * super_resolution); - - spdlog::debug("Creating TOF images with dimensions: {} x {}", dim_x, dim_y); - spdlog::debug("tof_bin_edges size: {}", tof_bin_edges.size()); - if (!tof_bin_edges.empty()) { - spdlog::debug("First bin edge: {}, Last bin edge: {}", tof_bin_edges.front(), tof_bin_edges.back()); - } - - // Initialize each TOF bin's 2D histogram - for (auto& tof_image : tof_images) { - tof_image.resize(dim_y, std::vector(dim_x, 0)); - } + const std::vector &batches, double super_resolution, + const std::vector &tof_bin_edges, const std::string &mode) { + auto start = std::chrono::high_resolution_clock::now(); - // Process neutrons from all batches - size_t total_entries = 0; - size_t binned_entries = 0; + // Initialize the TOF images container + std::vector>> tof_images( + tof_bin_edges.size() - 1); - for (size_t batch_index = 0; batch_index < batches.size(); ++batch_index) { - const auto& batch = batches[batch_index]; - spdlog::debug("Processing batch {}", batch_index); + // Sanity checks + if (tof_bin_edges.size() < 2) { + spdlog::error("Invalid TOF bin edges: at least 2 edges are required"); + return {}; + } + if (batches.empty()) { + spdlog::error("No batches to process"); + return tof_images; + } - std::vector entries; - if (mode == "hit") { - entries.reserve(batch.hits.size()); - for (const auto& hit : batch.hits) { - entries.push_back(static_cast(&hit)); - } - } else { - entries.reserve(batch.neutrons.size()); - for (const auto& neutron : batch.neutrons) { - entries.push_back(static_cast(&neutron)); - } - } + // Calculate the dimensions of each 2D histogram based on super_resolution + // one chip: 0-255 pixel pos + // gap: 5 + // total: 0-255 + 5 + 0-255 -> 517 (TPX3@VENUS only) + int dim_x = static_cast(517 * super_resolution); + int dim_y = static_cast(517 * super_resolution); + + spdlog::debug("Creating TOF images with dimensions: {} x {}", dim_x, dim_y); + spdlog::debug("tof_bin_edges size: {}", tof_bin_edges.size()); + if (!tof_bin_edges.empty()) { + spdlog::debug("First bin edge: {}, Last bin edge: {}", + tof_bin_edges.front(), tof_bin_edges.back()); + } - if (entries.empty()) { - spdlog::debug("Batch {} is empty", batch_index); - continue; - } + // Initialize each TOF bin's 2D histogram + for (auto &tof_image : tof_images) { + tof_image.resize(dim_y, std::vector(dim_x, 0)); + } - for (const auto& entry : entries) { - total_entries++; - const double tof_ns = entry->iGetTOF_ns(); - const double tof_s = tof_ns/1e9; + // Process neutrons from all batches + size_t total_entries = 0; + size_t binned_entries = 0; - // Find the correct TOF bin - // NOTE: tof_bin_edges are in sec, and tof_ns are in nano secs - spdlog::debug("tof_ns: {}, tof_ns/1e9: {}", tof_ns, tof_s); + for (size_t batch_index = 0; batch_index < batches.size(); ++batch_index) { + const auto &batch = batches[batch_index]; + spdlog::debug("Processing batch {}", batch_index); - if (const auto it = std::lower_bound(tof_bin_edges.cbegin(), tof_bin_edges.cend(), tof_s); it != tof_bin_edges.cbegin()) { - const size_t bin_index = std::distance(tof_bin_edges.cbegin(), it) - 1; + std::vector entries; + if (mode == "hit") { + entries.reserve(batch.hits.size()); + for (const auto &hit : batch.hits) { + entries.push_back(static_cast(&hit)); + } + } else { + entries.reserve(batch.neutrons.size()); + for (const auto &neutron : batch.neutrons) { + entries.push_back(static_cast(&neutron)); + } + } - // Calculate the x and y indices in the 2D histogram - const int x = std::round(entry->iGetX() * super_resolution); - const int y = std::round(entry->iGetY() * super_resolution); + if (entries.empty()) { + spdlog::debug("Batch {} is empty", batch_index); + continue; + } - // Ensure x and y are within bounds - if (x >= 0 && x < dim_x && y >= 0 && y < dim_y) { - // Increment the count in the appropriate bin and position - tof_images[bin_index][y][x]++; - binned_entries++; - } - } + for (const auto &entry : entries) { + total_entries++; + const double tof_ns = entry->iGetTOF_ns(); + const double tof_s = tof_ns / 1e9; + + // Find the correct TOF bin + // NOTE: tof_bin_edges are in sec, and tof_ns are in nano secs + spdlog::debug("tof_ns: {}, tof_ns/1e9: {}", tof_ns, tof_s); + + if (const auto it = std::lower_bound(tof_bin_edges.cbegin(), + tof_bin_edges.cend(), tof_s); + it != tof_bin_edges.cbegin()) { + const size_t bin_index = std::distance(tof_bin_edges.cbegin(), it) - 1; + + // Calculate the x and y indices in the 2D histogram + const int x = std::round(entry->iGetX() * super_resolution); + const int y = std::round(entry->iGetY() * super_resolution); + + // Ensure x and y are within bounds + if (x >= 0 && x < dim_x && y >= 0 && y < dim_y) { + // Increment the count in the appropriate bin and position + tof_images[bin_index][y][x]++; + binned_entries++; } + } } + } - const auto end = std::chrono::high_resolution_clock::now(); - const auto elapsed = std::chrono::duration_cast(end - start).count(); - spdlog::info("TOF image creation time: {} s", elapsed / 1e6); - spdlog::info("Total entries: {}, Binned entries: {}", total_entries, binned_entries); + const auto end = std::chrono::high_resolution_clock::now(); + const auto elapsed = + std::chrono::duration_cast(end - start) + .count(); + spdlog::info("TOF image creation time: {} s", elapsed / 1e6); + spdlog::info("Total entries: {}, Binned entries: {}", total_entries, + binned_entries); - return tof_images; + return tof_images; } /** @@ -274,111 +298,125 @@ std::vector>> timedCreateTOFImages( * @param[in] tof_filename_base */ void timedSaveTOFImagingToTIFF( - const std::string& out_tof_imaging, - const std::vector>>& tof_images, - const std::vector& tof_bin_edges, - const std::string& tof_filename_base) -{ - auto start = std::chrono::high_resolution_clock::now(); - - // 1. Create output directory if it doesn't exist - if (!std::filesystem::exists(out_tof_imaging)) { - std::filesystem::create_directories(out_tof_imaging); - spdlog::info("Created output directory: {}", out_tof_imaging); - } + const std::string &out_tof_imaging, + const std::vector>> &tof_images, + const std::vector &tof_bin_edges, + const std::string &tof_filename_base) { + auto start = std::chrono::high_resolution_clock::now(); - // 2. Initialize vector for spectral data - std::vector spectral_counts(tof_images.size(), 0); + // 1. Create output directory if it doesn't exist + if (!std::filesystem::exists(out_tof_imaging)) { + std::filesystem::create_directories(out_tof_imaging); + spdlog::info("Created output directory: {}", out_tof_imaging); + } + + // 2. Initialize vector for spectral data + std::vector spectral_counts(tof_images.size(), 0); - // 3. Iterate through each TOF bin and save TIFF files - tbb::parallel_for(tbb::blocked_range(0, tof_images.size()), [&](const tbb::blocked_range& range) { - for (size_t bin = range.begin(); bin < range.end(); ++bin) { + // 3. Iterate through each TOF bin and save TIFF files + tbb::parallel_for( + tbb::blocked_range(0, tof_images.size()), + [&](const tbb::blocked_range &range) { + for (size_t bin = range.begin(); bin < range.end(); ++bin) { // Construct filename - std::string filename = fmt::format("{}/{}_bin_{:04d}.tiff", out_tof_imaging, tof_filename_base, bin + 1); + std::string filename = + fmt::format("{}/{}_bin_{:04d}.tiff", out_tof_imaging, + tof_filename_base, bin + 1); // prepare container and fill with current hist2d const uint32_t width = tof_images[bin][0].size(); const uint32_t height = tof_images[bin].size(); - std::vector> accumulated_image = tof_images[bin]; + std::vector> accumulated_image = + tof_images[bin]; // check if file already exist if (std::filesystem::exists(filename)) { - TIFF* existing_tif = TIFFOpen(filename.c_str(), "r"); - if (existing_tif) { - uint32_t existing_width, existing_height; - TIFFGetField(existing_tif, TIFFTAG_IMAGEWIDTH, &existing_width); - TIFFGetField(existing_tif, TIFFTAG_IMAGELENGTH, &existing_height); - - if (existing_width == width && existing_height == height) { - // Dimensions match, proceed with accumulation - for (uint32_t row = 0; row < height; ++row) { - std::vector scanline(width); - TIFFReadScanline(existing_tif, scanline.data(), row); - for (uint32_t col = 0; col < width; ++col) { - accumulated_image[row][col] += scanline[col]; - } - } - spdlog::debug("Accumulated counts for existing file: {}", filename); - } else { - spdlog::error("Dimension mismatch for file: {}. Expected {}x{}, got {}x{}. Overwriting.", - filename, width, height, existing_width, existing_height); + TIFF *existing_tif = TIFFOpen(filename.c_str(), "r"); + if (existing_tif) { + uint32_t existing_width, existing_height; + TIFFGetField(existing_tif, TIFFTAG_IMAGEWIDTH, &existing_width); + TIFFGetField(existing_tif, TIFFTAG_IMAGELENGTH, &existing_height); + + if (existing_width == width && existing_height == height) { + // Dimensions match, proceed with accumulation + for (uint32_t row = 0; row < height; ++row) { + std::vector scanline(width); + TIFFReadScanline(existing_tif, scanline.data(), row); + for (uint32_t col = 0; col < width; ++col) { + accumulated_image[row][col] += scanline[col]; } - TIFFClose(existing_tif); + } + spdlog::debug("Accumulated counts for existing file: {}", + filename); } else { - spdlog::error("Failed to open existing TIFF file for reading: {}", filename); + spdlog::error( + "Dimension mismatch for file: {}. Expected {}x{}, got " + "{}x{}. Overwriting.", + filename, width, height, existing_width, existing_height); } + TIFFClose(existing_tif); + } else { + spdlog::error("Failed to open existing TIFF file for reading: {}", + filename); + } } // Write or update TIFF file - TIFF* tif = TIFFOpen(filename.c_str(), "w"); + TIFF *tif = TIFFOpen(filename.c_str(), "w"); if (tif) { - const uint32_t width = tof_images[bin][0].size(); - const uint32_t height = tof_images[bin].size(); - - TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); - TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); - TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); - TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32); - TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); - - for (uint32_t row = 0; row < height; ++row) { - TIFFWriteScanline(tif, accumulated_image[row].data(), row); - } + const uint32_t width = tof_images[bin][0].size(); + const uint32_t height = tof_images[bin].size(); + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + + for (uint32_t row = 0; row < height; ++row) { + TIFFWriteScanline(tif, accumulated_image[row].data(), row); + } - TIFFClose(tif); - spdlog::debug("Wrote TIFF file: {}", filename); + TIFFClose(tif); + spdlog::debug("Wrote TIFF file: {}", filename); } else { - spdlog::error("Failed to open TIFF file for writing: {}", filename); + spdlog::error("Failed to open TIFF file for writing: {}", filename); } // Accumulate counts for spectral file - spectral_counts[bin] = std::accumulate(accumulated_image.cbegin(), accumulated_image.cend(), static_cast(0), - [](const auto sum, const auto & row) { + spectral_counts[bin] = std::accumulate( + accumulated_image.cbegin(), accumulated_image.cend(), + static_cast(0), [](const auto sum, const auto &row) { return sum + std::accumulate(row.cbegin(), row.cend(), 0ULL); - }); - } - }); - - // 4. Write spectral file - std::string spectral_filename = fmt::format("{}/{}_Spectra.txt", out_tof_imaging, tof_filename_base); - // Write spectral data to file - std::ofstream spectral_file(spectral_filename); - if (spectral_file.is_open()) { - spectral_file << "shutter_time,counts\n"; - for (size_t bin = 0; bin < tof_bin_edges.size() - 1; ++bin) { - spectral_file << tof_bin_edges[bin + 1] << "," << spectral_counts[bin] << "\n"; + }); } - spectral_file.close(); - spdlog::info("Wrote spectral file: {}", spectral_filename); - } else { - spdlog::error("Failed to open spectra file for writing: {}", spectral_filename); + }); + + // 4. Write spectral file + std::string spectral_filename = + fmt::format("{}/{}_Spectra.txt", out_tof_imaging, tof_filename_base); + // Write spectral data to file + std::ofstream spectral_file(spectral_filename); + if (spectral_file.is_open()) { + spectral_file << "shutter_time,counts\n"; + for (size_t bin = 0; bin < tof_bin_edges.size() - 1; ++bin) { + spectral_file << tof_bin_edges[bin + 1] << "," << spectral_counts[bin] + << "\n"; } + spectral_file.close(); + spdlog::info("Wrote spectral file: {}", spectral_filename); + } else { + spdlog::error("Failed to open spectra file for writing: {}", + spectral_filename); + } - auto end = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(end - start); - spdlog::info("TIFF and spectra file writing completed in {} ms", duration.count()); + auto end = std::chrono::high_resolution_clock::now(); + auto duration = + std::chrono::duration_cast(end - start); + spdlog::info("TIFF and spectra file writing completed in {} ms", + duration.count()); } -} // namespace sophiread \ No newline at end of file +} // namespace sophiread \ No newline at end of file diff --git a/sophiread/SophireadCLI/src/user_config.cpp b/sophiread/SophireadCLI/src/user_config.cpp index e2fd5e5..133ba45 100644 --- a/sophiread/SophireadCLI/src/user_config.cpp +++ b/sophiread/SophireadCLI/src/user_config.cpp @@ -7,18 +7,7 @@ * @date 2023-09-18 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include "user_config.h" @@ -31,16 +20,28 @@ /** * @brief Construct a new UserConfig object with default values. */ -UserConfig::UserConfig() : m_abs_radius(5.0), m_abs_min_cluster_size(1), m_abs_spider_time_range(75), m_tof_binning(), m_super_resolution(1.0) {} +UserConfig::UserConfig() + : m_abs_radius(5.0), + m_abs_min_cluster_size(1), + m_abs_spider_time_range(75), + m_tof_binning(), + m_super_resolution(1.0) {} /** * @brief Construct a new UserConfig object with user-defined values */ -UserConfig::UserConfig(double abs_radius, unsigned long int abs_min_cluster_size, unsigned long int abs_spider_time_range) - : m_abs_radius(abs_radius), m_abs_min_cluster_size(abs_min_cluster_size), m_abs_spider_time_range(abs_spider_time_range), m_tof_binning(), m_super_resolution(1.0) {} +UserConfig::UserConfig(double abs_radius, + unsigned long int abs_min_cluster_size, + unsigned long int abs_spider_time_range) + : m_abs_radius(abs_radius), + m_abs_min_cluster_size(abs_min_cluster_size), + m_abs_spider_time_range(abs_spider_time_range), + m_tof_binning(), + m_super_resolution(1.0) {} /** - * @brief Helper function to convert a user configuration to a string for console output. + * @brief Helper function to convert a user configuration to a string for + * console output. * * @return std::string User configuration as a string */ @@ -53,9 +54,11 @@ std::string UserConfig::toString() const { // Add TOF binning information if (m_tof_binning.isUniform()) { ss << ", TOF bins=" << m_tof_binning.num_bins.value_or(0) - << ", TOF max=" << (m_tof_binning.tof_max.value_or(0.0) * 1000) << " ms"; // Convert to milliseconds + << ", TOF max=" << (m_tof_binning.tof_max.value_or(0.0) * 1000) + << " ms"; // Convert to milliseconds } else if (m_tof_binning.isCustom()) { - ss << ", Custom TOF binning with " << m_tof_binning.custom_edges.size() - 1 << " bins"; + ss << ", Custom TOF binning with " << m_tof_binning.custom_edges.size() - 1 + << " bins"; } else { ss << ", TOF binning not set"; } @@ -66,7 +69,8 @@ std::string UserConfig::toString() const { } /** - * @brief Parse the user-defined configuration file and return a UserConfig object. + * @brief Parse the user-defined configuration file and return a UserConfig + * object. * * @param[in] filepath * @return UserConfig User-defined configuration @@ -74,7 +78,8 @@ std::string UserConfig::toString() const { UserConfig parseUserDefinedConfigurationFile(const std::string& filepath) { // Check if the file exists if (!std::filesystem::exists(filepath)) { - spdlog::error("The user-defined configuration file {} does not exist.", filepath); + spdlog::error("The user-defined configuration file {} does not exist.", + filepath); exit(1); } @@ -118,9 +123,9 @@ UserConfig parseUserDefinedConfigurationFile(const std::string& filepath) { } else if (name == "tof_max") { double value; ss >> value; - } - else { - spdlog::warn("Unknown parameter {} in the user-defined configuration file.", name); + } else { + spdlog::warn( + "Unknown parameter {} in the user-defined configuration file.", name); } } diff --git a/sophiread/SophireadCLI/src/venus_auto_reducer.cpp b/sophiread/SophireadCLI/src/venus_auto_reducer.cpp index bee3155..bb8c351 100644 --- a/sophiread/SophireadCLI/src/venus_auto_reducer.cpp +++ b/sophiread/SophireadCLI/src/venus_auto_reducer.cpp @@ -4,254 +4,265 @@ * @brief Auto reducer demo application for VENUS@SNS * @version 0.1 * @date 2024-08-21 - * - * @copyright Copyright (c) 2024 - * 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 3 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, see . + * @copyright Copyright (c) 2024 + * SPDX - License - Identifier: GPL - 3.0 + */ +#include +#include +#include + +#include +#include +#include #include #include -#include #include -#include -#include -#include -#include #include -#include "sophiread_core.h" +#include + #include "json_config_parser.h" -#include -#include +#include "sophiread_core.h" namespace fs = std::filesystem; struct ProgramOptions { - std::string input_dir; - std::string output_dir; - std::string config_file; - std::string tiff_base = "tof_image"; - std::string tof_mode = "neutron"; - int check_interval = 5; - bool verbose = false; - bool debug = false; + std::string input_dir; + std::string output_dir; + std::string config_file; + std::string tiff_base = "tof_image"; + std::string tof_mode = "neutron"; + int check_interval = 5; + bool verbose = false; + bool debug = false; }; void print_usage(const char* program_name) { - spdlog::info("Usage: {} -i -o [-u ] [-f ] [-m ] [-c ] [-v] [-d]", program_name); - spdlog::info("Options:"); - spdlog::info(" -i Input directory with TPX3 files"); - spdlog::info(" -o Output directory for TIFF files"); - spdlog::info(" -u User configuration JSON file (optional)"); - spdlog::info(" -f Base name for TIFF files (default: tof_image)"); - spdlog::info(" -m TOF mode: 'hit' or 'neutron' (default: neutron)"); - spdlog::info(" -c Check interval in seconds (default: 5)"); - spdlog::info(" -d Debug output"); - spdlog::info(" -v Verbose output"); + spdlog::info( + "Usage: {} -i -o [-u ] [-f " + "] [-m ] [-c ] [-v] [-d]", + program_name); + spdlog::info("Options:"); + spdlog::info(" -i Input directory with TPX3 files"); + spdlog::info(" -o Output directory for TIFF files"); + spdlog::info(" -u User configuration JSON file (optional)"); + spdlog::info( + " -f Base name for TIFF files (default: tof_image)"); + spdlog::info( + " -m TOF mode: 'hit' or 'neutron' (default: neutron)"); + spdlog::info(" -c Check interval in seconds (default: 5)"); + spdlog::info(" -d Debug output"); + spdlog::info(" -v Verbose output"); } ProgramOptions parse_arguments(int argc, char* argv[]) { - ProgramOptions options; - int opt; - - while ((opt = getopt(argc, argv, "i:o:u:f:m:c:dv")) != -1) { - switch (opt) { - case 'i': - options.input_dir = optarg; - break; - case 'o': - options.output_dir = optarg; - break; - case 'u': - options.config_file = optarg; - break; - case 'f': - options.tiff_base = optarg; - break; - case 'm': - options.tof_mode = optarg; - break; - case 'c': - options.check_interval = std::stoi(optarg); - break; - case 'd': - options.debug = true; - break; - case 'v': - options.verbose = true; - break; - default: - print_usage(argv[0]); - throw std::runtime_error("Invalid argument"); - } - } + ProgramOptions options; + int opt; - // Validate required arguments - if (options.input_dir.empty() || options.output_dir.empty()) { + while ((opt = getopt(argc, argv, "i:o:u:f:m:c:dv")) != -1) { + switch (opt) { + case 'i': + options.input_dir = optarg; + break; + case 'o': + options.output_dir = optarg; + break; + case 'u': + options.config_file = optarg; + break; + case 'f': + options.tiff_base = optarg; + break; + case 'm': + options.tof_mode = optarg; + break; + case 'c': + options.check_interval = std::stoi(optarg); + break; + case 'd': + options.debug = true; + break; + case 'v': + options.verbose = true; + break; + default: print_usage(argv[0]); - throw std::runtime_error("Missing required arguments"); + throw std::runtime_error("Invalid argument"); } + } - // Validate tof_mode - if (options.tof_mode != "hit" && options.tof_mode != "neutron") { - throw std::runtime_error("Invalid TOF mode. Use 'hit' or 'neutron'."); - } + // Validate required arguments + if (options.input_dir.empty() || options.output_dir.empty()) { + print_usage(argv[0]); + throw std::runtime_error("Missing required arguments"); + } - // Validate check_interval - if (options.check_interval <= 0) { - throw std::runtime_error("Check interval must be a positive integer."); - } + // Validate tof_mode + if (options.tof_mode != "hit" && options.tof_mode != "neutron") { + throw std::runtime_error("Invalid TOF mode. Use 'hit' or 'neutron'."); + } - return options; + // Validate check_interval + if (options.check_interval <= 0) { + throw std::runtime_error("Check interval must be a positive integer."); + } + + return options; } /** * @brief Process all existing tpx3 files - * - * @param[in] input_dir - * @param[in] output_dir - * @param[in] tiff_base - * @param[in] tof_mode - * @param[in] config + * + * @param[in] input_dir + * @param[in] output_dir + * @param[in] tiff_base + * @param[in] tof_mode + * @param[in] config * @param[in, out] processed_files */ -void process_existing_files(const std::string& input_dir, const std::string& output_dir, - const std::string& tiff_base, const std::string& tof_mode, - const IConfig& config, std::unordered_set& processed_files) { - spdlog::info("Processing existing files in {}", input_dir); +void process_existing_files(const std::string& input_dir, + const std::string& output_dir, + const std::string& tiff_base, + const std::string& tof_mode, const IConfig& config, + std::unordered_set& processed_files) { + spdlog::info("Processing existing files in {}", input_dir); - // NOTE: we need to process files sequentially as we are accumulating the counts to the - // same set of tiff files in the output folder - for (const auto& entry : fs::directory_iterator(input_dir)) { - if (entry.is_regular_file() && entry.path().extension() == ".tpx3") { - std::string filename = entry.path().stem().string(); - - if (processed_files.find(filename) != processed_files.end()) { - spdlog::debug("Skipping already processed file: {}", filename); - continue; - } - - spdlog::info("Processing file: {}", entry.path().string()); - - try { - // Read the TPX3 file - auto raw_data = sophiread::timedReadDataToCharVec(entry.path().string()); - - // Find TPX3 headers - auto batches = sophiread::timedFindTPX3H(raw_data); - - // Process the data - sophiread::timedLocateTimeStamp(batches, raw_data); - sophiread::timedProcessing(batches, raw_data, config); - - // Generate output file name - std::string output_file = fs::path(output_dir) / (tiff_base + "_bin_xxxx.tiff"); - - // Create TOF images - auto tof_images = sophiread::timedCreateTOFImages(batches, config.getSuperResolution(), config.getTOFBinEdges(), tof_mode); - - // Save TOF images - sophiread::timedSaveTOFImagingToTIFF(output_dir, tof_images, config.getTOFBinEdges(), tiff_base); - - spdlog::info("Processed and saved: {}", output_file); - - // record processed file - processed_files.insert(entry.path().stem().string()); - } catch (const std::exception& e) { - spdlog::error("Error processing file {}: {}", entry.path().string(), e.what()); - } - } + // NOTE: we need to process files sequentially as we are accumulating the + // counts to the + // same set of tiff files in the output folder + for (const auto& entry : fs::directory_iterator(input_dir)) { + if (entry.is_regular_file() && entry.path().extension() == ".tpx3") { + std::string filename = entry.path().stem().string(); + + if (processed_files.find(filename) != processed_files.end()) { + spdlog::debug("Skipping already processed file: {}", filename); + continue; + } + + spdlog::info("Processing file: {}", entry.path().string()); + + try { + // Read the TPX3 file + auto raw_data = + sophiread::timedReadDataToCharVec(entry.path().string()); + + // Find TPX3 headers + auto batches = sophiread::timedFindTPX3H(raw_data); + + // Process the data + sophiread::timedLocateTimeStamp(batches, raw_data); + sophiread::timedProcessing(batches, raw_data, config); + + // Generate output file name + std::string output_file = + fs::path(output_dir) / (tiff_base + "_bin_xxxx.tiff"); + + // Create TOF images + auto tof_images = sophiread::timedCreateTOFImages( + batches, config.getSuperResolution(), config.getTOFBinEdges(), + tof_mode); + + // Save TOF images + sophiread::timedSaveTOFImagingToTIFF( + output_dir, tof_images, config.getTOFBinEdges(), tiff_base); + + spdlog::info("Processed and saved: {}", output_file); + + // record processed file + processed_files.insert(entry.path().stem().string()); + } catch (const std::exception& e) { + spdlog::error("Error processing file {}: {}", entry.path().string(), + e.what()); + } } + } - // Create a string to hold the formatted output - std::ostringstream oss; - oss << "Processed files: ["; + // Create a string to hold the formatted output + std::ostringstream oss; + oss << "Processed files: ["; - // Loop through the set and concatenate elements - for (auto it = processed_files.begin(); it != processed_files.end(); ++it) { - if (it != processed_files.begin()) { - oss << ", "; // Add a comma before each element except the first - } - oss << *it; + // Loop through the set and concatenate elements + for (auto it = processed_files.begin(); it != processed_files.end(); ++it) { + if (it != processed_files.begin()) { + oss << ", "; // Add a comma before each element except the first } - oss << "]"; - spdlog::info(oss.str()); + oss << *it; + } + oss << "]"; + spdlog::info(oss.str()); } -void monitor_directory(const std::string& input_dir, const std::string& output_dir, - const std::string& tiff_base, const std::string& tof_mode, - const IConfig& config, std::unordered_set& processed_files, +void monitor_directory(const std::string& input_dir, + const std::string& output_dir, + const std::string& tiff_base, + const std::string& tof_mode, const IConfig& config, + std::unordered_set& processed_files, int check_interval) { - spdlog::info("Starting directory monitoring: {}", input_dir); - spdlog::info("Check interval: {} seconds", check_interval); - - while (true) { - // Check for *.nxs.h5 file - for (const auto& entry : fs::directory_iterator(input_dir)) { - if (entry.is_regular_file() && entry.path().extension() == ".h5" && - entry.path().stem().extension() == ".nxs") { - spdlog::info("Found *.nxs.h5 file. Stopping monitoring."); - return; - } - } - - // Process any new files - process_existing_files(input_dir, output_dir, tiff_base, tof_mode, config, processed_files); - - // Wait before next check - std::this_thread::sleep_for(std::chrono::seconds(check_interval)); + spdlog::info("Starting directory monitoring: {}", input_dir); + spdlog::info("Check interval: {} seconds", check_interval); + + while (true) { + // Check for *.nxs.h5 file + for (const auto& entry : fs::directory_iterator(input_dir)) { + if (entry.is_regular_file() && entry.path().extension() == ".h5" && + entry.path().stem().extension() == ".nxs") { + spdlog::info("Found *.nxs.h5 file. Stopping monitoring."); + return; + } } + + // Process any new files + process_existing_files(input_dir, output_dir, tiff_base, tof_mode, config, + processed_files); + + // Wait before next check + std::this_thread::sleep_for(std::chrono::seconds(check_interval)); + } } int main(int argc, char* argv[]) { - try { - ProgramOptions options = parse_arguments(argc, argv); - - // Set logging level based on verbose flag - if (options.debug){ - spdlog::set_level(spdlog::level::debug); - spdlog::debug("Debug logging enabled"); - } else if (options.verbose) { - spdlog::set_level(spdlog::level::info); - } else { - spdlog::set_level(spdlog::level::warn); - } - - spdlog::info("Input directory: {}", options.input_dir); - spdlog::info("Output directory: {}", options.output_dir); - spdlog::info("Config file: {}", options.config_file); - spdlog::info("TIFF base name: {}", options.tiff_base); - spdlog::info("TOF mode: {}", options.tof_mode); - - // Load configuration - std::unique_ptr config; - if (!options.config_file.empty()) { - spdlog::info("Config file: {}", options.config_file); - config = std::make_unique(JSONConfigParser::fromFile(options.config_file)); - } else { - spdlog::info("Using default configuration"); - config = std::make_unique(JSONConfigParser::createDefault()); - } - - spdlog::info("Configuration: {}", config->toString()); - - // Process existing files - std::unordered_set processed_files; - monitor_directory(options.input_dir, options.output_dir, options.tiff_base, - options.tof_mode, *config, processed_files, options.check_interval); - - } catch (const std::exception& e) { - spdlog::error("Error: {}", e.what()); - return 1; + try { + ProgramOptions options = parse_arguments(argc, argv); + + // Set logging level based on verbose flag + if (options.debug) { + spdlog::set_level(spdlog::level::debug); + spdlog::debug("Debug logging enabled"); + } else if (options.verbose) { + spdlog::set_level(spdlog::level::info); + } else { + spdlog::set_level(spdlog::level::warn); } - return 0; + spdlog::info("Input directory: {}", options.input_dir); + spdlog::info("Output directory: {}", options.output_dir); + spdlog::info("Config file: {}", options.config_file); + spdlog::info("TIFF base name: {}", options.tiff_base); + spdlog::info("TOF mode: {}", options.tof_mode); + + // Load configuration + std::unique_ptr config; + if (!options.config_file.empty()) { + spdlog::info("Config file: {}", options.config_file); + config = std::make_unique( + JSONConfigParser::fromFile(options.config_file)); + } else { + spdlog::info("Using default configuration"); + config = + std::make_unique(JSONConfigParser::createDefault()); + } + + spdlog::info("Configuration: {}", config->toString()); + + // Process existing files + std::unordered_set processed_files; + monitor_directory(options.input_dir, options.output_dir, options.tiff_base, + options.tof_mode, *config, processed_files, + options.check_interval); + + } catch (const std::exception& e) { + spdlog::error("Error: {}", e.what()); + return 1; + } + + return 0; } \ No newline at end of file diff --git a/sophiread/SophireadCLI/tests/test_json_config_parser.cpp b/sophiread/SophireadCLI/tests/test_json_config_parser.cpp index 6c70f5e..d1a9353 100644 --- a/sophiread/SophireadCLI/tests/test_json_config_parser.cpp +++ b/sophiread/SophireadCLI/tests/test_json_config_parser.cpp @@ -3,32 +3,23 @@ * @author Chen Zhang (zhangc@orn.gov) * @brief Unit tests for JSONConfigParser class. * @date 2024-08-16 - * - * @copyright Copyright (c) 2024 - * 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 3 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, see . + * @copyright Copyright (c) 2024 + * SPDX - License - Identifier: GPL - 3.0 + */ -#include "json_config_parser.h" #include -#include + #include +#include + +#include "json_config_parser.h" class JSONConfigParserTest : public ::testing::Test { -protected: - void SetUp() override { - // This setup will be used for the uniform binning test - std::ofstream config_file("test_config_uniform.json"); - config_file << R"({ + protected: + void SetUp() override { + // This setup will be used for the uniform binning test + std::ofstream config_file("test_config_uniform.json"); + config_file << R"({ "abs": { "radius": 6.0, "min_cluster_size": 2, @@ -42,11 +33,11 @@ class JSONConfigParserTest : public ::testing::Test { "super_resolution": 2.0 } })"; - config_file.close(); + config_file.close(); - // Setup for custom binning test - std::ofstream config_file_custom("test_config_custom.json"); - config_file_custom << R"({ + // Setup for custom binning test + std::ofstream config_file_custom("test_config_custom.json"); + config_file_custom << R"({ "abs": { "radius": 7.0, "min_cluster_size": 3, @@ -56,84 +47,85 @@ class JSONConfigParserTest : public ::testing::Test { "bin_edges": [0, 0.001, 0.002, 0.005, 0.01, 0.0167] } })"; - config_file_custom.close(); + config_file_custom.close(); - // Setup for default values test - std::ofstream config_file_default("test_config_default.json"); - config_file_default << R"({ + // Setup for default values test + std::ofstream config_file_default("test_config_default.json"); + config_file_default << R"({ "abs": {} })"; - config_file_default.close(); - } - - void TearDown() override { - std::remove("test_config_uniform.json"); - std::remove("test_config_custom.json"); - std::remove("test_config_default.json"); - } + config_file_default.close(); + } + + void TearDown() override { + std::remove("test_config_uniform.json"); + std::remove("test_config_custom.json"); + std::remove("test_config_default.json"); + } }; TEST_F(JSONConfigParserTest, ParsesSuperResolutionCorrectly) { - auto config = JSONConfigParser::fromFile("test_config_uniform.json"); - EXPECT_DOUBLE_EQ(config.getSuperResolution(), 2.0); + auto config = JSONConfigParser::fromFile("test_config_uniform.json"); + EXPECT_DOUBLE_EQ(config.getSuperResolution(), 2.0); } TEST_F(JSONConfigParserTest, ParsesUniformConfigCorrectly) { - auto config = JSONConfigParser::fromFile("test_config_uniform.json"); - - EXPECT_DOUBLE_EQ(config.getABSRadius(), 6.0); - EXPECT_EQ(config.getABSMinClusterSize(), 2); - EXPECT_EQ(config.getABSSpiderTimeRange(), 80); - - auto bin_edges = config.getTOFBinEdges(); - EXPECT_EQ(bin_edges.size(), 1001); // 1000 bins + 1 - EXPECT_DOUBLE_EQ(bin_edges.front(), 0); - EXPECT_DOUBLE_EQ(bin_edges.back(), 0.0167); + auto config = JSONConfigParser::fromFile("test_config_uniform.json"); + + EXPECT_DOUBLE_EQ(config.getABSRadius(), 6.0); + EXPECT_EQ(config.getABSMinClusterSize(), 2); + EXPECT_EQ(config.getABSSpiderTimeRange(), 80); + + auto bin_edges = config.getTOFBinEdges(); + EXPECT_EQ(bin_edges.size(), 1001); // 1000 bins + 1 + EXPECT_DOUBLE_EQ(bin_edges.front(), 0); + EXPECT_DOUBLE_EQ(bin_edges.back(), 0.0167); } TEST_F(JSONConfigParserTest, ParsesCustomConfigCorrectly) { - auto config = JSONConfigParser::fromFile("test_config_custom.json"); - - EXPECT_DOUBLE_EQ(config.getABSRadius(), 7.0); - EXPECT_EQ(config.getABSMinClusterSize(), 3); - EXPECT_EQ(config.getABSSpiderTimeRange(), 85); - - auto bin_edges = config.getTOFBinEdges(); - EXPECT_EQ(bin_edges.size(), 6); - EXPECT_DOUBLE_EQ(bin_edges[0], 0); - EXPECT_DOUBLE_EQ(bin_edges[1], 0.001); - EXPECT_DOUBLE_EQ(bin_edges[2], 0.002); - EXPECT_DOUBLE_EQ(bin_edges[3], 0.005); - EXPECT_DOUBLE_EQ(bin_edges[4], 0.01); - EXPECT_DOUBLE_EQ(bin_edges[5], 0.0167); + auto config = JSONConfigParser::fromFile("test_config_custom.json"); + + EXPECT_DOUBLE_EQ(config.getABSRadius(), 7.0); + EXPECT_EQ(config.getABSMinClusterSize(), 3); + EXPECT_EQ(config.getABSSpiderTimeRange(), 85); + + auto bin_edges = config.getTOFBinEdges(); + EXPECT_EQ(bin_edges.size(), 6); + EXPECT_DOUBLE_EQ(bin_edges[0], 0); + EXPECT_DOUBLE_EQ(bin_edges[1], 0.001); + EXPECT_DOUBLE_EQ(bin_edges[2], 0.002); + EXPECT_DOUBLE_EQ(bin_edges[3], 0.005); + EXPECT_DOUBLE_EQ(bin_edges[4], 0.01); + EXPECT_DOUBLE_EQ(bin_edges[5], 0.0167); } TEST_F(JSONConfigParserTest, UsesDefaultValuesCorrectly) { - auto config = JSONConfigParser::fromFile("test_config_default.json"); - - EXPECT_DOUBLE_EQ(config.getABSRadius(), 5.0); - EXPECT_EQ(config.getABSMinClusterSize(), 1); - EXPECT_EQ(config.getABSSpiderTimeRange(), 75); - - auto bin_edges = config.getTOFBinEdges(); - EXPECT_EQ(bin_edges.size(), 1501); // 1500 bins + 1 - EXPECT_DOUBLE_EQ(bin_edges.front(), 0); - EXPECT_DOUBLE_EQ(bin_edges.back(), 0.0167); - EXPECT_DOUBLE_EQ(config.getSuperResolution(), 1.0); + auto config = JSONConfigParser::fromFile("test_config_default.json"); + + EXPECT_DOUBLE_EQ(config.getABSRadius(), 5.0); + EXPECT_EQ(config.getABSMinClusterSize(), 1); + EXPECT_EQ(config.getABSSpiderTimeRange(), 75); + + auto bin_edges = config.getTOFBinEdges(); + EXPECT_EQ(bin_edges.size(), 1501); // 1500 bins + 1 + EXPECT_DOUBLE_EQ(bin_edges.front(), 0); + EXPECT_DOUBLE_EQ(bin_edges.back(), 0.0167); + EXPECT_DOUBLE_EQ(config.getSuperResolution(), 1.0); } TEST_F(JSONConfigParserTest, ThrowsOnMissingFile) { - EXPECT_THROW(JSONConfigParser::fromFile("non_existent.json"), std::runtime_error); + EXPECT_THROW(JSONConfigParser::fromFile("non_existent.json"), + std::runtime_error); } TEST_F(JSONConfigParserTest, ToStringMethodWorksCorrectly) { - auto config = JSONConfigParser::fromFile("test_config_uniform.json"); - std::string result = config.toString(); - - EXPECT_TRUE(result.find("radius=6") != std::string::npos); - EXPECT_TRUE(result.find("min_cluster_size=2") != std::string::npos); - EXPECT_TRUE(result.find("spider_time_range=80") != std::string::npos); - EXPECT_TRUE(result.find("TOF bins=1000") != std::string::npos); - EXPECT_TRUE(result.find("TOF max=16.7 ms") != std::string::npos); - EXPECT_TRUE(result.find("Super Resolution=2") != std::string::npos); + auto config = JSONConfigParser::fromFile("test_config_uniform.json"); + std::string result = config.toString(); + + EXPECT_TRUE(result.find("radius=6") != std::string::npos); + EXPECT_TRUE(result.find("min_cluster_size=2") != std::string::npos); + EXPECT_TRUE(result.find("spider_time_range=80") != std::string::npos); + EXPECT_TRUE(result.find("TOF bins=1000") != std::string::npos); + EXPECT_TRUE(result.find("TOF max=16.7 ms") != std::string::npos); + EXPECT_TRUE(result.find("Super Resolution=2") != std::string::npos); } diff --git a/sophiread/SophireadCLI/tests/test_sophiread_core.cpp b/sophiread/SophireadCLI/tests/test_sophiread_core.cpp index cd634cf..7fdd048 100644 --- a/sophiread/SophireadCLI/tests/test_sophiread_core.cpp +++ b/sophiread/SophireadCLI/tests/test_sophiread_core.cpp @@ -3,149 +3,148 @@ * @author: Chen Zhang (zhangc@orn.gov) * @brief: Unit tests for the Sophiread Core module. * @date: 2024-08-21 - * - * @copyright Copyright (c) 2024 - * 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 3 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, see . + * @copyright Copyright (c) 2024 + * SPDX - License - Identifier: GPL - 3.0 + */ #include + #include #include -#include "sophiread_core.h" + #include "json_config_parser.h" +#include "sophiread_core.h" class SophireadCoreTest : public ::testing::Test { -protected: - std::vector generateMockTPX3Data(int num_packets = 10) { - std::vector data; - - for (int i = 0; i < num_packets; ++i) { - // Header packet - data.push_back('T'); - data.push_back('P'); - data.push_back('X'); - data.push_back('3'); - data.push_back(0); // chip_layout_type - data.push_back(0); // some random data - data.push_back(8); // data_packet_size (low byte) - data.push_back(0); // data_packet_size (high byte) - - // Data packet (8 bytes) - for (int j = 0; j < 8; ++j) { - data.push_back(0); - } - } - return data; - } + protected: + std::vector generateMockTPX3Data(int num_packets = 10) { + std::vector data; - std::vector generateMockTPX3Batches(int num_batches = 2, int hits_per_batch = 5) { - std::vector batches; - for (int i = 0; i < num_batches; ++i) { - TPX3 batch(i * 100, hits_per_batch, i % 3); // index, num_packets, chip_layout_type - - // Add mock hits - for (int j = 0; j < hits_per_batch; ++j) { - char mock_packet[8] = {0}; // Mock packet data - batch.emplace_back(mock_packet, 1000 + j, 2000 + j); - } - - // Add mock neutrons (derived from hits) - for (const auto& hit : batch.hits) { - batch.neutrons.emplace_back( - hit.getX(), hit.getY(), - hit.getTOF(), hit.getTOT(), - 1 // nHits, assume 1 hit per neutron for simplicity - ); - } - - batches.push_back(std::move(batch)); - } - return batches; - } + for (int i = 0; i < num_packets; ++i) { + // Header packet + data.push_back('T'); + data.push_back('P'); + data.push_back('X'); + data.push_back('3'); + data.push_back(0); // chip_layout_type + data.push_back(0); // some random data + data.push_back(8); // data_packet_size (low byte) + data.push_back(0); // data_packet_size (high byte) - void SetUp() override { - // Create a small test TPX3 file - auto test_data = generateMockTPX3Data(100); - std::ofstream test_file("test.tpx3", std::ios::binary); - test_file.write(test_data.data(), test_data.size()); - test_file.close(); + // Data packet (8 bytes) + for (int j = 0; j < 8; ++j) { + data.push_back(0); + } } + return data; + } + + std::vector generateMockTPX3Batches(int num_batches = 2, + int hits_per_batch = 5) { + std::vector batches; + for (int i = 0; i < num_batches; ++i) { + TPX3 batch(i * 100, hits_per_batch, + i % 3); // index, num_packets, chip_layout_type + + // Add mock hits + for (int j = 0; j < hits_per_batch; ++j) { + char mock_packet[8] = {0}; // Mock packet data + batch.emplace_back(mock_packet, 1000 + j, 2000 + j); + } - void TearDown() override { - // Remove the test file - std::filesystem::remove("test.tpx3"); + // Add mock neutrons (derived from hits) + for (const auto& hit : batch.hits) { + batch.neutrons.emplace_back( + hit.getX(), hit.getY(), hit.getTOF(), hit.getTOT(), + 1 // nHits, assume 1 hit per neutron for simplicity + ); + } + + batches.push_back(std::move(batch)); } + return batches; + } + + void SetUp() override { + // Create a small test TPX3 file + auto test_data = generateMockTPX3Data(100); + std::ofstream test_file("test.tpx3", std::ios::binary); + test_file.write(test_data.data(), test_data.size()); + test_file.close(); + } + + void TearDown() override { + // Remove the test file + std::filesystem::remove("test.tpx3"); + } }; TEST_F(SophireadCoreTest, TimedReadDataToCharVec) { - auto data = sophiread::timedReadDataToCharVec("test.tpx3"); - EXPECT_EQ(data.size(), 1600); // 100 * (8 + 8) bytes + auto data = sophiread::timedReadDataToCharVec("test.tpx3"); + EXPECT_EQ(data.size(), 1600); // 100 * (8 + 8) bytes } TEST_F(SophireadCoreTest, TimedFindTPX3H) { - auto rawdata = generateMockTPX3Data(100); - auto batches = sophiread::timedFindTPX3H(rawdata); - EXPECT_EQ(batches.size(), 100); + auto rawdata = generateMockTPX3Data(100); + auto batches = sophiread::timedFindTPX3H(rawdata); + EXPECT_EQ(batches.size(), 100); } TEST_F(SophireadCoreTest, TimedLocateTimeStamp) { - std::vector raw_data(8000, 'T'); // Simulating TPX3 data - std::vector batches = { TPX3(0, 10, 0) }; // Create a dummy TPX3 batch - sophiread::timedLocateTimeStamp(batches, raw_data); - // Add assertions based on expected behavior + std::vector raw_data(8000, 'T'); // Simulating TPX3 data + std::vector batches = {TPX3(0, 10, 0)}; // Create a dummy TPX3 batch + sophiread::timedLocateTimeStamp(batches, raw_data); + // Add assertions based on expected behavior } TEST_F(SophireadCoreTest, TimedProcessing) { - std::vector raw_data(8000, 'T'); // Simulating TPX3 data - std::vector batches = { TPX3(0, 10, 0) }; // Create a dummy TPX3 batch - JSONConfigParser config = JSONConfigParser::createDefault(); - sophiread::timedProcessing(batches, raw_data, config); - // Add assertions based on expected behavior + std::vector raw_data(8000, 'T'); // Simulating TPX3 data + std::vector batches = {TPX3(0, 10, 0)}; // Create a dummy TPX3 batch + JSONConfigParser config = JSONConfigParser::createDefault(); + sophiread::timedProcessing(batches, raw_data, config); + // Add assertions based on expected behavior } TEST_F(SophireadCoreTest, TimedSaveHitsToHDF5) { - std::vector batches = generateMockTPX3Batches(2, 5); // Create a dummy TPX3 batch - sophiread::timedSaveHitsToHDF5("test_hits.h5", batches); - EXPECT_TRUE(std::filesystem::exists("test_hits.h5")); - std::filesystem::remove("test_hits.h5"); + std::vector batches = + generateMockTPX3Batches(2, 5); // Create a dummy TPX3 batch + sophiread::timedSaveHitsToHDF5("test_hits.h5", batches); + EXPECT_TRUE(std::filesystem::exists("test_hits.h5")); + std::filesystem::remove("test_hits.h5"); } TEST_F(SophireadCoreTest, TimedSaveEventsToHDF5) { - std::vector batches = generateMockTPX3Batches(2, 5); // Create a dummy TPX3 batch - sophiread::timedSaveEventsToHDF5("test_events.h5", batches); - EXPECT_TRUE(std::filesystem::exists("test_events.h5")); - std::filesystem::remove("test_events.h5"); + std::vector batches = + generateMockTPX3Batches(2, 5); // Create a dummy TPX3 batch + sophiread::timedSaveEventsToHDF5("test_events.h5", batches); + EXPECT_TRUE(std::filesystem::exists("test_events.h5")); + std::filesystem::remove("test_events.h5"); } TEST_F(SophireadCoreTest, TimedCreateTOFImages) { - std::vector batches = generateMockTPX3Batches(2, 5); // Create a dummy TPX3 batch - std::vector tof_bin_edges = {0.0, 0.1, 0.2, 0.3}; - auto images = sophiread::timedCreateTOFImages(batches, 1.0, tof_bin_edges, "neutron"); - EXPECT_EQ(images.size(), 3); // 3 bins + std::vector batches = + generateMockTPX3Batches(2, 5); // Create a dummy TPX3 batch + std::vector tof_bin_edges = {0.0, 0.1, 0.2, 0.3}; + auto images = + sophiread::timedCreateTOFImages(batches, 1.0, tof_bin_edges, "neutron"); + EXPECT_EQ(images.size(), 3); // 3 bins } TEST_F(SophireadCoreTest, TimedSaveTOFImagingToTIFF) { - std::vector>> tof_images(3, std::vector>(10, std::vector(10, 1))); - std::vector tof_bin_edges = {0.0, 0.1, 0.2, 0.3}; - sophiread::timedSaveTOFImagingToTIFF("test_tof", tof_images, tof_bin_edges, "test"); - EXPECT_TRUE(std::filesystem::exists("test_tof/test_bin_0001.tiff")); - EXPECT_TRUE(std::filesystem::exists("test_tof/test_bin_0002.tiff")); - EXPECT_TRUE(std::filesystem::exists("test_tof/test_bin_0003.tiff")); - EXPECT_TRUE(std::filesystem::exists("test_tof/test_Spectra.txt")); - std::filesystem::remove_all("test_tof"); + std::vector>> tof_images( + 3, std::vector>( + 10, std::vector(10, 1))); + std::vector tof_bin_edges = {0.0, 0.1, 0.2, 0.3}; + sophiread::timedSaveTOFImagingToTIFF("test_tof", tof_images, tof_bin_edges, + "test"); + EXPECT_TRUE(std::filesystem::exists("test_tof/test_bin_0001.tiff")); + EXPECT_TRUE(std::filesystem::exists("test_tof/test_bin_0002.tiff")); + EXPECT_TRUE(std::filesystem::exists("test_tof/test_bin_0003.tiff")); + EXPECT_TRUE(std::filesystem::exists("test_tof/test_Spectra.txt")); + std::filesystem::remove_all("test_tof"); } -int main(int argc, char **argv) { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } \ No newline at end of file diff --git a/sophiread/SophireadCLI/tests/test_user_config.cpp b/sophiread/SophireadCLI/tests/test_user_config.cpp index 8c75d35..5f7b3d6 100644 --- a/sophiread/SophireadCLI/tests/test_user_config.cpp +++ b/sophiread/SophireadCLI/tests/test_user_config.cpp @@ -6,23 +6,14 @@ * @date 2023-09-18 * * @copyright Copyright (c) 2023 - * 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 3 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, see . + * SPDX - License - Identifier: GPL - 3.0 + */ #include + #include -#include "user_config.h" + #include "tof_binning.h" +#include "user_config.h" // Test default constructor TEST(UserConfigTest, DefaultConstructor) { @@ -30,11 +21,11 @@ TEST(UserConfigTest, DefaultConstructor) { EXPECT_DOUBLE_EQ(config.getABSRadius(), 5.0); EXPECT_EQ(config.getABSMinClusterSize(), 1); EXPECT_EQ(config.getABSSpiderTimeRange(), 75); - + auto tof_edges = config.getTOFBinEdges(); EXPECT_EQ(tof_edges.size(), 1501); // 1500 bins + 1 EXPECT_DOUBLE_EQ(tof_edges.front(), 0.0); - EXPECT_DOUBLE_EQ(tof_edges.back(), 1.0/60); + EXPECT_DOUBLE_EQ(tof_edges.back(), 1.0 / 60); } // Test parameterized constructor @@ -43,12 +34,12 @@ TEST(UserConfigTest, ParameterizedConstructor) { EXPECT_DOUBLE_EQ(config.getABSRadius(), 10.0); EXPECT_EQ(config.getABSMinClusterSize(), 5); EXPECT_EQ(config.getABSSpiderTimeRange(), 100); - + // TOF binning should still be default auto tof_edges = config.getTOFBinEdges(); EXPECT_EQ(tof_edges.size(), 1501); EXPECT_DOUBLE_EQ(tof_edges.front(), 0.0); - EXPECT_DOUBLE_EQ(tof_edges.back(), 1.0/60); + EXPECT_DOUBLE_EQ(tof_edges.back(), 1.0 / 60); } // Test setters @@ -57,7 +48,7 @@ TEST(UserConfigTest, Setters) { config.setABSRadius(15.0); config.setABSMinClusterSize(10); config.setABSSpiderTimeRange(150); - + EXPECT_DOUBLE_EQ(config.getABSRadius(), 15.0); EXPECT_EQ(config.getABSMinClusterSize(), 10); EXPECT_EQ(config.getABSSpiderTimeRange(), 150); @@ -70,7 +61,7 @@ TEST(UserConfigTest, TOFBinningSetter) { custom_binning.num_bins = 1000; custom_binning.tof_max = 20000.0; config.setTOFBinning(custom_binning); - + auto tof_edges = config.getTOFBinEdges(); EXPECT_EQ(tof_edges.size(), 1001); // 1000 bins + 1 EXPECT_DOUBLE_EQ(tof_edges.front(), 0.0); @@ -82,7 +73,7 @@ TEST(UserConfigTest, CustomTOFBinEdges) { UserConfig config; std::vector custom_edges = {0.0, 100.0, 200.0, 300.0, 400.0}; config.setCustomTOFBinEdges(custom_edges); - + auto tof_edges = config.getTOFBinEdges(); EXPECT_EQ(tof_edges.size(), 5); EXPECT_DOUBLE_EQ(tof_edges[0], 0.0); @@ -124,7 +115,7 @@ TEST(UserConfigTest, ParseValidConfigurationFile) { auto tof_edges = config.getTOFBinEdges(); EXPECT_EQ(tof_edges.size(), 1501); EXPECT_DOUBLE_EQ(tof_edges.front(), 0.0); - EXPECT_DOUBLE_EQ(tof_edges.back(), 1.0/60); + EXPECT_DOUBLE_EQ(tof_edges.back(), 1.0 / 60); // Cleanup std::remove("testConfig.txt"); @@ -139,7 +130,8 @@ TEST(UserConfigTest, ParseInvalidConfigurationFile) { testFile.close(); // It should ignore the unknown parameter and use the default value instead - UserConfig config = parseUserDefinedConfigurationFile("testInvalidConfig.txt"); + UserConfig config = + parseUserDefinedConfigurationFile("testInvalidConfig.txt"); EXPECT_DOUBLE_EQ(config.getABSRadius(), 5.0); // Default value EXPECT_EQ(config.getABSMinClusterSize(), 1); // Default value EXPECT_EQ(config.getABSSpiderTimeRange(), 75); // Default value diff --git a/sophiread/SophireadGUI/CMakeLists.txt b/sophiread/SophireadGUI/CMakeLists.txt index 9ccafff..8a74c21 100644 --- a/sophiread/SophireadGUI/CMakeLists.txt +++ b/sophiread/SophireadGUI/CMakeLists.txt @@ -1,48 +1,43 @@ -# Configure the GUI application -# wrap ui files to c++ header files -qt5_wrap_ui(SophireadDisplayUI - ui/mainwindow.ui -) +# Configure the GUI application wrap ui files to c++ header files +qt5_wrap_ui(SophireadDisplayUI ui/mainwindow.ui) # set include directories -include_directories( - include - ${PROJECT_SOURCE_DIR}/SophireadLib/include - ${CMAKE_CURRENT_BINARY_DIR} - $ENV{CONDA_PREFIX}/include -) +include_directories(include ${PROJECT_SOURCE_DIR}/SophireadLib/include + ${CMAKE_CURRENT_BINARY_DIR} $ENV{CONDA_PREFIX}/include) -link_directories( - $ENV{CONDA_PREFIX}/lib -) +link_directories($ENV{CONDA_PREFIX}/lib) # -set(SRC_FILES - src/sophiread_display.cpp - include/mainwindow.h - src/mainwindow.cpp - ${SophireadDisplayUI} -) +set(SRC_FILES src/sophiread_display.cpp include/mainwindow.h src/mainwindow.cpp + ${SophireadDisplayUI}) # add executable -add_executable(SophireadGUI - ${SRC_FILES} -) +add_executable(SophireadGUI ${SRC_FILES}) set_target_properties(SophireadGUI PROPERTIES VERSION ${PROJECT_VERSION}) -target_link_libraries(SophireadGUI SophireadLib Qt5::Widgets qwt hdf5 hdf5_cpp OpenMP::OpenMP_CXX) +target_link_libraries( + SophireadGUI + SophireadLib + Qt5::Widgets + qwt + hdf5 + hdf5_cpp + OpenMP::OpenMP_CXX) # symlink the executable to the build directory -add_custom_command(TARGET SophireadGUI POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink +add_custom_command( + TARGET SophireadGUI + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E create_symlink ${PROJECT_BINARY_DIR}/SophireadGUI/SophireadGUI - ${PROJECT_BINARY_DIR}/SophireadGUI.app -) + ${PROJECT_BINARY_DIR}/SophireadGUI.app) # ----------------- INSTALL ----------------- # if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Default install prefix" FORCE) + set(CMAKE_INSTALL_PREFIX + "/usr/local" + CACHE PATH "Default install prefix" FORCE) endif() -install(TARGETS SophireadGUI - RUNTIME DESTINATION bin) +install(TARGETS SophireadGUI RUNTIME DESTINATION bin) set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") include(CPack) diff --git a/sophiread/SophireadGUI/src/mainwindow.cpp b/sophiread/SophireadGUI/src/mainwindow.cpp index d6379ad..fba19ed 100644 --- a/sophiread/SophireadGUI/src/mainwindow.cpp +++ b/sophiread/SophireadGUI/src/mainwindow.cpp @@ -67,7 +67,7 @@ MainWindow::MainWindow(QWidget *parent) unsigned long int min_cluster_size = 1; unsigned long int spider_time_range = 75; - clustering_alg = new ABS(radius,min_cluster_size,spider_time_range); + clustering_alg = new ABS(radius, min_cluster_size, spider_time_range); clustering_alg->set_method("centroid"); // clustering_alg->set_method("fast_gaussian"); @@ -86,7 +86,7 @@ MainWindow::~MainWindow() { delete ui; } */ void MainWindow::handletimer() { // update percentage of data processed - // TODO: need to find a way to adapte the percentage number + // TODO: need to find a way to adapt the percentage number // // update time used to process data auto elapsed = myelapsedtime.elapsed(); diff --git a/sophiread/SophireadLib/CMakeLists.txt b/sophiread/SophireadLib/CMakeLists.txt index e63b8f1..bbdb1d0 100644 --- a/sophiread/SophireadLib/CMakeLists.txt +++ b/sophiread/SophireadLib/CMakeLists.txt @@ -1,74 +1,71 @@ # Config SophireadLib -include_directories( - include - $ENV{CONDA_PREFIX}/include - ${EIGEN3_INCLUDE_DIR} - ${HDF5_INCLUDE_DIRS} -) +include_directories(include $ENV{CONDA_PREFIX}/include ${EIGEN3_INCLUDE_DIR} + ${HDF5_INCLUDE_DIRS}) -link_directories( - $ENV{CONDA_PREFIX}/lib -) +link_directories($ENV{CONDA_PREFIX}/lib) -set(SRC_FILES - src/abs.cpp - src/centroid.cpp - src/dbscan.cpp - src/fastgaussian.cpp - src/tpx3.cpp -) +set(SRC_FILES src/abs.cpp src/centroid.cpp src/dbscan.cpp src/fastgaussian.cpp + src/tpx3.cpp) # ------------- SophireadLib -------------- # -add_library( - SophireadLib - ${SRC_FILES} -) +add_library(SophireadLib ${SRC_FILES}) -# ----------------- TESTS ----------------- # -# IO Tests +# ----------------- TESTS ----------------- # IO Tests add_executable(SophireadTests_IO tests/test_tpx3.cpp) -target_link_libraries(SophireadTests_IO SophireadLib GTest::GTest GTest::Main hdf5 hdf5_cpp OpenMP::OpenMP_CXX) +target_link_libraries( + SophireadTests_IO + SophireadLib + GTest::GTest + GTest::Main + hdf5 + hdf5_cpp + OpenMP::OpenMP_CXX) gtest_discover_tests(SophireadTests_IO) # Clustering Tests add_executable(SophireadTests_CLUSTER tests/test_clustering.cpp) -target_link_libraries(SophireadTests_CLUSTER SophireadLib GTest::GTest GTest::Main hdf5 hdf5_cpp OpenMP::OpenMP_CXX) +target_link_libraries( + SophireadTests_CLUSTER + SophireadLib + GTest::GTest + GTest::Main + hdf5 + hdf5_cpp + OpenMP::OpenMP_CXX) gtest_discover_tests(SophireadTests_CLUSTER) # Peakfitting Tests add_executable(SophireadTests_PEAKFITTING tests/test_peakfitting.cpp) -target_link_libraries(SophireadTests_PEAKFITTING SophireadLib GTest::GTest GTest::Main hdf5 hdf5_cpp OpenMP::OpenMP_CXX) +target_link_libraries( + SophireadTests_PEAKFITTING + SophireadLib + GTest::GTest + GTest::Main + hdf5 + hdf5_cpp + OpenMP::OpenMP_CXX) gtest_discover_tests(SophireadTests_PEAKFITTING) -# ------------------ Benchmarks ------------------ # -# ABS -add_executable( - SophireadBenchmarks_ABS - benchmarks/benchmark_abs.cpp -) -target_link_libraries( - SophireadBenchmarks_ABS - SophireadLib -) +# ------------------ Benchmarks ------------------ # ABS +add_executable(SophireadBenchmarks_ABS benchmarks/benchmark_abs.cpp) +target_link_libraries(SophireadBenchmarks_ABS SophireadLib) # symlink executable to the build directory -add_custom_command(TARGET SophireadLib POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink +add_custom_command( + TARGET SophireadLib + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E create_symlink ${PROJECT_BINARY_DIR}/SophireadLib/SophireadBenchmarks_ABS - ${PROJECT_BINARY_DIR}/SophireadBenchmarks_ABS.app -) + ${PROJECT_BINARY_DIR}/SophireadBenchmarks_ABS.app) -add_executable( - SophireadBenchmarks_ABS_Thread - benchmarks/benchmark_abs_thread.cpp -) -target_link_libraries( - SophireadBenchmarks_ABS_Thread - SophireadLib - pthread -) +add_executable(SophireadBenchmarks_ABS_Thread + benchmarks/benchmark_abs_thread.cpp) +target_link_libraries(SophireadBenchmarks_ABS_Thread SophireadLib pthread) # symlink executable to the build directory -add_custom_command(TARGET SophireadLib POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink +add_custom_command( + TARGET SophireadLib + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E create_symlink ${PROJECT_BINARY_DIR}/SophireadLib/SophireadBenchmarks_ABS_Thread - ${PROJECT_BINARY_DIR}/SophireadBenchmarks_ABS_Thread.app -) \ No newline at end of file + ${PROJECT_BINARY_DIR}/SophireadBenchmarks_ABS_Thread.app) diff --git a/sophiread/SophireadLib/benchmarks/benchmark_abs.cpp b/sophiread/SophireadLib/benchmarks/benchmark_abs.cpp index e7a0385..a3facfc 100644 --- a/sophiread/SophireadLib/benchmarks/benchmark_abs.cpp +++ b/sophiread/SophireadLib/benchmarks/benchmark_abs.cpp @@ -4,9 +4,9 @@ * @brief Benchmark the performance of abs clustering method * @version 0.1 * @date 2023-08-25 - * + * * @copyright Copyright (c) 2023 - * + * */ #include #include diff --git a/sophiread/SophireadLib/include/abs.h b/sophiread/SophireadLib/include/abs.h index 23ad21e..7c76c17 100644 --- a/sophiread/SophireadLib/include/abs.h +++ b/sophiread/SophireadLib/include/abs.h @@ -19,9 +19,11 @@ struct Cluster { */ class ABS : public ClusteringAlgorithm { public: - ABS(double r, unsigned long int min_cluster_size, - unsigned long int spider_time_range) : - m_feature(r), m_min_cluster_size(min_cluster_size), spiderTimeRange_(spider_time_range) {}; + ABS(double r, unsigned long int min_cluster_size, + unsigned long int spider_time_range) + : m_feature(r), + m_min_cluster_size(min_cluster_size), + spiderTimeRange_(spider_time_range){}; void fit(const std::vector& data); void set_method(std::string method) { m_method = method; } void reset() { clusterLabels_.clear(); } @@ -36,7 +38,7 @@ class ABS : public ClusteringAlgorithm { std::vector> clusterIndices_; // The cluster indices for // each cluster const int numClusters_ = 4; // The number of clusters use in runtime - unsigned long int m_min_cluster_size = 1; // The maximum cluster size - unsigned long int spiderTimeRange_ = 75; // The spider time range (in ns) + unsigned long int m_min_cluster_size = 1; // The maximum cluster size + unsigned long int spiderTimeRange_ = 75; // The spider time range (in ns) PeakFittingAlgorithm* peakFittingAlgorithm_; // The clustering algorithm }; diff --git a/sophiread/SophireadLib/include/tpx3.h b/sophiread/SophireadLib/include/tpx3.h index ff3bcb5..b6ada27 100644 --- a/sophiread/SophireadLib/include/tpx3.h +++ b/sophiread/SophireadLib/include/tpx3.h @@ -18,7 +18,14 @@ class Hit { public: // default constructor - Hit() : m_x(0), m_y(0), m_tot(0), m_toa(0), m_ftoa(0), m_tof(0), m_spidertime(0){}; + Hit() + : m_x(0), + m_y(0), + m_tot(0), + m_toa(0), + m_ftoa(0), + m_tof(0), + m_spidertime(0){}; // copy constructor Hit(const Hit& hit) : m_x(hit.m_x), @@ -41,7 +48,8 @@ class Hit { // special constructor that directly parse the raw packet from tpx3 // into a hit - Hit(const char* packet, const unsigned long long tdc, const unsigned long long gdc, const int chip_layout_type); + Hit(const char* packet, const unsigned long long tdc, + const unsigned long long gdc, const int chip_layout_type); Hit& operator=(const Hit& hit) { m_x = hit.m_x; @@ -100,7 +108,7 @@ class NeutronEvent { : m_x(x), m_y(y), m_tof(tof), m_tot(tot), m_nHits(nHits){}; double getX() const { return m_x; }; double getY() const { return m_y; }; - double getTOT() const { return m_tot;} + double getTOT() const { return m_tot; } double getTOF() const { return m_tof; }; double getTOF_ns() const { return m_tof * m_scale_to_ns_40mhz; }; int getNHits() const { return m_nHits; }; @@ -117,28 +125,29 @@ class NeutronEvent { }; /** - * @brief Class to store user-defined parameters for clustering algorithms + * @brief Class to store user-defined parameters for clustering algorithms * */ class Params { -public: - Params(const double abs_radius, - unsigned long int abs_min_cluster_size, - unsigned long int abs_spider_time_range) : - m_abs_radius(abs_radius), - m_abs_min_cluster_size(abs_min_cluster_size), - m_abs_spider_time_range(abs_spider_time_range){}; - - double getABSRadius() const {return m_abs_radius;}; - unsigned long int getABSMinClusterSize() - const {return m_abs_min_cluster_size;}; - unsigned long int getABSSpidertimeRange() - const {return m_abs_spider_time_range;}; + public: + Params(const double abs_radius, unsigned long int abs_min_cluster_size, + unsigned long int abs_spider_time_range) + : m_abs_radius(abs_radius), + m_abs_min_cluster_size(abs_min_cluster_size), + m_abs_spider_time_range(abs_spider_time_range){}; + + double getABSRadius() const { return m_abs_radius; }; + unsigned long int getABSMinClusterSize() const { + return m_abs_min_cluster_size; + }; + unsigned long int getABSSpidertimeRange() const { + return m_abs_spider_time_range; + }; std::string toString() const; -private: + private: // ABS members (see abs.h for details) - double m_abs_radius; + double m_abs_radius; unsigned long int m_abs_min_cluster_size; unsigned long int m_abs_spider_time_range; }; @@ -160,7 +169,7 @@ void saveHitsToHDF5(const std::string out_file_name, void saveEventsToHDF5(const std::string out_file_name, const std::vector& events); -// parse user-defined param file +// parse user-defined param file Params parseUserDefinedParams(const std::string& filepath); // for fast processing raw bytes into hit @@ -170,8 +179,12 @@ struct TPX3H { const int num_packets; const int chip_layout_type; - TPX3H(std::size_t index, int packet_size, int num_packets, int chip_layout_type) - : index(index), packet_size(packet_size), num_packets(num_packets), chip_layout_type(chip_layout_type){}; + TPX3H(std::size_t index, int packet_size, int num_packets, + int chip_layout_type) + : index(index), + packet_size(packet_size), + num_packets(num_packets), + chip_layout_type(chip_layout_type){}; }; std::vector fastParseTPX3Raw(const std::vector& raw_bytes); std::vector processBatch(TPX3H batch, const std::vector& raw_bytes); \ No newline at end of file diff --git a/sophiread/SophireadLib/src/abs.cpp b/sophiread/SophireadLib/src/abs.cpp index b3fd815..c1ec1c8 100644 --- a/sophiread/SophireadLib/src/abs.cpp +++ b/sophiread/SophireadLib/src/abs.cpp @@ -8,7 +8,6 @@ #include "centroid.h" #include "fastgaussian.h" - /** * @brief Generate cluster labels for the hits. * diff --git a/sophiread/SophireadLib/src/centroid.cpp b/sophiread/SophireadLib/src/centroid.cpp index f46dde9..ee624e7 100644 --- a/sophiread/SophireadLib/src/centroid.cpp +++ b/sophiread/SophireadLib/src/centroid.cpp @@ -48,6 +48,6 @@ NeutronEvent Centroid::fit(const std::vector& data) { } tof /= data.size(); - + return NeutronEvent(x, y, tof, tot, data.size()); } diff --git a/sophiread/SophireadLib/src/dbscan.cpp b/sophiread/SophireadLib/src/dbscan.cpp index b710bcb..637fd9b 100644 --- a/sophiread/SophireadLib/src/dbscan.cpp +++ b/sophiread/SophireadLib/src/dbscan.cpp @@ -170,7 +170,7 @@ void DBSCAN::fit(const std::vector& hits) { m_events.emplace_back( NeutronEvent(centroids_2D[label_count.first].first * DSCALE /*X*/, centroids_2D[label_count.first].second * DSCALE /*Y*/, - info.m_time_mean,0, label_count.second)); + info.m_time_mean, 0, label_count.second)); } } @@ -239,7 +239,7 @@ void DBSCAN::fit1D(std::vector& data, size_t& number_of_clusters, // create an arma matrix from the data vector arma::mat data_mat( &data[0], 1 /*nrows*/, data.size() /*ncols*/, - false /*arma::mat will re-use the input data vector memory*/); + false /*arma::mat will reuse the input data vector memory*/); // create the dbscan object mlpack::DBSCAN, mlpack::OrderedPointSelection> dbs( @@ -277,7 +277,7 @@ void DBSCAN::fit2D(std::vector>& data, // create an arma matrix from the data vector arma::mat data_mat( &(data[0].first), 2 /*nrows*/, data.size() /*ncols*/, - false /*arma::mat will re-use the input data vector memory*/); + false /*arma::mat will reuse the input data vector memory*/); // create the dbscan object mlpack::DBSCAN, mlpack::OrderedPointSelection> dbs( diff --git a/sophiread/SophireadLib/src/fastgaussian.cpp b/sophiread/SophireadLib/src/fastgaussian.cpp index 9b62170..887550c 100644 --- a/sophiread/SophireadLib/src/fastgaussian.cpp +++ b/sophiread/SophireadLib/src/fastgaussian.cpp @@ -114,7 +114,8 @@ NeutronEvent FastGaussian::fit(const std::vector& data) { tof_filtered.size(); // calculate the tot - double tot_event = std::accumulate(tot_filtered.begin(), tot_filtered.end(),0.0); + double tot_event = + std::accumulate(tot_filtered.begin(), tot_filtered.end(), 0.0); // even if we are throwing away to bottom half, we still need to return the // pre-filtered number of hits diff --git a/sophiread/SophireadLib/src/tpx3.cpp b/sophiread/SophireadLib/src/tpx3.cpp index 33baa96..8f64357 100644 --- a/sophiread/SophireadLib/src/tpx3.cpp +++ b/sophiread/SophireadLib/src/tpx3.cpp @@ -31,7 +31,7 @@ std::string NeutronEvent::toString() const { std::string Params::toString() const { std::stringstream ss; - ss << "ABS: radius=" << m_abs_radius + ss << "ABS: radius=" << m_abs_radius << ", min_cluster_size=" << m_abs_min_cluster_size << ", spider_time_range=" << m_abs_spider_time_range; @@ -46,7 +46,8 @@ std::string Params::toString() const { * @param gdc * @param chip_layout_type */ -Hit::Hit(const char *packet, const unsigned long long tdc, const unsigned long long gdc, const int chip_layout_type) { +Hit::Hit(const char *packet, const unsigned long long tdc, + const unsigned long long gdc, const int chip_layout_type) { unsigned short pixaddr, dcol, spix, pix; unsigned short *spider_time; unsigned short *nTOT; // bytes 2,3, raw time over threshold @@ -82,7 +83,8 @@ Hit::Hit(const char *packet, const unsigned long long tdc, const unsigned long l // tof calculation // TDC packets not always arrive before corresponding data packets if (m_spidertime < TDC_timestamp) { - m_tof = m_spidertime - TDC_timestamp + 16666667; // 1E9 / 60.0 is approximately 16666667 + m_tof = m_spidertime - TDC_timestamp + + 16666667; // 1E9 / 60.0 is approximately 16666667 } else { m_tof = m_spidertime - TDC_timestamp; } @@ -154,8 +156,8 @@ Hit packetToHitAlt(const std::vector &packet, *rollover_counter += 1; } - // if the curr hit arrives later than previous hit (in order) - // if it is a lot later, it belongs to the previous rollover + // if the curr hit arrives later than previous hit (in order) + // if it is a lot later, it belongs to the previous rollover } else { if (spidertime - *previous_time > time_range / 2) { if (*rollover_counter > 0) { @@ -172,7 +174,7 @@ Hit packetToHitAlt(const std::vector &packet, // a consistent round off error of 10ns due to using integer for modulus // which is way below the 100ns time resolution needed tof = SPDR_timestamp % 666667; - + // pixel address npixaddr = (unsigned int *)(&packet[4]); // Pixel address (14 bits) pixaddr = (*npixaddr >> 12) & 0xFFFF; @@ -216,7 +218,7 @@ Hit packetToHit(const std::vector &packet, const unsigned long long tdc, unsigned int *nTOA; // bytes 3,4,5,6, raw time of arrival unsigned int *npixaddr; // bytes 4,5,6,7 int x, y, tot, toa, ftoa; - unsigned int spidertime=0, tof=0; + unsigned int spidertime = 0, tof = 0; // timing information spider_time = (unsigned short *)(&packet[0]); // Spider time (16 bits) nTOT = (unsigned short *)(&packet[2]); // ToT (10 bits) @@ -245,8 +247,8 @@ Hit packetToHit(const std::vector &packet, const unsigned long long tdc, // tof calculation // TDC packets not always arrive before corresponding data packets - if (SPDR_timestamp < TDC_timestamp){ - tof = SPDR_timestamp - TDC_timestamp + 1E9/60.0; + if (SPDR_timestamp < TDC_timestamp) { + tof = SPDR_timestamp - TDC_timestamp + 1E9 / 60.0; } else { tof = SPDR_timestamp - TDC_timestamp; } @@ -393,7 +395,8 @@ std::vector readTimepix3RawData(const std::string &filepath) { // std::cout << "Hits: " << hit.getX() << " " << hit.getY() << " " << // hit.getTOF_ns()*1E-6 << " " << hit.getSPIDERTIME_ns()*1E-9 << // std::endl; - // std::cout << std::setprecision(15) << hit.getSPIDERTIME_ns()*1E-9 << std::endl; + // std::cout << std::setprecision(15) << hit.getSPIDERTIME_ns()*1E-9 + // << std::endl; hits.push_back(hit); } } @@ -430,25 +433,32 @@ std::vector fastParseTPX3Raw(const std::vector &raw_bytes) { // locate the data packet header if (char_array[0] == 'T' && char_array[1] == 'P' && char_array[2] == 'X') { data_packet_size = ((0xff & char_array[7]) << 8) | (0xff & char_array[6]); - data_packet_num = data_packet_size >> 3; // every 8 (2^3) bytes is a data packet + data_packet_num = + data_packet_size >> 3; // every 8 (2^3) bytes is a data packet chip_layout_type = static_cast(char_array[4]); - batches.emplace_back(static_cast(std::distance(iter_begin, iter)), data_packet_size, data_packet_num, - chip_layout_type); + batches.emplace_back(static_cast(std::distance(iter_begin, iter)), + data_packet_size, data_packet_num, chip_layout_type); } } // get upper estimate of total num_packets using std::accumulate - const auto total_num_packets = std::accumulate( - batches.cbegin(), batches.cend(), 0, [](const int &sum, const TPX3H &batch) { return sum + batch.num_packets; }); + const auto total_num_packets = + std::accumulate(batches.cbegin(), batches.cend(), 0, + [](const int &sum, const TPX3H &batch) { + return sum + batch.num_packets; + }); std::vector hits(total_num_packets); // // process each batch - // // tbb::parallel_for_each(batches.cbegin(), batches.cend(), [&](const TPX3H &batch) { + // // tbb::parallel_for_each(batches.cbegin(), batches.cend(), [&](const TPX3H + // &batch) { // // const auto batch_hits = processBatch(batch, raw_bytes); - // // std::copy(batch_hits.cbegin(), batch_hits.cend(), hits.begin() + batch.index); + // // std::copy(batch_hits.cbegin(), batch_hits.cend(), hits.begin() + + // batch.index); // // }); - // tbb::parallel_for(tbb::blocked_range(0, hits.size()), [&](const tbb::blocked_range &r) { + // tbb::parallel_for(tbb::blocked_range(0, hits.size()), [&](const + // tbb::blocked_range &r) { // for (auto i = r.begin(); i != r.end(); ++i) { // if (hits[i].getX() == 0 && hits[i].getY() == 0) { // hits[i] = Hit(); @@ -458,8 +468,8 @@ std::vector fastParseTPX3Raw(const std::vector &raw_bytes) { // remove empty Hit // hits.erase( - // std::remove_if(hits.begin(), hits.end(), [](const Hit &hit) { return hit.getX() == 0 && hit.getY() == 0; }), - // hits.end()); + // std::remove_if(hits.begin(), hits.end(), [](const Hit &hit) { return + // hit.getX() == 0 && hit.getY() == 0; }), hits.end()); return hits; } @@ -496,7 +506,8 @@ std::vector processBatch(TPX3H batch, const std::vector &raw_bytes) { if (char_array[7] == 0x6F) { // TDC data packets tdclast = (unsigned long *)(&char_array[0]); - mytdc = (((*tdclast) >> 12) & 0xFFFFFFFF); // rick: 0x3fffffff, get 32-bit tdc + mytdc = (((*tdclast) >> 12) & + 0xFFFFFFFF); // rick: 0x3fffffff, get 32-bit tdc TDC_LSB32 = GDC_timestamp & 0xFFFFFFFF; TDC_MSB16 = (GDC_timestamp >> 32) & 0xFFFF; if (mytdc < TDC_LSB32) { @@ -518,7 +529,8 @@ std::vector processBatch(TPX3H batch, const std::vector &raw_bytes) { } } else if ((char_array[7] & 0xF0) == 0xb0) { // record the packet info - hits.emplace_back(char_array, TDC_timestamp, GDC_timestamp, batch.chip_layout_type); + hits.emplace_back(char_array, TDC_timestamp, GDC_timestamp, + batch.chip_layout_type); } } @@ -563,7 +575,8 @@ std::vector parseRawBytesToHits(const std::vector &raw_bytes) { if (char_array[0] == 'T' && char_array[1] == 'P' && char_array[2] == 'X') { // get the size of the data packet data_packet_size = ((0xff & char_array[7]) << 8) | (0xff & char_array[6]); - data_packet_num = data_packet_size >> 3; // every 8 (2^3) bytes is a data packet + data_packet_num = + data_packet_size >> 3; // every 8 (2^3) bytes is a data packet // get chip layout type chip_layout_type = static_cast(char_array[4]); @@ -580,7 +593,8 @@ std::vector parseRawBytesToHits(const std::vector &raw_bytes) { if (char_array[7] == 0x6F) { // TDC data packets tdclast = (unsigned long *)(&char_array[0]); - mytdc = (((*tdclast) >> 12) & 0xFFFFFFFF); // rick: 0x3fffffff, get 32-bit tdc + mytdc = (((*tdclast) >> 12) & + 0xFFFFFFFF); // rick: 0x3fffffff, get 32-bit tdc TDC_LSB32 = GDC_timestamp & 0xFFFFFFFF; TDC_MSB16 = (GDC_timestamp >> 32) & 0xFFFF; if (mytdc < TDC_LSB32) { @@ -602,7 +616,8 @@ std::vector parseRawBytesToHits(const std::vector &raw_bytes) { } } else if ((char_array[7] & 0xF0) == 0xb0) { // Process the data into hit - hits.emplace_back(char_array, TDC_timestamp, GDC_timestamp, chip_layout_type); + hits.emplace_back(char_array, TDC_timestamp, GDC_timestamp, + chip_layout_type); } } } @@ -618,7 +633,9 @@ std::vector parseRawBytesToHits(const std::vector &raw_bytes) { * @param hits: hits to be saved. * @param labels: cluster ID for each hits. */ -void saveHitsToHDF5(const std::string out_file_name, const std::vector &hits, const std::vector &labels) { +void saveHitsToHDF5(const std::string out_file_name, + const std::vector &hits, + const std::vector &labels) { // sanity check if (hits.size() != labels.size()) { throw std::runtime_error("Hits and labels must have the same size"); @@ -635,42 +652,54 @@ void saveHitsToHDF5(const std::string out_file_name, const std::vector &hit H5::Group group = out_file.createGroup("hits"); // -- write x std::vector x(hits.size()); - std::transform(hits.begin(), hits.end(), x.begin(), [](const Hit &hit) { return hit.getX(); }); + std::transform(hits.begin(), hits.end(), x.begin(), + [](const Hit &hit) { return hit.getX(); }); H5::DataSet x_dataset = group.createDataSet("x", int_type, dataspace); x_dataset.write(x.data(), int_type); // -- write y std::vector y(hits.size()); - std::transform(hits.begin(), hits.end(), y.begin(), [](const Hit &hit) { return hit.getY(); }); + std::transform(hits.begin(), hits.end(), y.begin(), + [](const Hit &hit) { return hit.getY(); }); H5::DataSet y_dataset = group.createDataSet("y", int_type, dataspace); y_dataset.write(y.data(), int_type); // -- write tot_ns std::vector tot_ns(hits.size()); - std::transform(hits.begin(), hits.end(), tot_ns.begin(), [](const Hit &hit) { return hit.getTOT_ns(); }); - H5::DataSet tot_ns_dataset = group.createDataSet("tot_ns", float_type, dataspace); + std::transform(hits.begin(), hits.end(), tot_ns.begin(), + [](const Hit &hit) { return hit.getTOT_ns(); }); + H5::DataSet tot_ns_dataset = + group.createDataSet("tot_ns", float_type, dataspace); tot_ns_dataset.write(tot_ns.data(), float_type); // -- write toa_ns std::vector toa_ns(hits.size()); - std::transform(hits.begin(), hits.end(), toa_ns.begin(), [](const Hit &hit) { return hit.getTOA_ns(); }); - H5::DataSet toa_ns_dataset = group.createDataSet("toa_ns", float_type, dataspace); + std::transform(hits.begin(), hits.end(), toa_ns.begin(), + [](const Hit &hit) { return hit.getTOA_ns(); }); + H5::DataSet toa_ns_dataset = + group.createDataSet("toa_ns", float_type, dataspace); toa_ns_dataset.write(toa_ns.data(), float_type); // -- write ftoa_ns std::vector ftoa_ns(hits.size()); - std::transform(hits.begin(), hits.end(), ftoa_ns.begin(), [](const Hit &hit) { return hit.getFTOA_ns(); }); - H5::DataSet ftoa_ns_dataset = group.createDataSet("ftoa_ns", float_type, dataspace); + std::transform(hits.begin(), hits.end(), ftoa_ns.begin(), + [](const Hit &hit) { return hit.getFTOA_ns(); }); + H5::DataSet ftoa_ns_dataset = + group.createDataSet("ftoa_ns", float_type, dataspace); ftoa_ns_dataset.write(ftoa_ns.data(), float_type); // -- write tof_ns std::vector tof_ns(hits.size()); - std::transform(hits.begin(), hits.end(), tof_ns.begin(), [](const Hit &hit) { return hit.getTOF_ns(); }); - H5::DataSet tof_ns_dataset = group.createDataSet("tof_ns", float_type, dataspace); + std::transform(hits.begin(), hits.end(), tof_ns.begin(), + [](const Hit &hit) { return hit.getTOF_ns(); }); + H5::DataSet tof_ns_dataset = + group.createDataSet("tof_ns", float_type, dataspace); tof_ns_dataset.write(tof_ns.data(), float_type); // -- write spidertime_ns std::vector spidertime_ns(hits.size()); std::transform(hits.begin(), hits.end(), spidertime_ns.begin(), [](const Hit &hit) { return hit.getSPIDERTIME_ns(); }); - H5::DataSet spidertime_ns_dataset = group.createDataSet("spidertime_ns", float_type, dataspace); + H5::DataSet spidertime_ns_dataset = + group.createDataSet("spidertime_ns", float_type, dataspace); spidertime_ns_dataset.write(spidertime_ns.data(), float_type); // -- write labels - H5::DataSet labels_dataset = group.createDataSet("labels", int_type, dataspace); + H5::DataSet labels_dataset = + group.createDataSet("labels", int_type, dataspace); labels_dataset.write(labels.data(), int_type); // -- close file out_file.close(); @@ -682,7 +711,8 @@ void saveHitsToHDF5(const std::string out_file_name, const std::vector &hit * @param out_file_name: output file name. * @param events: neutron events to be saved. */ -void saveEventsToHDF5(const std::string out_file_name, const std::vector &events) { +void saveEventsToHDF5(const std::string out_file_name, + const std::vector &events) { // sanity check if (events.size() == 0) { throw std::runtime_error("No events to save"); @@ -699,19 +729,22 @@ void saveEventsToHDF5(const std::string out_file_name, const std::vector x(events.size()); - std::transform(events.begin(), events.end(), x.begin(), [](const NeutronEvent &event) { return event.getX(); }); + std::transform(events.begin(), events.end(), x.begin(), + [](const NeutronEvent &event) { return event.getX(); }); H5::DataSet x_dataset = group.createDataSet("x", float_type, dataspace); x_dataset.write(x.data(), float_type); // -- write y std::vector y(events.size()); - std::transform(events.begin(), events.end(), y.begin(), [](const NeutronEvent &event) { return event.getY(); }); + std::transform(events.begin(), events.end(), y.begin(), + [](const NeutronEvent &event) { return event.getY(); }); H5::DataSet y_dataset = group.createDataSet("y", float_type, dataspace); y_dataset.write(y.data(), float_type); // -- write TOF_ns std::vector tof_ns(events.size()); std::transform(events.begin(), events.end(), tof_ns.begin(), [](const NeutronEvent &event) { return event.getTOF_ns(); }); - H5::DataSet tof_ns_dataset = group.createDataSet("tof_ns", float_type, dataspace); + H5::DataSet tof_ns_dataset = + group.createDataSet("tof_ns", float_type, dataspace); tof_ns_dataset.write(tof_ns.data(), float_type); // -- write Nhits std::vector nhits(events.size()); @@ -721,47 +754,48 @@ void saveEventsToHDF5(const std::string out_file_name, const std::vector tot(events.size()); - std::transform(events.begin(), events.end(), tot.begin(), [](const NeutronEvent &event) { return event.getTOT(); }); + std::transform(events.begin(), events.end(), tot.begin(), + [](const NeutronEvent &event) { return event.getTOT(); }); H5::DataSet tot_dataset = group.createDataSet("tot", float_type, dataspace); tot_dataset.write(tot.data(), float_type); // -- close file out_file.close(); } - /** - * @brief Parse user-defined parameters from a parameter file - * - * @param filepath: path to the parameter file. - * @return Params - */ - - Params parseUserDefinedParams(const std::string &filepath) { - // default ABS settings - double radius = 5.0; - unsigned long int min_cluster_size = 1; - unsigned long int spider_time_range = 75; - - std::ifstream user_defined_params_file(filepath); - std::string line; - - while (std::getline(user_defined_params_file, line)) { - std::istringstream ss(line); - std::string name; - ss >> name; - if (name == "abs_radius") { +/** + * @brief Parse user-defined parameters from a parameter file + * + * @param filepath: path to the parameter file. + * @return Params + */ + +Params parseUserDefinedParams(const std::string &filepath) { + // default ABS settings + double radius = 5.0; + unsigned long int min_cluster_size = 1; + unsigned long int spider_time_range = 75; + + std::ifstream user_defined_params_file(filepath); + std::string line; + + while (std::getline(user_defined_params_file, line)) { + std::istringstream ss(line); + std::string name; + ss >> name; + if (name == "abs_radius") { ss >> radius; - } else if (name == "abs_min_cluster_size") { + } else if (name == "abs_min_cluster_size") { ss >> min_cluster_size; - } else if (name == "spider_time_range") { + } else if (name == "spider_time_range") { ss >> spider_time_range; - } } + } - Params p(radius, min_cluster_size, spider_time_range); + Params p(radius, min_cluster_size, spider_time_range); - // prints out user-defined parameters - std::cout << "User-defined params file: " << filepath << std::endl; - std::cout << p.toString() << std::endl; + // prints out user-defined parameters + std::cout << "User-defined params file: " << filepath << std::endl; + std::cout << p.toString() << std::endl; - return p; - } + return p; +} diff --git a/sophiread/SophireadLib/tests/generate_fake_tpx3_data.cpp b/sophiread/SophireadLib/tests/generate_fake_tpx3_data.cpp index 105da84..9ee36fd 100644 --- a/sophiread/SophireadLib/tests/generate_fake_tpx3_data.cpp +++ b/sophiread/SophireadLib/tests/generate_fake_tpx3_data.cpp @@ -1,248 +1,270 @@ -#include #include +#include #include #include -unsigned long long packDataHeader(unsigned long long t, unsigned long long p, unsigned long long x, - unsigned long long three, unsigned long long chip_nr, - unsigned long long mode, unsigned long long num_bytes){ - unsigned long long header; - header = ((num_bytes & 0x000000000000FFFF) << 48) | - ((mode & 0x00000000000000FF) << 40) | - ((chip_nr & 0x00000000000000FF) << 32) | - ((three & 0x00000000000000FF) << 24) | - ((x & 0x00000000000000FF) << 16) | - ((p & 0x00000000000000FF) << 8) | - (t & 0x00000000000000FF); - - // check - // unsigned short t1 = (unsigned short) header & 0xFF; - // unsigned short p1 = (unsigned short) (header >> 8) & 0xFF; - // unsigned short x1 = (unsigned short) (header >> 16) & 0xFF; - // unsigned short three1 = (unsigned short) (header >> 24) & 0xFF; - // unsigned short chip_nr1 = (unsigned short) (header >> 32) & 0xFF; - // unsigned short mode1 = (unsigned short) (header >> 40) & 0xFF; - // unsigned short num_bytes1 = (unsigned short) (header >> 48) & 0xFFFF; - - // std::cout << "T: " << t1 - // << ", P: " << p1 - // << ", X: " << x1 - // << ", three: " << three1 - // << ", chip_nr: " << chip_nr1 - // << ", mode: " << mode1 - // << ", num_bytes: " << num_bytes1; - - return header; +unsigned long long packDataHeader(unsigned long long t, unsigned long long p, + unsigned long long x, + unsigned long long three, + unsigned long long chip_nr, + unsigned long long mode, + unsigned long long num_bytes) { + unsigned long long header; + header = ((num_bytes & 0x000000000000FFFF) << 48) | + ((mode & 0x00000000000000FF) << 40) | + ((chip_nr & 0x00000000000000FF) << 32) | + ((three & 0x00000000000000FF) << 24) | + ((x & 0x00000000000000FF) << 16) | ((p & 0x00000000000000FF) << 8) | + (t & 0x00000000000000FF); + + // check + // unsigned short t1 = (unsigned short) header & 0xFF; + // unsigned short p1 = (unsigned short) (header >> 8) & 0xFF; + // unsigned short x1 = (unsigned short) (header >> 16) & 0xFF; + // unsigned short three1 = (unsigned short) (header >> 24) & 0xFF; + // unsigned short chip_nr1 = (unsigned short) (header >> 32) & 0xFF; + // unsigned short mode1 = (unsigned short) (header >> 40) & 0xFF; + // unsigned short num_bytes1 = (unsigned short) (header >> 48) & 0xFFFF; + + // std::cout << "T: " << t1 + // << ", P: " << p1 + // << ", X: " << x1 + // << ", three: " << three1 + // << ", chip_nr: " << chip_nr1 + // << ", mode: " << mode1 + // << ", num_bytes: " << num_bytes1; + + return header; } -unsigned long long packPixelHit(unsigned long long spider_time, unsigned long long ftoa, - unsigned long long TOT, unsigned long long TOA, unsigned long long pixaddr){ - unsigned long long temp; - unsigned long long header = 0xb; - - temp = ((header & 0x00000000000000FF) << 60) | - ((pixaddr & 0x000000000000FFFF) << 44) | - ((TOA & 0x0000000000003FFF) << 30) | - ((TOT & 0x00000000000003FF) << 20) | - ((ftoa & 0x00000000000000FF) << 16) | - (spider_time & 0x000000000000FFFF); - - // check - // unsigned short spider_time1 = (unsigned short) temp & 0xFFFF; - // unsigned char ftoa1 = (unsigned char) (temp >> 16) & 0xFF; - // unsigned short TOT1 = (unsigned short) (temp >> 20) & 0x300; - // unsigned short TOA1 = (unsigned short) (temp >> 30) & 0x3FFF; - // unsigned short pixaddr1 = (unsigned short) (temp >> 44) & 0xFFFF; - // unsigned char header1 = (unsigned char) (temp >> 60) & 0xFF; - - // std::cout << "spider_time: " << std::hex << spider_time1 - // << ", ftoa: " << std::hex << +ftoa1 - // << ", TOT: " << std::hex << TOT1 - // << ", TOA: " << std::hex << TOA1 - // << ", pixaddr: " << std::hex << pixaddr1 - // << ", header: " << std::hex << +header1 << std::endl; - - unsigned long long spidertime = (spider_time << 14) | TOA; - std::cout << "spidertime + toa: " << spidertime << " s\n"; - - return temp; +unsigned long long packPixelHit(unsigned long long spider_time, + unsigned long long ftoa, unsigned long long TOT, + unsigned long long TOA, + unsigned long long pixaddr) { + unsigned long long temp; + unsigned long long header = 0xb; + + temp = + ((header & 0x00000000000000FF) << 60) | + ((pixaddr & 0x000000000000FFFF) << 44) | + ((TOA & 0x0000000000003FFF) << 30) | ((TOT & 0x00000000000003FF) << 20) | + ((ftoa & 0x00000000000000FF) << 16) | (spider_time & 0x000000000000FFFF); + + // check + // unsigned short spider_time1 = (unsigned short) temp & 0xFFFF; + // unsigned char ftoa1 = (unsigned char) (temp >> 16) & 0xFF; + // unsigned short TOT1 = (unsigned short) (temp >> 20) & 0x300; + // unsigned short TOA1 = (unsigned short) (temp >> 30) & 0x3FFF; + // unsigned short pixaddr1 = (unsigned short) (temp >> 44) & 0xFFFF; + // unsigned char header1 = (unsigned char) (temp >> 60) & 0xFF; + + // std::cout << "spider_time: " << std::hex << spider_time1 + // << ", ftoa: " << std::hex << +ftoa1 + // << ", TOT: " << std::hex << TOT1 + // << ", TOA: " << std::hex << TOA1 + // << ", pixaddr: " << std::hex << pixaddr1 + // << ", header: " << std::hex << +header1 << std::endl; + + unsigned long long spidertime = (spider_time << 14) | TOA; + std::cout << "spidertime + toa: " << spidertime << " s\n"; + + return temp; } -int main(int argc, char** argv){ - - // create a .tpx3 file - std::ofstream write_file("rollover_test_data.tpx3", std::ios::out | std::ios::binary); - if (!write_file){ - std::cout << "Cannot open file!" << std::endl; - return 1; - } - - unsigned long long temp; - temp = packDataHeader('T','P','X','3',0,0,208); - write_file.write((char*) &temp, sizeof(unsigned long long)); - - - // disorder pixel hit datapackets - // std::cout << "Disorder: increment counter" << std::endl; - // increment counter - temp = packPixelHit(0xF000,0xFF,0x3FF,0x3FFF,0x9876); // 25.1662, 1006649343 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0xFF00,0xFF,0x3FF,0x3FFF,0x9876); // 26.7391, 1069563903 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0xFFFF,0xFF,0x3FF,0x3FFF,0x9876); // 26.8435, 1073741823 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - /* --------------------------------------------------------------*/ - - temp = packPixelHit(0x000F,0xFF,0x3FF,0x3FFF,0x9876); // 0.00655357, 262143 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x00FF,0xFF,0x3FF,0x3FFF,0x9876); // 0.104858, 4194303 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x0FFF,0xFF,0x3FF,0x3FFF,0x9876); // 1.67772, 67108863 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x2FFF,0xFF,0x3FF,0x3FFF,0x9876); // 5.03316, 201326591 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - - // disorder pixel hit datapackets - // std::cout << "Disorder: no changes counter" << std::endl; - // no changes to counter - // temp = packDataHeader('T','P','X','3',0,0,48); - // write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x000F,0xFF,0x3FF,0x3FFF,0x9876); // 0.00655357, 262143 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x3FFF,0xFF,0x3FF,0x3FFF,0x9876); // 6.71089, 268435455 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x00FF,0xFF,0x3FF,0x3FFF,0x9876); // 0.104858, 4194303 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x0FFF,0xFF,0x3FF,0x3FFF,0x9876); // 1.67772, 67108863 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x1FFF,0xFF,0x3FF,0x3FFF,0x9876); // 3.35544, 134217727 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x2FFF,0xFF,0x3FF,0x3FFF,0x9876); // 5.03316, 201326591 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - - // in order pixel hit datapackets - // std::cout << "In order: decrement counter" << std::endl; - // decrement counter - // temp = packDataHeader('T','P','X','3',0,0,56); - // write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x000F,0xFF,0x3FF,0x3FFF,0x9876); // 0.00655357, 262143 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x00FF,0xFF,0x3FF,0x3FFF,0x9876); // 0.104858, 4194303 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x0FFF,0xFF,0x3FF,0x3FFF,0x9876); // 1.67772, 67108863 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x2FFF,0xFF,0x3FF,0x3FFF,0x9876); // 5.03316, 201326591 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - /* --------------------------------------------------------------*/ - - temp = packPixelHit(0xF000,0xFF,0x3FF,0x3FFF,0x9876); // 25.1662, 1006649343 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0xFF00,0xFF,0x3FF,0x3FFF,0x9876); // 26.7391, 1069563903 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0xFFFF,0xFF,0x3FF,0x3FFF,0x9876); // 26.8435, 1073741823 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - - - // in order pixel - // std::cout << "In order: no changes counter" << std::endl; - // no changes to counter - // temp = packDataHeader('T','P','X','3',0,0,48); - // write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x000F,0xFF,0x3FF,0x3FFF,0x9876); // 0.00655357, 262143 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x00FF,0xFF,0x3FF,0x3FFF,0x9876); // 0.104858, 4194303 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x0FFF,0xFF,0x3FF,0x3FFF,0x9876); // 1.67772, 67108863 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x1FFF,0xFF,0x3FF,0x3FFF,0x9876); // 3.35544, 134217727 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x2FFF,0xFF,0x3FF,0x3FFF,0x9876); // 5.03316, 201326591 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - temp = packPixelHit(0x3FFF,0xFF,0x3FF,0x3FFF,0x9876); // 6.71089, 268435455 - write_file.write((char*) &temp, sizeof(unsigned long long)); - - - write_file.close(); - - // read in .tpx3 file - std::ifstream read_file("rollover_test_data.tpx3", std::ios::out | std::ios::binary); - if (!read_file){ - std::cout << "Cannot open file!" << std::endl; - return 1; - } - - std::cout << " \n Reading file: Checking \n"; - - unsigned long long temp1; - read_file.read((char*) &temp1, sizeof(unsigned long long)); - unsigned short t1 = (unsigned short) temp1 & 0xFF; - unsigned short p1 = (unsigned short) (temp1 >> 8) & 0xFF; - unsigned short x1 = (unsigned short) (temp1 >> 16) & 0xFF; - unsigned short three1 = (unsigned short) (temp1 >> 24) & 0xFF; - unsigned short chip_nr1 = (unsigned short) (temp1 >> 32) & 0xFF; - unsigned short mode1 = (unsigned short) (temp1 >> 40) & 0xFF; - unsigned short num_bytes1 = (unsigned short) (temp1 >> 48) & 0xFFFF; - - // std::cout << "T: " << t1 - // << ", P: " << p1 - // << ", X: " << x1 - // << ", three: " << three1 - // << ", chip_nr: " << chip_nr1 - // << ", mode: " << mode1 - // << ", num_bytes: " << num_bytes1 - // << std::endl; - - while (read_file.read((char*) &temp1, sizeof(unsigned long long))){ - // check - unsigned short spider_time1 = (unsigned short) temp1 & 0xFFFF; - unsigned char ftoa1 = (unsigned char) (temp1 >> 16) & 0xFF; - unsigned short TOT1 = (unsigned short) (temp1 >> 20) & 0x300; - unsigned short TOA1 = (unsigned short) (temp1 >> 30) & 0x3FFF; - unsigned short pixaddr1 = (unsigned short) (temp1 >> 44) & 0xFFFF; - unsigned char header1 = (unsigned char) (temp1 >> 60) & 0xFF; - - // std::cout << "spider_time: " << std::hex << spider_time1 - // << ", ftoa: " << std::hex << +ftoa1 - // << ", TOT: " << std::hex << TOT1 - // << ", TOA: " << std::hex << TOA1 - // << ", pixaddr: " << std::hex << pixaddr1 - // << ", header: " << std::hex << +header1 << std::endl; - - unsigned int spidertime1 = (spider_time1 << 14) | TOA1; - std::cout << "spidertime + toa: " << spidertime1 << " s\n"; - } - - - read_file.close(); - - return 0; - +int main(int argc, char** argv) { + // create a .tpx3 file + std::ofstream write_file("rollover_test_data.tpx3", + std::ios::out | std::ios::binary); + if (!write_file) { + std::cout << "Cannot open file!" << std::endl; + return 1; + } + + unsigned long long temp; + temp = packDataHeader('T', 'P', 'X', '3', 0, 0, 208); + write_file.write((char*)&temp, sizeof(unsigned long long)); + + // disorder pixel hit datapackets + // std::cout << "Disorder: increment counter" << std::endl; + // increment counter + temp = + packPixelHit(0xF000, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 25.1662, 1006649343 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0xFF00, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 26.7391, 1069563903 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0xFFFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 26.8435, 1073741823 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + /* --------------------------------------------------------------*/ + + temp = + packPixelHit(0x000F, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 0.00655357, 262143 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x00FF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 0.104858, 4194303 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x0FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 1.67772, 67108863 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x2FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 5.03316, 201326591 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + // disorder pixel hit datapackets + // std::cout << "Disorder: no changes counter" << std::endl; + // no changes to counter + // temp = packDataHeader('T','P','X','3',0,0,48); + // write_file.write((char*) &temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x000F, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 0.00655357, 262143 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x3FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 6.71089, 268435455 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x00FF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 0.104858, 4194303 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x0FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 1.67772, 67108863 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x1FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 3.35544, 134217727 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x2FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 5.03316, 201326591 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + // in order pixel hit datapackets + // std::cout << "In order: decrement counter" << std::endl; + // decrement counter + // temp = packDataHeader('T','P','X','3',0,0,56); + // write_file.write((char*) &temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x000F, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 0.00655357, 262143 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x00FF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 0.104858, 4194303 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x0FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 1.67772, 67108863 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x2FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 5.03316, 201326591 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + /* --------------------------------------------------------------*/ + + temp = + packPixelHit(0xF000, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 25.1662, 1006649343 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0xFF00, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 26.7391, 1069563903 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0xFFFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 26.8435, 1073741823 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + // in order pixel + // std::cout << "In order: no changes counter" << std::endl; + // no changes to counter + // temp = packDataHeader('T','P','X','3',0,0,48); + // write_file.write((char*) &temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x000F, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 0.00655357, 262143 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x00FF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 0.104858, 4194303 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x0FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 1.67772, 67108863 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x1FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 3.35544, 134217727 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x2FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 5.03316, 201326591 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + temp = + packPixelHit(0x3FFF, 0xFF, 0x3FF, 0x3FFF, 0x9876); // 6.71089, 268435455 + write_file.write((char*)&temp, sizeof(unsigned long long)); + + write_file.close(); + + // read in .tpx3 file + std::ifstream read_file("rollover_test_data.tpx3", + std::ios::out | std::ios::binary); + if (!read_file) { + std::cout << "Cannot open file!" << std::endl; + return 1; + } + + std::cout << " \n Reading file: Checking \n"; + + unsigned long long temp1; + read_file.read((char*)&temp1, sizeof(unsigned long long)); + unsigned short t1 = (unsigned short)temp1 & 0xFF; + unsigned short p1 = (unsigned short)(temp1 >> 8) & 0xFF; + unsigned short x1 = (unsigned short)(temp1 >> 16) & 0xFF; + unsigned short three1 = (unsigned short)(temp1 >> 24) & 0xFF; + unsigned short chip_nr1 = (unsigned short)(temp1 >> 32) & 0xFF; + unsigned short mode1 = (unsigned short)(temp1 >> 40) & 0xFF; + unsigned short num_bytes1 = (unsigned short)(temp1 >> 48) & 0xFFFF; + + // std::cout << "T: " << t1 + // << ", P: " << p1 + // << ", X: " << x1 + // << ", three: " << three1 + // << ", chip_nr: " << chip_nr1 + // << ", mode: " << mode1 + // << ", num_bytes: " << num_bytes1 + // << std::endl; + + while (read_file.read((char*)&temp1, sizeof(unsigned long long))) { + // check + unsigned short spider_time1 = (unsigned short)temp1 & 0xFFFF; + unsigned char ftoa1 = (unsigned char)(temp1 >> 16) & 0xFF; + unsigned short TOT1 = (unsigned short)(temp1 >> 20) & 0x300; + unsigned short TOA1 = (unsigned short)(temp1 >> 30) & 0x3FFF; + unsigned short pixaddr1 = (unsigned short)(temp1 >> 44) & 0xFFFF; + unsigned char header1 = (unsigned char)(temp1 >> 60) & 0xFF; + + // std::cout << "spider_time: " << std::hex << spider_time1 + // << ", ftoa: " << std::hex << +ftoa1 + // << ", TOT: " << std::hex << TOT1 + // << ", TOA: " << std::hex << TOA1 + // << ", pixaddr: " << std::hex << pixaddr1 + // << ", header: " << std::hex << +header1 << std::endl; + + unsigned int spidertime1 = (spider_time1 << 14) | TOA1; + std::cout << "spidertime + toa: " << spidertime1 << " s\n"; + } + + read_file.close(); + + return 0; } \ No newline at end of file diff --git a/sophiread/SophireadLib/tests/test_clustering.cpp b/sophiread/SophireadLib/tests/test_clustering.cpp index 96bae7e..16d5316 100644 --- a/sophiread/SophireadLib/tests/test_clustering.cpp +++ b/sophiread/SophireadLib/tests/test_clustering.cpp @@ -53,7 +53,7 @@ TEST(Clustering, ABSAlgorithm) { auto data = gen_clusters(); // create the ABS algorithm - ABS abs(5.,1,75); + ABS abs(5., 1, 75); abs.fit(data); abs.set_method("centroid"); auto events = abs.get_events(data); diff --git a/sophiread/SophireadLib/tests/test_tpx3.cpp b/sophiread/SophireadLib/tests/test_tpx3.cpp index 3a630fa..082426e 100644 --- a/sophiread/SophireadLib/tests/test_tpx3.cpp +++ b/sophiread/SophireadLib/tests/test_tpx3.cpp @@ -1,4 +1,5 @@ #include + #include #include "tpx3.h" @@ -6,8 +7,8 @@ // Test the readTimepix3RawData function TEST(FileHandlingTest, ReadTPX3RawData) { // read the testing raw data - auto hits = - readTimepix3RawData("../data/frames_pinhole_3mm_1s_RESOLUTION_000001.tpx3"); + auto hits = readTimepix3RawData( + "../data/frames_pinhole_3mm_1s_RESOLUTION_000001.tpx3"); // check the number of hits EXPECT_EQ(hits.size(), 9933804); @@ -54,64 +55,80 @@ TEST(FileHandlingTest, VerifyTiming) { // EXPECT_EQ(hits[365 - 1].getSPIDERTIME(), 8809347419); } -TEST(FileHandlingTest, VerifyRollover){ - // reading the testing raw data - auto hits = - readTimepix3RawData("../data/rollover_test_data.tpx3"); +TEST(FileHandlingTest, VerifyRollover) { + // reading the testing raw data + auto hits = readTimepix3RawData("../data/rollover_test_data.tpx3"); // check the number of hits - EXPECT_EQ(hits.size(),26); - - // check disordered pixels: increment counter - EXPECT_EQ(hits[0].getSPIDERTIME(),1006649343); // 25.1662, 1006649343 - EXPECT_EQ(hits[1].getSPIDERTIME(),1069563903); // 26.7391, 1069563903 - EXPECT_EQ(hits[2].getSPIDERTIME(),1073741823); // 26.8435, 1073741823 - EXPECT_EQ(hits[3].getSPIDERTIME(),262143 + 1073741824); // 0.00655357, 262143 - EXPECT_EQ(hits[4].getSPIDERTIME(),4194303 + 1073741824); // 0.104858, 4194303 - EXPECT_EQ(hits[5].getSPIDERTIME(),67108863 + 1073741824); // 1.67772, 67108863 - EXPECT_EQ(hits[6].getSPIDERTIME(), 201326591 + 1073741824); // 5.03316, 201326591 + EXPECT_EQ(hits.size(), 26); + + // check disordered pixels: increment counter + EXPECT_EQ(hits[0].getSPIDERTIME(), 1006649343); // 25.1662, 1006649343 + EXPECT_EQ(hits[1].getSPIDERTIME(), 1069563903); // 26.7391, 1069563903 + EXPECT_EQ(hits[2].getSPIDERTIME(), 1073741823); // 26.8435, 1073741823 + EXPECT_EQ(hits[3].getSPIDERTIME(), + 262143 + 1073741824); // 0.00655357, 262143 + EXPECT_EQ(hits[4].getSPIDERTIME(), + 4194303 + 1073741824); // 0.104858, 4194303 + EXPECT_EQ(hits[5].getSPIDERTIME(), + 67108863 + 1073741824); // 1.67772, 67108863 + EXPECT_EQ(hits[6].getSPIDERTIME(), + 201326591 + 1073741824); // 5.03316, 201326591 // check disordered pixels: do nothing to counter - EXPECT_EQ(hits[7].getSPIDERTIME(),262143 + 1073741824); // 0.00655357, 262143 - EXPECT_EQ(hits[8].getSPIDERTIME(),268435455 + 1073741824); // 6.71089, 268435455 - EXPECT_EQ(hits[9].getSPIDERTIME(),4194303 + 1073741824); // 0.104858, 4194303 - EXPECT_EQ(hits[10].getSPIDERTIME(),67108863 + 1073741824); // 1.67772, 67108863 - EXPECT_EQ(hits[11].getSPIDERTIME(),134217727 + 1073741824); // 3.35544, 134217727 - EXPECT_EQ(hits[12].getSPIDERTIME(),201326591 + 1073741824); // 5.03316, 201326591 - - // check order pixels: decrement counter - EXPECT_EQ(hits[13].getSPIDERTIME(),262143 + 1073741824); // 0.00655357, 262143 - EXPECT_EQ(hits[14].getSPIDERTIME(),4194303 + 1073741824); // 0.104858, 4194303 - EXPECT_EQ(hits[15].getSPIDERTIME(),67108863 + 1073741824); // 1.67772, 67108863 - EXPECT_EQ(hits[16].getSPIDERTIME(),201326591 + 1073741824); // 5.03316, 201326591 - EXPECT_EQ(hits[17].getSPIDERTIME(),1006649343); // 25.1662, 1006649343 - EXPECT_EQ(hits[18].getSPIDERTIME(),1069563903); // 26.7391, 1069563903 - EXPECT_EQ(hits[19].getSPIDERTIME(),1073741823); // 26.8435, 1073741823 - - // check ordered pixels: do nothing to counter - EXPECT_EQ(hits[20].getSPIDERTIME(),262143 + 1073741824); // 0.00655357, 262143 - EXPECT_EQ(hits[21].getSPIDERTIME(),4194303 + 1073741824); // 0.104858, 4194303 - EXPECT_EQ(hits[22].getSPIDERTIME(),67108863 + 1073741824); // 1.67772, 67108863 - EXPECT_EQ(hits[23].getSPIDERTIME(),134217727 + 1073741824); // 3.35544, 134217727 - EXPECT_EQ(hits[24].getSPIDERTIME(),201326591 + 1073741824); // 5.03316, 201326591 - EXPECT_EQ(hits[25].getSPIDERTIME(),268435455 + 1073741824); // 6.71089, 268435455 - + EXPECT_EQ(hits[7].getSPIDERTIME(), + 262143 + 1073741824); // 0.00655357, 262143 + EXPECT_EQ(hits[8].getSPIDERTIME(), + 268435455 + 1073741824); // 6.71089, 268435455 + EXPECT_EQ(hits[9].getSPIDERTIME(), + 4194303 + 1073741824); // 0.104858, 4194303 + EXPECT_EQ(hits[10].getSPIDERTIME(), + 67108863 + 1073741824); // 1.67772, 67108863 + EXPECT_EQ(hits[11].getSPIDERTIME(), + 134217727 + 1073741824); // 3.35544, 134217727 + EXPECT_EQ(hits[12].getSPIDERTIME(), + 201326591 + 1073741824); // 5.03316, 201326591 + + // check order pixels: decrement counter + EXPECT_EQ(hits[13].getSPIDERTIME(), + 262143 + 1073741824); // 0.00655357, 262143 + EXPECT_EQ(hits[14].getSPIDERTIME(), + 4194303 + 1073741824); // 0.104858, 4194303 + EXPECT_EQ(hits[15].getSPIDERTIME(), + 67108863 + 1073741824); // 1.67772, 67108863 + EXPECT_EQ(hits[16].getSPIDERTIME(), + 201326591 + 1073741824); // 5.03316, 201326591 + EXPECT_EQ(hits[17].getSPIDERTIME(), 1006649343); // 25.1662, 1006649343 + EXPECT_EQ(hits[18].getSPIDERTIME(), 1069563903); // 26.7391, 1069563903 + EXPECT_EQ(hits[19].getSPIDERTIME(), 1073741823); // 26.8435, 1073741823 + + // check ordered pixels: do nothing to counter + EXPECT_EQ(hits[20].getSPIDERTIME(), + 262143 + 1073741824); // 0.00655357, 262143 + EXPECT_EQ(hits[21].getSPIDERTIME(), + 4194303 + 1073741824); // 0.104858, 4194303 + EXPECT_EQ(hits[22].getSPIDERTIME(), + 67108863 + 1073741824); // 1.67772, 67108863 + EXPECT_EQ(hits[23].getSPIDERTIME(), + 134217727 + 1073741824); // 3.35544, 134217727 + EXPECT_EQ(hits[24].getSPIDERTIME(), + 201326591 + 1073741824); // 5.03316, 201326591 + EXPECT_EQ(hits[25].getSPIDERTIME(), + 268435455 + 1073741824); // 6.71089, 268435455 } // Test the parseUserDefinedParams function TEST(FileHandlingTest, ParseUserDefinedParams) { - - // read user-defined param files + // read user-defined param files auto p1 = parseUserDefinedParams("../data/user_defined_params.txt"); auto p2 = parseUserDefinedParams("../data/user_defined_params_1.txt"); - // check user-defined params + // check user-defined params EXPECT_EQ(p1.getABSRadius(), 5.0); - EXPECT_EQ(p1.getABSMinClusterSize(),1); + EXPECT_EQ(p1.getABSMinClusterSize(), 1); EXPECT_EQ(p1.getABSSpidertimeRange(), 75); EXPECT_EQ(p2.getABSRadius(), 20.0); - EXPECT_EQ(p2.getABSMinClusterSize(),30); - EXPECT_EQ(p2.getABSSpidertimeRange(),500000); - + EXPECT_EQ(p2.getABSMinClusterSize(), 30); + EXPECT_EQ(p2.getABSSpidertimeRange(), 500000); } \ No newline at end of file diff --git a/sophiread/SophireadStreamCLI/CMakeLists.txt b/sophiread/SophireadStreamCLI/CMakeLists.txt index be8cb61..0b8720a 100644 --- a/sophiread/SophireadStreamCLI/CMakeLists.txt +++ b/sophiread/SophireadStreamCLI/CMakeLists.txt @@ -4,42 +4,39 @@ include(FetchContent) FetchContent_Declare( - readerwriterqueue - GIT_REPOSITORY https://github.com/cameron314/readerwriterqueue - GIT_TAG master -) + readerwriterqueue + GIT_REPOSITORY https://github.com/cameron314/readerwriterqueue + GIT_TAG master) FetchContent_MakeAvailable(readerwriterqueue) # Add the source files -set(SRC_FILES - src/sophiread_stream.cpp -) +set(SRC_FILES src/sophiread_stream.cpp) -# Add inlcude directories -include_directories( - ${PROJECT_SOURCE_DIR}/SophireadLib/include -) +# Add include directories +include_directories(${PROJECT_SOURCE_DIR}/SophireadLib/include) # ------------------ CLI STREAM DEMO ------------------ # -add_executable(SophireadStream - ${SRC_FILES} -) +add_executable(SophireadStream ${SRC_FILES}) set_target_properties(SophireadStream PROPERTIES VERSION ${PROJECT_VERSION}) -target_link_libraries(SophireadStream PUBLIC readerwriterqueue SophireadLib hdf5 hdf5_cpp OpenMP::OpenMP_CXX) +target_link_libraries(SophireadStream PUBLIC readerwriterqueue SophireadLib + hdf5 hdf5_cpp OpenMP::OpenMP_CXX) # symlink the executable to the build directory -add_custom_command(TARGET SophireadStream POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink +add_custom_command( + TARGET SophireadStream + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E create_symlink ${PROJECT_BINARY_DIR}/SophireadStreamCLI/SophireadStream - ${PROJECT_BINARY_DIR}/SophireadStream -) + ${PROJECT_BINARY_DIR}/SophireadStream) # ----------------- INSTALL ----------------- # if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "Default install prefix" FORCE) + set(CMAKE_INSTALL_PREFIX + "/usr/local" + CACHE PATH "Default install prefix" FORCE) endif() -install(TARGETS SophireadStream - RUNTIME DESTINATION bin) +install(TARGETS SophireadStream RUNTIME DESTINATION bin) set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") include(CPack) diff --git a/sophiread/SophireadStreamCLI/src/sophiread_stream.cpp b/sophiread/SophireadStreamCLI/src/sophiread_stream.cpp index 794c541..11c8f02 100644 --- a/sophiread/SophireadStreamCLI/src/sophiread_stream.cpp +++ b/sophiread/SophireadStreamCLI/src/sophiread_stream.cpp @@ -25,7 +25,7 @@ std::vector neutron_events; */ void process_batch(const std::vector &batch) { ClusteringAlgorithm *alg; - alg = new ABS(5.0,1,75); // select clustering algorithm + alg = new ABS(5.0, 1, 75); // select clustering algorithm alg->set_method("fast_gaussian"); // select peak fitting method alg->fit(batch); std::vector events = alg->get_events(batch); diff --git a/sophiread/environment_linux.yml b/sophiread/environment_linux.yml index 8cb9f08..2b7f35c 100644 --- a/sophiread/environment_linux.yml +++ b/sophiread/environment_linux.yml @@ -10,8 +10,6 @@ dependencies: - gtest - qwt - eigen - - mlpack - - cereal - tbb-devel - spdlog - nlohmann_json @@ -31,3 +29,6 @@ dependencies: - graphviz # Mac users should use its native version, MacTex - texlive-core + + # misc + - pre-commit diff --git a/sophiread/environment_mac.yml b/sophiread/environment_mac.yml index c5a6bb9..1cfcc3d 100644 --- a/sophiread/environment_mac.yml +++ b/sophiread/environment_mac.yml @@ -23,3 +23,6 @@ dependencies: # documentation - doxygen - graphviz + + # misc + - pre-commit diff --git a/sophiread/resources/data/user_defined_params.txt b/sophiread/resources/data/user_defined_params.txt index 279f58f..5a88915 100644 --- a/sophiread/resources/data/user_defined_params.txt +++ b/sophiread/resources/data/user_defined_params.txt @@ -1,4 +1,4 @@ # ABS -abs_radius 5.0 # in number of pixels +abs_radius 5.0 # in number of pixels abs_min_cluster_size 1 # in number of pixels spider_time_range 75 # in nanoseconds \ No newline at end of file diff --git a/sophiread/resources/data/user_defined_params_1.txt b/sophiread/resources/data/user_defined_params_1.txt index 6a4a4e8..195f9fe 100644 --- a/sophiread/resources/data/user_defined_params_1.txt +++ b/sophiread/resources/data/user_defined_params_1.txt @@ -1,4 +1,4 @@ # ABS -abs_radius 20.0 # in number of pixels +abs_radius 20.0 # in number of pixels abs_min_cluster_size 30 # in number of pixels spider_time_range 500000 # in nanoseconds \ No newline at end of file diff --git a/sophiread/resources/manufacture/tpx3cam.cpp b/sophiread/resources/manufacture/tpx3cam.cpp index 9c38e7e..a5eb625 100644 --- a/sophiread/resources/manufacture/tpx3cam.cpp +++ b/sophiread/resources/manufacture/tpx3cam.cpp @@ -2,204 +2,209 @@ Example C++ script to convert a raw data .tpx3 to text file - copyright JL@ Amsterdam Scientific Instruments B.V. - www.amscins.com - 05-12-2019 + copyright JL@ Amsterdam Scientific Instruments B.V. + www.amscins.com + 05-12-2019 ****************************************************************/ #include -#include + +#include #include #include +#include #include -#include using namespace std; - -int main(int argc, char *argv[]) -{ - char* TPX_name; - if (argc == 1) { - cout << "Usage: tpx3 raw data" << endl << endl; - return 0; - } - else { - TPX_name = argv[1]; - cout << "imported file: " << TPX_name << endl; - } - - ofstream xy_file("converted.txt"); //Converted and saved txt file - streampos begin, end; - ifstream myfile(TPX_name, ios::binary); - unsigned short xpix, ypix, TOT, TOA, spidrTime; - char chipnr, FTOA; - int frameNr; - int CTOA; - int mode; - unsigned long Timer_LSB32 = 0; - unsigned long Timer_MSB16 = 0; - unsigned long numofTDC=0; - - if (!myfile) { - cout << "This file is not found!" << endl; - } - else { - myfile.seekg(0, myfile.end); - unsigned long long fileLength = myfile.tellg(); - myfile.seekg(0, myfile.beg); - unsigned long long temp64; - cout << "filesize: " << fileLength/(1024*1024) <<"MB" << endl; - unsigned long long NumofPacket = fileLength / 8; - unsigned long long* datapacket = new unsigned long long [NumofPacket]; - myfile.read((char*) datapacket, fileLength); - myfile.close(); - char* HeaderBuffer = new char[8]; - unsigned long long temp; - - for (unsigned long long i = 0; i < NumofPacket; i++) { - memcpy(HeaderBuffer, &datapacket[i], 8); - if (HeaderBuffer[0] == 'T' && HeaderBuffer[1] == 'P' && HeaderBuffer[2] == 'X') { - int size = ((0xff & HeaderBuffer[7]) << 8) | (0xff & HeaderBuffer[6]); - chipnr = HeaderBuffer[4]; - mode = HeaderBuffer[5]; - for (int j = 0; j < size / 8; j++) { - temp = datapacket[i + j + 1]; - int hdr = (int)(temp >> 56); - int packet = temp >> 60; - double coarsetime; - unsigned long tmpfine; - unsigned long trigtime_fine; - double time_unit, global_timestamp; - int trigger_counter; - unsigned long long int timemaster; - int heartbeatL, heartbeatM; - double TDC_timestamp; - double spidrTimens; - int x, y; - double TOTns; - double TOAns; - long dcol; - long spix; - long pix; - - switch (packet) - { - case 0x6: //TDC timestamp packet header - - if ((temp >> 56) == 0x6f) cout << "tdc1 rising edge is working" << endl; - if ((temp >> 56) == 0x6a) cout << "tdc1 falling edge is working" << endl; - if ((temp >> 56) == 0x6e) cout << "tdc2 rising edge is working" << endl; - if ((temp >> 56) == 0x6b) cout << "tdc2 falling edge is working" << endl; - coarsetime = (temp >> 12) & 0xFFFFFFFF; - tmpfine = (temp >> 5) & 0xF; - tmpfine = ((tmpfine - 1) << 9) / 12; - trigtime_fine = (temp & 0x0000000000000E00) | (tmpfine & 0x00000000000001FF); - time_unit = 25. / 4096; - trigger_counter = temp >> 44 & 0xFFF; - TDC_timestamp = coarsetime * 25E-9 + trigtime_fine * time_unit*1E-9; - //uncomment below to save TDC timestamps into the txt file - xy_file << setprecision(15) << TDC_timestamp << endl; - // cout<< "TDC timestamp: " << setprecision(15) << TDC_timestamp << endl; - numofTDC=numofTDC+1; - break; - - case 0xb: //Chip data: ToA and ToT timestamp packet, x, y - - spidrTime = (unsigned short)(temp & 0xffff); - dcol = (temp & 0x0FE0000000000000L) >> 52; - spix = (temp & 0x001F800000000000L) >> 45; - pix = (temp & 0x0000700000000000L) >> 44; - x = (int)(dcol + pix / 4); - y = (int)(spix + (pix & 0x3)); - TOA = (unsigned short)((temp >> (16 + 14)) & 0x3fff); - TOT = (unsigned short)((temp >> (16 + 4)) & 0x3ff); - FTOA = (unsigned char)((temp >> 16) & 0xf); - CTOA = (TOA << 4) | (~FTOA & 0xf); - spidrTimens = spidrTime * 25.0 * 16384.0; - TOAns = TOA * 25.0; - TOTns = TOT * 25.0; - global_timestamp = spidrTimens + CTOA * (25.0 / 16); - - /************************************************************ - Condition is different for single Timepix3 chip or quad chips: - Single chip, using "int (Chipnr) +3" - Quad chips, using "int (Chipnr)" - ************************************************************/ - switch (int (chipnr)) // for quad chips; - { - - case 0: - x += 260; - y = y; - break; - - case 1: - x = 255 - x + 260; - y = 255 - y + 260; - break; - - case 2: - x = 255 - x; - y = 255 - y + 260; - break; - - case 3: - break; - - default: - break; - - } - - //uncomment below to save the chip data into the text file; - xy_file << setprecision(15) << x << " " << y << " " << global_timestamp / 1E9 << " " << TOTns << endl; //x, y, toa, tot data can be saved into txt data - cout<< "Chip-ToA: " << setprecision(15) << global_timestamp / 1E9 << " ToT: " << TOTns << " x: " << x << " y: " << y << endl; - - break; - - case 0x4: //the global timestamps. - - if (((temp >> 56) & 0xF) == 0x4) { - Timer_LSB32 = (temp >> 16) & 0xFFFFFFFF; - } - else if (((temp >> 56) & 0xF) == 0x5) - { - Timer_MSB16 = (temp >> 16) & 0xFFFF; - unsigned long long int timemaster; - timemaster = Timer_MSB16; - timemaster = (timemaster << 32) & 0xFFFF00000000; - timemaster = timemaster | Timer_LSB32; - int diff = (spidrTime >> 14) - ((Timer_LSB32 >> 28) & 0x3); - - if ((spidrTime >> 14) == ((Timer_LSB32 >> 28) & 0x3)) - { - } - else { - Timer_MSB16 = Timer_MSB16 - diff; - } - //uncomment below to save the global timestamps into the text file; - xy_file << " Global time: " << setprecision(15) << timemaster * 25e-9 << endl; //global timestamps can be saved into text file - } - - break; - - default: - break; - } - +int main(int argc, char* argv[]) { + char* TPX_name; + if (argc == 1) { + cout << "Usage: tpx3 raw data" << endl << endl; + return 0; + } else { + TPX_name = argv[1]; + cout << "imported file: " << TPX_name << endl; + } + + ofstream xy_file("converted.txt"); // Converted and saved txt file + streampos begin, end; + ifstream myfile(TPX_name, ios::binary); + unsigned short xpix, ypix, TOT, TOA, spidrTime; + char chipnr, FTOA; + int frameNr; + int CTOA; + int mode; + unsigned long Timer_LSB32 = 0; + unsigned long Timer_MSB16 = 0; + unsigned long numofTDC = 0; + + if (!myfile) { + cout << "This file is not found!" << endl; + } else { + myfile.seekg(0, myfile.end); + unsigned long long fileLength = myfile.tellg(); + myfile.seekg(0, myfile.beg); + unsigned long long temp64; + cout << "filesize: " << fileLength / (1024 * 1024) << "MB" << endl; + unsigned long long NumofPacket = fileLength / 8; + unsigned long long* datapacket = new unsigned long long[NumofPacket]; + myfile.read((char*)datapacket, fileLength); + myfile.close(); + char* HeaderBuffer = new char[8]; + unsigned long long temp; + + for (unsigned long long i = 0; i < NumofPacket; i++) { + memcpy(HeaderBuffer, &datapacket[i], 8); + if (HeaderBuffer[0] == 'T' && HeaderBuffer[1] == 'P' && + HeaderBuffer[2] == 'X') { + int size = ((0xff & HeaderBuffer[7]) << 8) | (0xff & HeaderBuffer[6]); + chipnr = HeaderBuffer[4]; + mode = HeaderBuffer[5]; + for (int j = 0; j < size / 8; j++) { + temp = datapacket[i + j + 1]; + int hdr = (int)(temp >> 56); + int packet = temp >> 60; + double coarsetime; + unsigned long tmpfine; + unsigned long trigtime_fine; + double time_unit, global_timestamp; + int trigger_counter; + unsigned long long int timemaster; + int heartbeatL, heartbeatM; + double TDC_timestamp; + double spidrTimens; + int x, y; + double TOTns; + double TOAns; + long dcol; + long spix; + long pix; + + switch (packet) { + case 0x6: // TDC timestamp packet header + + if ((temp >> 56) == 0x6f) + cout << "tdc1 rising edge is working" << endl; + if ((temp >> 56) == 0x6a) + cout << "tdc1 falling edge is working" << endl; + if ((temp >> 56) == 0x6e) + cout << "tdc2 rising edge is working" << endl; + if ((temp >> 56) == 0x6b) + cout << "tdc2 falling edge is working" << endl; + coarsetime = (temp >> 12) & 0xFFFFFFFF; + tmpfine = (temp >> 5) & 0xF; + tmpfine = ((tmpfine - 1) << 9) / 12; + trigtime_fine = + (temp & 0x0000000000000E00) | (tmpfine & 0x00000000000001FF); + time_unit = 25. / 4096; + trigger_counter = temp >> 44 & 0xFFF; + TDC_timestamp = + coarsetime * 25E-9 + trigtime_fine * time_unit * 1E-9; + // uncomment below to save TDC timestamps into the txt file + xy_file << setprecision(15) << TDC_timestamp << endl; + // cout<< "TDC timestamp: " << setprecision(15) << TDC_timestamp + // << endl; + numofTDC = numofTDC + 1; + break; + + case 0xb: // Chip data: ToA and ToT timestamp packet, x, y + + spidrTime = (unsigned short)(temp & 0xffff); + dcol = (temp & 0x0FE0000000000000L) >> 52; + spix = (temp & 0x001F800000000000L) >> 45; + pix = (temp & 0x0000700000000000L) >> 44; + x = (int)(dcol + pix / 4); + y = (int)(spix + (pix & 0x3)); + TOA = (unsigned short)((temp >> (16 + 14)) & 0x3fff); + TOT = (unsigned short)((temp >> (16 + 4)) & 0x3ff); + FTOA = (unsigned char)((temp >> 16) & 0xf); + CTOA = (TOA << 4) | (~FTOA & 0xf); + spidrTimens = spidrTime * 25.0 * 16384.0; + TOAns = TOA * 25.0; + TOTns = TOT * 25.0; + global_timestamp = spidrTimens + CTOA * (25.0 / 16); + + /************************************************************ + Condition is different for single Timepix3 chip or quad chips: + Single chip, using "int (Chipnr) +3" + Quad chips, using "int (Chipnr)" + ************************************************************/ + switch (int(chipnr)) // for quad chips; + { + case 0: + x += 260; + y = y; + break; + + case 1: + x = 255 - x + 260; + y = 255 - y + 260; + break; + + case 2: + x = 255 - x; + y = 255 - y + 260; + break; + + case 3: + break; + + default: + break; + } + + // uncomment below to save the chip data into the text file; + xy_file + << setprecision(15) << x << " " << y << " " + << global_timestamp / 1E9 << " " << TOTns + << endl; // x, y, toa, tot data can be saved into txt data + cout << "Chip-ToA: " << setprecision(15) << global_timestamp / 1E9 + << " ToT: " << TOTns << " x: " << x << " y: " << y << endl; + + break; + + case 0x4: // the global timestamps. + + if (((temp >> 56) & 0xF) == 0x4) { + Timer_LSB32 = (temp >> 16) & 0xFFFFFFFF; + } else if (((temp >> 56) & 0xF) == 0x5) { + Timer_MSB16 = (temp >> 16) & 0xFFFF; + unsigned long long int timemaster; + timemaster = Timer_MSB16; + timemaster = (timemaster << 32) & 0xFFFF00000000; + timemaster = timemaster | Timer_LSB32; + int diff = (spidrTime >> 14) - ((Timer_LSB32 >> 28) & 0x3); + + if ((spidrTime >> 14) == ((Timer_LSB32 >> 28) & 0x3)) { + } else { + Timer_MSB16 = Timer_MSB16 - diff; } - i += (size / 8); - printf("i : %lld\r", i); - } + // uncomment below to save the global timestamps into the text + // file; + xy_file + << " Global time: " << setprecision(15) + << timemaster * 25e-9 + << endl; // global timestamps can be saved into text file + } + + break; + + default: + break; + } } - - delete [] HeaderBuffer; - delete [] datapacket; + i += (size / 8); + printf("i : %lld\r", i); + } } - cout<<"the number of TDCs: "<killthread=1; } @@ -47,9 +47,9 @@ int Hit_worker::runme() unsigned int itof; int pindex=0; // these are for the cluster memory area. int cindex=0; - double xmean,ymean; // + double xmean,ymean; // int ix,iy; - int isize=(int)DSCALE*512; + int isize=(int)DSCALE*512; totalClusters=0; acceptedClusters=0; this->killthread=0; @@ -73,39 +73,39 @@ int Hit_worker::runme() // nomatch=1; - // going through a list of 128 clusters and + // going through a list of 128 clusters and // see if the hit belongs to an existing cluster - // or a new cluster + // or a new cluster for (i=0;ici].spdrtime; + k=myclusters[i].firstspdr- myhits[myinfo->ci].spdrtime; - if (abs(k) < 3) // in ns units - - //spatial check + if (abs(k) < 3) // in ns units + + //spatial check { //is it this cluster or another at the same time? //could I use FTOA to avoid this? - // check if it is within +5 pixels away cluster boundary - if ((myhits[myinfo->ci].x <= myclusters[i].maxx+CLUSTERADD) && - (myhits[myinfo->ci].x >= myclusters[i].minx-CLUSTERADD) && - (myhits[myinfo->ci].y <= myclusters[i].maxy+CLUSTERADD) && + // check if it is within +5 pixels away cluster boundary + if ((myhits[myinfo->ci].x <= myclusters[i].maxx+CLUSTERADD) && + (myhits[myinfo->ci].x >= myclusters[i].minx-CLUSTERADD) && + (myhits[myinfo->ci].y <= myclusters[i].maxy+CLUSTERADD) && (myhits[myinfo->ci].y >= myclusters[i].miny-CLUSTERADD)) { - // update cluster information + // update cluster information myclusters[i].totalpix+=1; - myclusters[i].runningX+=myhits[myinfo->ci].myTOT*myhits[myinfo->ci].x; + myclusters[i].runningX+=myhits[myinfo->ci].myTOT*myhits[myinfo->ci].x; myclusters[i].runningY+=myhits[myinfo->ci].myTOT*myhits[myinfo->ci].y; myclusters[i].totalTOT+=myhits[myinfo->ci].myTOT; - // update cluster boundary as necessary - if (myhits[myinfo->ci].x < myclusters[i].minx) + // update cluster boundary as necessary + if (myhits[myinfo->ci].x < myclusters[i].minx) { myclusters[i].minx=myhits[myinfo->ci].x; } diff --git a/sophiread_display/hit_worker.h b/sophiread_display/hit_worker.h index e9ab380..a2513c1 100755 --- a/sophiread_display/hit_worker.h +++ b/sophiread_display/hit_worker.h @@ -14,10 +14,10 @@ class Hit_worker Hit_worker(struct newRawPacket *myrawpacket, struct hitinfo *myinfo, double *my2dhisto, unsigned int *mytofhisto); ~Hit_worker(void); - // shared memory among threads + // shared memory among threads struct cluster *myclusters; // an array of clusters - struct newRawPacket *myhits; // an array of hits - struct hitinfo *myinfo; // file info + struct newRawPacket *myhits; // an array of hits + struct hitinfo *myinfo; // file info double *my2dhisto; // 2D array of counts/TOT unsigned int *mytofhisto; // an array of ToF?? diff --git a/sophiread_display/mainwindow.cpp b/sophiread_display/mainwindow.cpp index 8f84455..48c1dd3 100755 --- a/sophiread_display/mainwindow.cpp +++ b/sophiread_display/mainwindow.cpp @@ -8,7 +8,7 @@ #include #include -// Custom class of color map +// Custom class of color map class ColorMap: public QwtLinearColorMap { public: @@ -23,14 +23,14 @@ class ColorMap: public QwtLinearColorMap }; -// read file to hit +// read file to hit int filetohits(QString filename, struct newRawPacket *myhits, struct hitinfo *myinfo, unsigned int *mytofhisto, QLabel *infobox) { char data[128]; // pixel hit data + TDC data, no need 128 bytes char inbytes[128]; // mostly to store data packet header, no need 128 bytes - int notempty=1; - int i; // store the number of bytes read for each hit event - int dwords; + int notempty=1; + int i; // store the number of bytes read for each hit event + int dwords; QString inname; int k; int n; @@ -45,26 +45,26 @@ int filetohits(QString filename, struct newRawPacket *myhits, struct hitinfo *my struct newRawPacket mynewraw; mytdc=0; -// Load data from raw file +// Load data from raw file FILE *infile; struct stat myfilestat; inname=filename.section("/",-1,-1); infobox->setText("reading file" + inname); infile=fopen(qPrintable(filename),"rb"); - fstat(fileno(infile),&myfilestat); + fstat(fileno(infile),&myfilestat); myinfo->bytesinfile=myfilestat.st_size; // store file size (hitinfo/myinfo) while(notempty) { i=fread(&inbytes[0],1,8,infile); // read 8 1-bytes data to inbytes[0] (8 bytes = 64 bits) - if (i==0) // if num of bytes read is 0, break - { // loop to read file + if (i==0) // if num of bytes read is 0, break + { // loop to read file notempty=0; break; } myinfo->bytesread+=i; // store bytes read (hitinfo/myinfo) - if (inbytes[0]=='T' && inbytes[1]=='P' && inbytes[2]=='X') // check for data packet header + if (inbytes[0]=='T' && inbytes[1]=='P' && inbytes[2]=='X') // check for data packet header { myinfo->chuckheaders+=1; // count number of data packet header (hitinfo/myinfo) @@ -72,19 +72,19 @@ int filetohits(QString filename, struct newRawPacket *myhits, struct hitinfo *my dwords=dwords >> 3; // data words is the number of bytes chunk? (>> 3 means divide by 8) /* ------------------------------------------------------------------------------------------------*/ // testing purpose - // dwords = 3 + // dwords = 3 /* ------------------------------------------------------------------------------------------------*/ for (k=0;kbytesread+=i; // increment number of bytes read (hitinfo/myinfo) - - if ((data[7] & 0xF0) == 0xb0) //Chip data: ToA and ToT timestamp packet, x, y + + if ((data[7] & 0xF0) == 0xb0) //Chip data: ToA and ToT timestamp packet, x, y { /* ------------------------------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------------------------------*/ - // char data[128] + // char data[128] // 0: 0-7 bits // 1: 8-15 bits // 2: 16-23 bits @@ -93,28 +93,28 @@ int filetohits(QString filename, struct newRawPacket *myhits, struct hitinfo *my // 5: 40-47 bits // 6: 48-55 bits // 7: 56-63 bits - // little endian: the least significant value in the sequence is stored first + // little endian: the least significant value in the sequence is stored first /* ------------------------------------------------------------------------------------------------*/ spdrtime=(unsigned short *)(&data[0]); // spider time (16 bits) nTOT=(unsigned short *)(&data[2]); // ToT (10 bits) nTOA=(unsigned int *)(&data[3]); // ToA (14 bits) mynewraw.myFToA= *nTOT & 0xF; // FToA (4 bits) - mynewraw.myTOT=(*nTOT >> 4) & 0x3FF; - mynewraw.myTOA=(*nTOA >> 6) & 0x3FFF; - + mynewraw.myTOT=(*nTOT >> 4) & 0x3FF; + mynewraw.myTOA=(*nTOA >> 6) & 0x3FFF; + npixaddr=(unsigned int *)(&data[4]); // PixAddr (16 bits) - pixaddr=(*npixaddr >> 12) & 0xFFFF; + pixaddr=(*npixaddr >> 12) & 0xFFFF; dcol=((pixaddr & 0xFE00)>>8); spix=((pixaddr & 0x1F8) >>1); - pix=pixaddr & 0x7; + pix=pixaddr & 0x7; mynewraw.x=dcol+(pix >> 2); // x coordinate - mynewraw.y=spix+(pix & 0x3); // y coordinate + mynewraw.y=spix+(pix & 0x3); // y coordinate + + mynewraw.spdrtime=16384*(*spdrtime)+mynewraw.myTOA; // not the same as global_timestamp + mynewraw.tof=mynewraw.spdrtime-mytdc; // supposedly for time-of-flight - mynewraw.spdrtime=16384*(*spdrtime)+mynewraw.myTOA; // not the same as global_timestamp - mynewraw.tof=mynewraw.spdrtime-mytdc; // supposedly for time-of-flight - - itof=(int)(mynewraw.tof*0.25); // tof in seconds + itof=(int)(mynewraw.tof*0.25); // tof in seconds // not sure why the tofhist is updated this way...?? if (itof 250 && mynewraw.x < 425 && mynewraw.y > 125 && mynewraw.y < 325) @@ -140,15 +140,15 @@ int filetohits(QString filename, struct newRawPacket *myhits, struct hitinfo *my myinfo->total_hits+=1; - n=(myinfo->pi+1) & HSIZEM1; // get the next slot n = (pi+1) & HSIZEM1 + n=(myinfo->pi+1) & HSIZEM1; // get the next slot n = (pi+1) & HSIZEM1 - while (n==myinfo->ci) // let the program sleep for 100 usec - { // while the next slot n == ci + while (n==myinfo->ci) // let the program sleep for 100 usec + { // while the next slot n == ci usleep(100); } - if (n != myinfo->ci) // copy raw data to myhits - { // otherwise the pi = n + if (n != myinfo->ci) // copy raw data to myhits + { // otherwise the pi = n memcpy(&myhits[myinfo->pi],&mynewraw,sizeof(mynewraw)); myinfo->pi=n; } @@ -157,7 +157,7 @@ int filetohits(QString filename, struct newRawPacket *myhits, struct hitinfo *my { // unclear what is going on here myinfo->numTDCs+=1; tdclast=(unsigned long *)(&data[0]); - mytdc=(((*tdclast) >> 12) & 0x3fffffff); + mytdc=(((*tdclast) >> 12) & 0x3fffffff); } else if ((data[7] & 0xF0) == 0x40) // for controls