mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-21 09:08:00 +02:00
Compare commits
71 Commits
jf_h5reade
...
dev/roi_pe
Author | SHA1 | Date | |
---|---|---|---|
953c3f1587 | |||
230d43d1fe | |||
24f878a17b | |||
aac3f8904b | |||
8dd9165078 | |||
982383980f | |||
56aa96e9b5 | |||
06f06cfbf4 | |||
e97eae88bc | |||
925176b661 | |||
e4f329466c | |||
d19fe8b66a | |||
f4345a91a1 | |||
ec67617e5c | |||
bab6a5e9e1 | |||
f84454fbc1 | |||
c92830f854 | |||
e77fd8d85d | |||
cd0fb1b7bb | |||
50ab20317d | |||
d0a946a919 | |||
ed142aa34e | |||
1227574590 | |||
3ac7b579a0 | |||
feb1b0868e | |||
6d2f34ef1d | |||
b36a5b9933 | |||
d8ce5eabb8 | |||
ceecb0ca27 | |||
ac3670dcd2 | |||
1c7bc61531 | |||
58245a62a4 | |||
a464262558 | |||
995d3e0034 | |||
90d57cb6a9 | |||
30eab42294 | |||
1d0eeea7ee | |||
d7c012d306 | |||
1665937540 | |||
9343e3c667 | |||
b4c8fc1765 | |||
3ad4e01a5d | |||
015b4add65 | |||
9051dae787 | |||
68bdd75c9c | |||
a53873b695 | |||
77a39b4ef2 | |||
64be8b1e89 | |||
68bd9fb4f7 | |||
0d5d851585 | |||
eb3d51d20c | |||
9f4298ac15 | |||
fb79ba768c | |||
7bc48e3111 | |||
53b90d92d7 | |||
fb6ef8b818 | |||
8bb9de0de1 | |||
451b50dfed | |||
22f2662e3b | |||
ce3f555c08 | |||
dedab6010d | |||
62a5fda33f | |||
5073769403 | |||
aabec193ff | |||
d4a1044fce | |||
dca0edcfcc | |||
5a24a79bf7 | |||
91f9c4fa83 | |||
3940d6f56e | |||
f09879a46c | |||
adf0124ea3 |
64
.github/workflows/build_wheel.yml
vendored
Normal file
64
.github/workflows/build_wheel.yml
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
name: Build wheel
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
|
||||
jobs:
|
||||
build_wheels:
|
||||
name: Build wheels on ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest,]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build wheels
|
||||
run: pipx run cibuildwheel==2.23.0
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
build_sdist:
|
||||
name: Build source distribution
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Build sdist
|
||||
run: pipx run build --sdist
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cibw-sdist
|
||||
path: dist/*.tar.gz
|
||||
|
||||
upload_pypi:
|
||||
needs: [build_wheels, build_sdist]
|
||||
runs-on: ubuntu-latest
|
||||
environment: pypi
|
||||
permissions:
|
||||
id-token: write
|
||||
if: github.event_name == 'release' && github.event.action == 'published'
|
||||
# or, alternatively, upload to PyPI on every tag starting with 'v' (remove on: release above to use this)
|
||||
# if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
# unpacks all CIBW artifacts into dist/
|
||||
pattern: cibw-*
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
|
||||
- uses: pypa/gh-action-pypi-publish@release/v1
|
@ -21,6 +21,7 @@ if (${CMAKE_VERSION} VERSION_GREATER "3.24")
|
||||
endif()
|
||||
include(cmake/project_version.cmake)
|
||||
include(cmake/SlsAddFlag.cmake)
|
||||
include(cmake/helpers.cmake)
|
||||
|
||||
|
||||
|
||||
@ -193,11 +194,9 @@ find_package(ClangFormat)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "No build type selected, default to Release")
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type (default Release)" FORCE)
|
||||
endif()
|
||||
|
||||
default_build_type("Release")
|
||||
set_std_fs_lib()
|
||||
message(STATUS "Extra linking to fs lib:${STD_FS_LIB}")
|
||||
|
||||
#Enable LTO if available
|
||||
include(CheckIPOSupported)
|
||||
|
@ -25,7 +25,9 @@ mark_as_advanced(
|
||||
ClangFormat_BIN)
|
||||
|
||||
if(ClangFormat_FOUND)
|
||||
exec_program(${ClangFormat_BIN} ${CMAKE_CURRENT_SOURCE_DIR} ARGS --version OUTPUT_VARIABLE CLANG_VERSION_TEXT)
|
||||
execute_process(COMMAND ${ClangFormat_BIN} --version
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE CLANG_VERSION_TEXT)
|
||||
string(REGEX MATCH "([0-9]+)\\.[0-9]+\\.[0-9]+" CLANG_VERSION ${CLANG_VERSION_TEXT})
|
||||
if((${CLANG_VERSION} GREATER "9") OR (${CLANG_VERSION} EQUAL "9"))
|
||||
# A CMake script to find all source files and setup clang-format targets for them
|
||||
|
46
cmake/helpers.cmake
Normal file
46
cmake/helpers.cmake
Normal file
@ -0,0 +1,46 @@
|
||||
function(default_build_type val)
|
||||
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "No build type selected, default to Release")
|
||||
set(CMAKE_BUILD_TYPE ${val} CACHE STRING "Build type (default ${val})" FORCE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(set_std_fs_lib)
|
||||
# from pybind11
|
||||
# Check if we need to add -lstdc++fs or -lc++fs or nothing
|
||||
if(DEFINED CMAKE_CXX_STANDARD AND CMAKE_CXX_STANDARD LESS 17)
|
||||
set(STD_FS_NO_LIB_NEEDED TRUE)
|
||||
elseif(MSVC)
|
||||
set(STD_FS_NO_LIB_NEEDED TRUE)
|
||||
else()
|
||||
file(
|
||||
WRITE ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||
"#include <filesystem>\nint main(int argc, char ** argv) {\n std::filesystem::path p(argv[0]);\n return p.string().length();\n}"
|
||||
)
|
||||
try_compile(
|
||||
STD_FS_NO_LIB_NEEDED ${CMAKE_CURRENT_BINARY_DIR}
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||
COMPILE_DEFINITIONS -std=c++17)
|
||||
try_compile(
|
||||
STD_FS_NEEDS_STDCXXFS ${CMAKE_CURRENT_BINARY_DIR}
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||
COMPILE_DEFINITIONS -std=c++17
|
||||
LINK_LIBRARIES stdc++fs)
|
||||
try_compile(
|
||||
STD_FS_NEEDS_CXXFS ${CMAKE_CURRENT_BINARY_DIR}
|
||||
SOURCES ${CMAKE_CURRENT_BINARY_DIR}/main.cpp
|
||||
COMPILE_DEFINITIONS -std=c++17
|
||||
LINK_LIBRARIES c++fs)
|
||||
endif()
|
||||
|
||||
if(${STD_FS_NEEDS_STDCXXFS})
|
||||
set(STD_FS_LIB stdc++fs PARENT_SCOPE)
|
||||
elseif(${STD_FS_NEEDS_CXXFS})
|
||||
set(STD_FS_LIB c++fs PARENT_SCOPE)
|
||||
elseif(${STD_FS_NO_LIB_NEEDED})
|
||||
set(STD_FS_LIB "" PARENT_SCOPE)
|
||||
else()
|
||||
message(WARNING "Unknown C++17 compiler - not passing -lstdc++fs")
|
||||
set(STD_FS_LIB "")
|
||||
endif()
|
||||
endfunction()
|
@ -28,7 +28,8 @@ requirements:
|
||||
- libgl-devel # [linux]
|
||||
- libtiff
|
||||
- zlib
|
||||
|
||||
- expat
|
||||
|
||||
run:
|
||||
- libstdcxx-ng
|
||||
- libgcc-ng
|
||||
@ -57,6 +58,7 @@ outputs:
|
||||
- {{ compiler('c') }}
|
||||
- {{compiler('cxx')}}
|
||||
- {{ pin_subpackage('slsdetlib', exact=True) }}
|
||||
|
||||
|
||||
run:
|
||||
- {{ pin_subpackage('slsdetlib', exact=True) }}
|
||||
|
@ -42,6 +42,7 @@ set(SPHINX_SOURCE_FILES
|
||||
src/pyexamples.rst
|
||||
src/pyPatternGenerator.rst
|
||||
src/servers.rst
|
||||
src/multidet.rst
|
||||
src/receiver_api.rst
|
||||
src/result.rst
|
||||
src/type_traits.rst
|
||||
|
@ -6,6 +6,8 @@ Usage
|
||||
|
||||
The syntax is *'[detector index]-[module index]:[command]'*, where the indices are by default '0', when not specified.
|
||||
|
||||
.. _cl-module-index-label:
|
||||
|
||||
Module index
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Modules are indexed based on their order in the hostname command. They are used to configure a specific module within a detector and are followed by a ':' in syntax.
|
||||
|
@ -28,6 +28,12 @@ Welcome to slsDetectorPackage's documentation!
|
||||
receiver_api
|
||||
examples
|
||||
|
||||
.. toctree::
|
||||
:caption: how to
|
||||
:maxdepth: 2
|
||||
|
||||
multidet
|
||||
|
||||
.. toctree::
|
||||
:caption: Python API
|
||||
:maxdepth: 2
|
||||
@ -81,8 +87,9 @@ Welcome to slsDetectorPackage's documentation!
|
||||
:caption: Receiver
|
||||
:maxdepth: 2
|
||||
|
||||
receivers
|
||||
slsreceiver
|
||||
receivers
|
||||
|
||||
|
||||
.. toctree::
|
||||
:caption: Receiver Files
|
||||
|
@ -6,18 +6,33 @@
|
||||
Installation
|
||||
===============
|
||||
|
||||
One can either install pre-built binaries using conda or build from source.
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 2
|
||||
:backlinks: top
|
||||
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
The ``slsDetectorPackage`` provides core detector software implemented in C++, along with Python bindings packaged as the ``slsdet`` Python extension module. Choose the option that best fits your environment and use case.
|
||||
|
||||
:ref:`conda pre-built binaries`:
|
||||
Install pre-built binaries for the C++ client, receiver, GUI and the Python API (``slsdet``), simplifying setup across platforms.
|
||||
|
||||
:ref:`pip`:
|
||||
Install only the Python extension module, either by downloading the pre-built library from PyPI or by building the extension locally from source. Available only from v9.2.0 onwards.
|
||||
|
||||
:ref:`build from source`:
|
||||
Compile the entire package yourself, including both the C++ core and the Python bindings, for maximum control and customization. However, make sure that you have the :doc:`dependencies <../dependencies>` installed. If installing using conda, conda will manage the dependencies. Avoid installing packages with pip and conda simultaneously.
|
||||
|
||||
|
||||
|
||||
.. warning ::
|
||||
|
||||
Before building from source make sure that you have the
|
||||
:doc:`dependencies <../dependencies>` installed. If installing using conda, conda will
|
||||
manage the dependencies. Avoid also installing packages with pip.
|
||||
|
||||
.. _conda pre-built binaries:
|
||||
|
||||
|
||||
Install binaries using conda
|
||||
----------------------------------
|
||||
1. Install pre-built binaries using conda (Recommended)
|
||||
--------------------------------------------------------
|
||||
|
||||
Conda is not only useful to manage python environments but can also
|
||||
be used as a user space package manager. Dates in the tag (for eg. 2020.07.23.dev0)
|
||||
@ -63,12 +78,29 @@ We have four different packages available:
|
||||
conda search moenchzmq
|
||||
|
||||
|
||||
.. _pip:
|
||||
|
||||
2. Pip
|
||||
-------
|
||||
The Python extension module ``slsdet`` can be installed using pip. This is available from v9.2.0 onwards.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#Install the Python extension module from PyPI
|
||||
pip install slsdet
|
||||
|
||||
# or install the python extension locally from source
|
||||
git clone https://github.com/slsdetectorgroup/slsDetectorPackage.git --branch 9.2.0
|
||||
cd slsDetectorPackage
|
||||
pip install .
|
||||
|
||||
|
||||
Build from source
|
||||
----------------------
|
||||
.. _build from source:
|
||||
|
||||
1. Download Source Code from github
|
||||
3. Build from source
|
||||
-------------------------
|
||||
|
||||
3.1. Download Source Code from github
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: bash
|
||||
@ -83,12 +115,12 @@ Build from source
|
||||
|
||||
|
||||
|
||||
2. Build from Source
|
||||
3.2. Build from Source
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
One can either build using cmake or use the in-built cmk.sh script.
|
||||
|
||||
Build using CMake
|
||||
3.2.1. Build using CMake
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: bash
|
||||
@ -135,7 +167,7 @@ Example cmake options Comment
|
||||
For v7.x.x of slsDetectorPackage and older, refer :ref:`zeromq notes for cmake option to hint library location. <zeromq for different slsDetectorPackage versions>`
|
||||
|
||||
|
||||
Build using in-built cmk.sh script
|
||||
3.2.2. Build using in-built cmk.sh script
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@ -185,8 +217,8 @@ Build using in-built cmk.sh script
|
||||
For v7.x.x of slsDetectorPackage and older, refer :ref:`zeromq notes for cmk script option to hint library location. <zeromq for different slsDetectorPackage versions>`
|
||||
|
||||
|
||||
Build on old distributions
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
3.3. Build on old distributions using conda
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If your linux distribution doesn't come with a C++11 compiler (gcc>4.8) then
|
||||
it's possible to install a newer gcc using conda and build the slsDetectorPackage
|
||||
@ -210,7 +242,7 @@ using this compiler
|
||||
|
||||
|
||||
|
||||
Build slsDetectorGui (Qt5)
|
||||
3.4. Build slsDetectorGui (Qt5)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
1. Using pre-built binary on conda
|
||||
@ -271,7 +303,7 @@ Build slsDetectorGui (Qt5)
|
||||
|
||||
|
||||
|
||||
Build this documentation
|
||||
3.5. Build this documentation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The documentation for the slsDetectorPackage is build using a combination
|
||||
@ -294,8 +326,8 @@ is to use conda
|
||||
make rst # rst only, saves time in case the API did not change
|
||||
|
||||
|
||||
Pybind and Zeromq
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
4. Pybind and Zeromq
|
||||
-------------------------
|
||||
|
||||
.. _pybind for different slsDetectorPackage versions:
|
||||
|
||||
|
228
docs/src/multidet.rst
Normal file
228
docs/src/multidet.rst
Normal file
@ -0,0 +1,228 @@
|
||||
Using multiple detectors
|
||||
==========================
|
||||
|
||||
The slsDetectorPackage supports using several detectors on the same computer.
|
||||
This can either be two users, that need to use the same computer without interfering
|
||||
with each other, or the same user that wants to use multiple detectors at the same time.
|
||||
The detectors in turn can consist of multiple modules. For example, a 9M Jungfrau detector
|
||||
consists of 18 modules which typically are addressed at once as a single detector.
|
||||
|
||||
.. note ::
|
||||
|
||||
To address a single module of a multi-module detector you can use the module index.
|
||||
|
||||
- Command line: :ref:`cl-module-index-label`
|
||||
- Python: :ref:`py-module-index-label`
|
||||
|
||||
|
||||
Coming back to multiple detectors we have two tools to our disposal:
|
||||
|
||||
#. Detector index
|
||||
#. The SLSDETNAME environment variable
|
||||
|
||||
They can be used together or separately depending on the use case.
|
||||
|
||||
Detector index
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When configuring a detector you can specify a detector index. The default is 0.
|
||||
|
||||
**Command line**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Given that we have two detectors (my-det and my-det2) that we want to use,
|
||||
# we can configure them with different indices.
|
||||
|
||||
# Configure the first detector with index 0
|
||||
$ sls_detector_put hostname my-det
|
||||
|
||||
# Set number of frames for detector 0 to 10
|
||||
$ sls_detector_put frames 10
|
||||
|
||||
|
||||
#
|
||||
#Configure the second detector with index 1 (notice the 1- before hostname)
|
||||
$ sls_detector_put 1-hostname my-det2
|
||||
|
||||
|
||||
# Further configuration
|
||||
...
|
||||
|
||||
# Set number of frames for detector 1 to 19
|
||||
$ sls_detector_put 1-frames 19
|
||||
|
||||
# Note that if we call sls_detector_get without specifying the index,
|
||||
# it will return the configuration of detector 0
|
||||
$ sls_detector_get frames
|
||||
10
|
||||
|
||||
The detector index is added to the name of the shared memory segment, so in this case
|
||||
the shared memory segments would be:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
||||
#First detector
|
||||
/dev/shm/slsDetectorPackage_detector_0
|
||||
/dev/shm/slsDetectorPackage_detector_0_module_0
|
||||
|
||||
#Second detector
|
||||
/dev/shm/slsDetectorPackage_detector_1
|
||||
/dev/shm/slsDetectorPackage_detector_1_module_0
|
||||
|
||||
|
||||
**Python**
|
||||
|
||||
The main difference between the command line and the Python API is that you set the index
|
||||
when you create the detector object and you don't have to repeat it for every call.
|
||||
|
||||
The C++ API works int the same way.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from slsdet import Detector
|
||||
|
||||
|
||||
# The same can be achieved in Python by creating a detector object with an index.
|
||||
# Again we have two detectors (my-det and my-det2) that we want to use:
|
||||
|
||||
# Configure detector with index 0
|
||||
d = Detector()
|
||||
|
||||
# If the detector has already been configured and has a shared memory
|
||||
# segment, you can omit setting the hostname again
|
||||
d.hostname = 'my-det'
|
||||
|
||||
#Further configuration
|
||||
...
|
||||
|
||||
# Configure a second detector with index 1
|
||||
d2 = Detector(1)
|
||||
d2.hostname = 'my-det2'
|
||||
|
||||
d.frames = 10
|
||||
d2.frames = 19
|
||||
|
||||
|
||||
$SLSDETNAME
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To avoid interfering with other users on shared PCs it is best to always set the SLSDETNAME environmental variable.
|
||||
Imagining a fictive user: Anna, we can set SLSDETNAME from the shell before configuring the detector:
|
||||
|
||||
**Command line**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Set the SLSDETNAME variable
|
||||
$ export SLSDETNAME=Anna
|
||||
|
||||
# You can check that it is set
|
||||
$ echo $SLSDETNAME
|
||||
Anna
|
||||
|
||||
# Now configures a detector with index 0 and prefixed with the name Anna
|
||||
# /dev/shm/slsDetectorPackage_detector_0_Anna
|
||||
$ sls_detector_put hostname my-det
|
||||
|
||||
|
||||
.. tip ::
|
||||
|
||||
Set SLSDETNAME in your .bashrc in order to not forget it when opening a new terminal.
|
||||
|
||||
|
||||
**Python**
|
||||
|
||||
With python the best way is to set the SLSDETNAME from the command line before starting the python interpreter.
|
||||
|
||||
Bash:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ export SLSDETNAME=Anna
|
||||
|
||||
Python:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from slsdet import Detector
|
||||
|
||||
# Now configures a detector with index 0 and prefixed with the name Anna
|
||||
# /dev/shm/slsDetectorPackage_detector_0_Anna
|
||||
d = Detector()
|
||||
d.hostname = 'my-det'
|
||||
|
||||
You can also set SLSDETNAME from within the Python interpreter, but you have to be aware that it will only
|
||||
affect the current process and not the whole shell session.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import os
|
||||
os.environ['SLSDETNAME'] = 'Anna'
|
||||
|
||||
# You can check that it is set
|
||||
print(os.environ['SLSDETNAME']) # Output: Anna
|
||||
|
||||
#Now SLSDETNAME is set to Anna but as soon as you exit the python interpreter
|
||||
# it will not be set anymore
|
||||
|
||||
.. note ::
|
||||
|
||||
Python has two ways of reading environment variables: `**os.environ**` as shown above which throws a
|
||||
KeyError if the variable is not set and `os.getenv('SLSDETNAME')` which returns None if the variable is not set.
|
||||
|
||||
For more details see the official python documentation on: https://docs.python.org/3/library/os.html#os.environ
|
||||
|
||||
|
||||
Checking for other detectors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
If using shared accounts on a shared computer (which you anyway should not do), it is good practice to check
|
||||
if there are other detectors configured by other users before configuring your own detector.
|
||||
|
||||
You can do this by listing the files in the shared memory directory `/dev/shm/` that start with `sls`. In this
|
||||
example we can see that two single module detectors are configured one with index 0 and one with index 1.
|
||||
SLSDETNAME is set to `Anna` so it makes sense to assume that she is the user that configured these detectors.
|
||||
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# List the files in /dev/shm that starts with sls
|
||||
$ ls /dev/shm/sls*
|
||||
/dev/shm/slsDetectorPackage_detector_0_Anna
|
||||
/dev/shm/slsDetectorPackage_detector_0_module_0_Anna
|
||||
/dev/shm/slsDetectorPackage_detector_1_Anna
|
||||
/dev/shm/slsDetectorPackage_detector_1_module_0_Anna
|
||||
|
||||
We also provide a command: user, which gets information about the shared memory segment that
|
||||
the client points to without doing any changes.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
#in this case 3 simulated Mythen3 modules
|
||||
$ sls_detector_get user
|
||||
user
|
||||
Hostname: localhost+localhost+localhost+
|
||||
Type: Mythen3
|
||||
PID: 1226078
|
||||
User: l_msdetect
|
||||
Date: Mon Jun 2 05:46:20 PM CEST 2025
|
||||
|
||||
|
||||
Other considerations
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The shared memory is not the only way to interfere with other users. You also need to make sure that you are not
|
||||
using the same:
|
||||
|
||||
* rx_tcpport
|
||||
* Unique combination of udp_dstip and udp_dstport
|
||||
* rx_zmqport
|
||||
* zmqport
|
||||
|
||||
.. attention ::
|
||||
|
||||
The computer that you are using need to have enough resources to run multiple detectors at the same time.
|
||||
This includes CPU and network bandwidth. Please coordinate with the other users!
|
||||
|
@ -123,6 +123,47 @@ in a large detector.
|
||||
# Set exposure time for module 1, 5 and 7
|
||||
d.setExptime(0.1, [1,5,7])
|
||||
|
||||
|
||||
|
||||
.. _py-module-index-label:
|
||||
|
||||
----------------------------------
|
||||
Accessing individual modules
|
||||
----------------------------------
|
||||
|
||||
Using the C++ like API you can access individual modules in a large detector
|
||||
by passing in the module index as an argument to the function.
|
||||
|
||||
::
|
||||
|
||||
# Read the UDP destination port for all modules
|
||||
>>> d.getDestinationUDPPort()
|
||||
[50001, 50002, 50003]
|
||||
|
||||
|
||||
# Read it for module 0 and 1
|
||||
>>> d.getDestinationUDPPort([0, 1])
|
||||
[50001, 50002]
|
||||
|
||||
>>> d.setDestinationUDPPort(50010, 1)
|
||||
>>> d.getDestinationUDPPort()
|
||||
[50001, 50010, 50003]
|
||||
|
||||
From the more pythonic API there is no way to read from only one module but you can read
|
||||
and then use list slicing to get the values for the modules you are interested in.
|
||||
|
||||
::
|
||||
|
||||
>>> d.udp_dstport
|
||||
[50001, 50010, 50003]
|
||||
>>> d.udp_dstport[0]
|
||||
50001
|
||||
|
||||
#For some but not all properties you can also pass in a dictionary with module index as key
|
||||
>>> ip = IpAddr('127.0.0.1')
|
||||
>>> d.udp_dstip = {1:ip}
|
||||
|
||||
|
||||
--------------------
|
||||
Finding functions
|
||||
--------------------
|
||||
|
@ -1,25 +1,25 @@
|
||||
Receivers
|
||||
Custom Receiver
|
||||
=================
|
||||
|
||||
Receiver processes can be run on same or different machines as the client, receives the data from the detector (via UDP packets).
|
||||
When using the slsReceiver/ slsMultiReceiver, they can be further configured by the client control software (via TCP/IP) to set file name, file path, progress of acquisition etc.
|
||||
The receiver essentially listens to UDP data packets sent out by the detector.
|
||||
|
||||
To know more about detector receiver setup in the config file, please check out :ref:`the detector-receiver UDP configuration in the config file<detector udp header config>` and the :ref:`detector udp format<detector udp header>`.
|
||||
|
||||
|
||||
To know more about detector receiver configuration, please check out :ref:`detector udp header and udp commands in the config file <detector udp header>`
|
||||
| Please note the following when using a custom receiver:
|
||||
|
||||
Custom Receiver
|
||||
----------------
|
||||
* **udp_dstmac** must be configured in the config file. This parameter is not required when using an in-built receiver.
|
||||
|
||||
| When using custom receiver with our package, ensure that **udp_dstmac** is also configured in the config file. This parameter is not required when using slsReceiver.
|
||||
* Cannot use "auto" for **udp_dstip**.
|
||||
|
||||
| Cannot use "auto" for **udp_dstip**.
|
||||
* No **rx_** commands in the config file. These commands are for configuring the slsReceiver.
|
||||
|
||||
| Also ensure that there are no **rx_** commands in the config file. These commands are for configuring the slsReceiver.
|
||||
|
||||
|
||||
The main difference is the lack of **rx_** commands or file commands (eg. **f**write, **f**path) and the **udp_dstmac** is required in config file.
|
||||
|
||||
Example of a custom receiver config file
|
||||
|
||||
* The main difference is the lack of **rx_** commands or file commands (eg. fwrite, fpath) and the udp_dstmac is required in config file.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# detector hostname
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. _Detector Server Upgrade:
|
||||
|
||||
Upgrade
|
||||
========
|
||||
|
||||
|
@ -1,16 +1,55 @@
|
||||
slsReceiver/ slsMultiReceiver
|
||||
In-built Receiver
|
||||
================================
|
||||
|
||||
| One has to start the slsReceiver before loading config file or using any receiver commands (prefix: **rx_** )
|
||||
|
||||
|
||||
The receiver essentially listens to UDP data packets sent out by the detector. It's main features are:
|
||||
|
||||
- **Listening**: Receives UDP data from the detector.
|
||||
- **Writing to File**: Optionally writes received data to disk.
|
||||
- **Streaming via ZMQ**: Optionally streams out the data using ZeroMQ.
|
||||
|
||||
Each of these operations runs asynchronously and in parallel for each UDP port.
|
||||
|
||||
|
||||
.. note ::
|
||||
|
||||
* Can be run on the same or different machine as the client.
|
||||
* Can be configured by the client. (set file name/ discard policy, get progress etc.)
|
||||
* Has to be started before the client runs any receiver specific command.
|
||||
|
||||
|
||||
Receiver Variants
|
||||
-----------------
|
||||
There are three main receiver types. How to start them is described :ref:`below<Starting up the Receiver>`.
|
||||
|
||||
+----------------------+--------------------+-----------------------------------------+--------------------------------+
|
||||
| Receiver Type | slsReceiver | slsMultiReceiver |slsFrameSynchronizer |
|
||||
+======================+====================+=========================================+================================+
|
||||
| Modules Supported | 1 | Multiple | Multiple |
|
||||
+----------------------+--------------------+-----------------------------------------+--------------------------------+
|
||||
| Internal Architecture| Threads per porttt | Multiple child processes of slsReceiver | Multi-threading of slsReceiver |
|
||||
+----------------------+--------------------+-----------------------------------------+--------------------------------+
|
||||
| ZMQ Streaming | Disabled by default| Disabled by default | Enabled, not optional |
|
||||
+----------------------+--------------------+-----------------------------------------+--------------------------------+
|
||||
| ZMQ Synchronization | No | No | Yes, across ports |
|
||||
+----------------------+--------------------+-----------------------------------------+--------------------------------+
|
||||
| Image Reconstruction | No | No | No |
|
||||
+----------------------+--------------------+-----------------------------------------+--------------------------------+
|
||||
|
||||
|
||||
|
||||
|
||||
.. _Starting up the Receiver:
|
||||
|
||||
Starting up the Receiver
|
||||
-------------------------
|
||||
For a Single Module
|
||||
.. code-block:: bash
|
||||
|
||||
slsReceiver # default port 1954
|
||||
|
||||
# default port 1954
|
||||
slsReceiver
|
||||
|
||||
# custom port 2012
|
||||
slsReceiver -t2012
|
||||
slsReceiver -t2012 # custom port 2012
|
||||
|
||||
|
||||
For Multiple Modules
|
||||
@ -18,57 +57,66 @@ For Multiple Modules
|
||||
|
||||
# each receiver (for each module) requires a unique tcp port (if all on same machine)
|
||||
|
||||
# using slsReceiver in multiple consoles
|
||||
# option 1 (one for each module)
|
||||
slsReceiver
|
||||
slsReceiver -t1955
|
||||
|
||||
# slsMultiReceiver [starting port] [number of receivers]
|
||||
# option 2
|
||||
slsMultiReceiver 2012 2
|
||||
|
||||
# slsMultiReceiver [starting port] [number of receivers] [print each frame header for debugging]
|
||||
slsMultiReceiver 2012 2 1
|
||||
# option 3
|
||||
slsFrameSynchronizer 2012 2
|
||||
|
||||
|
||||
|
||||
Client Commands
|
||||
-----------------
|
||||
|
||||
| One can remove **udp_dstmac** from the config file, as the slsReceiver fetches this from the **udp_ip**.
|
||||
* Client commands to the receiver begin with **rx_** or **f_** (file commands).
|
||||
|
||||
| One can use "auto" for **udp_dstip** if one wants to use default ip of **rx_hostname**.
|
||||
* **rx_hostname** has to be the first command to the receiver so the client knows which receiver process to communicate with.
|
||||
|
||||
| The first command to the receiver (**rx_** commands) should be **rx_hostname**. The following are the different ways to establish contact.
|
||||
* Can use 'auto' for **udp_dstip** if using 1GbE interface or the :ref:`virtual simulators<Virtual Detector Servers>`.
|
||||
|
||||
|
||||
To know more about detector receiver setup in the config file, please check out :ref:`the detector-receiver UDP configuration in the config file<detector udp header config>` and the :ref:`detector udp format<detector udp header>`.
|
||||
|
||||
|
||||
The following are the different ways to establish contact using **rx_hostname** command.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# default receiver tcp port (1954)
|
||||
# ---single module---
|
||||
|
||||
# default receiver port at 1954
|
||||
rx_hostname xxx
|
||||
|
||||
# custom receiver port
|
||||
rx_hostname xxx:1957 # option 1
|
||||
|
||||
rx_tcpport 1957 # option 2
|
||||
rx_hostname xxx
|
||||
|
||||
# custom receiver port
|
||||
rx_hostname xxx:1957
|
||||
|
||||
# custom receiver port
|
||||
rx_tcpport 1954
|
||||
rx_hostname xxx
|
||||
# ---multi module---
|
||||
|
||||
# multi modules with custom ports
|
||||
rx_hostname xxx:1955+xxx:1956+
|
||||
|
||||
|
||||
# multi modules using increasing tcp ports when using multi detector command
|
||||
# using increasing tcp ports
|
||||
rx_tcpport 1955
|
||||
rx_hostname xxx
|
||||
|
||||
# or specify multi modules with custom ports on same rxr pc
|
||||
0:rx_tcpport 1954
|
||||
# custom ports
|
||||
rx_hostname xxx:1955+xxx:1958+ # option 1
|
||||
|
||||
0:rx_tcpport 1954 # option 2
|
||||
1:rx_tcpport 1955
|
||||
2:rx_tcpport 1956
|
||||
rx_hostname xxx
|
||||
|
||||
# multi modules with custom ports on different rxr pc
|
||||
# custom ports on different receiver machines
|
||||
0:rx_tcpport 1954
|
||||
0:rx_hostname xxx
|
||||
1:rx_tcpport 1955
|
||||
1:rx_hostname yyy
|
||||
1:rx_hostname yyyrxr
|
||||
|
||||
|
||||
| Example commands:
|
||||
@ -91,6 +139,32 @@ Client Commands
|
||||
sls_detector_get -h rx_framescaught
|
||||
|
||||
|
||||
Example of a config file using in-built receiver
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# detector hostname
|
||||
hostname bchip052+bchip053+
|
||||
|
||||
# udp destination port (receiver)
|
||||
# sets increasing destination udp ports starting at 50004
|
||||
udp_dstport 50004
|
||||
|
||||
# udp destination ip (receiver)
|
||||
0:udp_dstip 10.0.1.100
|
||||
1:udp_dstip 10.0.2.100
|
||||
|
||||
# udp source ip (same subnet as udp_dstip)
|
||||
0:udp_srcip 10.0.1.184
|
||||
1:udp_srcip 10.0.2.184
|
||||
|
||||
# udp destination mac - not required (picked up from udp_dstip)
|
||||
#udp_dstmac 22:47:d5:48:ad:ef
|
||||
|
||||
# connects to receivers at increasing tcp port starting at 1954
|
||||
rx_hostname mpc3434
|
||||
# same as rx_hostname mpc3434:1954+mpc3434:1955+
|
||||
|
||||
|
||||
|
||||
Performance
|
||||
|
@ -1,4 +1,4 @@
|
||||
.. _detector udp header:
|
||||
.. _detector udp header config:
|
||||
|
||||
|
||||
Config file
|
||||
|
@ -1,4 +1,5 @@
|
||||
.. _Virtual Detector Servers:
|
||||
|
||||
Simulators
|
||||
===========
|
||||
|
||||
|
@ -13,5 +13,5 @@ slsDetectorPackage/8.0.2_rh7 stable cmake/3.15.5 Qt/5.12.10
|
||||
slsDetectorPackage/8.0.2_rh8 stable cmake/3.15.5 Qt/5.12.10
|
||||
slsDetectorPackage/9.0.0_rh8 stable cmake/3.15.5 Qt/5.12.10
|
||||
slsDetectorPackage/9.1.0_rh8 stable cmake/3.15.5 Qt/5.12.10
|
||||
|
||||
|
||||
slsDetectorPackage/9.1.1_rh8 stable cmake/3.15.5 Qt/5.12.10
|
||||
slsDetectorPackage/9.2.0_rh8 stable cmake/3.15.5 Qt/5.12.10
|
||||
|
@ -11,9 +11,13 @@ build-backend = "scikit_build_core.build"
|
||||
[project]
|
||||
name = "slsdet"
|
||||
dynamic = ["version"]
|
||||
dependencies = [
|
||||
"numpy",
|
||||
]
|
||||
|
||||
[tool.cibuildwheel]
|
||||
before-all = "uname -a"
|
||||
build = "cp{311,312,313}-manylinux_x86_64"
|
||||
|
||||
[tool.scikit-build.build]
|
||||
verbose = true
|
||||
|
@ -65,6 +65,9 @@ configure_file( scripts/test_virtual.py
|
||||
${CMAKE_BINARY_DIR}/test_virtual.py
|
||||
)
|
||||
|
||||
configure_file(scripts/frameSynchronizerPullSocket.py
|
||||
${CMAKE_BINARY_DIR}/bin/frameSynchronizerPullSocket.py COPYONLY)
|
||||
|
||||
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../VERSION
|
||||
${CMAKE_BINARY_DIR}/bin/slsdet/VERSION
|
||||
)
|
||||
|
@ -924,17 +924,6 @@ void init_det(py::module &m) {
|
||||
(void (Detector::*)(bool, sls::Positions)) &
|
||||
Detector::setRxArping,
|
||||
py::arg(), py::arg() = Positions{});
|
||||
CppDetectorApi.def("getIndividualRxROIs",
|
||||
(Result<defs::ROI>(Detector::*)(sls::Positions) const) &
|
||||
Detector::getIndividualRxROIs,
|
||||
py::arg());
|
||||
CppDetectorApi.def("getRxROI",
|
||||
(defs::ROI(Detector::*)() const) & Detector::getRxROI);
|
||||
CppDetectorApi.def(
|
||||
"setRxROI", (void (Detector::*)(const defs::ROI)) & Detector::setRxROI,
|
||||
py::arg());
|
||||
CppDetectorApi.def("clearRxROI",
|
||||
(void (Detector::*)()) & Detector::clearRxROI);
|
||||
CppDetectorApi.def(
|
||||
"getFileFormat",
|
||||
(Result<defs::fileFormat>(Detector::*)(sls::Positions) const) &
|
||||
|
@ -3,14 +3,14 @@
|
||||
#ifndef ANALOGDETECTOR_H
|
||||
#define ANALOGDETECTOR_H
|
||||
|
||||
#include <mutex>
|
||||
//#include <mutex>
|
||||
|
||||
#include "commonModeSubtractionNew.h"
|
||||
#include "ghostSummation.h"
|
||||
#include "pedestalSubtraction.h"
|
||||
#include "sls/tiffIO.h"
|
||||
#include "slsDetectorData.h"
|
||||
#include "slsInterpolation.h"
|
||||
#include "sls/tiffIO.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef ROOTSPECTRUM
|
||||
@ -90,8 +90,6 @@ template <class dataType> class analogDetector {
|
||||
ymin = 0;
|
||||
ymax = ny;
|
||||
fMode = ePedestal;
|
||||
dMode = eInterpolating;
|
||||
// std::cout << "dMode " << dMode << std::endl;
|
||||
thr = 0;
|
||||
myFile = NULL;
|
||||
#ifdef ROOTSPECTRUM
|
||||
@ -113,20 +111,15 @@ template <class dataType> class analogDetector {
|
||||
destructor. Deletes the pdestalSubtraction array and the image
|
||||
*/
|
||||
virtual ~analogDetector() {
|
||||
// std::cout << "#### Debug: Destructing analogDetector! ####"
|
||||
// << std::endl;
|
||||
for (int i = 0; i < ny; i++) {
|
||||
if (stat[i]) { delete[] stat[i]; stat[i] = nullptr; }
|
||||
// delete[] stat[i];
|
||||
delete[] stat[i];
|
||||
/* delete [] pedMean[i]; */
|
||||
/* delete [] pedVariance[i]; */
|
||||
}
|
||||
};
|
||||
/* delete [] pedMean; */
|
||||
/* delete [] pedVariance; */
|
||||
// delete[] stat;
|
||||
// delete[] image;
|
||||
if (stat) { delete[] stat; stat = nullptr; }
|
||||
if (image) { delete[] image; image = nullptr; }
|
||||
delete[] stat;
|
||||
delete[] image;
|
||||
#ifdef ROOTSPECTRUM
|
||||
delete hs;
|
||||
#ifdef ROOTCLUST
|
||||
@ -144,8 +137,6 @@ template <class dataType> class analogDetector {
|
||||
*/
|
||||
analogDetector(analogDetector *orig) {
|
||||
/* copy construction from orig*/
|
||||
// std::cout << "#### Debug: Calling analogDetector cloning method! ####"
|
||||
// << std::endl;
|
||||
det = orig->det;
|
||||
nx = orig->nx;
|
||||
ny = orig->ny;
|
||||
@ -161,8 +152,6 @@ template <class dataType> class analogDetector {
|
||||
thr = orig->thr;
|
||||
// nSigma=orig->nSigma;
|
||||
fMode = orig->fMode;
|
||||
dMode = orig->dMode;
|
||||
// std::cout << "dMode " << dMode << std::endl;
|
||||
myFile = orig->myFile;
|
||||
|
||||
stat = new pedestalSubtraction *[ny];
|
||||
@ -227,75 +216,12 @@ template <class dataType> class analogDetector {
|
||||
ghSum = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
constructor creating a deep copy of another analog detector
|
||||
\param other analog Detector structure to be copied
|
||||
*/
|
||||
analogDetector(const analogDetector &other)
|
||||
: det(other.det), nx(other.nx), ny(other.ny), dataSign(other.dataSign),
|
||||
iframe(other.iframe), gmap(other.gmap), id(other.id),
|
||||
xmin(other.xmin), xmax(other.xmax), ymin(other.ymin),
|
||||
ymax(other.ymax), thr(other.thr), fMode(other.fMode),
|
||||
dMode(other.dMode), myFile(NULL) {
|
||||
|
||||
// std::cout << "#### Debug: Calling analogDetector copy constructor! ####"
|
||||
// << std::endl;
|
||||
|
||||
// Deep copy the stat array
|
||||
stat = new pedestalSubtraction *[ny];
|
||||
for (int i = 0; i < ny; i++) {
|
||||
stat[i] = new pedestalSubtraction[nx];
|
||||
std::copy(other.stat[i], other.stat[i] + nx, stat[i]);
|
||||
}
|
||||
|
||||
// Deep copy image array
|
||||
image = new int[nx * ny];
|
||||
std::copy(other.image, other.image + (nx * ny), image);
|
||||
|
||||
// Copy common-mode subtraction object (if it exists)
|
||||
if (other.cmSub) {
|
||||
cmSub = other.cmSub->Clone();
|
||||
std::cout << "Copying cmSub" << std::endl;
|
||||
} else {
|
||||
cmSub = nullptr;
|
||||
}
|
||||
|
||||
// Copy ghost summation object (if it exists)
|
||||
if (other.ghSum) {
|
||||
ghSum = other.ghSum->Clone();
|
||||
std::cout << "Copying ghSum" << std::endl;
|
||||
} else {
|
||||
ghSum = nullptr;
|
||||
}
|
||||
|
||||
// Ensure pedestal values are copied properly
|
||||
int nped = other.GetNPedestals(0, 0);
|
||||
for (int iy = 0; iy < ny; ++iy) {
|
||||
for (int ix = 0; ix < nx; ++ix) {
|
||||
stat[iy][ix].SetNPedestals(nped);
|
||||
setPedestal(ix, iy, other.getPedestal(ix, iy),
|
||||
other.getPedestalRMS(ix, iy),
|
||||
other.GetNPedestals(ix, iy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
clone. Must be virtual!
|
||||
\returns a clone of the original analog detector
|
||||
*/
|
||||
virtual analogDetector *Clone() = 0;
|
||||
|
||||
/**
|
||||
Deep copy. Must be virtual!
|
||||
This is a new addition because of multithreaded storage cell data (where
|
||||
each sc has its own mutex). If the pure virtual function exists here,
|
||||
EVERY derived class has to overwrite it! That means a Copy() function
|
||||
must also be implemented in any derived class. \returns a deep copy of
|
||||
the original analog detector
|
||||
*/
|
||||
virtual analogDetector *Copy() = 0;
|
||||
|
||||
/**
|
||||
Gives an id to the structure. For debugging purposes in case of
|
||||
multithreading. \param i is to be set \returns current id
|
||||
@ -622,11 +548,6 @@ template <class dataType> class analogDetector {
|
||||
return ped;
|
||||
};
|
||||
|
||||
// Const version for use in the copy constructor
|
||||
virtual double getPedestal(int ix, int iy, int cm = 0) const {
|
||||
return stat[iy][ix].getPedestal();
|
||||
};
|
||||
|
||||
/**
|
||||
gets pedestal rms (i.e. noise)
|
||||
\param ix pixel x coordinate
|
||||
@ -645,11 +566,6 @@ template <class dataType> class analogDetector {
|
||||
return ped;
|
||||
};
|
||||
|
||||
// Const version for use in the copy constructor
|
||||
virtual double getPedestalRMS(int ix, int iy) const {
|
||||
return stat[iy][ix].getPedestalRMS();
|
||||
};
|
||||
|
||||
/**
|
||||
sets pedestal
|
||||
\param ix pixel x coordinate
|
||||
@ -1310,7 +1226,7 @@ template <class dataType> class analogDetector {
|
||||
/** gets number of samples for moving average pedestal calculation
|
||||
\returns actual number of samples
|
||||
*/
|
||||
int GetNPedestals(int ix, int iy) const {
|
||||
int GetNPedestals(int ix, int iy) {
|
||||
if (ix >= 0 && ix < nx && iy >= 0 && iy < ny)
|
||||
return stat[iy][ix].GetNPedestals();
|
||||
else
|
||||
|
@ -50,8 +50,6 @@ template <typename Element> class CircularFifo {
|
||||
mutable sem_t data_mutex;
|
||||
mutable sem_t free_mutex;
|
||||
unsigned int increment(unsigned int idx_) const;
|
||||
int id_;
|
||||
int thread_id_;
|
||||
};
|
||||
|
||||
template <typename Element> int CircularFifo<Element>::getDataValue() const {
|
||||
@ -76,18 +74,14 @@ template <typename Element> int CircularFifo<Element>::getFreeValue() const {
|
||||
template <typename Element>
|
||||
bool CircularFifo<Element>::push(Element *&item_, bool no_block) {
|
||||
// check for fifo full
|
||||
if (no_block && isFull()) {
|
||||
//std::cout << "Full Fifo at push. Returning." << std::endl;
|
||||
return false; // No space, return immediately
|
||||
}
|
||||
if (no_block && isFull())
|
||||
return false;
|
||||
|
||||
//std::cout << "Thread " << thread_id_ <<" Push Fifo " << id_ << " item " << static_cast<void*>(item_) << std::endl;
|
||||
|
||||
sem_wait(&free_mutex); // Wait for space
|
||||
array[tail] = item_; // Add item to the buffer
|
||||
tail = increment(tail); // Move the tail pointer
|
||||
sem_post(&data_mutex); // Signal that there is new data
|
||||
return true; // Success
|
||||
sem_wait(&free_mutex);
|
||||
array[tail] = item_;
|
||||
tail = increment(tail);
|
||||
sem_post(&data_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Consumer only: Removes and returns item from the queue
|
||||
@ -100,18 +94,14 @@ bool CircularFifo<Element>::push(Element *&item_, bool no_block) {
|
||||
template <typename Element>
|
||||
bool CircularFifo<Element>::pop(Element *&item_, bool no_block) {
|
||||
// check for fifo empty
|
||||
if (no_block && isEmpty()) {
|
||||
//std::cout << "Empty Fifo at pop. Returning." << std::endl;
|
||||
return false; // No data in fifo, return immediately
|
||||
}
|
||||
if (no_block && isEmpty())
|
||||
return false;
|
||||
|
||||
//std::cout << "Thread " << thread_id_ << " Pop Fifo " << id_ << " item " << static_cast<void*>(item_) << std::endl;
|
||||
|
||||
sem_wait(&data_mutex); // Wait for data
|
||||
item_ = array[head]; // Retreive item from the current head of the buffer
|
||||
head = increment(head); // Move the head pointer (to point to the next item)
|
||||
sem_post(&free_mutex); // Signal that there is new free space available
|
||||
return true; //Success
|
||||
sem_wait(&data_mutex);
|
||||
item_ = array[head];
|
||||
head = increment(head);
|
||||
sem_post(&free_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Useful for testinng and Consumer check of status
|
||||
|
@ -1,482 +0,0 @@
|
||||
#include "HDF5File.h"
|
||||
|
||||
#include "ansi.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
/*
|
||||
* No class member helper functions
|
||||
*/
|
||||
std::string vectorToString(std::vector<hsize_t> const& v) {
|
||||
return fmt::format("({})", fmt::join(v, ", "));
|
||||
}
|
||||
|
||||
/*
|
||||
* increment frame offset (if s dimension exists, loop through all before incrementing z)
|
||||
* should also work if file_dims[1] is not s but x (in that case we ignore it)
|
||||
*/
|
||||
void conditionalIncrement(std::vector<hsize_t>& vec, hsize_t max_value) {
|
||||
|
||||
if (vec.size() < 3) {
|
||||
throw std::invalid_argument("Vector must have at least 3 elements.");
|
||||
}
|
||||
|
||||
// If vector has 4 elements, increment vec[1] first
|
||||
if (vec.size() == 4) {
|
||||
if (++vec[1] >= max_value) { //max_value is never reached!
|
||||
vec[1] = 0; // Reset and increment vec[0]
|
||||
++vec[0];
|
||||
}
|
||||
}
|
||||
// If vector has 3 elements, increment vec[0] directly
|
||||
else if (vec.size() == 3) {
|
||||
++vec[0];
|
||||
}
|
||||
}
|
||||
|
||||
void printDatatypeSize(hid_t dataset) {
|
||||
|
||||
hid_t datatype = H5Dget_type(dataset);
|
||||
H5T_class_t class_id = H5Tget_class(datatype);
|
||||
size_t type_size = H5Tget_size(datatype);
|
||||
|
||||
H5Tclose(datatype);
|
||||
|
||||
std::cout << " dataset type class: " << class_id
|
||||
<< ", size: " << type_size << " bytes\n";
|
||||
|
||||
//Ensure the read datatype matches a system native type correctly
|
||||
//hid_t read_type = (type_size == 8) ? H5T_NATIVE_LLONG : H5T_NATIVE_UINT;
|
||||
|
||||
//return read_type;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* **********************
|
||||
* Class member functions
|
||||
* **********************
|
||||
*/
|
||||
|
||||
// Default constructor
|
||||
/*
|
||||
HDF5File::HDF5File () {
|
||||
//InitializeParameters(); //old
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
HDF5File::~HDF5File () {
|
||||
|
||||
if(current_image)
|
||||
delete [] current_image;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
void HDF5File::SetImageDataPath (std::string const& name) {
|
||||
std::cout << "Image dataset path set to " << name << std::endl;
|
||||
data_datasetname = name;
|
||||
}
|
||||
|
||||
void HDF5File::SetFrameIndexPath (std::string const& name) {
|
||||
std::cout << "Frame index dataset path set to " << name << std::endl;
|
||||
index_datasetname = name;
|
||||
}
|
||||
|
||||
void HDF5File::InitializeDimensions () {
|
||||
|
||||
rank = H5Sget_simple_extent_ndims(dataspace);
|
||||
file_dims.resize(rank);
|
||||
H5Sget_simple_extent_dims(dataspace, file_dims.data(), nullptr);
|
||||
|
||||
std::cout << "Dataset dimensions: " << vectorToString(file_dims) << "\n";
|
||||
|
||||
}
|
||||
|
||||
std::vector<hsize_t> HDF5File::GetDatasetDimensions() {
|
||||
return file_dims;
|
||||
}
|
||||
|
||||
std::vector<hsize_t> HDF5File::GetChunkDimensions() {
|
||||
return chunk_dims;
|
||||
}
|
||||
|
||||
hsize_t HDF5File::GetRank() {
|
||||
return rank;
|
||||
}
|
||||
|
||||
bool HDF5File::ValidateDimensions () {
|
||||
|
||||
// validate rank
|
||||
if(rank != RANK) {
|
||||
cprintf(RED,"rank found %llu. Expected %d\n", rank, RANK);
|
||||
std::cerr << "Error: Rank could not be validated\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate file dimensions of x and y (assuming those are the last two dimensions of the dataset)
|
||||
if ( (file_dims[file_dims.size()-2] != DEFAULT_X_DIMS) || (file_dims[file_dims.size()-1] != DEFAULT_Y_DIMS) ) {
|
||||
cprintf(RED,"file dimensions of x found %llu. Expected %d\n", file_dims[file_dims.size()-2], DEFAULT_X_DIMS);
|
||||
cprintf(RED,"file dimensions of y found %llu. Expected %d\n", file_dims[file_dims.size()-1], DEFAULT_Y_DIMS);
|
||||
std::cerr << "Error: Dataset dimensions could not be validated\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
cprintf(GREEN, "File rank & dimensions validated.");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HDF5File::ReadChunkDimensions () {
|
||||
|
||||
// Get layout
|
||||
hid_t plist_id = H5Dget_create_plist(dataset);
|
||||
|
||||
if (H5Pget_layout (plist_id) != H5D_CHUNKED) {
|
||||
cprintf(RED,"NOTE: Dataset is not chunked!\n");
|
||||
std::cerr << "Error: Dataset is not chunked\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get Chunk Dimensions
|
||||
int rank_chunk = H5Pget_chunk (plist_id, 0, nullptr);
|
||||
chunk_dims.resize(rank_chunk);
|
||||
H5Pget_chunk (plist_id, rank_chunk, chunk_dims.data());
|
||||
|
||||
std::cout << "Chunk dimensions: " << vectorToString(chunk_dims) << "\n";
|
||||
|
||||
H5Pclose (plist_id);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool HDF5File::ValidateChunkDimensions () {
|
||||
|
||||
// validate rank
|
||||
if(chunk_dims.size() != rank) {
|
||||
cprintf(RED,"Chunk rank does not match dataset rank! Found %lu. Expected %llu\n", chunk_dims.size(), rank);
|
||||
std::cerr << "Error: Chunk rank does not match dataset rank\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate chunk dimensions of x and y (assuming those are the last two dimensions of the dataset)
|
||||
if ( (chunk_dims[chunk_dims.size()-2] != DEFAULT_CHUNK_X_DIMS) || (chunk_dims[chunk_dims.size()-1] != DEFAULT_CHUNK_Y_DIMS) ) {
|
||||
cprintf(RED,"file dimensions of x found %llu. Expected %d\n", chunk_dims[chunk_dims.size()-2], DEFAULT_CHUNK_X_DIMS);
|
||||
cprintf(RED,"file dimensions of y found %llu. Expected %d\n", chunk_dims[chunk_dims.size()-1], DEFAULT_CHUNK_Y_DIMS);
|
||||
std::cerr << "Error: Chunk dimensions could not be validated\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
cprintf(GREEN, "Chunk rank & dimensions validated.");
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool HDF5File::OpenFrameIndexDataset() {
|
||||
|
||||
// Get all the frame numbers
|
||||
// Open frame index dataset
|
||||
hid_t fi_dataset = H5Dopen2 (file, index_datasetname.c_str(), H5P_DEFAULT);
|
||||
if (fi_dataset < 0){
|
||||
cprintf (RED,"Could not open frame index dataset %s\n", index_datasetname.c_str());
|
||||
std::cerr << "Error: Could not open frame index dataset\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
hid_t fi_dataspace = H5Dget_space (fi_dataset);
|
||||
int fi_rank = H5Sget_simple_extent_ndims(fi_dataspace);
|
||||
std::vector<hsize_t> fi_dims(fi_rank);
|
||||
H5Sget_simple_extent_dims (fi_dataspace, fi_dims.data(), nullptr);
|
||||
|
||||
std::cout << "Frame index dataset dimensions: " << vectorToString(fi_dims) << "\n";
|
||||
|
||||
// validate size
|
||||
if (fi_dims[0] != file_dims[0]) {
|
||||
cprintf (RED,"Frame index dimensions of z found %llu. Expected %llu\n", fi_dims[0], file_dims[0]);
|
||||
std::cerr << "Error: Z dimension of frame index dataset does not align with z dimension of image dataset\n";
|
||||
H5Sclose (fi_dataspace);
|
||||
H5Dclose (fi_dataset);
|
||||
return false;
|
||||
}
|
||||
|
||||
// allocate frame index memory
|
||||
frame_index_list.resize(fi_dims[0]); //file_dims
|
||||
|
||||
// read and print datatype size of dataset
|
||||
std::cout << "Frame index";
|
||||
printDatatypeSize(fi_dataset);
|
||||
|
||||
// make sure we only read the first column of the frame index dataset (not all storage cells)
|
||||
//NOTE: For XFEL datasets, this may mean that some frame numbers are skipped
|
||||
//(because they assign a unique frame number to every storage cell)
|
||||
//Possibly, there is a cleaner fix for this...
|
||||
std::vector<hsize_t> start(fi_rank,0);
|
||||
std::vector<hsize_t> count(fi_rank,1);
|
||||
count[0] = fi_dims[0];
|
||||
hid_t memspace = H5Screate_simple (fi_rank, count.data(), nullptr);
|
||||
if (memspace < 0) {
|
||||
std::cerr << "Error: Failed to create memory space for HDF5 read operation\n";
|
||||
H5Sclose(memspace);
|
||||
H5Sclose(fi_dataspace);
|
||||
H5Dclose(fi_dataset);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create hyperslab selection
|
||||
if (H5Sselect_hyperslab(fi_dataspace, H5S_SELECT_SET, start.data(), nullptr, count.data(), nullptr) < 0 ) {
|
||||
cprintf (RED,"Could not create hyperslab for %s\n", vectorToString(start).c_str());
|
||||
std::cerr << "Error: Hyperslab creation failed for " << vectorToString(start) << "\n";
|
||||
H5Sclose(memspace);
|
||||
H5Sclose (fi_dataspace);
|
||||
H5Dclose(fi_dataset);
|
||||
return false;
|
||||
}
|
||||
|
||||
//read frame index values
|
||||
//Is u32 correct? I would think not. But I get a segmentation fault if I use u64.
|
||||
if (H5Dread (fi_dataset, H5T_STD_U64LE, memspace, fi_dataspace, H5P_DEFAULT, frame_index_list.data()) < 0) {
|
||||
cprintf (RED,"Could not read frame index dataset %s\n", index_datasetname.c_str());
|
||||
std::cerr << "Error: Could not read frame index dataset\n";
|
||||
H5Sclose(memspace);
|
||||
H5Sclose (fi_dataspace);
|
||||
H5Dclose (fi_dataset);
|
||||
return false;
|
||||
}
|
||||
|
||||
H5Sclose(memspace);
|
||||
H5Sclose (fi_dataspace);
|
||||
H5Dclose(fi_dataset);
|
||||
return true;
|
||||
}
|
||||
|
||||
int HDF5File::OpenResources (char const*const fname, bool validate) {
|
||||
|
||||
std::cout << "Debug HDF5File.cpp: Attempting to open file " << fname << std::endl;
|
||||
// Open File
|
||||
file = H5Fopen (fname, H5F_ACC_RDONLY, H5P_DEFAULT);
|
||||
if (file < 0) {
|
||||
cprintf(RED,"Could not open hdf5 file\n");
|
||||
std::cerr << "Error: H5Fopen failed\n";
|
||||
return 0;
|
||||
}
|
||||
cprintf(BLUE, "Opened File: %s\n", fname);
|
||||
|
||||
// Open Dataset
|
||||
dataset = H5Dopen2 (file, data_datasetname.c_str(), H5P_DEFAULT);
|
||||
if (dataset < 0){
|
||||
cprintf(RED,"Could not open dataset\n");
|
||||
std::cerr << "Error: H5Dopen2 failed\n";
|
||||
CloseResources ();
|
||||
return 0;
|
||||
}
|
||||
cprintf(BLUE, "Opened Dataset: %s\n", data_datasetname.c_str());
|
||||
|
||||
// print datatype size of dataset
|
||||
std::cout << "Image";
|
||||
printDatatypeSize(dataset);
|
||||
|
||||
// Create Dataspace
|
||||
dataspace = H5Dget_space (dataset);
|
||||
if (dataspace < 0){
|
||||
cprintf(RED,"Could not open dataspace\n");
|
||||
std::cerr << "Error: H5Dget_space failed\n";
|
||||
CloseResources ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get Dimensions
|
||||
InitializeDimensions();
|
||||
// Get chunk dimensions
|
||||
if (!ReadChunkDimensions()) {
|
||||
CloseResources();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// validate file dimensions
|
||||
if (validate) {
|
||||
if ( !ValidateDimensions() || !ValidateChunkDimensions() ) {
|
||||
CloseResources();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//Read frame indices
|
||||
if (!OpenFrameIndexDataset()) {
|
||||
CloseResources();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void HDF5File::CloseResources () {
|
||||
if (dataspace >=0 ) {
|
||||
H5Sclose(dataspace);
|
||||
dataspace = -1;
|
||||
}
|
||||
if (dataset >=0 ) {
|
||||
H5Dclose(dataset);
|
||||
dataset = -1;
|
||||
}
|
||||
if (file >=0 ) {
|
||||
H5Fclose(file);
|
||||
file = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function takes uint16_t* argument to make explicit that the caller has to handle memory allocation and deallocation.
|
||||
* This is legacy caused by the structure with which the slsDetectorCalibration cluster finder is written.
|
||||
* (Best practice for modern C++ would be using smart pointers.)
|
||||
*
|
||||
* Originially, this function took uint16_t** which may lead to memory management issues since image gets redirected
|
||||
* to point to current_image, which is owned by HDF5File.
|
||||
* (Good practice in classic C-style. HDF5File needs to clean up the resource at destruction.)
|
||||
*
|
||||
* \param image pointer to uint16_t, buffer which the image is read into. (Memory handled by caller!)
|
||||
* \param offset contains iFrame at [0] and storage cell number at [1],
|
||||
* depending on dimensionality of the dataset, the storage cell number may not be included.
|
||||
* Note that frame number (as read from file) may (likely) differ from frame index (in the dataset)!
|
||||
*/
|
||||
int HDF5File::ReadImage (uint16_t* image, std::vector<hsize_t>& offset ) {
|
||||
|
||||
// Validate input arguments
|
||||
if (!image) {
|
||||
std::cerr << "Error: image buffer is null.\n";
|
||||
return -99;
|
||||
}
|
||||
if ( offset.size() != rank-2 ) {
|
||||
cprintf ( RED,"Offset vector must have size %llu. Found %lu\n", rank-2, offset.size() );
|
||||
std::cerr << "Error: Wrong offset vector size\n";
|
||||
CloseResources ();
|
||||
return -99;
|
||||
}
|
||||
|
||||
// Initialize frame_offset
|
||||
if (frame_offset.empty())
|
||||
frame_offset.resize(rank,0);
|
||||
|
||||
// Check if we reached the end of file
|
||||
// Compares that the offsets of frame and storage cell (Z and S) have reached the end of file
|
||||
// Excludes X and Y indices (of the image dataset) from the comparison
|
||||
// As it is now, this never triggers, because frame_offset[1] is never equals file_dims[1]=16
|
||||
/*
|
||||
if( std::equal( frame_offset.cbegin(), frame_offset.cend()-2, file_dims.cbegin() ) ) {
|
||||
printf("End of file reached\n");
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
if (frame_offset[0] == file_dims[0]) {
|
||||
printf("End of file reached\n");
|
||||
return -1;
|
||||
}
|
||||
/* //old
|
||||
if (frame_offset[0] == file_dims[0]-1) {
|
||||
printf("end of file\n");
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
// Validate frame_offset index
|
||||
if (frame_offset[0] >= frame_index_list.size()) {
|
||||
std::cerr << "Error: frame_offset[0] = " << frame_offset[0] << " of bounds.\n";
|
||||
return -99;
|
||||
}
|
||||
|
||||
// Check if images exist at the current frame offset
|
||||
if (frame_index_list[frame_offset[0]] == 0) {
|
||||
cprintf (RED,"No images at this frame offset %llu\n", frame_offset[0]);
|
||||
std::cerr << "Error: Framenumber 0 at this frame offset\n";
|
||||
CloseResources ();
|
||||
return -99;
|
||||
}
|
||||
|
||||
// Optional: Ensure dataset and dataspace are valid
|
||||
if (dataset < 0) {
|
||||
std::cerr << "Error: Invalid dataset ID.\n";
|
||||
return -99;
|
||||
}
|
||||
if (dataspace < 0) {
|
||||
std::cerr << "Error: Invalid dataspace.\n";
|
||||
return -99;
|
||||
}
|
||||
|
||||
// Define the size of the hyperslab to read
|
||||
std::vector<hsize_t> frame_size(rank, 1);
|
||||
std::copy(file_dims.begin() + rank-2, file_dims.end(), frame_size.begin() + rank-2);
|
||||
/*
|
||||
for ( int d=0; d < rank; ++d ) {
|
||||
if (d < rank-2)
|
||||
frame_size[d] = 1;
|
||||
if ( d >= rank-2 )
|
||||
frame_size[d] = file_dims[d];
|
||||
}
|
||||
*/
|
||||
|
||||
// Define memory space
|
||||
hid_t memspace = H5Screate_simple (rank, frame_size.data(), nullptr);
|
||||
if (memspace < 0) {
|
||||
std::cerr << "Error: Failed to create memory space for HDF5 read operation\n";
|
||||
CloseResources();
|
||||
return -99;
|
||||
}
|
||||
|
||||
// Create hyperslab selection
|
||||
// This aligns dataspace such that we read the correct frame
|
||||
if (H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, frame_offset.data(), nullptr, frame_size.data(), nullptr) < 0 ) {
|
||||
cprintf (RED,"Could not create hyperslab for frame offset %s\n", vectorToString(frame_offset).c_str());
|
||||
std::cerr << "Error: Hyperslab creation failed for frame offset " << vectorToString(frame_offset) << "\n";
|
||||
CloseResources();
|
||||
H5Sclose(memspace);
|
||||
return -99;
|
||||
}
|
||||
|
||||
// Read dataset into image buffer (previously read to current_image owned by HDF5File)
|
||||
if (H5Dread(dataset, H5T_STD_U16LE, memspace, dataspace, H5P_DEFAULT, image) < 0 ) {
|
||||
cprintf (RED,"Could not read dataset for frame offset %s\n", vectorToString(frame_offset).c_str());
|
||||
std::cerr << "Error: Reading of dataset failed for given start frame offset " << vectorToString(frame_offset) << "\n";
|
||||
CloseResources ();
|
||||
H5Sclose(memspace);
|
||||
return -99;
|
||||
}
|
||||
|
||||
// Clean up memory space
|
||||
H5Sclose(memspace);
|
||||
|
||||
//*image = current_image; //if uint16_t** is passed, HDF5File owns the resource image points to, which is potentially dangerous
|
||||
|
||||
// Return frame number
|
||||
unsigned int retval = frame_index_list[frame_offset[0]];
|
||||
|
||||
// Pass updated frame offset value(s) via offset parameter vector
|
||||
std::copy_n(frame_offset.begin(), offset.size(), offset.begin());
|
||||
/*
|
||||
std::transform( offset.begin(), offset.end(), offset.begin(),
|
||||
[&, i = 0](size_t) mutable { return frame_offset[i++]; } );
|
||||
*/
|
||||
|
||||
// Increment frame offset correctly
|
||||
conditionalIncrement(frame_offset, file_dims[1]);
|
||||
//++frame_offset[0]; //old
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void HDF5File::PrintCurrentImage (uint16_t* image) {
|
||||
printf("\n");
|
||||
printf("Frame %llu, Image: %llu\n", frame_offset[0]-1, frame_index_list[frame_offset[0]-1]);
|
||||
|
||||
hsize_t size = file_dims[rank-1] * file_dims[rank-2];
|
||||
for (hsize_t i = 0; i < size; ++i){
|
||||
printf("%u ", image[i]);
|
||||
if (!((i+1) % file_dims[rank-2] ))
|
||||
printf("\n\n");
|
||||
}
|
||||
printf("\n\n\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,159 +0,0 @@
|
||||
#pragma once
|
||||
/************************************************
|
||||
* @file HDF5Fle.h
|
||||
* @short functions to open/close/read HDF5 File
|
||||
* Adapted for generalization, accepts rank 3 and 4
|
||||
* Supports control over storage cells
|
||||
***********************************************/
|
||||
/**
|
||||
*@short functions to open/close/read HDF5 File
|
||||
*/
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "hdf5.h"
|
||||
#include "hdf5_hl.h"
|
||||
|
||||
|
||||
//#define MAX_STR_LENGTH 1000
|
||||
|
||||
#define RANK 4 // Dimension of the image dataset, only for validation
|
||||
#define DEFAULT_Z_DIMS 10000 // only for validation
|
||||
#define DEFAULT_Y_DIMS 1024 // only for validation
|
||||
#define DEFAULT_X_DIMS 512 // only for validation
|
||||
//#define DEFAULT_S_DIMS 1 // Storage cells
|
||||
|
||||
#define DEFAULT_CHUNK_Z_DIMS 1 // only for validation
|
||||
#define DEFAULT_CHUNK_Y_DIMS 1024 // only for validation
|
||||
#define DEFAULT_CHUNK_X_DIMS 512 // only for validation
|
||||
//#define DEFAULT_CHUNK_S_DIMS 1
|
||||
|
||||
|
||||
#define DATA_DATASETNAME "/data/JF18T01V01/data" //Furka JF
|
||||
#define INDEX_DATASETNAME "/data/JF18T01V01/frame_index"
|
||||
|
||||
//enum{Z,S,X,Y}; //S is the storage cell //enum is not used
|
||||
|
||||
class HDF5File {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
//HDF5File () = default; //No need to declare if it is default
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
//~HDF5File () = default; //Since the destructor is default (and copy and move are default too)
|
||||
|
||||
|
||||
std::vector<hsize_t> GetDatasetDimensions ();
|
||||
|
||||
std::vector<hsize_t> GetChunkDimensions ();
|
||||
|
||||
hsize_t GetRank ();
|
||||
|
||||
void SetImageDataPath (std::string const& name);
|
||||
|
||||
void SetFrameIndexPath (std::string const& name);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Open HDF5 file and dataset,
|
||||
* reads frame index dataset to array
|
||||
* @param fname file name
|
||||
* @param validate true if one must validate if file is
|
||||
* chunked with dims [? x 128 x 512] and chunk dims [1 x 128 x 512]
|
||||
* @returns 1 if successful, else 0 if fail
|
||||
*/
|
||||
int OpenResources (const char* const fname, bool validate);
|
||||
|
||||
/**
|
||||
* Close Open resources
|
||||
*/
|
||||
void CloseResources ();
|
||||
|
||||
/**
|
||||
* Read an image into current_image,
|
||||
* increment Z-offset (frame) and (if rank==4) storage cell
|
||||
* @returns frame number read from file,
|
||||
*/
|
||||
int ReadImage (uint16_t* image, std::vector<hsize_t>& offset);
|
||||
|
||||
/**
|
||||
* Print current image in memory
|
||||
*/
|
||||
void PrintCurrentImage (uint16_t* image);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Initialize dimensions of image dataset for each new file
|
||||
*/
|
||||
void InitializeDimensions ();
|
||||
|
||||
bool ReadChunkDimensions ();
|
||||
|
||||
bool ValidateDimensions ();
|
||||
|
||||
bool ValidateChunkDimensions ();
|
||||
|
||||
/**
|
||||
* Open dataset containing the frame numbers
|
||||
*/
|
||||
bool OpenFrameIndexDataset ();
|
||||
|
||||
|
||||
/** file name */
|
||||
std::string file_name{};
|
||||
/** dataset name for image data */
|
||||
std::string data_datasetname = DATA_DATASETNAME;
|
||||
/** dataset name for frame index data */
|
||||
std::string index_datasetname = INDEX_DATASETNAME;
|
||||
|
||||
/** file handle */
|
||||
hid_t file{};
|
||||
/** dataspace handle */
|
||||
hid_t dataspace{};
|
||||
/** memory space handle */
|
||||
//hid_t memspace; //old
|
||||
/** dataset handle */
|
||||
hid_t dataset{};
|
||||
|
||||
/** file dimensions */
|
||||
std::vector<hsize_t> file_dims{};
|
||||
//hsize_t file_dims[RANK]{}; //static array (dimensions are known)
|
||||
|
||||
/** chunk dimensions
|
||||
** not necessarily required
|
||||
** useful for optimization or validation */
|
||||
std::vector<hsize_t> chunk_dims{};
|
||||
//hsize_t chunk_dims[RANK]{};
|
||||
|
||||
/** Rank of the image dataset */
|
||||
hsize_t rank{};
|
||||
|
||||
/** number of frames */
|
||||
unsigned int number_of_frames{};
|
||||
|
||||
/** frame index list */
|
||||
std::vector<hsize_t> frame_index_list{};
|
||||
|
||||
/** Current image
|
||||
** dynamic array
|
||||
** uint16_t pointer format is chosen to support use with slsDetectorCalibration cluster finder */
|
||||
//uint16_t* current_image{nullptr};
|
||||
//uint16_t current_chunk[DEFAULT_CHUNK_Z_DIMS][DEFAULT_CHUNK_Y_DIMS][DEFAULT_CHUNK_X_DIMS];
|
||||
|
||||
/** Current frame offset
|
||||
** (Z-offset, S-offset, 0, 0) or (Z-offset, 0, 0), increments automatically with ReadImage */
|
||||
std::vector<hsize_t> frame_offset{};
|
||||
//hsize_t frame_offset[RANK]{};
|
||||
|
||||
};
|
@ -1,422 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#ifndef JUNGFRAULGADSTRIXELSDATAQUAD_H
|
||||
#define JUNGFRAULGADSTRIXELSDATAQUAD_H
|
||||
#ifdef CINT
|
||||
#include "sls/sls_detector_defs_CINT.h"
|
||||
#else
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#endif
|
||||
#include "slsDetectorData.h"
|
||||
|
||||
// #define VERSION_V2
|
||||
/**
|
||||
@short structure for a Detector Packet or Image Header
|
||||
@li frameNumber is the frame number
|
||||
@li expLength is the subframe number (32 bit eiger) or real time exposure
|
||||
time in 100ns (others)
|
||||
@li packetNumber is the packet number
|
||||
@li bunchId is the bunch id from beamline
|
||||
@li timestamp is the time stamp with 10 MHz clock
|
||||
@li modId is the unique module id (unique even for left, right, top, bottom)
|
||||
@li xCoord is the x coordinate in the complete detector system
|
||||
@li yCoord is the y coordinate in the complete detector system
|
||||
@li zCoord is the z coordinate in the complete detector system
|
||||
@li debug is for debugging purposes
|
||||
@li roundRNumber is the round robin set number
|
||||
@li detType is the detector type see :: detectorType
|
||||
@li version is the version number of this structure format
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
|
||||
namespace strixelQuad {
|
||||
constexpr int nc_rawimg = 1024; // for full images //256;
|
||||
constexpr int nc_quad = 512;
|
||||
constexpr int nr_rawimg = 512;
|
||||
constexpr int nr_chip = 256;
|
||||
constexpr int gr = 9;
|
||||
|
||||
//shift due to extra pixels
|
||||
constexpr int shift_x = 2; //left
|
||||
|
||||
constexpr int nc_strixel = ( nc_quad - shift_x - 2*gr ) / 3; //164
|
||||
constexpr int nr_strixel = ( nr_chip - 1 - gr ) * 3; //one half (-1 because double sided pixel) //738
|
||||
constexpr int nr_center = 12; //double sided pixels to be skipped
|
||||
|
||||
// boundaries in ASIC coordinates (pixels at both bounds are included)
|
||||
constexpr int xstart = 256 + gr; // 265
|
||||
constexpr int xend = 255 + nc_quad - gr; // 758
|
||||
constexpr int bottom_ystart = gr; // 9
|
||||
constexpr int bottom_yend = nr_chip - 2; // 254
|
||||
constexpr int top_ystart = nr_chip + 1; // 257
|
||||
constexpr int top_yend = nr_chip*2 - gr - 1; // 502
|
||||
|
||||
// x shift because of 2-pixel strixels on one side
|
||||
constexpr int shift = 2;
|
||||
|
||||
} // namespace strixelQuad
|
||||
|
||||
//to account for module rotation
|
||||
enum rotation {
|
||||
NORMAL = 0,
|
||||
INVERSE = 1
|
||||
};
|
||||
|
||||
const int rota = NORMAL;
|
||||
|
||||
typedef struct {
|
||||
uint64_t bunchNumber; /**< is the frame number */
|
||||
uint64_t pre; /**< something */
|
||||
|
||||
} jf_header; // Aldo's header
|
||||
|
||||
using namespace strixelQuad;
|
||||
|
||||
class jungfrauLGADStrixelsDataQuad : public slsDetectorData<uint16_t> {
|
||||
|
||||
private:
|
||||
int iframe;
|
||||
int x0, y0, x1, y1, shifty;
|
||||
struct {
|
||||
uint16_t xmin;
|
||||
uint16_t xmax;
|
||||
uint16_t ymin;
|
||||
uint16_t ymax;
|
||||
int nc;
|
||||
} globalROI;
|
||||
|
||||
//to account for the inverted routing of the two different quad halfs
|
||||
enum location {
|
||||
BOTTOM = 0,
|
||||
TOP = 1
|
||||
};
|
||||
|
||||
int multiplicator = 3;
|
||||
std::vector<int> mods{ 0, 1, 2 };
|
||||
|
||||
void reverseVector( std::vector<int>& v ) {
|
||||
std::reverse( v.begin(), v.end() );
|
||||
std::cout << "mods reversed ";
|
||||
for ( auto i : v )
|
||||
std::cout << i << " ";
|
||||
std::cout << '\n';
|
||||
}
|
||||
|
||||
void setMappingShifts( const int rot, const int half ) {
|
||||
|
||||
x0 = xstart;
|
||||
x1 = xend;
|
||||
|
||||
if (rot==NORMAL) {
|
||||
x0 += shift;
|
||||
} else {
|
||||
x1-=shift;
|
||||
reverseVector(mods);
|
||||
}
|
||||
|
||||
if (half==BOTTOM) {
|
||||
y0 = bottom_ystart;
|
||||
y1 = bottom_yend;
|
||||
shifty = 0;
|
||||
} else {
|
||||
y0 = top_ystart;
|
||||
y1 = top_yend;
|
||||
reverseVector(mods);
|
||||
shifty = nr_strixel + nr_center; //double-sided pixels in the center have to be jumped
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void remap( int xmin=0, int xmax=0, int ymin=0, int ymax=0 ) {
|
||||
|
||||
int ix, iy = 0;
|
||||
// remapping loop
|
||||
for (int ipy = y0; ipy <= y1; ipy++) {
|
||||
for (int ipx = x0; ipx <= x1; ipx++) {
|
||||
|
||||
ix = int((ipx - x0) / multiplicator);
|
||||
for (int m = 0; m < multiplicator; ++m) {
|
||||
if ((ipx - x0) % multiplicator == m)
|
||||
iy = (ipy - y0) * multiplicator + mods[m] + shifty;
|
||||
}
|
||||
|
||||
// if (iy< 40) cout << iy << " " << ix <<endl;
|
||||
if (xmin < xmax && ymin < ymax) {
|
||||
if ( ipx>=xmin && ipx<=xmax && ipy>=ymin && ipy <=ymax )
|
||||
dataMap[iy][ix] =
|
||||
sizeof(header) + (globalROI.nc * (ipy - globalROI.ymin) + (ipx - globalROI.xmin)) * 2;
|
||||
} else {
|
||||
dataMap[iy][ix] = sizeof(header) + (nc_rawimg * ipy + ipx) * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void remapQuad(const int rot) {
|
||||
|
||||
setMappingShifts( rot, BOTTOM );
|
||||
remap();
|
||||
setMappingShifts( rot, TOP );
|
||||
remap();
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::tuple< uint16_t, uint16_t, uint16_t, uint16_t > adjustROItoLimits(uint16_t xmin,
|
||||
uint16_t xmax,
|
||||
uint16_t ymin,
|
||||
uint16_t ymax,
|
||||
uint16_t lim_roi_xmin,
|
||||
uint16_t lim_roi_xmax,
|
||||
uint16_t lim_roi_ymin,
|
||||
uint16_t lim_roi_ymax) {
|
||||
uint16_t xmin_roi, xmax_roi, ymin_roi, ymax_roi;
|
||||
if ( xmin < lim_roi_xmin)
|
||||
xmin_roi = lim_roi_xmin;
|
||||
else
|
||||
xmin_roi = xmin;
|
||||
if ( xmax > lim_roi_xmax )
|
||||
xmax_roi = lim_roi_xmax;
|
||||
else
|
||||
xmax_roi = xmax;
|
||||
if ( ymin < lim_roi_ymin )
|
||||
ymin_roi = lim_roi_ymin;
|
||||
else
|
||||
ymin_roi = ymin;
|
||||
if ( ymax > lim_roi_ymax )
|
||||
ymax_roi = lim_roi_ymax;
|
||||
else
|
||||
ymax_roi = ymax;
|
||||
return std::make_tuple(xmin_roi, xmax_roi, ymin_roi, ymax_roi);
|
||||
}
|
||||
|
||||
std::vector < std::tuple< int, uint16_t, uint16_t, uint16_t, uint16_t > > mapSubROIs(uint16_t xmin,
|
||||
uint16_t xmax,
|
||||
uint16_t ymin,
|
||||
uint16_t ymax) {
|
||||
bool bottom = false;
|
||||
bool top = false;
|
||||
|
||||
for ( int x=xmin; x!=xmax+1; ++x ) {
|
||||
for ( int y=ymin; y!=ymax; ++y ) {
|
||||
if ( xstart<=x && x<=xend && bottom_ystart<=y && y<=bottom_yend )
|
||||
bottom = true;
|
||||
if ( xstart<=x && x<=xend && top_ystart<=y && y<=top_yend )
|
||||
top = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t xmin_roi{}, xmax_roi{}, ymin_roi{}, ymax_roi{};
|
||||
std::vector < std::tuple< int, uint16_t, uint16_t, uint16_t, uint16_t > > rois{};
|
||||
|
||||
if (bottom) {
|
||||
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
|
||||
adjustROItoLimits( xmin, xmax, ymin, ymax,
|
||||
xstart, xend, bottom_ystart, bottom_yend );
|
||||
rois.push_back( std::make_tuple( BOTTOM, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
|
||||
}
|
||||
if (top) {
|
||||
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
|
||||
adjustROItoLimits( xmin, xmax, ymin, ymax,
|
||||
xstart, xend, top_ystart, top_yend );
|
||||
rois.push_back( std::make_tuple( TOP, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
|
||||
}
|
||||
|
||||
return rois;
|
||||
}
|
||||
|
||||
void remapROI(std::tuple< int, uint16_t, uint16_t, uint16_t, uint16_t > roi, const int rot ) {
|
||||
|
||||
int half, xmin, xmax, ymin, ymax;
|
||||
std::tie( half, xmin, xmax, ymin, ymax ) = roi;
|
||||
|
||||
setMappingShifts(rot, half);
|
||||
|
||||
std::cout << "remapping roi: "
|
||||
<< ", x0: " << x0 << ", x1: " << x1 << ", y0: " << y0
|
||||
<< ", y1: " << y1 << std::endl;
|
||||
std::cout << "Adjusted roi: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]" << std::endl;
|
||||
|
||||
remap( xmin, xmax, ymin, ymax );
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
using header = sls::defs::sls_receiver_header;
|
||||
|
||||
jungfrauLGADStrixelsDataQuad(uint16_t xmin = 0, uint16_t xmax = 0,
|
||||
uint16_t ymin = 0, uint16_t ymax = 0)
|
||||
: slsDetectorData<uint16_t>(
|
||||
nc_strixel,
|
||||
nr_strixel * 2 + nr_center,
|
||||
nc_strixel * ( nr_strixel * 2 + nr_center ) * 2 + sizeof(header)) {
|
||||
std::cout << "Jungfrau strixels quad with full module data "
|
||||
<< std::endl;
|
||||
|
||||
// Fill all strixels with dummy values
|
||||
for (int ix = 0; ix != nc_strixel; ++ix) {
|
||||
for (int iy = 0; iy != nr_strixel * 2 + nr_center; ++iy) {
|
||||
dataMap[iy][ix] = sizeof(header);
|
||||
}
|
||||
}
|
||||
|
||||
globalROI.xmin = xmin;
|
||||
globalROI.xmax = xmax;
|
||||
globalROI.ymin = ymin;
|
||||
globalROI.ymax = ymax;
|
||||
|
||||
std::cout << "sizeofheader = " << sizeof(header) << std::endl;
|
||||
std::cout << "Jungfrau strixels quad with full module data "
|
||||
<< std::endl;
|
||||
|
||||
if (xmin < xmax && ymin < ymax) {
|
||||
|
||||
// get ROI raw image number of columns
|
||||
globalROI.nc = xmax - xmin + 1;
|
||||
std::cout << "nc_roi = " << globalROI.nc << std::endl;
|
||||
|
||||
dataSize =
|
||||
(xmax - xmin + 1) * (ymax - ymin + 1) * 2 + sizeof(header);
|
||||
std::cout << "datasize " << dataSize << std::endl;
|
||||
|
||||
auto rois = mapSubROIs(xmin, xmax, ymin, ymax);
|
||||
//function to fill vector of rois from globalROI
|
||||
|
||||
for ( auto roi : rois )
|
||||
remapROI(roi, rota);
|
||||
|
||||
} else {
|
||||
|
||||
remapQuad( rota );
|
||||
|
||||
}
|
||||
|
||||
iframe = 0;
|
||||
std::cout << "data struct created" << std::endl;
|
||||
};
|
||||
|
||||
/**
|
||||
Returns the value of the selected channel for the given dataset as
|
||||
double. \param data pointer to the dataset (including headers etc) \param
|
||||
ix pixel number in the x direction \param iy pixel number in the y
|
||||
direction \returns data for the selected channel, with inversion if
|
||||
required as double
|
||||
|
||||
*/
|
||||
virtual double getValue(char *data, int ix, int iy = 0) {
|
||||
|
||||
uint16_t val = getChannel(data, ix, iy) & 0x3fff;
|
||||
return val;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Returns the frame number for the given dataset. Purely virtual func.
|
||||
\param buff pointer to the dataset
|
||||
\returns frame number
|
||||
|
||||
*/
|
||||
|
||||
int getFrameNumber(char *buff) {
|
||||
#ifdef ALDO // VH
|
||||
return ((jf_header *)buff)->bunchNumber; // VH
|
||||
#endif // VH
|
||||
return ((header *)buff)->detHeader.frameNumber;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Returns the packet number for the given dataset. purely virtual func
|
||||
\param buff pointer to the dataset
|
||||
\returns packet number number
|
||||
|
||||
|
||||
|
||||
*/
|
||||
int getPacketNumber(char *buff) {
|
||||
#ifdef ALDO // VH
|
||||
// uint32_t fakePacketNumber = 1000;
|
||||
// return fakePacketNumber; //VH //TODO: Keep in mind in case of bugs!
|
||||
// //This is definitely bad!
|
||||
return 1000;
|
||||
#endif // VH
|
||||
return ((header *)buff)->detHeader.packetNumber;
|
||||
};
|
||||
|
||||
char *readNextFrame(std::ifstream &filebin) {
|
||||
int ff = -1, np = -1;
|
||||
return readNextFrame(filebin, ff, np);
|
||||
};
|
||||
|
||||
char *readNextFrame(std::ifstream &filebin, int &ff) {
|
||||
int np = -1;
|
||||
return readNextFrame(filebin, ff, np);
|
||||
};
|
||||
|
||||
char *readNextFrame(std::ifstream &filebin, int &ff, int &np) {
|
||||
char *data = new char[dataSize];
|
||||
char *d = readNextFrame(filebin, ff, np, data);
|
||||
if (d == NULL) {
|
||||
delete[] data;
|
||||
data = NULL;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
char *readNextFrame(std::ifstream &filebin, int &ff, int &np, char *data) {
|
||||
//char *retval = 0;
|
||||
//int nd;
|
||||
//int fnum = -1;
|
||||
np = 0;
|
||||
//int pn;
|
||||
|
||||
//std::cout << dataSize << std::endl;
|
||||
//if (ff >= 0) {
|
||||
// fnum = ff; }
|
||||
|
||||
if (filebin.is_open()) {
|
||||
if (filebin.read(data, dataSize)) {
|
||||
std::cout << "*";
|
||||
ff = getFrameNumber(data);
|
||||
np = getPacketNumber(data);
|
||||
return data;
|
||||
}
|
||||
std::cout << "#";
|
||||
} else {
|
||||
std::cout << "File not open" << std::endl;
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
/* Loops over a memory slot until a complete frame is found (i.e. all */
|
||||
/* packets 0 to nPackets, same frame number). purely virtual func \param
|
||||
*/
|
||||
/* data pointer to the memory to be analyzed \param ndata reference to
|
||||
* the */
|
||||
/* amount of data found for the frame, in case the frame is incomplete at
|
||||
*/
|
||||
/* the end of the memory slot \param dsize size of the memory slot to be
|
||||
*/
|
||||
/* analyzed \returns pointer to the beginning of the last good frame
|
||||
* (might */
|
||||
/* be incomplete if ndata smaller than dataSize), or NULL if no frame is
|
||||
*/
|
||||
/* found */
|
||||
|
||||
/* *\/ */
|
||||
virtual char *findNextFrame(char *data, int &ndata, int dsize) {
|
||||
if (dsize < dataSize)
|
||||
ndata = dsize;
|
||||
else
|
||||
ndata = dataSize;
|
||||
return data;
|
||||
};
|
||||
|
||||
// int getPacketNumber(int x, int y) {return dataMap[y][x]/packetSize;};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,432 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#ifndef JUNGFRAULGADSTRIXELSDATAQUADH5_H
|
||||
#define JUNGFRAULGADSTRIXELSDATAQUADH5_H
|
||||
#ifdef CINT
|
||||
#include "sls/sls_detector_defs_CINT.h"
|
||||
#else
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#endif
|
||||
#include "slsDetectorData.h"
|
||||
|
||||
// This needs to be linked correctly
|
||||
#include "HDF5File.cpp"
|
||||
#include "HDF5File.h" //this includes hdf5.h and hdf5_hl.h
|
||||
|
||||
// #define VERSION_V2
|
||||
/**
|
||||
@short structure for a Detector Packet or Image Header
|
||||
@li frameNumber is the frame number
|
||||
@li expLength is the subframe number (32 bit eiger) or real time exposure
|
||||
time in 100ns (others)
|
||||
@li packetNumber is the packet number
|
||||
@li bunchId is the bunch id from beamline
|
||||
@li timestamp is the time stamp with 10 MHz clock
|
||||
@li modId is the unique module id (unique even for left, right, top, bottom)
|
||||
@li xCoord is the x coordinate in the complete detector system
|
||||
@li yCoord is the y coordinate in the complete detector system
|
||||
@li zCoord is the z coordinate in the complete detector system
|
||||
@li debug is for debugging purposes
|
||||
@li roundRNumber is the round robin set number
|
||||
@li detType is the detector type see :: detectorType
|
||||
@li version is the version number of this structure format
|
||||
*/
|
||||
|
||||
// #include <algorithm>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
|
||||
namespace strixelQuad {
|
||||
constexpr int nc_rawimg = 1024; // for full images //256;
|
||||
constexpr int nc_quad = 512;
|
||||
constexpr int nr_rawimg = 512;
|
||||
constexpr int nr_chip = 256;
|
||||
constexpr int gr = 9;
|
||||
|
||||
// shift due to extra pixels
|
||||
constexpr int shift_x = 2; // left
|
||||
|
||||
constexpr int nc_strixel = (nc_quad - shift_x - 2 * gr) / 3; // 164
|
||||
constexpr int nr_strixel =
|
||||
(nr_chip - 1 - gr) * 3; // one half (-1 because double sided pixel) //738
|
||||
constexpr int nr_center = 12; // double sided pixels to be skipped
|
||||
|
||||
// boundaries in ASIC coordinates (pixels at both bounds are included)
|
||||
constexpr int xstart = 256 + gr; // 265
|
||||
constexpr int xend = 255 + nc_quad - gr; // 758
|
||||
constexpr int bottom_ystart = gr; // 9
|
||||
constexpr int bottom_yend = nr_chip - 2; // 254
|
||||
constexpr int top_ystart = nr_chip + 1; // 257
|
||||
constexpr int top_yend = nr_chip * 2 - gr - 1; // 502
|
||||
|
||||
// x shift because of 2-pixel strixels on one side
|
||||
constexpr int shift = 2;
|
||||
|
||||
} // namespace strixelQuad
|
||||
|
||||
// to account for module rotation
|
||||
enum rotation { NORMAL = 0, INVERSE = 1 };
|
||||
|
||||
const int rota = NORMAL;
|
||||
|
||||
typedef struct {
|
||||
uint64_t bunchNumber; /**< is the frame number */
|
||||
uint64_t pre; /**< something */
|
||||
|
||||
} jf_header; // Aldo's header
|
||||
|
||||
using namespace strixelQuad;
|
||||
|
||||
class jungfrauLGADStrixelsDataQuadH5 : public slsDetectorData<uint16_t> {
|
||||
|
||||
private:
|
||||
int iframe;
|
||||
int x0, y0, x1, y1, shifty;
|
||||
struct {
|
||||
uint16_t xmin;
|
||||
uint16_t xmax;
|
||||
uint16_t ymin;
|
||||
uint16_t ymax;
|
||||
int nc;
|
||||
} globalROI;
|
||||
|
||||
// to account for the inverted routing of the two different quad halfs
|
||||
enum location { BOTTOM = 0, TOP = 1 };
|
||||
|
||||
int multiplicator = 3;
|
||||
std::vector<int> mods{0, 1, 2};
|
||||
|
||||
void reverseVector(std::vector<int> &v) {
|
||||
std::reverse(v.begin(), v.end());
|
||||
std::cout << "mods reversed ";
|
||||
for (auto i : v)
|
||||
std::cout << i << " ";
|
||||
std::cout << '\n';
|
||||
}
|
||||
|
||||
void setMappingShifts(const int rot, const int half) {
|
||||
|
||||
x0 = xstart;
|
||||
x1 = xend;
|
||||
|
||||
if (rot == NORMAL) {
|
||||
x0 += shift;
|
||||
} else {
|
||||
x1 -= shift;
|
||||
reverseVector(mods);
|
||||
}
|
||||
|
||||
if (half == BOTTOM) {
|
||||
y0 = bottom_ystart;
|
||||
y1 = bottom_yend;
|
||||
shifty = 0;
|
||||
} else {
|
||||
y0 = top_ystart;
|
||||
y1 = top_yend;
|
||||
reverseVector(mods);
|
||||
shifty = nr_strixel + nr_center; // double-sided pixels in the
|
||||
// center have to be jumped
|
||||
}
|
||||
}
|
||||
|
||||
void remap(int xmin = 0, int xmax = 0, int ymin = 0, int ymax = 0) {
|
||||
|
||||
int ix, iy = 0;
|
||||
// remapping loop
|
||||
for (int ipy = y0; ipy <= y1; ++ipy) {
|
||||
for (int ipx = x0; ipx <= x1; ++ipx) {
|
||||
|
||||
ix = int((ipx - x0) / multiplicator);
|
||||
for (int m = 0; m < multiplicator; ++m) {
|
||||
if ((ipx - x0) % multiplicator == m)
|
||||
iy = (ipy - y0) * multiplicator + mods[m] + shifty;
|
||||
}
|
||||
|
||||
// if (iy< 40) cout << iy << " " << ix <<endl;
|
||||
if (xmin < xmax && ymin < ymax) { // if ROI
|
||||
if (ipx >= xmin && ipx <= xmax && ipy >= ymin &&
|
||||
ipy <= ymax)
|
||||
dataMap[iy][ix] =
|
||||
(globalROI.nc * (ipy - globalROI.ymin) +
|
||||
(ipx - globalROI.xmin)) *
|
||||
2;
|
||||
} else { // if full Quad
|
||||
dataMap[iy][ix] = (nc_rawimg * ipy + ipx) * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void remapQuad(const int rot) {
|
||||
|
||||
setMappingShifts(rot, BOTTOM);
|
||||
remap();
|
||||
setMappingShifts(rot, TOP);
|
||||
remap();
|
||||
}
|
||||
|
||||
std::tuple<uint16_t, uint16_t, uint16_t, uint16_t>
|
||||
adjustROItoLimits(uint16_t xmin, uint16_t xmax, uint16_t ymin,
|
||||
uint16_t ymax, uint16_t lim_roi_xmin,
|
||||
uint16_t lim_roi_xmax, uint16_t lim_roi_ymin,
|
||||
uint16_t lim_roi_ymax) {
|
||||
uint16_t xmin_roi, xmax_roi, ymin_roi, ymax_roi;
|
||||
if (xmin < lim_roi_xmin)
|
||||
xmin_roi = lim_roi_xmin;
|
||||
else
|
||||
xmin_roi = xmin;
|
||||
if (xmax > lim_roi_xmax)
|
||||
xmax_roi = lim_roi_xmax;
|
||||
else
|
||||
xmax_roi = xmax;
|
||||
if (ymin < lim_roi_ymin)
|
||||
ymin_roi = lim_roi_ymin;
|
||||
else
|
||||
ymin_roi = ymin;
|
||||
if (ymax > lim_roi_ymax)
|
||||
ymax_roi = lim_roi_ymax;
|
||||
else
|
||||
ymax_roi = ymax;
|
||||
return std::make_tuple(xmin_roi, xmax_roi, ymin_roi, ymax_roi);
|
||||
}
|
||||
|
||||
// The strixel Quad has a mirrored symmetry from the center axis
|
||||
// So we need to distinguish between bottom and top half for remapping
|
||||
std::vector<std::tuple<int, uint16_t, uint16_t, uint16_t, uint16_t>>
|
||||
mapSubROIs(uint16_t xmin, uint16_t xmax, uint16_t ymin, uint16_t ymax) {
|
||||
bool bottom = false;
|
||||
bool top = false;
|
||||
|
||||
for (int x = xmin; x != xmax + 1; ++x) {
|
||||
for (int y = ymin; y != ymax; ++y) {
|
||||
if (xstart <= x && x <= xend && bottom_ystart <= y &&
|
||||
y <= bottom_yend)
|
||||
bottom = true;
|
||||
if (xstart <= x && x <= xend && top_ystart <= y &&
|
||||
y <= top_yend)
|
||||
top = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t xmin_roi{}, xmax_roi{}, ymin_roi{}, ymax_roi{};
|
||||
std::vector<std::tuple<int, uint16_t, uint16_t, uint16_t, uint16_t>>
|
||||
rois{};
|
||||
|
||||
if (bottom) {
|
||||
std::tie(xmin_roi, xmax_roi, ymin_roi, ymax_roi) =
|
||||
adjustROItoLimits(xmin, xmax, ymin, ymax, xstart, xend,
|
||||
bottom_ystart, bottom_yend);
|
||||
rois.push_back(std::make_tuple(BOTTOM, xmin_roi, xmax_roi, ymin_roi,
|
||||
ymax_roi));
|
||||
}
|
||||
if (top) {
|
||||
std::tie(xmin_roi, xmax_roi, ymin_roi, ymax_roi) =
|
||||
adjustROItoLimits(xmin, xmax, ymin, ymax, xstart, xend,
|
||||
top_ystart, top_yend);
|
||||
rois.push_back(
|
||||
std::make_tuple(TOP, xmin_roi, xmax_roi, ymin_roi, ymax_roi));
|
||||
}
|
||||
|
||||
return rois;
|
||||
}
|
||||
|
||||
void remapROI(std::tuple<int, uint16_t, uint16_t, uint16_t, uint16_t> roi,
|
||||
const int rot) {
|
||||
|
||||
int half, xmin, xmax, ymin, ymax;
|
||||
std::tie(half, xmin, xmax, ymin, ymax) = roi;
|
||||
|
||||
setMappingShifts(rot, half);
|
||||
|
||||
std::cout << "remapping roi: "
|
||||
<< ", x0: " << x0 << ", x1: " << x1 << ", y0: " << y0
|
||||
<< ", y1: " << y1 << std::endl;
|
||||
std::cout << "Adjusted roi: [" << xmin << ", " << xmax << ", " << ymin
|
||||
<< ", " << ymax << "]" << std::endl;
|
||||
|
||||
remap(xmin, xmax, ymin, ymax);
|
||||
}
|
||||
|
||||
// The following functions are pure virtual in the base class. But I don't
|
||||
// want them to be accessible here! Implement the functions as private (to
|
||||
// satisfy the linker) int getFrameNumber(char* buff){return 0;} //This is
|
||||
// actually needed because the cluster finder writes the framenumber
|
||||
int getPacketNumber(char *buff) { return 0; } // Not provided
|
||||
|
||||
// Mark overwritten functions as override final
|
||||
char *readNextFrame(std::ifstream &filebin) override final {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
using header = sls::defs::sls_receiver_header;
|
||||
|
||||
jungfrauLGADStrixelsDataQuadH5(uint16_t xmin = 0, uint16_t xmax = 0,
|
||||
uint16_t ymin = 0, uint16_t ymax = 0)
|
||||
: slsDetectorData<uint16_t>(
|
||||
// nc_strixel,
|
||||
// nr_strixel * 2 + nr_center,
|
||||
// nc_strixel * ( nr_strixel * 2 + nr_center ) * 2
|
||||
512 / 2, 1024 * 2, 512 * 1024 * 2) {
|
||||
std::cout << "Jungfrau strixels quad with full module data "
|
||||
<< std::endl;
|
||||
|
||||
// Fill all strixels with dummy values
|
||||
// for (int ix = 0; ix != nc_strixel; ++ix) {
|
||||
// for (int iy = 0; iy != nr_strixel * 2 + nr_center; ++iy) {
|
||||
for (int ix = 0; ix != 512 / 2; ++ix) {
|
||||
for (int iy = 0; iy != 1024 * 2; ++iy) {
|
||||
// Set everything to dummy value
|
||||
dataMap[iy][ix] = sizeof(header);
|
||||
}
|
||||
}
|
||||
|
||||
globalROI.xmin = xmin;
|
||||
globalROI.xmax = xmax;
|
||||
globalROI.ymin = ymin;
|
||||
globalROI.ymax = ymax;
|
||||
|
||||
// std::cout << "sizeofheader = " << sizeof(header) << std::endl;
|
||||
std::cout << "Jungfrau strixels quad with full module data "
|
||||
<< std::endl;
|
||||
|
||||
if (xmin < xmax && ymin < ymax) {
|
||||
|
||||
// get ROI raw image number of columns
|
||||
globalROI.nc = xmax - xmin + 1;
|
||||
std::cout << "nc_roi = " << globalROI.nc << std::endl;
|
||||
|
||||
dataSize = (xmax - xmin + 1) * (ymax - ymin + 1) * 2;
|
||||
std::cout << "datasize " << dataSize << std::endl;
|
||||
|
||||
auto rois = mapSubROIs(xmin, xmax, ymin, ymax);
|
||||
// function to fill vector of rois from globalROI
|
||||
|
||||
for (auto roi : rois)
|
||||
remapROI(roi, rota);
|
||||
|
||||
} else {
|
||||
remapQuad(rota);
|
||||
}
|
||||
|
||||
iframe = 0;
|
||||
std::cout << "data struct created" << std::endl;
|
||||
};
|
||||
|
||||
/**
|
||||
Returns the value of the selected channel for the given dataset as
|
||||
double. \param data pointer to the dataset (including headers etc) \param
|
||||
ix pixel number in the x direction \param iy pixel number in the y
|
||||
direction \returns data for the selected channel, with inversion if
|
||||
required as double
|
||||
|
||||
*/
|
||||
virtual double getValue(char *data, int ix, int iy = 0) {
|
||||
|
||||
uint16_t val = getChannel(data, ix, iy) & 0x3fff;
|
||||
return val;
|
||||
};
|
||||
|
||||
char *readNextFrame(HDF5File &hfile) {
|
||||
int fn = 0;
|
||||
std::vector<hsize_t> h5offset(1);
|
||||
return readNextFrame(hfile, fn, h5offset);
|
||||
};
|
||||
|
||||
char *readNextFrame(HDF5File &hfile, int &fn) {
|
||||
std::vector<hsize_t> h5offset(1);
|
||||
return readNextFrame(hfile, fn, h5offset);
|
||||
};
|
||||
|
||||
char *readNextFrame(HDF5File &hfile, int &fn,
|
||||
std::vector<hsize_t> &h5offset) {
|
||||
|
||||
// Ensure dataSize is a valid size for allocation
|
||||
if (dataSize <= 0) {
|
||||
// Handle error case appropriately, e.g., log an error message
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char *data = new char[dataSize];
|
||||
char *readResult = readNextFrame(hfile, fn, h5offset, data);
|
||||
|
||||
// Check if reading failed
|
||||
if (readResult == nullptr) {
|
||||
delete[] data; // Free allocated memory
|
||||
data = nullptr; // Set to nullptr to avoid dangling pointer
|
||||
}
|
||||
|
||||
return data; // returning data is equivalent to returning
|
||||
// reinterpret_cast<char*>(data_ptr) as they both point to
|
||||
// the same memory
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the most recent function. This is used in the cluster finder!
|
||||
* The overloads are legacy!
|
||||
* Note that caller has to allocate and deallocate memory for data!
|
||||
* \param hfile object of type HDF5File (reader class)
|
||||
* \param framenumber frame number as read from the HDF5 file
|
||||
* \param h5offset vector defining offset parameters for HDF5 hyperslab
|
||||
* selection (dimensions Z and S), incremented automatially
|
||||
* \param data pointer to image buffer (converted to hold uint16_t by
|
||||
* definition of HDF5File)
|
||||
*/
|
||||
char *readNextFrame(HDF5File &hfile, int &framenumber,
|
||||
std::vector<hsize_t> &h5offset, char *data) {
|
||||
|
||||
if (framenumber >= 0) {
|
||||
if (h5offset[0] % 10 == 0)
|
||||
std::cout << "*";
|
||||
|
||||
// Storing the reinterpret_cast in the variable data_ptr ensures
|
||||
// that I can pass it to a function that expects at uint16_t*
|
||||
uint16_t *data_ptr = reinterpret_cast<uint16_t *>(
|
||||
data); // now data_ptr points where data points (thus modifies
|
||||
// the same memory)
|
||||
|
||||
framenumber = hfile.ReadImage(data_ptr, h5offset);
|
||||
iframe = h5offset[0]; // iframe is a class member!
|
||||
return data; // return reinterpret_cast<char*>(data_ptr); //
|
||||
// Equivalent
|
||||
}
|
||||
|
||||
std::cout << "#";
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
int getFrameNumber(char *buff) {
|
||||
return iframe;
|
||||
} // Provided via public method readNextFrame
|
||||
// It is debatable if one might not instead want to provide the "real" frame
|
||||
// number as read from the file here For now, this is the frame offset
|
||||
// counter (that always has to start at 0 for each new file)
|
||||
|
||||
/* Loops over a memory slot until a complete frame is found (i.e. all */
|
||||
/* packets 0 to nPackets, same frame number). purely virtual func \param
|
||||
*/
|
||||
/* data pointer to the memory to be analyzed \param ndata reference to
|
||||
* the */
|
||||
/* amount of data found for the frame, in case the frame is incomplete at
|
||||
*/
|
||||
/* the end of the memory slot \param dsize size of the memory slot to be
|
||||
*/
|
||||
/* analyzed \returns pointer to the beginning of the last good frame
|
||||
* (might */
|
||||
/* be incomplete if ndata smaller than dataSize), or NULL if no frame is
|
||||
*/
|
||||
/* found */
|
||||
|
||||
/* *\/ */
|
||||
virtual char *findNextFrame(char *data, int &ndata, int dsize) {
|
||||
if (dsize < dataSize)
|
||||
ndata = dsize;
|
||||
else
|
||||
ndata = dataSize;
|
||||
return data;
|
||||
};
|
||||
|
||||
// int getPacketNumber(int x, int y) {return dataMap[y][x]/packetSize;};
|
||||
};
|
||||
|
||||
#endif
|
@ -28,10 +28,6 @@
|
||||
@li version is the version number of this structure format
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <tuple>
|
||||
|
||||
namespace strixelSingleChip {
|
||||
constexpr int nc_rawimg = 1024; // for full images //256;
|
||||
constexpr int nr_rawimg = 512;
|
||||
@ -81,7 +77,7 @@ constexpr int c6g1_ystart = c6g2_yend + 1; // 448
|
||||
constexpr int c6g1_yend = c6g2_yend + 64 - gr; // 502
|
||||
|
||||
// y shift due to faulty bonding (relevant for M408)
|
||||
constexpr int bond_shift_y = 0; // CHANGE IF YOU CHANGE MODULE!
|
||||
constexpr int bond_shift_y = 1; // CHANGE IF YOU CHANGE MODULE!
|
||||
|
||||
} // namespace strixelSingleChip
|
||||
|
||||
@ -101,13 +97,6 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
|
||||
int chip_x0;
|
||||
int chip_y0;
|
||||
int x0, y0, x1, y1, shifty;
|
||||
struct {
|
||||
uint16_t xmin;
|
||||
uint16_t xmax;
|
||||
uint16_t ymin;
|
||||
uint16_t ymax;
|
||||
int nc;
|
||||
} globalROI;
|
||||
|
||||
int getMultiplicator(const int group) {
|
||||
int multiplicator;
|
||||
@ -226,113 +215,9 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::tuple< uint16_t, uint16_t, uint16_t, uint16_t > adjustROItoLimits(uint16_t xmin,
|
||||
uint16_t xmax,
|
||||
uint16_t ymin,
|
||||
uint16_t ymax,
|
||||
uint16_t lim_roi_xmin,
|
||||
uint16_t lim_roi_xmax,
|
||||
uint16_t lim_roi_ymin,
|
||||
uint16_t lim_roi_ymax) {
|
||||
uint16_t xmin_roi, xmax_roi, ymin_roi, ymax_roi;
|
||||
if ( xmin < lim_roi_xmin)
|
||||
xmin_roi = lim_roi_xmin;
|
||||
else
|
||||
xmin_roi = xmin;
|
||||
if ( xmax > lim_roi_xmax )
|
||||
xmax_roi = lim_roi_xmax;
|
||||
else
|
||||
xmax_roi = xmax;
|
||||
if ( ymin < lim_roi_ymin )
|
||||
ymin_roi = lim_roi_ymin;
|
||||
else
|
||||
ymin_roi = ymin;
|
||||
if ( ymax > lim_roi_ymax )
|
||||
ymax_roi = lim_roi_ymax;
|
||||
else
|
||||
ymax_roi = ymax;
|
||||
return std::make_tuple(xmin_roi, xmax_roi, ymin_roi, ymax_roi);
|
||||
}
|
||||
|
||||
std::vector < std::tuple< int, int, uint16_t, uint16_t, uint16_t, uint16_t > > mapSubROIs(uint16_t xmin,
|
||||
uint16_t xmax,
|
||||
uint16_t ymin,
|
||||
uint16_t ymax) {
|
||||
bool chip_1_1 = false;
|
||||
bool chip_1_2 = false;
|
||||
bool chip_1_3 = false;
|
||||
bool chip_6_1 = false;
|
||||
bool chip_6_2 = false;
|
||||
bool chip_6_3 = false;
|
||||
|
||||
for ( int x=xmin; x!=xmax+1; ++x ) {
|
||||
for ( int y=ymin; y!=ymax; ++y ) {
|
||||
if ( c1g1_xstart<=x && x<=c1_xend && (c1g1_ystart+bond_shift_y)<=y && y<=(c1g1_yend+bond_shift_y) )
|
||||
chip_1_1 = true;
|
||||
if ( c1g2_xstart<=x && x<=c1_xend && (c1g2_ystart+bond_shift_y)<=y && y<=(c1g2_yend+bond_shift_y) )
|
||||
chip_1_2 = true;
|
||||
if ( c1g3_xstart<=x && x<=c1_xend && (c1g3_ystart+bond_shift_y)<=y && y<=(c1g3_yend+bond_shift_y) )
|
||||
chip_1_3 = true;
|
||||
if ( c6_xstart<=x && x<=c6g1_xend && (c6g1_ystart-bond_shift_y)<=y && y<=(c6g1_yend-bond_shift_y) )
|
||||
chip_6_1 = true;
|
||||
if ( c6_xstart<=x && x<=c6g2_xend && (c6g2_ystart-bond_shift_y)<=y && y<=(c6g2_yend-bond_shift_y) )
|
||||
chip_6_2 = true;
|
||||
if ( c6_xstart<=x && x<=c6g3_xend && (c6g3_ystart-bond_shift_y)<=y && y<=(c6g3_yend-bond_shift_y) )
|
||||
chip_6_3 = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t xmin_roi{}, xmax_roi{}, ymin_roi{}, ymax_roi{};
|
||||
//[ chip, group, xmin, xmax, ymin, ymax ]
|
||||
std::vector < std::tuple< int, int, uint16_t, uint16_t, uint16_t, uint16_t > > rois{};
|
||||
|
||||
if (chip_1_1) {
|
||||
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
|
||||
adjustROItoLimits( xmin, xmax, ymin, ymax,
|
||||
c1g1_xstart, c1_xend, 0, c1g1_yend+bond_shift_y );
|
||||
rois.push_back( std::make_tuple( 1, 1, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
|
||||
}
|
||||
if (chip_1_2) {
|
||||
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
|
||||
adjustROItoLimits( xmin, xmax, ymin, ymax,
|
||||
c1g2_xstart, c1_xend, c1g2_ystart+bond_shift_y, c1g2_yend+bond_shift_y );
|
||||
rois.push_back( std::make_tuple( 1, 2, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
|
||||
}
|
||||
if (chip_1_3) {
|
||||
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
|
||||
adjustROItoLimits( xmin, xmax, ymin, ymax,
|
||||
c1g3_xstart, c1_xend, c1g3_ystart+bond_shift_y, c1g3_yend+bond_shift_y );
|
||||
rois.push_back( std::make_tuple( 1, 3, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
|
||||
}
|
||||
if (chip_6_3) {
|
||||
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
|
||||
adjustROItoLimits( xmin, xmax, ymin, ymax,
|
||||
c6_xstart, c6g3_xend, c6g3_ystart-bond_shift_y, c6g3_yend-bond_shift_y );
|
||||
rois.push_back( std::make_tuple( 6, 3, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
|
||||
}
|
||||
if (chip_6_2) {
|
||||
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
|
||||
adjustROItoLimits( xmin, xmax, ymin, ymax,
|
||||
c6_xstart, c6g2_xend, c6g2_ystart-bond_shift_y, c6g2_yend-bond_shift_y );
|
||||
rois.push_back( std::make_tuple( 6, 2, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
|
||||
}
|
||||
if (chip_6_1) {
|
||||
std::tie( xmin_roi, xmax_roi, ymin_roi, ymax_roi ) =
|
||||
adjustROItoLimits( xmin, xmax, ymin, ymax,
|
||||
c6_xstart, c6g1_xend, c6g1_ystart-bond_shift_y, 511 );
|
||||
rois.push_back( std::make_tuple( 6, 1, xmin_roi, xmax_roi, ymin_roi, ymax_roi ) );
|
||||
}
|
||||
|
||||
return rois;
|
||||
|
||||
}
|
||||
|
||||
void remapROI(std::tuple< int, int, uint16_t, uint16_t, uint16_t, uint16_t > roi) {
|
||||
void remapROI(uint16_t xmin, uint16_t xmax, uint16_t ymin, uint16_t ymax) {
|
||||
// determine group and chip selected by ROI
|
||||
int group, xmin, xmax, ymin, ymax;
|
||||
std::tie( mchip, group, xmin, xmax, ymin, ymax ) = roi;
|
||||
/*
|
||||
int group;
|
||||
if (ymax <= c1g1_yend + bond_shift_y) {
|
||||
group = 1;
|
||||
mchip = 1;
|
||||
@ -358,17 +243,18 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
|
||||
group = -1;
|
||||
mchip = -1;
|
||||
}
|
||||
*/
|
||||
int multiplicator = getMultiplicator(group);
|
||||
setMappingShifts(group);
|
||||
|
||||
std::cout << "remapping chip: " << mchip << ", group: " << group << ", m: " << multiplicator
|
||||
<< ", x0: " << x0 << ", x1: " << x1 << ", y0: " << y0
|
||||
<< ", y1: " << y1 << std::endl;
|
||||
std::cout << "Adjusted roi: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]" << std::endl;
|
||||
int multiplicator = getMultiplicator(group);
|
||||
setMappingShifts(group);
|
||||
|
||||
std::cout << "chip: " << mchip << ", group: " << group << ", m: " << multiplicator
|
||||
<< ", x0: " << x0 << ", x1: " << x1 << ", y0: " << y0
|
||||
<< ", y1: " << y1 << std::endl;
|
||||
|
||||
// get ROI raw image number of columns
|
||||
int nc_roi = xmax - xmin + 1;
|
||||
std::cout << "nc_roi = " << nc_roi << std::endl;
|
||||
|
||||
// make sure loop bounds are correct
|
||||
/*
|
||||
if (y0 < ymin)
|
||||
std::cout << "Error ymin" << std::endl;
|
||||
if (y1 > ymax)
|
||||
@ -378,27 +264,24 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
|
||||
std::cout << "Error xmin" << std::endl;
|
||||
if (x1 > xmax)
|
||||
std::cout << "Error xmax" << std::endl;
|
||||
*/
|
||||
|
||||
// remapping loop
|
||||
int ix, iy = 0;
|
||||
for (int ipy = y0; ipy <= y1; ++ipy) {
|
||||
for (int ipx = x0; ipx <= x1; ++ipx) {
|
||||
int ix, iy = 0;
|
||||
for (int ipy = y0; ipy <= y1; ++ipy) {
|
||||
for (int ipx = x0; ipx <= x1; ++ipx) {
|
||||
|
||||
ix = int((ipx - x0 /*-xmin*/) / multiplicator);
|
||||
for (int m = 0; m < multiplicator; m++) {
|
||||
if ((ipx - x0 /*-xmin*/) % multiplicator == m)
|
||||
iy = (ipy - y0 /*-ymin*/) * multiplicator + m + shifty;
|
||||
}
|
||||
|
||||
// if (iy< 40) cout << iy << " " << ix <<endl;
|
||||
if ( ipx>=xmin && ipx<=xmax && ipy>=ymin && ipy <=ymax )
|
||||
dataMap[iy][ix] =
|
||||
sizeof(header) + (globalROI.nc * (ipy - globalROI.ymin) + (ipx - globalROI.xmin)) * 2;
|
||||
else dataMap[iy][ix] = sizeof(header);
|
||||
groupmap[iy][ix] = group - 1;
|
||||
}
|
||||
}
|
||||
ix = int((ipx - x0 /*-xmin*/) / multiplicator);
|
||||
for (int m = 0; m < multiplicator; m++) {
|
||||
if ((ipx - x0 /*-xmin*/) % multiplicator == m)
|
||||
iy = (ipy - y0 /*-ymin*/) * multiplicator + m + shifty;
|
||||
}
|
||||
|
||||
// if (iy< 40) cout << iy << " " << ix <<endl;
|
||||
dataMap[iy][ix] =
|
||||
sizeof(header) + (nc_roi * (ipy - ymin) + (ipx - xmin)) * 2;
|
||||
groupmap[iy][ix] = group - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@ -424,31 +307,16 @@ class jungfrauLGADStrixelsData : public slsDetectorData<uint16_t> {
|
||||
}
|
||||
}
|
||||
|
||||
globalROI.xmin = xmin;
|
||||
globalROI.xmax = xmax;
|
||||
globalROI.ymin = ymin;
|
||||
globalROI.ymax = ymax;
|
||||
|
||||
std::cout << "sizeofheader = " << sizeof(header) << std::endl;
|
||||
std::cout << "Jungfrau strixels 2X single chip with full module data "
|
||||
<< std::endl;
|
||||
|
||||
if (xmin < xmax && ymin < ymax) {
|
||||
|
||||
// get ROI raw image number of columns
|
||||
globalROI.nc = xmax - xmin + 1;
|
||||
std::cout << "nc_roi = " << globalROI.nc << std::endl;
|
||||
|
||||
dataSize =
|
||||
(xmax - xmin + 1) * (ymax - ymin + 1) * 2 + sizeof(header);
|
||||
std::cout << "datasize " << dataSize << std::endl;
|
||||
|
||||
//[ chip, group, xmin, xmax, ymin, ymax ]
|
||||
auto rois = mapSubROIs(xmin, xmax, ymin, ymax);
|
||||
//function to fill vector of rois from globalROI
|
||||
|
||||
for ( auto roi : rois )
|
||||
remapROI(roi);
|
||||
dataSize =
|
||||
(xmax - xmin + 1) * (ymax - ymin + 1) * 2 + sizeof(header);
|
||||
std::cout << "datasize " << dataSize << std::endl;
|
||||
remapROI(xmin, xmax, ymin, ymax);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
#ifndef JUNGFRAUMODULEDATA_H
|
||||
#define JUNGFRAUMODULEDATA_H
|
||||
#include <cstdint>
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "slsDetectorData.h"
|
||||
|
||||
//#define VERSION_V2
|
||||
@ -28,7 +27,7 @@ typedef struct {
|
||||
uint64_t bunchNumber; /**< is the frame number */
|
||||
uint64_t pre; /**< something */
|
||||
|
||||
} jf_header; //Aldo's header!
|
||||
} jf_header;
|
||||
|
||||
using namespace std;
|
||||
class jungfrauModuleData : public slsDetectorData<uint16_t> {
|
||||
@ -43,56 +42,20 @@ class jungfrauModuleData : public slsDetectorData<uint16_t> {
|
||||
1286 large etc.) \param c crosstalk parameter for the output buffer
|
||||
|
||||
*/
|
||||
|
||||
#ifdef ALDO
|
||||
using header = jf_header;
|
||||
#else
|
||||
using header = sls::defs::sls_receiver_header;
|
||||
#endif
|
||||
|
||||
#ifndef ZMQ
|
||||
#define off sizeof(header)
|
||||
#define off sizeof(jf_header)
|
||||
#endif
|
||||
#ifdef ZMQ
|
||||
#define off 0
|
||||
#endif
|
||||
|
||||
|
||||
jungfrauModuleData(uint16_t xmin=0, uint16_t xmax=0,
|
||||
uint16_t ymin=0, uint16_t ymax=0)
|
||||
jungfrauModuleData()
|
||||
: slsDetectorData<uint16_t>(1024, 512,
|
||||
1024* 512 * 2 + off) {
|
||||
|
||||
for (int ix = 0; ix != 1024; ++ix) {
|
||||
for (int iy = 0; iy != 512; ++iy) {
|
||||
dataMap[iy][ix] = off;
|
||||
}
|
||||
}
|
||||
|
||||
if (xmin < xmax && ymin < ymax) {
|
||||
|
||||
int nc_roi = xmax - xmin + 1;
|
||||
int nr_roi = ymax - ymin + 1;
|
||||
std::cout << "nc_roi = " << nc_roi << std::endl;
|
||||
std::cout << "nr_roi = " << nr_roi << std::endl;
|
||||
|
||||
dataSize =
|
||||
(xmax - xmin + 1) * (ymax - ymin + 1) * 2 + off;
|
||||
std::cout << "datasize " << dataSize << std::endl;
|
||||
|
||||
for (int ix = xmin; ix < xmax+1; ++ix) {
|
||||
for (int iy = ymin; iy < ymax+1; ++iy) {
|
||||
dataMap[iy][ix] = off + (nc_roi * iy + ix) * 2;
|
||||
#ifdef HIGHZ
|
||||
dataMask[iy][ix] = 0x3fff;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (int ix = 0; ix < 1024; ++ix) {
|
||||
for (int iy = 0; iy < 512; ++iy) {
|
||||
|
||||
for (int ix = 0; ix < 1024; ix++) {
|
||||
for (int iy = 0; iy < 512; iy++) {
|
||||
dataMap[iy][ix] = off + (1024 * iy + ix) * 2;
|
||||
#ifdef HIGHZ
|
||||
dataMask[iy][ix] = 0x3fff;
|
||||
@ -100,7 +63,7 @@ class jungfrauModuleData : public slsDetectorData<uint16_t> {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
iframe = 0;
|
||||
@ -187,7 +150,7 @@ class jungfrauModuleData : public slsDetectorData<uint16_t> {
|
||||
//int pn;
|
||||
|
||||
// cout << dataSize << endl;
|
||||
//if (ff >= 0)
|
||||
if (ff >= 0)
|
||||
//fnum = ff;
|
||||
|
||||
if (filebin.is_open()) {
|
||||
|
@ -1,226 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#ifndef JUNGFRAUSINGLECHIPDATA_H
|
||||
#define JUNGFRAUSINGLECHIPDATA_H
|
||||
#include <cstdint>
|
||||
#include "sls/sls_detector_defs.h"
|
||||
#include "slsDetectorData.h"
|
||||
|
||||
//#define VERSION_V2
|
||||
/**
|
||||
@short structure for a Detector Packet or Image Header
|
||||
@li frameNumber is the frame number
|
||||
@li expLength is the subframe number (32 bit eiger) or real time exposure
|
||||
time in 100ns (others)
|
||||
@li packetNumber is the packet number
|
||||
@li bunchId is the bunch id from beamline
|
||||
@li timestamp is the time stamp with 10 MHz clock
|
||||
@li modId is the unique module id (unique even for left, right, top, bottom)
|
||||
@li xCoord is the x coordinate in the complete detector system
|
||||
@li yCoord is the y coordinate in the complete detector system
|
||||
@li zCoord is the z coordinate in the complete detector system
|
||||
@li debug is for debugging purposes
|
||||
@li roundRNumber is the round robin set number
|
||||
@li detType is the detector type see :: detectorType
|
||||
@li version is the version number of this structure format
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t bunchNumber; /**< is the frame number */
|
||||
uint64_t pre; /**< something */
|
||||
|
||||
} jf_header; //Aldo's header!
|
||||
|
||||
using namespace std;
|
||||
class jungfrauSingleChipData : public slsDetectorData<uint16_t> {
|
||||
|
||||
private:
|
||||
int iframe;
|
||||
|
||||
public:
|
||||
/**
|
||||
Implements the slsReceiverData structure for the moench02 prototype read
|
||||
out by a module i.e. using the slsReceiver (160x160 pixels, 40 packets
|
||||
1286 large etc.) \param c crosstalk parameter for the output buffer
|
||||
|
||||
*/
|
||||
|
||||
#ifdef ALDO
|
||||
using header = jf_header;
|
||||
#else
|
||||
using header = sls::defs::sls_receiver_header;
|
||||
#endif
|
||||
|
||||
#ifndef ZMQ
|
||||
#define off sizeof(header)
|
||||
#endif
|
||||
#ifdef ZMQ
|
||||
#define off 0
|
||||
#endif
|
||||
|
||||
|
||||
jungfrauSingleChipData(uint16_t xmin=0, uint16_t xmax=0,
|
||||
uint16_t ymin=0, uint16_t ymax=0)
|
||||
: slsDetectorData<uint16_t>(256, 256,
|
||||
256* 256 * 2 + off) {
|
||||
|
||||
for (int ix = 0; ix != 256; ++ix) {
|
||||
for (int iy = 0; iy != 256; ++iy) {
|
||||
dataMap[iy][ix] = off;
|
||||
}
|
||||
}
|
||||
|
||||
if (xmin < xmax && ymin < ymax) {
|
||||
|
||||
int nc_roi = xmax - xmin + 1;
|
||||
int nr_roi = ymax - ymin + 1;
|
||||
std::cout << "nc_roi = " << nc_roi << std::endl;
|
||||
std::cout << "nr_roi = " << nr_roi << std::endl;
|
||||
|
||||
dataSize =
|
||||
(xmax - xmin + 1) * (ymax - ymin + 1) * 2 + off;
|
||||
std::cout << "datasize " << dataSize << std::endl;
|
||||
|
||||
for (int ix = xmin; ix < xmax+1; ++ix) {
|
||||
for (int iy = ymin; iy < ymax+1; ++iy) {
|
||||
dataMap[iy][ix] = off + (nc_roi * iy + ix) * 2;
|
||||
#ifdef HIGHZ
|
||||
dataMask[iy][ix] = 0x3fff;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (int ix = 0; ix < 256; ++ix) {
|
||||
for (int iy = 0; iy < 256; ++iy) {
|
||||
dataMap[iy][ix] = off + (256 * iy + ix) * 2;
|
||||
#ifdef HIGHZ
|
||||
dataMask[iy][ix] = 0x3fff;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
iframe = 0;
|
||||
// cout << "data struct created" << endl;
|
||||
};
|
||||
|
||||
/**
|
||||
Returns the value of the selected channel for the given dataset as
|
||||
double. \param data pointer to the dataset (including headers etc) \param
|
||||
ix pixel number in the x direction \param iy pixel number in the y
|
||||
direction \returns data for the selected channel, with inversion if
|
||||
required as double
|
||||
|
||||
*/
|
||||
virtual double getValue(char *data, int ix, int iy = 0) {
|
||||
|
||||
uint16_t val = getChannel(data, ix, iy) & 0x3fff;
|
||||
/* if (ix==0 && iy==0) */
|
||||
/* cout << val << endl; */
|
||||
return val;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Returns the frame number for the given dataset. Purely virtual func.
|
||||
\param buff pointer to the dataset
|
||||
\returns frame number
|
||||
|
||||
*/
|
||||
|
||||
/* class jfrau_packet_header_t { */
|
||||
/* public: */
|
||||
/* unsigned char reserved[4]; */
|
||||
/* unsigned char packetNumber[1]; */
|
||||
/* unsigned char frameNumber[3]; */
|
||||
/* unsigned char bunchid[8]; */
|
||||
/* }; */
|
||||
|
||||
int getFrameNumber(char *buff) {
|
||||
return ((jf_header *)buff)->bunchNumber;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Returns the packet number for the given dataset. purely virtual func
|
||||
\param buff pointer to the dataset
|
||||
\returns packet number number
|
||||
|
||||
|
||||
|
||||
*/
|
||||
int getPacketNumber(char *buff) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
char *readNextFrame(ifstream &filebin) {
|
||||
int ff = -1, np = -1;
|
||||
return readNextFrame(filebin, ff, np);
|
||||
};
|
||||
|
||||
char *readNextFrame(ifstream &filebin, int &ff) {
|
||||
int np = -1;
|
||||
return readNextFrame(filebin, ff, np);
|
||||
};
|
||||
|
||||
char *readNextFrame(ifstream &filebin, int &ff, int &np) {
|
||||
char *data = new char[dataSize];
|
||||
char *d = readNextFrame(filebin, ff, np, data);
|
||||
if (d == NULL) {
|
||||
delete[] data;
|
||||
data = NULL;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
char *readNextFrame(ifstream &filebin, int &ff, int &np,char *data) {
|
||||
//char *retval = 0;
|
||||
//int nd;
|
||||
//int fnum = -1;
|
||||
np = 0;
|
||||
//int pn;
|
||||
|
||||
// cout << dataSize << endl;
|
||||
//if (ff >= 0)
|
||||
//fnum = ff;
|
||||
|
||||
if (filebin.is_open()) {
|
||||
if (filebin.read(data, dataSize)) {
|
||||
ff = getFrameNumber(data);
|
||||
np = getPacketNumber(data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Loops over a memory slot until a complete frame is found (i.e. all
|
||||
packets 0 to nPackets, same frame number). purely virtual func \param
|
||||
data pointer to the memory to be analyzed \param ndata reference to the
|
||||
amount of data found for the frame, in case the frame is incomplete at
|
||||
the end of the memory slot \param dsize size of the memory slot to be
|
||||
analyzed \returns pointer to the beginning of the last good frame (might
|
||||
be incomplete if ndata smaller than dataSize), or NULL if no frame is
|
||||
found
|
||||
|
||||
*/
|
||||
virtual char *findNextFrame(char *data, int &ndata, int dsize) {
|
||||
if (dsize < dataSize)
|
||||
ndata = dsize;
|
||||
else
|
||||
ndata = dataSize;
|
||||
return data;
|
||||
};
|
||||
|
||||
// int getPacketNumber(int x, int y) {return dataMap[y][x]/packetSize;};
|
||||
};
|
||||
|
||||
#endif
|
@ -54,10 +54,6 @@ class interpolatingDetector : public singlePhotonDetector {
|
||||
pthread_mutex_init(fi, NULL);
|
||||
};
|
||||
|
||||
/**
|
||||
pointer-based copy constructor (cloner)
|
||||
\param orig detector to be copied
|
||||
*/
|
||||
interpolatingDetector(interpolatingDetector *orig)
|
||||
: singlePhotonDetector(orig) {
|
||||
// if (orig->interp)
|
||||
@ -70,28 +66,10 @@ class interpolatingDetector : public singlePhotonDetector {
|
||||
fi = orig->fi;
|
||||
}
|
||||
|
||||
/**
|
||||
* copy constructor (deep copy)
|
||||
* stricly, TODO: Implement Rule of Five!
|
||||
* (copy op=, move ctor, and move op= would need to be defined)
|
||||
*/
|
||||
interpolatingDetector(interpolatingDetector const& other)
|
||||
: singlePhotonDetector(other) {
|
||||
|
||||
interp = other.interp;
|
||||
|
||||
id = other.id;
|
||||
fi = other.fi;
|
||||
}
|
||||
|
||||
virtual interpolatingDetector *Clone() {
|
||||
return new interpolatingDetector(this);
|
||||
}
|
||||
|
||||
virtual interpolatingDetector *Copy() {
|
||||
return new interpolatingDetector(*this);
|
||||
}
|
||||
|
||||
virtual int setId(int i) {
|
||||
id = i;
|
||||
// interp->setId(id);
|
||||
|
@ -6,86 +6,18 @@
|
||||
|
||||
set(JUNGFRAU_EXECUTABLES)
|
||||
|
||||
#find_package(fmt REQUIRED)
|
||||
|
||||
#nlohmann_json
|
||||
#If the library was INSTALLED (i.e. sudo dnf install nlohmann-json3-dev), do stuff described in the repo under CMake -> External
|
||||
#find_package(nlohmann_json 3.2.0 REQUIRED)
|
||||
#find_package(nlohmann_json 3.11.2 REQUIRED)
|
||||
#find_package(nlohmann_json 3.11.3 REQUIRED)
|
||||
#
|
||||
#If the library was not installed but just cloned from https://github.com/nlohmann/json.git (possible, because it is a header-only library),
|
||||
# do stuff described in the repo under CMake -> Embedded
|
||||
#set(JSON_BuildTests OFF CACHE INTERNAL "")
|
||||
# If you only include this third party in PRIVATE source files, you do not
|
||||
# need to install it when your main project gets installed.
|
||||
# set(JSON_Install OFF CACHE INTERNAL "")
|
||||
#add_subdirectory(nlohmann_json) #Put the actual path to json
|
||||
#
|
||||
#Alternative: Fetch and install it from remote
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
json
|
||||
GIT_REPOSITORY https://github.com/nlohmann/json.git
|
||||
GIT_TAG v3.11.3 # Replace with the version you need
|
||||
)
|
||||
#FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz) #Alternative (from the repo documentation)
|
||||
FetchContent_MakeAvailable(json)
|
||||
|
||||
FetchContent_Declare(
|
||||
fmt
|
||||
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
|
||||
GIT_TAG master
|
||||
)
|
||||
FetchContent_MakeAvailable(fmt)
|
||||
|
||||
# HDF5 file writing
|
||||
if (SLS_USE_HDF5)
|
||||
find_package(HDF5 1.10 COMPONENTS CXX REQUIRED)
|
||||
list (APPEND SOURCES
|
||||
HDF5File.cpp
|
||||
)
|
||||
endif (SLS_USE_HDF5)
|
||||
|
||||
|
||||
find_package(fmt REQUIRED)
|
||||
|
||||
# jungfrauRawDataProcess
|
||||
add_executable(jungfrauRawDataProcess jungfrauRawDataProcess.cpp)
|
||||
target_compile_definitions(jungfrauRawDataProcess PRIVATE MODULE)
|
||||
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcess)
|
||||
|
||||
# jungfrauRawDataProcessChipAldo
|
||||
add_executable(jungfrauRawDataProcessChipAldo jungfrauRawDataProcess_filetxt.cpp)
|
||||
target_compile_definitions(jungfrauRawDataProcessChipAldo PRIVATE CHIP ALDO)
|
||||
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessChipAldo)
|
||||
|
||||
# jungfrauRawDataProcessStrx
|
||||
add_executable(jungfrauRawDataProcessStrx jungfrauRawDataProcess_filetxt.cpp)
|
||||
target_compile_definitions(jungfrauRawDataProcessStrx PRIVATE JFSTRX)
|
||||
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessStrx)
|
||||
|
||||
# jungfrauRawDataProcessStrxQuad
|
||||
add_executable(jungfrauRawDataProcessStrxQuad jungfrauRawDataProcess_filetxt.cpp)
|
||||
target_compile_definitions(jungfrauRawDataProcessStrxQuad PRIVATE JFSTRXQ)
|
||||
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessStrxQuad)
|
||||
|
||||
# jungfrauRawDataProcessStrxQuadH5
|
||||
# HDF5
|
||||
if (SLS_USE_HDF5)
|
||||
if (HDF5_FOUND)
|
||||
add_executable(jungfrauRawDataProcessStrxQuadH5 jungfrauRawDataProcess_filetxtH5.cpp)
|
||||
#target_compile_definitions(jungfrauRawDataProcessStrxQuadH5 PRIVATE JFSTRXQH5)
|
||||
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessStrxQuadH5)
|
||||
target_include_directories(jungfrauRawDataProcessStrxQuadH5 PRIVATE ${HDF5_INCLUDE_DIRS} ${CMAKE_INSTALL_PREFIX}/include)
|
||||
target_link_libraries(jungfrauRawDataProcessStrxQuadH5 PRIVATE ${HDF5_LIBRARIES})
|
||||
|
||||
add_executable(jungfrauRawDataProcessStrxQuadH5SC jungfrauRawDataProcess_filetxtH5_SC.cpp)
|
||||
#target_compile_definitions(jungfrauRawDataProcessStrxQuadH5 PRIVATE JFSTRXQH5)
|
||||
list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessStrxQuadH5SC)
|
||||
target_include_directories(jungfrauRawDataProcessStrxQuadH5SC PRIVATE ${HDF5_INCLUDE_DIRS} ${CMAKE_INSTALL_PREFIX}/include)
|
||||
target_link_libraries(jungfrauRawDataProcessStrxQuadH5SC PRIVATE ${HDF5_LIBRARIES})
|
||||
endif ()
|
||||
endif (SLS_USE_HDF5)
|
||||
|
||||
# jungfrauRawDataProcessStrxChip1
|
||||
add_executable(jungfrauRawDataProcessStrxChip1 jungfrauRawDataProcess.cpp)
|
||||
@ -126,22 +58,6 @@ list(APPEND JUNGFRAU_EXECUTABLES jungfrauRawDataProcessStrxOldAldo)
|
||||
# others to be added if needed (might already be there in Makefile.cluster_finder TO BE CHECKED)
|
||||
|
||||
|
||||
if (SLS_USE_HDF5)
|
||||
if (HDF5_FOUND)
|
||||
target_include_directories(jungfrauRawDataProcessStrxQuadH5 PRIVATE
|
||||
${HDF5_INCLUDE_DIRS}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
)
|
||||
target_link_libraries(jungfrauRawDataProcessStrxQuadH5 PRIVATE ${HDF5_LIBRARIES})
|
||||
|
||||
target_include_directories(jungfrauRawDataProcessStrxQuadH5SC PRIVATE
|
||||
${HDF5_INCLUDE_DIRS}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
)
|
||||
target_link_libraries(jungfrauRawDataProcessStrxQuadH5SC PRIVATE ${HDF5_LIBRARIES})
|
||||
|
||||
endif ()
|
||||
endif (SLS_USE_HDF5)
|
||||
|
||||
|
||||
foreach(exe ${JUNGFRAU_EXECUTABLES})
|
||||
@ -151,16 +67,11 @@ foreach(exe ${JUNGFRAU_EXECUTABLES})
|
||||
../interpolations
|
||||
../dataStructures
|
||||
../interpolations/etaVEL
|
||||
../../slsSupportLib/include/sls/
|
||||
../../slsSupportLib/include/
|
||||
../../slsReceiverSoftware/include/
|
||||
../tiffio/include
|
||||
${fmt_INCLUDE_DIRS}
|
||||
)
|
||||
# if (SLS_USE_HDF5)
|
||||
# if (HDF5_FOUND)
|
||||
# target_include_directories(${exe} PRIVATE ${HDF5_INCLUDE_DIRS} ${CMAKE_INSTALL_PREFIX}/include)
|
||||
# endif ()
|
||||
# endif (SLS_USE_HDF5)
|
||||
|
||||
target_link_libraries(${exe}
|
||||
PUBLIC
|
||||
@ -168,7 +79,6 @@ foreach(exe ${JUNGFRAU_EXECUTABLES})
|
||||
pthread
|
||||
tiffio
|
||||
fmt::fmt
|
||||
nlohmann_json::nlohmann_json
|
||||
#-L/usr/lib64/
|
||||
#-lm -lstdc++ -lrt
|
||||
|
||||
@ -176,11 +86,7 @@ foreach(exe ${JUNGFRAU_EXECUTABLES})
|
||||
slsProjectWarnings
|
||||
slsProjectOptions
|
||||
)
|
||||
# if (SLS_USE_HDF5)
|
||||
# if (HDF5_FOUND)
|
||||
# target_link_libraries(${exe} PRIVATE ${HDF5_LIBRARIES})
|
||||
# endif ()
|
||||
# endif (SLS_USE_HDF5)
|
||||
|
||||
|
||||
set_target_properties(${exe} PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
|
||||
@ -192,8 +98,4 @@ foreach(exe ${JUNGFRAU_EXECUTABLES})
|
||||
|
||||
endforeach(exe ${JUNGFRAU_EXECUTABLES})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
install(TARGETS ${JUNGFRAU_EXECUTABLES} DESTINATION bin)
|
||||
install(TARGETS ${JUNGFRAU_EXECUTABLES} DESTINATION bin)
|
@ -11,7 +11,7 @@
|
||||
#define RAWDATA
|
||||
|
||||
#if !defined JFSTRX && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
|
||||
!defined JFSTRXCHIP6 && !defined CHIP
|
||||
!defined JFSTRXCHIP6
|
||||
#ifndef MODULE
|
||||
#include "jungfrauHighZSingleChipData.h"
|
||||
#endif
|
||||
@ -20,10 +20,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CHIP
|
||||
#include "jungfrauSingleChipData.h"
|
||||
#endif
|
||||
|
||||
#ifdef JFSTRX
|
||||
#include "jungfrauLGADStrixelsData_new.h"
|
||||
#endif
|
||||
@ -45,9 +41,6 @@
|
||||
#include <ctime>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
|
||||
|
||||
std::string getRootString( const std::string& filepath ) {
|
||||
size_t pos1 = filepath.find_last_of("/");
|
||||
@ -68,24 +61,20 @@ std::string getRootString( const std::string& filepath ) {
|
||||
std::string createFileName( const std::string& dir, const std::string& fprefix="run", const std::string& fsuffix="", const std::string& fext="raw", int aindex=0, int mindex=0, int findex=0, int outfilecounter=-1 ) {
|
||||
if (outfilecounter >= 0)
|
||||
return fmt::format("{:s}/{:s}_d{:d}_f{:d}_{:d}_f{:05d}.{:s}", dir, fprefix, mindex, findex, aindex, outfilecounter, fext);
|
||||
else if (fsuffix.length()!=0) {
|
||||
if (fsuffix == "master")
|
||||
return fmt::format("{:s}/{:s}_master_{:d}.{:s}", dir, fprefix, aindex, fext);
|
||||
else
|
||||
return fmt::format("{:s}/{:s}_{:s}.{:s}", dir, fprefix, fsuffix, fext);
|
||||
}
|
||||
else if (fsuffix.length()!=0)
|
||||
return fmt::format("{:s}/{:s}_{:s}.{:s}", dir, fprefix, fsuffix, fext);
|
||||
else
|
||||
return fmt::format("{:s}/{:s}_d{:d}_f{:d}_{:d}.{:s}", dir, fprefix, mindex, findex, aindex, fext);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc < 6) {
|
||||
if (argc < 5) {
|
||||
std::cout
|
||||
<< "Usage is " << argv[0]
|
||||
<< "indir outdir [fprefix(excluding slsDetector standard suffixes and extension)] [fextension] "
|
||||
"[fmin] [fmax] [runmin] [runmax] [pedfile (raw or tiff)] [threshold] "
|
||||
"[nframes] [xmin xmax ymin ymax] [optional: bool read rxroi from data file header] [gainmap]"
|
||||
<< "indir outdir fprefix(excluding slsDetector standard suffixes and extension) fextension "
|
||||
"[runmin] [runmax] [pedfile (raw or tiff)] [threshold] "
|
||||
"[nframes] [xmin xmax ymin ymax] [gainmap]"
|
||||
<< std::endl;
|
||||
std::cout
|
||||
<< "threshold <0 means analog; threshold=0 means cluster finder; "
|
||||
@ -117,131 +106,94 @@ int main(int argc, char *argv[]) {
|
||||
std::string outdir(argv[2]);
|
||||
std::string fprefix(argv[3]);
|
||||
std::string fext(argv[4]);
|
||||
|
||||
int fmin = 0;
|
||||
if (argc >= 6)
|
||||
fmin = atoi(argv[5]);
|
||||
int fmax = fmin;
|
||||
if (argc >= 7)
|
||||
fmax = atoi(argv[6]);
|
||||
|
||||
int runmin = 0;
|
||||
|
||||
// cout << "argc is " << argc << endl;
|
||||
if (argc >= 8) {
|
||||
runmin = atoi(argv[7]);
|
||||
if (argc >= 6) {
|
||||
runmin = atoi(argv[5]);
|
||||
}
|
||||
|
||||
int runmax = runmin;
|
||||
if (argc >= 9) {
|
||||
runmax = atoi(argv[8]);
|
||||
|
||||
if (argc >= 7) {
|
||||
runmax = atoi(argv[6]);
|
||||
}
|
||||
|
||||
std::string pedfilename{};
|
||||
if (argc >= 10) {
|
||||
pedfilename = argv[9];
|
||||
if (argc >= 8) {
|
||||
pedfilename = argv[7];
|
||||
}
|
||||
double thr = 0;
|
||||
double thr1 = 1;
|
||||
|
||||
if (argc >= 11) {
|
||||
thr = atof(argv[10]);
|
||||
if (argc >= 9) {
|
||||
thr = atof(argv[8]);
|
||||
}
|
||||
|
||||
int nframes = 0;
|
||||
|
||||
if (argc >= 12) {
|
||||
nframes = atoi(argv[11]);
|
||||
if (argc >= 10) {
|
||||
nframes = atoi(argv[9]);
|
||||
}
|
||||
|
||||
bool readrxroifromdatafile = false;
|
||||
if (argc >= 17)
|
||||
readrxroifromdatafile = atoi(argv[16]);
|
||||
|
||||
// Receiver ROI
|
||||
uint16_t rxroi_xmin = 0;
|
||||
uint16_t rxroi_xmax = 0;
|
||||
uint16_t rxroi_ymin = 0;
|
||||
uint16_t rxroi_ymax = 0;
|
||||
|
||||
{ //protective scope so ifstream gets destroyed properly
|
||||
|
||||
auto jsonmastername = createFileName( indir, fprefix, "master", "json", runmin );
|
||||
std::cout << "json master file " << jsonmastername << std::endl;
|
||||
std::ifstream masterfile(jsonmastername); //, ios::in | ios::binary);
|
||||
if (masterfile.is_open()) {
|
||||
json j;
|
||||
masterfile >> j;
|
||||
rxroi_xmin = j["Receiver Roi"]["xmin"];
|
||||
rxroi_xmax = j["Receiver Roi"]["xmax"];
|
||||
rxroi_ymin = j["Receiver Roi"]["ymin"];
|
||||
rxroi_ymax = j["Receiver Roi"]["ymax"];
|
||||
masterfile.close();
|
||||
std::cout << "Read Receiver ROI [" << rxroi_xmin << ", " << rxroi_xmax << ", "
|
||||
<< rxroi_ymin << ", " << rxroi_ymax << "] from json master file" << std::endl;
|
||||
} else
|
||||
std::cout << "Could not open master file " << jsonmastername << std::endl;
|
||||
|
||||
}
|
||||
|
||||
// Define decoders...
|
||||
#if !defined JFSTRX && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
|
||||
!defined JFSTRXCHIP6 && !defined CHIP
|
||||
!defined JFSTRXCHIP6
|
||||
#ifndef MODULE
|
||||
jungfrauHighZSingleChipData *decoder = new jungfrauHighZSingleChipData();
|
||||
int nx = 256, ny = 256;
|
||||
#endif
|
||||
#ifdef MODULE
|
||||
jungfrauModuleData *decoder = new jungfrauModuleData(rxroi_xmin, rxroi_xmax, rxroi_ymin, rxroi_ymax);
|
||||
jungfrauModuleData *decoder = new jungfrauModuleData();
|
||||
int nx = 1024, ny = 512;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CHIP
|
||||
std::cout << "Jungfrau pixel module single chip readout" << std::endl;
|
||||
jungfrauSingleChipData *decoder = new jungfrauSingleChipData();
|
||||
int nx = 256, ny = 256;
|
||||
#endif
|
||||
|
||||
#ifdef JFSTRX
|
||||
std::cout << "Jungfrau strixel full module readout" << std::endl;
|
||||
cout << "Jungfrau strixel full module readout" << endl;
|
||||
// ROI
|
||||
uint16_t xxmin = 0;
|
||||
uint16_t xxmax = 0;
|
||||
uint16_t yymin = 0;
|
||||
uint16_t yymax = 0;
|
||||
|
||||
#ifndef ALDO
|
||||
if (readrxroifromdatafile)
|
||||
{ //THIS SCOPE IS IMPORTANT! (To ensure proper destruction of ifstream)
|
||||
using header = sls::defs::sls_receiver_header;
|
||||
// check if there is a roi in the header
|
||||
typedef struct {
|
||||
uint16_t xmin;
|
||||
uint16_t xmax;
|
||||
uint16_t ymin;
|
||||
uint16_t ymax;
|
||||
} receiverRoi_compact;
|
||||
receiverRoi_compact croi;
|
||||
std::string fsuffix{};
|
||||
auto filename = createFileName( indir, fprefix, fsuffix, fext, runmin );
|
||||
std::cout << "Reading header of file " << filename << " to check for ROI "
|
||||
<< std::endl;
|
||||
ifstream firstfile(filename, ios::in | ios::binary);
|
||||
if (firstfile.is_open()) {
|
||||
header hbuffer;
|
||||
std::cout << "sizeof(header) = " << sizeof(header) << std::endl;
|
||||
if (firstfile.read((char *)&hbuffer, sizeof(header))) {
|
||||
memcpy(&croi, &hbuffer.detHeader.detSpec1, 8);
|
||||
std::cout << "Read ROI [" << croi.xmin << ", " << croi.xmax << ", "
|
||||
<< croi.ymin << ", " << croi.ymax << "]" << std::endl;
|
||||
rxroi_xmin = croi.xmin;
|
||||
rxroi_xmax = croi.xmax;
|
||||
rxroi_ymin = croi.ymin;
|
||||
rxroi_ymax = croi.ymax;
|
||||
} else
|
||||
std::cout << "reading error" << std::endl;
|
||||
firstfile.close();
|
||||
} else
|
||||
std::cout << "Could not open " << filename << " for reading " << std::endl;
|
||||
} //end of protective scope
|
||||
{ //THIS SCOPE IS IMPORTANT! (To ensure proper destruction of ifstream)
|
||||
using header = sls::defs::sls_receiver_header;
|
||||
// check if there is a roi in the header
|
||||
typedef struct {
|
||||
uint16_t xmin;
|
||||
uint16_t xmax;
|
||||
uint16_t ymin;
|
||||
uint16_t ymax;
|
||||
} receiverRoi_compact;
|
||||
receiverRoi_compact croi;
|
||||
std::string fsuffix{};
|
||||
auto filename = createFileName( indir, fprefix, fsuffix, fext, runmin );
|
||||
std::cout << "Reading header of file " << filename << " to check for ROI "
|
||||
<< std::endl;
|
||||
ifstream firstfile(filename, ios::in | ios::binary);
|
||||
if (firstfile.is_open()) {
|
||||
header hbuffer;
|
||||
std::cout << "sizeof(header) = " << sizeof(header) << std::endl;
|
||||
if (firstfile.read((char *)&hbuffer, sizeof(header))) {
|
||||
memcpy(&croi, &hbuffer.detHeader.detSpec1, 8);
|
||||
std::cout << "Read ROI [" << croi.xmin << ", " << croi.xmax << ", "
|
||||
<< croi.ymin << ", " << croi.ymax << "]" << std::endl;
|
||||
xxmin = croi.xmin;
|
||||
xxmax = croi.xmax;
|
||||
yymin = croi.ymin;
|
||||
yymax = croi.ymax;
|
||||
} else
|
||||
std::cout << "reading error" << std::endl;
|
||||
firstfile.close();
|
||||
} else
|
||||
std::cout << "Could not open " << filename << " for reading " << std::endl;
|
||||
} //end of protective scope
|
||||
#endif
|
||||
|
||||
jungfrauLGADStrixelsData *decoder =
|
||||
new jungfrauLGADStrixelsData(rxroi_xmin, rxroi_xmax, rxroi_ymin, rxroi_ymax);
|
||||
new jungfrauLGADStrixelsData(xxmin, xxmax, yymin, yymax);
|
||||
int nx = 1024 / 3, ny = 512 * 5;
|
||||
#endif
|
||||
#ifdef JFSTRXCHIP1
|
||||
@ -266,20 +218,19 @@ int main(int argc, char *argv[]) {
|
||||
decoder->getDetectorSize(nx, ny);
|
||||
std::cout << "Detector size is " << nx << " " << ny << std::endl;
|
||||
|
||||
//Cluster finder ROI
|
||||
int xmin = 0, xmax = nx-1, ymin = 0, ymax = ny-1;
|
||||
if (argc >= 16) {
|
||||
xmin = atoi(argv[12]);
|
||||
xmax = atoi(argv[13]);
|
||||
ymin = atoi(argv[14]);
|
||||
ymax = atoi(argv[15]);
|
||||
int xmin = 0, xmax = nx, ymin = 0, ymax = ny;
|
||||
if (argc >= 14) {
|
||||
xmin = atoi(argv[10]);
|
||||
xmax = atoi(argv[11]);
|
||||
ymin = atoi(argv[12]);
|
||||
ymax = atoi(argv[13]);
|
||||
}
|
||||
std::cout << "Cluster finder ROI: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]"
|
||||
std::cout << xmin << " " << xmax << " " << ymin << " " << ymax << " "
|
||||
<< std::endl;
|
||||
|
||||
char *gainfname = NULL;
|
||||
if (argc > 17) {
|
||||
gainfname = argv[17];
|
||||
if (argc > 14) {
|
||||
gainfname = argv[14];
|
||||
std::cout << "Gain map file name is: " << gainfname << std::endl;
|
||||
}
|
||||
|
||||
@ -288,8 +239,6 @@ int main(int argc, char *argv[]) {
|
||||
std::cout << "input directory is " << indir << std::endl;
|
||||
std::cout << "output directory is " << outdir << std::endl;
|
||||
std::cout << "input file prefix is " << fprefix << std::endl;
|
||||
std::cout << "fmin is " << fmin << std::endl;
|
||||
std::cout << "fmax is " << fmax << std::endl;
|
||||
std::cout << "runmin is " << runmin << std::endl;
|
||||
std::cout << "runmax is " << runmax << std::endl;
|
||||
if (pedfilename.length()!=0)
|
||||
@ -370,7 +319,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
mt->setFrameMode(ePedestal);
|
||||
|
||||
std::ifstream pedefile(fname, ios::in | ios::binary);
|
||||
ifstream pedefile(fname, ios::in | ios::binary);
|
||||
// //open file
|
||||
if (pedefile.is_open()) {
|
||||
std::cout << "bbbb " << std::ctime(&end_time) << std::endl;
|
||||
@ -431,27 +380,26 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
ifr = 0;
|
||||
int ioutfile = 0;
|
||||
int ifile = 0;
|
||||
|
||||
mt->setFrameMode(eFrame);
|
||||
|
||||
FILE *of = NULL;
|
||||
|
||||
for (int irun = runmin; irun <= runmax; ++irun) {
|
||||
for (int ifile = fmin; ifile <= fmax; ++ifile) {
|
||||
for (int irun = runmin; irun <= runmax; irun++) {
|
||||
std::cout << "DATA ";
|
||||
std::string fsuffix{};
|
||||
auto fname = createFileName( indir, fprefix, fsuffix, fext, irun, 0, ifile );
|
||||
auto imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun, 0, ifile );
|
||||
auto cfname = createFileName( outdir, fprefix, fsuffix, "clust", irun, 0, ifile );
|
||||
auto fname = createFileName( indir, fprefix, fsuffix, fext, irun );
|
||||
auto imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun );
|
||||
auto cfname = createFileName( outdir, fprefix, fsuffix, "clust", irun );
|
||||
std::cout << fname << " ";
|
||||
std::cout << imgfname << std::endl;
|
||||
std::time(&end_time);
|
||||
std::cout << std::ctime(&end_time) << std::endl;
|
||||
// std::cout << fname << " " << outfname << " " << imgfname << std::endl;
|
||||
std::ifstream filebin(fname, ios::in | ios::binary);
|
||||
ifstream filebin(fname, ios::in | ios::binary);
|
||||
// //open file
|
||||
ioutfile = 0;
|
||||
ifile = 0;
|
||||
if (filebin.is_open()) {
|
||||
if (thr <= 0 && cf != 0) { // cluster finder
|
||||
if (of == NULL) {
|
||||
@ -488,10 +436,10 @@ int main(int argc, char *argv[]) {
|
||||
std::cout << " " << ifr << " " << ff << std::endl;
|
||||
if (nframes > 0) {
|
||||
if (ifr % nframes == 0) {
|
||||
imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun, 0, 0, ioutfile );
|
||||
imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun, 0, 0, ifile );
|
||||
mt->writeImage(imgfname.c_str(), thr1);
|
||||
mt->clearImage();
|
||||
ioutfile++;
|
||||
ifile++;
|
||||
}
|
||||
}
|
||||
// } else
|
||||
@ -505,7 +453,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
if (nframes >= 0) {
|
||||
if (nframes > 0)
|
||||
imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun, 0, 0, ioutfile );
|
||||
imgfname = createFileName( outdir, fprefix, fsuffix, "tiff", irun, 0, 0, ifile );
|
||||
std::cout << "Writing tiff to " << imgfname << " " << thr1
|
||||
<< std::endl;
|
||||
mt->writeImage(imgfname.c_str(), thr1);
|
||||
@ -521,10 +469,9 @@ int main(int argc, char *argv[]) {
|
||||
} else
|
||||
std::cout << "Could not open " << fname << " for reading "
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
if (nframes < 0) {
|
||||
auto imgfname = createFileName( outdir, fprefix, "sum", "tiff", runmin, 0, fmin, -1 );
|
||||
auto imgfname = createFileName( outdir, fprefix, "sum", "tiff", -1, 0, 0, -1 );
|
||||
std::cout << "Writing tiff to " << imgfname << " " << thr1 << std::endl;
|
||||
mt->writeImage(imgfname.c_str(), thr1);
|
||||
}
|
||||
|
@ -10,8 +10,8 @@
|
||||
|
||||
#define RAWDATA
|
||||
|
||||
#if !defined JFSTRX && !defined JFSTRXQ && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
|
||||
!defined JFSTRXCHIP6 && !defined CHIP
|
||||
#if !defined JFSTRX && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
|
||||
!defined JFSTRXCHIP6
|
||||
#ifndef MODULE
|
||||
#include "jungfrauHighZSingleChipData.h"
|
||||
#endif
|
||||
@ -20,16 +20,9 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CHIP
|
||||
#include "jungfrauSingleChipData.h"
|
||||
#endif
|
||||
|
||||
#ifdef JFSTRX
|
||||
#include "jungfrauLGADStrixelsData_new.h"
|
||||
#endif
|
||||
#ifdef JFSTRXQ
|
||||
#include "jungfrauLGADStrixelsDataQuad.h"
|
||||
#endif
|
||||
#if defined JFSTRXCHIP1 || defined JFSTRXCHIP6
|
||||
#include "jungfrauLGADStrixelsDataSingleChip.h"
|
||||
#endif
|
||||
@ -48,9 +41,6 @@
|
||||
#include <ctime>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
|
||||
|
||||
std::string getRootString( const std::string& filepath ) {
|
||||
size_t pos1;
|
||||
@ -81,11 +71,11 @@ std::string createFileName( const std::string& dir, const std::string& fprefix="
|
||||
//NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS!
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc < 11) {
|
||||
if (argc < 10) {
|
||||
std::cout
|
||||
<< "Usage is " << argv[0]
|
||||
<< " filestxt outdir [json master] [pedfile (raw or tiff)] [xmin xmax ymin ymax] "
|
||||
"[threshold] [nframes] [optional: bool read rxroi from data file header]"
|
||||
<< " filestxt outdir [pedfile (raw or tiff)] [xmin xmax ymin ymax] "
|
||||
"[threshold] [nframes] "
|
||||
"NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS! "
|
||||
<< std::endl;
|
||||
std::cout
|
||||
@ -115,19 +105,19 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
const std::string txtfilename(argv[1]);
|
||||
const std::string outdir(argv[2]);
|
||||
const std::string jsonmastername(argv[3]);
|
||||
const std::string pedfilename(argv[4]);
|
||||
const std::string pedfilename(argv[3]);
|
||||
|
||||
int xmin = atoi(argv[4]);
|
||||
int xmax = atoi(argv[5]);
|
||||
int ymin = atoi(argv[6]);
|
||||
int ymax = atoi(argv[7]);
|
||||
|
||||
double thr = 0;
|
||||
double thr1 = 1;
|
||||
thr = atof(argv[9]);
|
||||
thr = atof(argv[8]);
|
||||
|
||||
int nframes = 0;
|
||||
nframes = atoi(argv[10]);
|
||||
|
||||
bool readrxroifromdatafile = false;
|
||||
if (argc > 11)
|
||||
readrxroifromdatafile = atoi(argv[11]);
|
||||
nframes = atoi(argv[9]);
|
||||
|
||||
//Get vector of filenames from input txt-file
|
||||
std::vector<std::string> filenames{};
|
||||
@ -156,34 +146,10 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
std::cout << "###############" << std::endl;
|
||||
|
||||
// Receiver ROI
|
||||
uint16_t rxroi_xmin = 0;
|
||||
uint16_t rxroi_xmax = 0;
|
||||
uint16_t rxroi_ymin = 0;
|
||||
uint16_t rxroi_ymax = 0;
|
||||
|
||||
{ //protective scope so ifstream gets destroyed properly
|
||||
|
||||
std::ifstream masterfile(jsonmastername); //, ios::in | ios::binary);
|
||||
if (masterfile.is_open()) {
|
||||
json j;
|
||||
masterfile >> j;
|
||||
rxroi_xmin = j["Receiver Roi"]["xmin"];
|
||||
rxroi_xmax = j["Receiver Roi"]["xmax"];
|
||||
rxroi_ymin = j["Receiver Roi"]["ymin"];
|
||||
rxroi_ymax = j["Receiver Roi"]["ymax"];
|
||||
masterfile.close();
|
||||
std::cout << "Read rxROI [" << rxroi_xmin << ", " << rxroi_xmax << ", "
|
||||
<< rxroi_ymin << ", " << rxroi_ymax << "]" << std::endl;
|
||||
} else
|
||||
std::cout << "Could not open master file " << jsonmastername << std::endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Define decoders...
|
||||
#if !defined JFSTRX && !defined JFSTRXQ && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
|
||||
!defined JFSTRXCHIP6 && !defined CHIP
|
||||
#if !defined JFSTRX && !defined JFSTRXOLD && !defined JFSTRXCHIP1 && \
|
||||
!defined JFSTRXCHIP6
|
||||
#ifndef MODULE
|
||||
jungfrauHighZSingleChipData *decoder = new jungfrauHighZSingleChipData();
|
||||
int nx = 256, ny = 256;
|
||||
@ -194,60 +160,52 @@ int main(int argc, char *argv[]) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CHIP
|
||||
std::cout << "Jungfrau pixel module single chip readout" << std::endl;
|
||||
jungfrauSingleChipData *decoder = new jungfrauSingleChipData();
|
||||
int nx = 256, ny = 256;
|
||||
#endif
|
||||
|
||||
#ifdef JFSTRX
|
||||
std::cout << "Jungfrau strixel full module readout" << std::endl;
|
||||
cout << "Jungfrau strixel full module readout" << endl;
|
||||
// ROI
|
||||
uint16_t xxmin = 0;
|
||||
uint16_t xxmax = 0;
|
||||
uint16_t yymin = 0;
|
||||
uint16_t yymax = 0;
|
||||
|
||||
#ifndef ALDO
|
||||
if (readrxroifromdatafile)
|
||||
{ //THIS SCOPE IS IMPORTANT! (To ensure proper destruction of ifstream)
|
||||
using header = sls::defs::sls_receiver_header;
|
||||
// check if there is a roi in the header
|
||||
typedef struct {
|
||||
uint16_t xmin;
|
||||
uint16_t xmax;
|
||||
uint16_t ymin;
|
||||
uint16_t ymax;
|
||||
} receiverRoi_compact;
|
||||
receiverRoi_compact croi;
|
||||
//std::string filepath(argv[9]); //This is a problem if the input files have different ROIs!
|
||||
std::cout << "Reading header of file " << filenames[0] << " to check for ROI "
|
||||
<< std::endl;
|
||||
std::ifstream firstfile( filenames[0], ios::in | ios::binary);
|
||||
if (firstfile.is_open()) {
|
||||
header hbuffer;
|
||||
std::cout << "sizeof(header) = " << sizeof(header) << std::endl;
|
||||
if (firstfile.read((char *)&hbuffer, sizeof(header))) {
|
||||
memcpy(&croi, &hbuffer.detHeader.detSpec1, 8);
|
||||
std::cout << "Read ROI [" << croi.xmin << ", " << croi.xmax << ", "
|
||||
<< croi.ymin << ", " << croi.ymax << "]" << std::endl;
|
||||
rxroi_xmin = croi.xmin;
|
||||
rxroi_xmax = croi.xmax;
|
||||
rxroi_ymin = croi.ymin;
|
||||
rxroi_ymax = croi.ymax;
|
||||
} else
|
||||
std::cout << "reading error" << std::endl;
|
||||
firstfile.close();
|
||||
} else
|
||||
std::cout << "Could not open " << filenames[0] << " for reading " << std::endl;
|
||||
} //end of protective scope
|
||||
{ //THIS SCOPE IS IMPORTANT! (To ensure proper destruction of ifstream)
|
||||
using header = sls::defs::sls_receiver_header;
|
||||
// check if there is a roi in the header
|
||||
typedef struct {
|
||||
uint16_t xmin;
|
||||
uint16_t xmax;
|
||||
uint16_t ymin;
|
||||
uint16_t ymax;
|
||||
} receiverRoi_compact;
|
||||
receiverRoi_compact croi;
|
||||
//std::string filepath(argv[9]); //This is a problem if the input files have different ROIs!
|
||||
std::cout << "Reading header of file " << filenames[0] << " to check for ROI "
|
||||
<< std::endl;
|
||||
ifstream firstfile(filenames[0], ios::in | ios::binary);
|
||||
if (firstfile.is_open()) {
|
||||
header hbuffer;
|
||||
std::cout << "sizeof(header) = " << sizeof(header) << std::endl;
|
||||
if (firstfile.read((char *)&hbuffer, sizeof(header))) {
|
||||
memcpy(&croi, &hbuffer.detHeader.detSpec1, 8);
|
||||
std::cout << "Read ROI [" << croi.xmin << ", " << croi.xmax << ", "
|
||||
<< croi.ymin << ", " << croi.ymax << "]" << std::endl;
|
||||
xxmin = croi.xmin;
|
||||
xxmax = croi.xmax;
|
||||
yymin = croi.ymin;
|
||||
yymax = croi.ymax;
|
||||
} else
|
||||
std::cout << "reading error" << std::endl;
|
||||
firstfile.close();
|
||||
} else
|
||||
std::cout << "Could not open " << filenames[0] << " for reading " << std::endl;
|
||||
} //end of protective scope
|
||||
#endif
|
||||
|
||||
jungfrauLGADStrixelsData *decoder =
|
||||
new jungfrauLGADStrixelsData(rxroi_xmin, rxroi_xmax, rxroi_ymin, rxroi_ymax);
|
||||
new jungfrauLGADStrixelsData(xxmin, xxmax, yymin, yymax);
|
||||
int nx = 1024 / 3, ny = 512 * 5;
|
||||
#endif
|
||||
#ifdef JFSTRXQ
|
||||
std::cout << "Jungfrau strixel quad" << std::endl;
|
||||
jungfrauLGADStrixelsDataQuad *decoder =
|
||||
new jungfrauLGADStrixelsDataQuad(rxroi_xmin, rxroi_xmax, rxroi_ymin, rxroi_ymax);
|
||||
int nx = 1024 / 3, ny = 512 * 3;
|
||||
#endif
|
||||
#ifdef JFSTRXCHIP1
|
||||
std::cout << "Jungfrau strixel LGAD single chip 1" << std::endl;
|
||||
jungfrauLGADStrixelsDataSingleChip *decoder =
|
||||
@ -270,16 +228,7 @@ int main(int argc, char *argv[]) {
|
||||
decoder->getDetectorSize(nx, ny);
|
||||
std::cout << "Detector size is " << nx << " " << ny << std::endl;
|
||||
|
||||
//Cluster finder ROI
|
||||
int xmin = 0, xmax = nx-1, ymin = 0, ymax = ny-1;
|
||||
xmin = atoi(argv[5]);
|
||||
xmax = atoi(argv[6]);
|
||||
ymin = atoi(argv[7]);
|
||||
ymax = atoi(argv[8]);
|
||||
std::cout << "Cluster finder ROI: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]"
|
||||
<< std::endl;
|
||||
|
||||
/* old
|
||||
if ( xmin == xmax ) {
|
||||
xmin = 0;
|
||||
xmax = nx;
|
||||
@ -290,7 +239,6 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
std::cout << xmin << " " << xmax << " " << ymin << " " << ymax << " "
|
||||
<< std::endl;
|
||||
*/
|
||||
|
||||
/*
|
||||
char *gainfname = NULL;
|
||||
@ -462,7 +410,7 @@ int main(int argc, char *argv[]) {
|
||||
std::time(&end_time);
|
||||
std::cout << std::ctime(&end_time) << std::endl;
|
||||
|
||||
std::ifstream filebin(filenames[ifile], ios::in | ios::binary);
|
||||
ifstream filebin(filenames[ifile], ios::in | ios::binary);
|
||||
// //open file
|
||||
ioutfile = 0;
|
||||
if (filebin.is_open()) {
|
||||
|
@ -1,457 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
// #include "sls/ansi.h"
|
||||
//#include <iostream>
|
||||
#undef CORR
|
||||
|
||||
#define C_GHOST 0.0004
|
||||
|
||||
#define CM_ROWS 50
|
||||
|
||||
#define RAWDATA
|
||||
|
||||
|
||||
#include "jungfrauLGADStrixelsDataQuadH5.h"
|
||||
|
||||
#include "multiThreadedCountingDetector.h"
|
||||
#include "singlePhotonDetector.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <fmt/core.h>
|
||||
|
||||
/*
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
*/
|
||||
|
||||
/*Dataset paths according to different beamlines*/
|
||||
std::string const data_datasetname_furka("/data/JF18T01V01/data");
|
||||
std::string const index_datasetname_furka("/data/JF18T01V01/frame_index");
|
||||
std::string const data_datasetname_xfelSCS("/INSTRUMENT/SCS_HRIXS_JUNGF/DET/JNGFR01:daqOutput/data/adc");
|
||||
std::string const index_datasetname_xfelSCS("/INSTRUMENT/SCS_HRIXS_JUNGF/DET/JNGFR01:daqOutput/data/frameNumber");
|
||||
|
||||
std::string getRootString( std::string const& filepath ) {
|
||||
size_t pos1;
|
||||
if (filepath.find("/") == std::string::npos )
|
||||
pos1 = 0;
|
||||
else
|
||||
pos1 = filepath.find_last_of("/")+1;
|
||||
size_t pos2 = filepath.find_last_of(".");
|
||||
//std::cout << "pos1 " << pos1 << " pos2 " << pos2 << " size " << filepath.length() << std::endl;
|
||||
return filepath.substr( pos1, pos2-pos1 );
|
||||
}
|
||||
|
||||
//Create file name string
|
||||
// dir: directory
|
||||
// fprefix: fileprefix (without extension)
|
||||
// fsuffix: filesuffix (for output files, e.g. "ped")
|
||||
// fext: file extension (e.g. "raw")
|
||||
std::string createFileName( std::string const& dir, std::string const& fprefix="run",
|
||||
std::string const& fsuffix="", std::string const& fext="raw", int const outfilecounter=-1 ) {
|
||||
std::string return_string;
|
||||
if (outfilecounter >= 0)
|
||||
return_string = fmt::format("{:s}/{:s}_{:s}_f{:05d}", dir, fprefix, fsuffix, outfilecounter);
|
||||
else if (fsuffix.length()!=0)
|
||||
return_string = fmt::format("{:s}/{:s}_{:s}", dir, fprefix, fsuffix);
|
||||
else
|
||||
return_string = fmt::format("{:s}/{:s}", dir, fprefix);
|
||||
|
||||
if (fext.length()!=0)
|
||||
return_string += "." + fext;
|
||||
|
||||
return return_string;
|
||||
}
|
||||
|
||||
|
||||
//NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS!
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc < 4) {
|
||||
std::cout
|
||||
<< "Usage is " << argv[0]
|
||||
<< " filestxt outdir [pedfile (h5)] "
|
||||
" optional: [int dataset path; 0 means Furka, 1 means XFEL; overwrites default given in HDF5File.h] "
|
||||
" [bool validate h5 rank] "
|
||||
" [xmin xmax ymin ymax] [threshold] [nframes] "
|
||||
" NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS! "
|
||||
<< std::endl;
|
||||
std::cout
|
||||
<< "threshold <0 means analog; threshold=0 means cluster finder; "
|
||||
"threshold>0 means photon counting"
|
||||
<< std::endl;
|
||||
std::cout
|
||||
<< "nframes <0 means sum everything; nframes=0 means one file per "
|
||||
"run; nframes>0 means one file every nframes"
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int const fifosize = 100; //1000;
|
||||
int const nthreads = 10;
|
||||
int const csize = 3; // 3
|
||||
int const nsigma = 5;
|
||||
int const nped = 10000;
|
||||
|
||||
int cf = 0;
|
||||
|
||||
std::string const txtfilename(argv[1]);
|
||||
std::string const outdir(argv[2]);
|
||||
std::string const pedfilename(argv[3]);
|
||||
|
||||
std::string datasetpath{};
|
||||
std::string frameindexpath{};
|
||||
if (argc > 4) {
|
||||
switch (atoi(argv[4])) {
|
||||
case 0:
|
||||
datasetpath = data_datasetname_furka;
|
||||
frameindexpath = index_datasetname_furka;
|
||||
break;
|
||||
case 1:
|
||||
datasetpath = data_datasetname_xfelSCS;
|
||||
frameindexpath = index_datasetname_xfelSCS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool validate_rank=true;
|
||||
if (argc > 5)
|
||||
validate_rank = atoi(argv[5]);
|
||||
|
||||
double thr = 0;
|
||||
double thr1 = 1;
|
||||
if (argc > 9)
|
||||
thr = atof(argv[9]);
|
||||
|
||||
int nframes = 0;
|
||||
if (argc > 10)
|
||||
nframes = atoi(argv[10]);
|
||||
|
||||
//Get vector of filenames from input txt-file
|
||||
std::vector<std::string> filenames{};
|
||||
//filenames.reserve(512);
|
||||
{ //Safety scope for ifstream
|
||||
ifstream inputs( txtfilename, std::ios::in );
|
||||
if (inputs.is_open()) {
|
||||
std::cout << "Reading imput filenames from txt-file ..." << std::endl;
|
||||
std::string line{};
|
||||
while (!inputs.eof()) {
|
||||
std::getline(inputs, line);
|
||||
if(line.find(".h5") != std::string::npos) {
|
||||
filenames.emplace_back(line);
|
||||
std::cout << line << std::endl; //" line.max_size() " << line.max_size() << " filenames.capacity() " << filenames.capacity() << '\n';
|
||||
}
|
||||
}
|
||||
inputs.close();
|
||||
std::cout << "---- Reached end of txt-file. ----" << std::endl;
|
||||
} else
|
||||
std::cout << "Could not open " << txtfilename << std::endl;
|
||||
if (filenames.size()>0) {
|
||||
std::cout << filenames.size() << " filenames found in " << txtfilename << std::endl;
|
||||
std::cout << "The files will be processed in the same order as found in the txt-file." << std::endl;
|
||||
} else {
|
||||
std::cout << "No files found in txt-file!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "###############" << std::endl;
|
||||
|
||||
// Define decoder
|
||||
std::cout << "Jungfrau strixel quad h5" << std::endl;
|
||||
jungfrauLGADStrixelsDataQuadH5* decoder = new jungfrauLGADStrixelsDataQuadH5();
|
||||
//auto decoder = std::make_unique<jungfrauLGADStrixelsDataQuadH5>();
|
||||
int nx = 1024 / 3, ny = 512 * 3;
|
||||
|
||||
//Cluster finder ROI
|
||||
int xmin = 0, xmax = nx-1, ymin = 0, ymax = ny-1;
|
||||
if (argc > 9) {
|
||||
xmin = atoi(argv[6]);
|
||||
xmax = atoi(argv[7]);
|
||||
ymin = atoi(argv[8]);
|
||||
ymax = atoi(argv[9]);
|
||||
}
|
||||
std::cout << "Cluster finder ROI: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]"
|
||||
<< std::endl;
|
||||
|
||||
decoder->getDetectorSize(nx, ny);
|
||||
std::cout << "Detector size is " << nx << " " << ny << std::endl;
|
||||
|
||||
std::time_t end_time;
|
||||
|
||||
std::cout << "output directory is " << outdir << std::endl;
|
||||
if (pedfilename.length()!=0)
|
||||
std::cout << "pedestal file is " << pedfilename << std::endl;
|
||||
if (thr > 0)
|
||||
std::cout << "threshold is " << thr << std::endl;
|
||||
std::cout << "Nframes is " << nframes << std::endl;
|
||||
|
||||
uint32_t nnx, nny;
|
||||
|
||||
singlePhotonDetector* filter =
|
||||
new singlePhotonDetector(decoder, 3, nsigma, 1, NULL, nped, 200, -1, -1, NULL, NULL);
|
||||
//auto filter = std::make_unique<singlePhotonDetector>(decoder.get(), 3, nsigma, 1, nullptr, nped, 200, -1, -1, nullptr, nullptr);
|
||||
|
||||
thr = 0.15 * thr;
|
||||
//filter->newDataSet(); //This only initializes the dataset for the first thread (the other threads are created via cloning)
|
||||
// int dsize = decoder->getDataSize();
|
||||
|
||||
if (thr > 0) {
|
||||
std::cout << "threshold is " << thr << std::endl;
|
||||
filter->setThreshold(thr);
|
||||
cf = 0;
|
||||
|
||||
} else
|
||||
cf = 1;
|
||||
|
||||
filter->setROI(xmin, xmax, ymin, ymax);
|
||||
std::time(&end_time);
|
||||
std::cout << std::ctime(&end_time) << std::endl;
|
||||
|
||||
char* buff;
|
||||
|
||||
multiThreadedCountingDetector* mt =
|
||||
new multiThreadedCountingDetector(filter, nthreads, fifosize);
|
||||
//auto mt = std::make_unique<multiThreadedCountingDetector>(filter.get(), nthreads, fifosize);
|
||||
mt->setClusterSize(csize, csize);
|
||||
mt->newDataSet(); //Initialize new dataset for each thread
|
||||
|
||||
#ifndef ANALOG
|
||||
mt->setDetectorMode(ePhotonCounting);
|
||||
std::cout << "Counting!" << std::endl;
|
||||
if (thr > 0) {
|
||||
cf = 0;
|
||||
}
|
||||
#endif
|
||||
//{
|
||||
#ifdef ANALOG
|
||||
mt->setDetectorMode(eAnalog);
|
||||
std::cout << "Analog!" << std::endl;
|
||||
cf = 0;
|
||||
// thr1=thr;
|
||||
#endif
|
||||
// }
|
||||
|
||||
mt->StartThreads();
|
||||
mt->popFree(buff);
|
||||
|
||||
int ifr = 0; //frame counter of while loop
|
||||
int framenumber = 0; //framenumber as read from file (detector)
|
||||
std::vector<hsize_t> h5offset(1,0); //frame counter internal to HDF5File::ReadImage (provided for sanity check/debugging)
|
||||
|
||||
if (pedfilename.length()>1) {
|
||||
|
||||
std::cout << "PEDESTAL " << std::endl;
|
||||
|
||||
if (pedfilename.find(".tif") == std::string::npos) { //not a tiff file
|
||||
std::string const fname(pedfilename);
|
||||
std::cout << fname << std::endl;
|
||||
std::time(&end_time);
|
||||
std::cout << "aaa " << std::ctime(&end_time) << std::endl;
|
||||
|
||||
mt->setFrameMode(ePedestal);
|
||||
|
||||
//HDF5File pedefile;
|
||||
auto pedefile = std::make_unique<HDF5File>();
|
||||
pedefile->SetFrameIndexPath(frameindexpath);
|
||||
pedefile->SetImageDataPath(datasetpath);
|
||||
// //open file
|
||||
if ( pedefile->OpenResources(fname.c_str(),validate_rank) ) {
|
||||
std::cout << "bbbb " << std::ctime(&end_time) << std::endl;
|
||||
|
||||
framenumber = 0;
|
||||
|
||||
while ( decoder->readNextFrame(*pedefile, framenumber, h5offset, buff) ) {
|
||||
|
||||
if ((ifr + 1) % 100 == 0) {
|
||||
std::cout
|
||||
<< " ****"
|
||||
<< decoder->getValue(buff, 20, 20); // << std::endl;
|
||||
}
|
||||
mt->pushData(buff);
|
||||
mt->nextThread();
|
||||
mt->popFree(buff);
|
||||
++ifr;
|
||||
if (ifr % 100 == 0) {
|
||||
std::cout << " ****" << ifr << " " << framenumber << " " << h5offset[0]
|
||||
<< std::endl;
|
||||
} // else
|
||||
|
||||
if (ifr >= 1000)
|
||||
break;
|
||||
//framenumber = 0;
|
||||
}
|
||||
|
||||
pedefile->CloseResources();
|
||||
while (mt->isBusy()) {
|
||||
;
|
||||
}
|
||||
|
||||
std::cout << "Writing pedestal to " << getRootString(pedfilename) << "_ped.tiff" << std::endl;
|
||||
auto imgfname = createFileName( outdir, getRootString(pedfilename), "ped", "");
|
||||
mt->writePedestal(imgfname.c_str());
|
||||
std::cout << "Writing pedestal rms to " << getRootString(pedfilename) << "_rms.tiff" << std::endl;
|
||||
imgfname = createFileName( outdir, getRootString(pedfilename), "rms", "");
|
||||
mt->writePedestalRMS(imgfname.c_str());
|
||||
|
||||
} else
|
||||
std::cout << "Could not open pedestal file " << fname
|
||||
<< " for reading " << std::endl;
|
||||
|
||||
} else { //is a tiff file
|
||||
|
||||
std::vector<double> ped(nx * ny);
|
||||
float* pp = ReadFromTiff(pedfilename.c_str(), nny, nnx);
|
||||
if (pp && (int)nnx == nx && (int)nny == ny) {
|
||||
for (int i = 0; i < nx * ny; i++) {
|
||||
ped[i] = pp[i];
|
||||
}
|
||||
delete[] pp;
|
||||
mt->setPedestal(ped.data());
|
||||
std::cout << "Pedestal set from tiff file " << pedfilename
|
||||
<< std::endl;
|
||||
} else {
|
||||
std::cout << "Could not open pedestal tiff file " << pedfilename
|
||||
<< " for reading " << std::endl;
|
||||
}
|
||||
}
|
||||
std::time(&end_time);
|
||||
std::cout << std::ctime(&end_time) << std::endl;
|
||||
}
|
||||
|
||||
ifr = 0;
|
||||
int ioutfile = 0;
|
||||
|
||||
mt->setFrameMode(eFrame);
|
||||
|
||||
FILE* of = nullptr;
|
||||
|
||||
//NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS!
|
||||
for (unsigned int ifile = 0; ifile != filenames.size(); ++ifile) {
|
||||
std::cout << "DATA " << filenames[ifile] << " " << std::endl;
|
||||
auto imgfname( createFileName( outdir, getRootString(filenames[ifile]), "", "" ) );
|
||||
std::string const cfname( createFileName( outdir, getRootString(filenames[ifile]), "", "clust" ) );
|
||||
|
||||
std::time(&end_time);
|
||||
std::cout << std::ctime(&end_time) << std::endl;
|
||||
|
||||
//HDF5File fileh5;
|
||||
auto fileh5 = std::make_unique<HDF5File>();
|
||||
fileh5->SetFrameIndexPath(frameindexpath);
|
||||
fileh5->SetImageDataPath(datasetpath);
|
||||
// //open file
|
||||
ioutfile = 0;
|
||||
if ( fileh5->OpenResources(filenames[ifile].c_str(), validate_rank) ) {
|
||||
if (thr <= 0 && cf != 0) { // cluster finder
|
||||
if (of == nullptr) {
|
||||
of = fopen(cfname.c_str(), "w");
|
||||
if (of) {
|
||||
if (mt) {
|
||||
mt->setFilePointer(of);
|
||||
std::cout << "file pointer set " << std::endl;
|
||||
} else {
|
||||
std::cerr << "Error: mt is null." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
//mt->setFilePointer(of);
|
||||
//std::cout << "file pointer set " << std::endl;
|
||||
//std::cout << "Here! " << framenumber << " ";
|
||||
} else {
|
||||
std::cout << "Could not open " << cfname
|
||||
<< " for writing " << std::endl;
|
||||
mt->setFilePointer(nullptr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// //while read frame
|
||||
framenumber = 0;
|
||||
h5offset[0] = 0;
|
||||
ifr = 0;
|
||||
//std::cout << "Here! " << framenumber << " ";
|
||||
while ( decoder->readNextFrame(*fileh5, framenumber, h5offset, buff) ) {
|
||||
//std::cout << "Here! " << framenumber << " ";
|
||||
// //push
|
||||
if ((ifr + 1) % 1000 == 0) {
|
||||
std::cout << " ****"
|
||||
<< decoder->getValue(buff, 20, 20); // << std::endl;
|
||||
}
|
||||
mt->pushData(buff);
|
||||
|
||||
// // //pop
|
||||
mt->nextThread();
|
||||
mt->popFree(buff); /* In the last execution of the loop,
|
||||
* this leaves buff outside of the Fifo!
|
||||
* Free explicitely at the end! */
|
||||
|
||||
++ifr;
|
||||
if (ifr % 1000 == 0)
|
||||
std::cout << " " << ifr << " " << framenumber << " " << h5offset[0]
|
||||
<< std::endl;
|
||||
if (nframes > 0) {
|
||||
if (ifr % nframes == 0) {
|
||||
imgfname = createFileName( outdir, getRootString(filenames[ifile]), "", "", ioutfile );
|
||||
mt->writeImage(imgfname.c_str(), thr1);
|
||||
mt->clearImage();
|
||||
++ioutfile;
|
||||
}
|
||||
}
|
||||
|
||||
//framenumber = 0;
|
||||
}
|
||||
|
||||
//std::cout << "aa --" << std::endl;
|
||||
fileh5->CloseResources();
|
||||
|
||||
//std::cout << "bb --" << std::endl;
|
||||
while (mt->isBusy()) {
|
||||
;
|
||||
}
|
||||
|
||||
//std::cout << "cc --" << std::endl;
|
||||
if (nframes >= 0) {
|
||||
if (nframes > 0)
|
||||
imgfname = createFileName( outdir, getRootString(filenames[ifile]), "", "", ioutfile );
|
||||
std::cout << "Writing tiff to " << imgfname << " " << thr1 << ".tiff"
|
||||
<< std::endl;
|
||||
mt->writeImage(imgfname.c_str(), thr1);
|
||||
mt->clearImage();
|
||||
if (of) {
|
||||
fclose(of);
|
||||
of = nullptr;
|
||||
mt->setFilePointer(nullptr);
|
||||
}
|
||||
}
|
||||
std::time(&end_time);
|
||||
std::cout << std::ctime(&end_time) << std::endl;
|
||||
} else
|
||||
std::cout << "Could not open " << filenames[ifile] << " for reading "
|
||||
<< std::endl;
|
||||
}
|
||||
if (nframes < 0) {
|
||||
//std::string fprefix( getRootString(filenames[0]) ); //Possibly, non-ideal name choice for file
|
||||
auto imgfname( createFileName( outdir, getRootString(filenames[0]), "sum", "" ) );
|
||||
std::cout << "Writing tiff to " << imgfname << " " << thr1 << ".tiff" << std::endl;
|
||||
mt->writeImage(imgfname.c_str(), thr1);
|
||||
}
|
||||
|
||||
|
||||
//std::cout << "Calling delete..." << std::endl;
|
||||
/* Info: Previously, 'delete mt' caused crash
|
||||
(double calls of StopThread() in both destructors of
|
||||
multiThreadedAnalogDetector and threadedAnalogDetector)
|
||||
Now fixed! */
|
||||
delete mt; // triggers cleanup of all threads and singlePhotonDetector instances (delete filter is obsolete)
|
||||
delete decoder;
|
||||
free(buff); // Free explicitly as it gets popped out of the Fifo at termination of while(readNextFrame)
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,468 +0,0 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
// #include "sls/ansi.h"
|
||||
//#include <iostream>
|
||||
#undef CORR
|
||||
|
||||
#define RAWDATA
|
||||
|
||||
|
||||
#include "jungfrauLGADStrixelsDataQuadH5.h"
|
||||
|
||||
#include "multiThreadedCountingDetector.h"
|
||||
#include "singlePhotonDetector.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <csignal>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <fmt/core.h>
|
||||
|
||||
|
||||
/*Dataset paths according to different beamlines*/
|
||||
std::string const data_datasetname_furka("/data/JF18T01V01/data");
|
||||
std::string const index_datasetname_furka("/data/JF18T01V01/frame_index");
|
||||
std::string const data_datasetname_xfelSCS("/INSTRUMENT/SCS_HRIXS_JUNGF/DET/JNGFR01:daqOutput/data/adc");
|
||||
std::string const index_datasetname_xfelSCS("/INSTRUMENT/SCS_HRIXS_JUNGF/DET/JNGFR01:daqOutput/data/frameNumber");
|
||||
|
||||
std::string getRootString( std::string const& filepath ) {
|
||||
size_t pos1;
|
||||
if (filepath.find("/") == std::string::npos )
|
||||
pos1 = 0;
|
||||
else
|
||||
pos1 = filepath.find_last_of("/")+1;
|
||||
size_t pos2 = filepath.find_last_of(".");
|
||||
//std::cout << "pos1 " << pos1 << " pos2 " << pos2 << " size " << filepath.length() << std::endl;
|
||||
return filepath.substr( pos1, pos2-pos1 );
|
||||
}
|
||||
|
||||
/* Create file name string
|
||||
* \param dir directory
|
||||
* \param fprefix fileprefix (without extension)
|
||||
* \param fsuffix filesuffix (for output files, e.g. "ped")
|
||||
* \param fext file extension (e.g. "raw")
|
||||
*/
|
||||
std::string createFileName( std::string const& dir, std::string const& fprefix="run",
|
||||
std::string const& fsuffix="", std::string const& fext="raw", int const outfilecounter=-1 ) {
|
||||
std::string return_string;
|
||||
if (outfilecounter >= 0)
|
||||
return_string = fmt::format("{:s}/{:s}_{:s}_f{:05d}", dir, fprefix, fsuffix, outfilecounter);
|
||||
else if (fsuffix.length()!=0)
|
||||
return_string = fmt::format("{:s}/{:s}_{:s}", dir, fprefix, fsuffix);
|
||||
else
|
||||
return_string = fmt::format("{:s}/{:s}", dir, fprefix);
|
||||
|
||||
if (fext.length()!=0)
|
||||
return_string += "." + fext;
|
||||
|
||||
return return_string;
|
||||
}
|
||||
|
||||
/* Adjusts number of threads to be a multiple of number of storage cells
|
||||
* \param requestedThreads number of threads requested by the user
|
||||
* \param nSC number of storage cells
|
||||
*/
|
||||
int adjustThreads(int requestedThreads, int nSC) {
|
||||
if (nSC <= 0) {
|
||||
std::cerr << "Error: Number of S values must be greater than zero!" << std::endl;
|
||||
return requestedThreads; // Return the original value as a fallback
|
||||
}
|
||||
|
||||
// Calculate the remainder
|
||||
int remainder = requestedThreads % nSC;
|
||||
|
||||
// If remainder is non-zero, round up by adding the difference
|
||||
int adjustedThreads = (remainder == 0) ? requestedThreads : requestedThreads + (nSC - remainder);
|
||||
|
||||
// Ensure at least `nSC` threads are used
|
||||
if (adjustedThreads < nSC) {
|
||||
adjustedThreads = nSC;
|
||||
}
|
||||
|
||||
std::cout << "Adjusted thread count (rounded up): " << adjustedThreads << " (nearest multiple of "
|
||||
<< nSC << ")" << std::endl;
|
||||
|
||||
return adjustedThreads;
|
||||
}
|
||||
|
||||
// Signal handler for segmentation faults
|
||||
void signal_handler(int signum) {
|
||||
std::cerr << "Caught signal " << signum << ": Segmentation fault (core dump)" << std::endl;
|
||||
// Handle the error (e.g., clean up, abort, etc.)
|
||||
exit(signum); // Exit program with the signal code
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc < 4) {
|
||||
std::cout
|
||||
<< "Usage is " << argv[0]
|
||||
<< " filestxt outdir [pedfile (h5)] "
|
||||
" optional: [int dataset path; 0 means Furka, 1 means XFEL; overwrites default given in HDF5File.h] "
|
||||
" [bool validate h5 rank] "
|
||||
" [xmin xmax ymin ymax] [nframes] "
|
||||
" NOTE THAT THE DATA FILES HAVE TO BE IN THE RIGHT ORDER SO THAT PEDESTAL TRACKING WORKS! "
|
||||
<< std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set up the signal handler for segmentation faults
|
||||
signal(SIGSEGV, signal_handler);
|
||||
|
||||
int const fifosize = 100; //1000;
|
||||
int const nthreads = 10;
|
||||
int const csize = 3; // 3
|
||||
int const nsigma = 5;
|
||||
int const nped = 10000;
|
||||
|
||||
//int cf = 0;
|
||||
|
||||
std::string const txtfilename(argv[1]);
|
||||
std::string const outdir(argv[2]);
|
||||
std::string const pedfilename(argv[3]);
|
||||
|
||||
std::string datasetpath{};
|
||||
std::string frameindexpath{};
|
||||
if (argc > 4) {
|
||||
switch (atoi(argv[4])) {
|
||||
case 0:
|
||||
datasetpath = data_datasetname_furka;
|
||||
frameindexpath = index_datasetname_furka;
|
||||
break;
|
||||
case 1:
|
||||
datasetpath = data_datasetname_xfelSCS;
|
||||
frameindexpath = index_datasetname_xfelSCS;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool validate_rank=true;
|
||||
if (argc > 5)
|
||||
validate_rank = atoi(argv[5]);
|
||||
|
||||
//Get vector of filenames from input txt-file
|
||||
std::vector<std::string> filenames{};
|
||||
|
||||
{ //Safety scope for ifstream
|
||||
ifstream inputs( txtfilename, std::ios::in );
|
||||
if (inputs.is_open()) {
|
||||
std::cout << "Reading imput filenames from txt-file ..." << std::endl;
|
||||
std::string line{};
|
||||
while (!inputs.eof()) {
|
||||
std::getline(inputs, line);
|
||||
if(line.find(".h5") != std::string::npos) {
|
||||
filenames.emplace_back(line);
|
||||
std::cout << line << std::endl;
|
||||
}
|
||||
}
|
||||
inputs.close();
|
||||
std::cout << "---- Reached end of txt-file. ----" << std::endl;
|
||||
} else
|
||||
std::cout << "Could not open " << txtfilename << std::endl;
|
||||
if (filenames.size()>0) {
|
||||
std::cout << filenames.size() << " filenames found in " << txtfilename << std::endl;
|
||||
std::cout << "The files will be processed in the same order as found in the txt-file." << std::endl;
|
||||
} else {
|
||||
std::cout << "No files found in txt-file!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "###############" << std::endl;
|
||||
|
||||
// Define decoder
|
||||
std::cout << "Jungfrau strixel quad h5" << std::endl;
|
||||
jungfrauLGADStrixelsDataQuadH5* decoder = new jungfrauLGADStrixelsDataQuadH5();
|
||||
//auto decoder = std::make_unique<jungfrauLGADStrixelsDataQuadH5>();
|
||||
int nx = 1024 / 3, ny = 512 * 3;
|
||||
|
||||
//Cluster finder ROI
|
||||
int xmin = 0, xmax = nx-1, ymin = 0, ymax = ny-1;
|
||||
if (argc > 9) {
|
||||
xmin = atoi(argv[6]);
|
||||
xmax = atoi(argv[7]);
|
||||
ymin = atoi(argv[8]);
|
||||
ymax = atoi(argv[9]);
|
||||
}
|
||||
std::cout << "Cluster finder ROI: [" << xmin << ", " << xmax << ", " << ymin << ", " << ymax << "]"
|
||||
<< std::endl;
|
||||
|
||||
decoder->getDetectorSize(nx, ny);
|
||||
std::cout << "Detector size is " << nx << " " << ny << std::endl;
|
||||
|
||||
std::time_t end_time;
|
||||
|
||||
std::cout << "Output directory is " << outdir << std::endl;
|
||||
if (pedfilename.length()!=0)
|
||||
std::cout << "Pedestal file is " << pedfilename << std::endl;
|
||||
|
||||
//uint32_t nnx, nny;
|
||||
|
||||
singlePhotonDetector* filter =
|
||||
new singlePhotonDetector(decoder, 3, nsigma, 1, NULL, nped, 200, -1, -1, NULL, NULL);
|
||||
//auto filter = std::make_unique<singlePhotonDetector>(decoder.get(), 3, nsigma, 1, nullptr, nped, 200, -1, -1, nullptr, nullptr);
|
||||
|
||||
filter->setROI(xmin, xmax, ymin, ymax);
|
||||
|
||||
std::time(&end_time);
|
||||
std::cout << std::ctime(&end_time) << std::endl;
|
||||
|
||||
// Validate number of threads for number of storage cells (if applicable)
|
||||
int nThreads = nthreads;
|
||||
int nSC = 1;
|
||||
// Determine the dimensions of the dataset from the first datafile
|
||||
auto firstfileh5 = std::make_unique<HDF5File>();
|
||||
firstfileh5->SetFrameIndexPath(frameindexpath);
|
||||
firstfileh5->SetImageDataPath(datasetpath);
|
||||
//std::cout << "Debug: Attempting to open file " << filenames[0].c_str() << std::endl;
|
||||
if ( firstfileh5->OpenResources(filenames[0].c_str(), validate_rank) ) {
|
||||
|
||||
// Validate number of threads
|
||||
if( firstfileh5->GetRank() == 4 ) {
|
||||
auto h5dims = firstfileh5->GetDatasetDimensions();
|
||||
nSC = h5dims[1];
|
||||
nThreads = adjustThreads(nthreads,nSC);
|
||||
}
|
||||
|
||||
firstfileh5->CloseResources();
|
||||
} else {
|
||||
std::cerr << "Error: Could not open data file " << filenames[0]
|
||||
<< " for validating rank " << std::endl;
|
||||
}
|
||||
|
||||
multiThreadedCountingDetector* mt =
|
||||
new multiThreadedCountingDetector(filter, nThreads, fifosize, nSC);
|
||||
//auto mt = std::make_unique<multiThreadedCountingDetector>(filter.get(), nthreads, fifosize);
|
||||
mt->setClusterSize(csize, csize);
|
||||
mt->newDataSet(); //Initialize new dataset for each thread
|
||||
mt->setDetectorMode(ePhotonCounting);
|
||||
|
||||
char* buff;
|
||||
|
||||
mt->StartThreads();
|
||||
mt->popFree(buff); // Get the first pointer to write image to
|
||||
|
||||
size_t ifr = 0; //frame counter of while loop
|
||||
int framenumber = 0; //framenumber as read from file (detector)
|
||||
std::vector<hsize_t> h5offset; //hyperslab offset internal to HDF5File::ReadImage
|
||||
hsize_t h5rank;
|
||||
|
||||
if (pedfilename.length()>1) {
|
||||
|
||||
std::string froot = getRootString(pedfilename);
|
||||
|
||||
std::cout << "PEDESTAL " << pedfilename << std::endl;
|
||||
std::time(&end_time);
|
||||
std::cout << "aaa " << std::ctime(&end_time) << std::endl;
|
||||
|
||||
mt->setFrameMode(ePedestal);
|
||||
|
||||
//HDF5File pedefile;
|
||||
auto pedefile = std::make_unique<HDF5File>();
|
||||
pedefile->SetFrameIndexPath(frameindexpath);
|
||||
pedefile->SetImageDataPath(datasetpath);
|
||||
// //open file
|
||||
if ( pedefile->OpenResources(pedfilename.c_str(),validate_rank) ) {
|
||||
|
||||
// Initialize offset vector to 0
|
||||
h5rank = pedefile->GetRank();
|
||||
h5offset.resize(h5rank-2, 0);
|
||||
framenumber = 0;
|
||||
|
||||
while ( decoder->readNextFrame(*pedefile, framenumber, h5offset, buff) ) {
|
||||
|
||||
if ((ifr + 1) % 100 == 0) {
|
||||
std::cout
|
||||
<< " ****"
|
||||
<< decoder->getValue(buff, 20, 20); // << std::endl;
|
||||
}
|
||||
|
||||
int storageCell = 0;
|
||||
hsize_t n_storageCells = 1;
|
||||
if (h5rank == 4) {
|
||||
storageCell = h5offset[1];
|
||||
n_storageCells = pedefile->GetDatasetDimensions()[1];
|
||||
}
|
||||
|
||||
// push buff into fifoData for a thread corresponding to the active storage cell
|
||||
mt->pushData(buff, storageCell);
|
||||
// increment (round-robin) the internal thread counter for that storage cell
|
||||
mt->nextThread(storageCell);
|
||||
// get a free memory address from fifoFree of the active storage cell for the next read operation
|
||||
mt->popFree(buff, storageCell);
|
||||
/* NOTE: the buff that was popped free from the current thread, will be (likely) pushed into
|
||||
* the fifoData of a different thread in the next iteration of the loop! */
|
||||
|
||||
++ifr;
|
||||
if (ifr % 100 == 0) {
|
||||
std::cout << " ****" << ifr << " " << framenumber << " " << h5offset[0];
|
||||
if (n_storageCells>1)
|
||||
std::cout << " sc " << storageCell;
|
||||
std::cout << "\n";
|
||||
} // else
|
||||
|
||||
if (ifr >= 1000*n_storageCells)
|
||||
break;
|
||||
//framenumber = 0;
|
||||
}
|
||||
|
||||
pedefile->CloseResources();
|
||||
while (mt->isBusy()) {
|
||||
;
|
||||
}
|
||||
|
||||
std::cout << "Writing pedestal to " << getRootString(pedfilename) << "_ped_SCxx.tiff" << std::endl;
|
||||
auto imgfname = createFileName( outdir, getRootString(pedfilename), "ped", "" );
|
||||
mt->writePedestal(imgfname.c_str());
|
||||
std::cout << "Writing pedestal rms to " << getRootString(pedfilename) << "_rms_SCxx.tiff" << std::endl;
|
||||
imgfname = createFileName( outdir, getRootString(pedfilename), "rms", "");
|
||||
mt->writePedestalRMS(imgfname.c_str());
|
||||
|
||||
} else {
|
||||
std::cerr << "Error: Could not open pedestal file " << pedfilename
|
||||
<< " for reading " << std::endl;
|
||||
}
|
||||
|
||||
std::time(&end_time);
|
||||
std::cout << std::ctime(&end_time) << std::endl;
|
||||
}
|
||||
|
||||
ifr = 0;
|
||||
//int ioutfile = 0;
|
||||
|
||||
mt->setFrameMode(eFrame);
|
||||
|
||||
std::vector<FILE*> of(nSC, nullptr);
|
||||
|
||||
for (unsigned int ifile = 0; ifile != filenames.size(); ++ifile) {
|
||||
std::cout << "DATA " << filenames[ifile] << " " << std::endl;
|
||||
std::time(&end_time);
|
||||
std::cout << std::ctime(&end_time) << std::endl;
|
||||
|
||||
//HDF5File fileh5;
|
||||
auto fileh5 = std::make_unique<HDF5File>();
|
||||
fileh5->SetFrameIndexPath(frameindexpath);
|
||||
fileh5->SetImageDataPath(datasetpath);
|
||||
|
||||
// Open HDF5 file
|
||||
if ( fileh5->OpenResources(filenames[ifile].c_str(), validate_rank) ) {
|
||||
|
||||
std::vector<std::string> cfnames(nSC);
|
||||
for ( int s = 0; s < nSC; ++s ) {
|
||||
std::string fsuffix = "SC" + std::to_string(s);
|
||||
cfnames[s] = createFileName( outdir, getRootString(filenames[ifile]), fsuffix, "clust" );
|
||||
}
|
||||
|
||||
//Open output files and set file pointers according to storage cells
|
||||
for ( size_t f = 0; f < of.size(); ++f ) {
|
||||
if (!of[f]) {
|
||||
of[f] = fopen(cfnames[f].c_str(), "w");
|
||||
if (of[f])
|
||||
{
|
||||
if (mt) {
|
||||
mt->setFilePointer(of[f],f); // assumes f == sc
|
||||
std::cout << "File pointer set for storage cell " << f << std::endl;
|
||||
} else {
|
||||
std::cerr << "Error: mt is null." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Error: could not open " << cfnames[f]
|
||||
<< " for writing " << std::endl;
|
||||
mt->setFilePointer(nullptr,f);
|
||||
return 1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Read frames
|
||||
framenumber = 0;
|
||||
std::fill(h5offset.begin(), h5offset.end(), 0);
|
||||
ifr = 0;
|
||||
|
||||
while ( decoder->readNextFrame(*fileh5, framenumber, h5offset, buff) ) {
|
||||
|
||||
if ((ifr + 1) % 1000 == 0) {
|
||||
std::cout << " ****"
|
||||
<< decoder->getValue(buff, 20, 20); // << std::endl;
|
||||
}
|
||||
|
||||
int storageCell = 0;
|
||||
hsize_t n_storageCells = 1;
|
||||
if (h5rank == 4) {
|
||||
storageCell = h5offset[1];
|
||||
n_storageCells = fileh5->GetDatasetDimensions()[1];
|
||||
}
|
||||
|
||||
// push buff into fifoData for a thread corresponding to the active storage cell
|
||||
mt->pushData(buff, storageCell);
|
||||
// increment (round-robin) the internal thread counter for that storage cell
|
||||
mt->nextThread(storageCell);
|
||||
// get a free memory address from fifoFree of the active storage cell for the next read operation
|
||||
mt->popFree(buff, storageCell); /* In the last execution of the loop,
|
||||
* this leaves buff outside of the Fifo!
|
||||
* Free explicitely at the end! */
|
||||
|
||||
++ifr;
|
||||
if (ifr % 1000 == 0) {
|
||||
std::cout << " " << ifr << " " << framenumber << " " << h5offset[0];
|
||||
if (n_storageCells>1) std::cout << " sc " << storageCell;
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
//framenumber = 0;
|
||||
}
|
||||
|
||||
//std::cout << "aa --" << std::endl;
|
||||
fileh5->CloseResources();
|
||||
|
||||
//std::cout << "bb --" << std::endl;
|
||||
while (mt->isBusy()) {
|
||||
;
|
||||
}
|
||||
|
||||
//std::cout << "cc --" << std::endl;
|
||||
|
||||
auto imgfname = createFileName( outdir, getRootString(filenames[ifile]), "", "" );
|
||||
std::cout << "Writing tiff to " << imgfname << "_SCxx.tiff" << std::endl;
|
||||
mt->writeImage(imgfname.c_str());
|
||||
mt->clearImage();
|
||||
|
||||
// Close output files
|
||||
for ( size_t f = 0; f < of.size(); ++f ) {
|
||||
if (of[f]) {
|
||||
fclose(of[f]);
|
||||
mt->setFilePointer(nullptr,f);
|
||||
of[f] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::time(&end_time);
|
||||
std::cout << std::ctime(&end_time) << std::endl;
|
||||
} else {
|
||||
std::cerr << "Error: Could not open " << filenames[ifile] << " for reading "
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//std::cout << "Calling delete..." << std::endl;
|
||||
/* Info: Previously, 'delete mt' caused crash
|
||||
(double calls of StopThread() in both destructors of
|
||||
multiThreadedAnalogDetector and threadedAnalogDetector)
|
||||
Now fixed! */
|
||||
delete mt; // triggers cleanup of all threads and singlePhotonDetector instances (delete filter is obsolete)
|
||||
delete decoder;
|
||||
free(buff); // Free explicitly as it gets popped out of the Fifo at termination of while(readNextFrame)
|
||||
|
||||
return 0;
|
||||
}
|
@ -336,7 +336,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
string fname;
|
||||
// int length;
|
||||
int *detimage = nullptr;
|
||||
int *detimage = NULL;
|
||||
int nnx, nny, nnsx, nnsy;
|
||||
// uint32_t imageSize = 0, nPixelsX = 0, nPixelsY = 0,
|
||||
// uint32_t dynamicRange = 0;
|
||||
|
@ -23,9 +23,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <mutex>
|
||||
#include <algorithm>
|
||||
#include<unordered_map>
|
||||
//#include <mutex>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -49,20 +47,12 @@ class threadedAnalogDetector {
|
||||
|
||||
if (mm) {
|
||||
// memset(mm,0, det->getDataSize());
|
||||
/*
|
||||
if (i == 0) { // debug
|
||||
first_mm = mm;
|
||||
}
|
||||
*/
|
||||
|
||||
fifoFree->push(mm);
|
||||
//std::cout << "Allocated memory at: " << static_cast<void*>(mm) << " (fifoslot " << i << ")" << std::endl;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < fs)
|
||||
std::cout << "Could allocate only " << i << " frames";
|
||||
cout << "Could allocate only " << i << " frames";
|
||||
|
||||
busy = 0;
|
||||
stop = 1;
|
||||
@ -112,50 +102,24 @@ class threadedAnalogDetector {
|
||||
};
|
||||
|
||||
virtual ~threadedAnalogDetector() {
|
||||
|
||||
// std::cout << "#### Debug: Destructing threadedAnalogDetector! ####" << std::endl;
|
||||
|
||||
StopThread();
|
||||
|
||||
if (fifoFree) { delete fifoFree; fifoFree = nullptr; }
|
||||
if (fifoData) { delete fifoData; fifoData = nullptr; }
|
||||
if (det) {
|
||||
delete det; // Call destructor for singlePhotonDetector
|
||||
det = nullptr;
|
||||
}
|
||||
delete fifoFree;
|
||||
delete fifoData;
|
||||
}
|
||||
|
||||
/** Returns true if the thread was successfully started, false if there was
|
||||
* an error starting the thread */
|
||||
virtual bool StartThread() {
|
||||
stop = 0;
|
||||
std::cout << "Detector number " << det->getId() << std::endl;
|
||||
std::cout << "common mode is " << det->getCommonModeSubtraction() << std::endl;
|
||||
std::cout << "ghos summation is " << det->getGhostSummation() << std::endl;
|
||||
|
||||
cout << "Detector number " << det->getId() << endl;
|
||||
cout << "common mode is " << det->getCommonModeSubtraction() << endl;
|
||||
cout << "ghos summation is " << det->getGhostSummation() << endl;
|
||||
return (pthread_create(&_thread, NULL, processData, this) == 0);
|
||||
}
|
||||
|
||||
virtual void StopThread() {
|
||||
stop = 1;
|
||||
//std::cout << "Attempting to stop thread..." << std::endl;
|
||||
|
||||
// Free all remaining allocated memory in fifoFree
|
||||
char *mm = nullptr;
|
||||
while (fifoFree->pop(mm, true)) { // Use no_block to avoid waiting
|
||||
//std::cout << "fifo Free: Freeing memory at: " << static_cast<void*>(mm) << std::endl;
|
||||
free(mm); // Free the allocated memory
|
||||
}
|
||||
|
||||
if (_thread) {
|
||||
//(void)pthread_join(_thread, NULL);
|
||||
//std::cout << "Calling pthread_join for thread: " << det->getId() << std::endl;
|
||||
pthread_join(_thread, NULL);
|
||||
_thread = 0;
|
||||
std::cout << "Thread " << det->getId() << " stopped and joined." << std::endl;
|
||||
} else {
|
||||
std::cout << "No thread to join." << std::endl;
|
||||
}
|
||||
(void)pthread_join(_thread, NULL);
|
||||
}
|
||||
|
||||
virtual bool pushData(char *&ptr) { return fifoData->push(ptr); }
|
||||
@ -302,8 +266,6 @@ class threadedAnalogDetector {
|
||||
char *data;
|
||||
int *ff;
|
||||
|
||||
//char* first_mm = nullptr; // For debug; to track first allocated block
|
||||
|
||||
static void *processData(void *ptr) {
|
||||
threadedAnalogDetector *This = ((threadedAnalogDetector *)ptr);
|
||||
return This->processData();
|
||||
@ -316,118 +278,55 @@ class threadedAnalogDetector {
|
||||
usleep(100);
|
||||
if (fifoData->isEmpty()) {
|
||||
busy = 0;
|
||||
} else {
|
||||
} else
|
||||
busy = 1;
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
busy = 1;
|
||||
}
|
||||
|
||||
if (busy == 1) {
|
||||
// Check stop flag before making a blocking call
|
||||
//if (stop) {
|
||||
// break;
|
||||
//}
|
||||
|
||||
// Blocking call
|
||||
fifoData->pop(data); // blocking!
|
||||
|
||||
// Process data if not stopping
|
||||
//if (!stop) {
|
||||
det->processData(data);
|
||||
fifoFree->push(data);
|
||||
|
||||
//}
|
||||
// busy=0;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
class multiThreadedAnalogDetector {
|
||||
public:
|
||||
multiThreadedAnalogDetector(analogDetector<uint16_t> *d, int num_threads,
|
||||
int fs = 1000, int num_sc = 1)
|
||||
: stop(0), nThreads(num_threads), nSC(num_sc) {
|
||||
|
||||
/*
|
||||
multiThreadedAnalogDetector(analogDetector<uint16_t> *d, int n,
|
||||
int fs = 1000)
|
||||
: stop(0), nThreads(n), ithread(0) {
|
||||
dd[0] = d;
|
||||
if (nThreads == 1)
|
||||
dd[0]->setId(100);
|
||||
else
|
||||
dd[0]->setId(0);
|
||||
*/
|
||||
|
||||
// Create separate detectorObjects for each SC (each owns its mutex)
|
||||
std::vector< analogDetector<uint16_t>* > sc_detectors(nSC, nullptr);
|
||||
sc_detectors[0] = d; // First storage cell uses the given detector
|
||||
// std::cout << "#### Debug: Copied analogDetector object for storage cell 0! ####" << std::endl;
|
||||
|
||||
for (int sc = 1; sc < nSC; ++sc) {
|
||||
sc_detectors[sc] = d->Copy(); // Ensure unique mutex for each SC
|
||||
// std::cout << "#### Debug: Copied analogDetector object for storage cell " << sc << "! ####" << std::endl;
|
||||
for (int i = 1; i < nThreads; i++) {
|
||||
dd[i] = d->Clone();
|
||||
dd[i]->setId(i);
|
||||
}
|
||||
|
||||
// Distribute threads among storage cells
|
||||
int threads_per_sc = nThreads / nSC;
|
||||
int remaining_threads = nThreads % nSC; // additional safety measure if nThreads is not divisible by nSC
|
||||
|
||||
sc_to_threads.clear();
|
||||
for (int s = 0, thread_idx = 0; s < nSC; ++s) {
|
||||
// Remaining threads (if any) are assigned to the first storage cells
|
||||
int current_sc_threads = threads_per_sc + (s < remaining_threads ? 1 : 0);
|
||||
|
||||
for (int t = 0; t < current_sc_threads; ++t, ++thread_idx) {
|
||||
|
||||
if (t == 0) {
|
||||
dd[thread_idx] = sc_detectors[s]; // First thread gets main SC detector
|
||||
} else {
|
||||
dd[thread_idx] = sc_detectors[s]->Clone(); // Other threads get clones
|
||||
}
|
||||
|
||||
std::cout << "Assigned thread " << thread_idx << " to storage cell " << s << std::endl;
|
||||
|
||||
dd[thread_idx]->setId(thread_idx);
|
||||
|
||||
// Store which threads belong to which SC
|
||||
sc_to_threads[s].push_back(thread_idx);
|
||||
}
|
||||
}
|
||||
|
||||
if (nSC == 1 && nThreads == 1) {
|
||||
dd[0]->setId(100);
|
||||
}
|
||||
|
||||
// Initialize threadedAnalogDetector objects
|
||||
for (int i = 0; i < nThreads; i++) {
|
||||
cout << "**" << i << endl;
|
||||
dets[i] = new threadedAnalogDetector(dd[i], fs);
|
||||
}
|
||||
|
||||
// Set all thread counters to zero for each storage cell
|
||||
thread_counters_by_sc.resize(nSC,0);
|
||||
|
||||
image = nullptr;
|
||||
image = NULL;
|
||||
ff = NULL;
|
||||
ped = NULL;
|
||||
//std::cout << "Ithread is " << ithread << std::endl;
|
||||
cout << "Ithread is " << ithread << endl;
|
||||
}
|
||||
|
||||
virtual ~multiThreadedAnalogDetector() {
|
||||
// std::cout << "#### Debug: Destructing multiThreadedAnalogDetector! ####" << std::endl;
|
||||
//StopThreads(); // Superfluous, leads to double delete
|
||||
|
||||
/* Reverse loop for destruction.
|
||||
* Deletes clones first, then root object, which owns the mutex
|
||||
* (ensure shared mutex is deleted last).
|
||||
* Optional solution: reference counting (safer but more complex) */
|
||||
for (int i = nThreads - 1; i >= 0; --i) {
|
||||
delete dets[i]; //StopThread() called by each ~threadedAnalogDetector()
|
||||
dets[i] = nullptr;
|
||||
}
|
||||
|
||||
StopThreads();
|
||||
for (int i = 0; i < nThreads; i++)
|
||||
delete dets[i];
|
||||
/* for (int i=1; i<nThreads; i++) */
|
||||
/* delete dd[i]; */
|
||||
// delete [] image;
|
||||
}
|
||||
|
||||
virtual int setFrameMode(int fm) {
|
||||
@ -460,52 +359,36 @@ class multiThreadedAnalogDetector {
|
||||
dets[i]->newDataSet();
|
||||
};
|
||||
|
||||
// Storage cell sensitive
|
||||
virtual int *getImage(int &nnx, int &nny, int &ns, int &nsy, int sc = 0) {
|
||||
//int *img;
|
||||
virtual int *getImage(int &nnx, int &nny, int &ns, int &nsy) {
|
||||
int *img;
|
||||
// int nnx, nny, ns;
|
||||
// int nnx, nny, ns;
|
||||
int nn = dets[0]->getImageSize(nnx, nny, ns, nsy);
|
||||
|
||||
if (sc_images[sc]) {
|
||||
delete[] sc_images[sc];
|
||||
sc_images[sc] = nullptr;
|
||||
if (image) {
|
||||
delete[] image;
|
||||
image = NULL;
|
||||
}
|
||||
|
||||
// Allocate memory for image and zero-initialize
|
||||
sc_images[sc] = new int[nn]();
|
||||
image = new int[nn];
|
||||
// int nn=dets[0]->getImageSize(nnx, nny, ns);
|
||||
// for (i=0; i<nn; i++) image[i]=0;
|
||||
|
||||
// Get the threads assigned to this storage cell
|
||||
auto const& assigned_threads = sc_to_threads[sc];
|
||||
|
||||
// Only iterate over threads assigned to this storage cell
|
||||
for (int thread_id : assigned_threads) {
|
||||
|
||||
int* tmp_img = dets[thread_id]->getImage();
|
||||
if (!tmp_img) continue; // Skip if null
|
||||
|
||||
/* std::cout << "## Thread " << ii
|
||||
<< " # image size " << nn
|
||||
<< " # nnx " << nnx
|
||||
<< " # nny " << nny
|
||||
<< " # ns " << ns; */
|
||||
|
||||
// Sum images across threads
|
||||
for (int ii = 0; ii < nThreads; ii++) {
|
||||
// cout << ii << " " << nn << " " << nnx << " " << nny << " " << ns
|
||||
// << endl;
|
||||
img = dets[ii]->getImage();
|
||||
for (int i = 0; i < nn; i++) {
|
||||
|
||||
/* std::cout << " # pixel " << i
|
||||
<< " # value " << tmp_img[i]
|
||||
<< " ## " << std::endl; */
|
||||
|
||||
|
||||
sc_images[sc][i] += tmp_img[i];
|
||||
if (ii == 0)
|
||||
// if (img[i]>0)
|
||||
image[i] = img[i];
|
||||
// else
|
||||
// image[i]=0;
|
||||
else // if (img[i]>0)
|
||||
image[i] += img[i];
|
||||
// if (img[i]) cout << "det " << ii << " pix " << i << " val
|
||||
// " << img[i] << " " << image[i] << endl;
|
||||
}
|
||||
}
|
||||
return sc_images[sc];
|
||||
return image;
|
||||
}
|
||||
|
||||
virtual void clearImage() {
|
||||
@ -515,7 +398,7 @@ class multiThreadedAnalogDetector {
|
||||
}
|
||||
}
|
||||
|
||||
virtual void *writeImage(char const* base_imgname, double t = 1) {
|
||||
virtual void *writeImage(const char *imgname, double t = 1) {
|
||||
/* #ifdef SAVE_ALL */
|
||||
/* for (int ii=0; ii<nThreads; ii++) { */
|
||||
/* char tit[10000];cout << "m" <<endl; */
|
||||
@ -524,30 +407,11 @@ class multiThreadedAnalogDetector {
|
||||
/* } */
|
||||
/* #endif */
|
||||
int nnx, nny, ns, nsy;
|
||||
getImage(nnx, nny, ns, nsy);
|
||||
// int nnx, nny, ns;
|
||||
int nn = dets[0]->getImageSize(nnx, nny, ns, nsy);
|
||||
|
||||
// Allocate teporary float buffer and zero-initialize
|
||||
std::vector<float> gm(nn);
|
||||
|
||||
// Lambda for pixel conversion
|
||||
auto convert_pixel = [t](int pixel) -> float {
|
||||
return (t > 0) ? static_cast<float>(std::max(0, pixel)) / static_cast<float>(t) : pixel;
|
||||
}; // t ... threshold
|
||||
|
||||
// Loop over each storage cell
|
||||
for (auto const& [sc, _] : sc_to_threads) { // structured bindings [sc, _] only available with -std=c++17
|
||||
std::string imgname(base_imgname);
|
||||
if (nSC > 1) imgname += "_SC" + std::to_string(sc);
|
||||
imgname += ".tiff";
|
||||
|
||||
//Retrieve the image for this storage cell
|
||||
int *image = getImage(nnx, nny, ns, nsy, sc);
|
||||
if (!image) continue; // Skip if null
|
||||
|
||||
// Convert image data to float
|
||||
std::transform(image, image + nn, gm.begin(), convert_pixel);
|
||||
|
||||
/* old loop implementing same logic as convert_pixel
|
||||
float *gm = new float[nn];
|
||||
if (gm) {
|
||||
for (int ix = 0; ix < nn; ix++) {
|
||||
if (t) {
|
||||
if (image[ix] < 0)
|
||||
@ -560,18 +424,11 @@ class multiThreadedAnalogDetector {
|
||||
// if (image[ix]>0 && ix/nnx<350) cout << ix/nnx << " " <<
|
||||
// ix%nnx << " " << image[ix]<< " " << gm[ix] << endl;
|
||||
}
|
||||
*/
|
||||
|
||||
WriteToTiff(gm.data(), imgname.c_str(), nnx, nny);
|
||||
|
||||
// Clean up memory for this storage cell
|
||||
if (sc_images[sc]) {
|
||||
delete[] sc_images[sc];
|
||||
sc_images[sc] = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// cout << "image " << nnx << " " << nny << endl;
|
||||
WriteToTiff(gm, imgname, nnx, nny);
|
||||
delete[] gm;
|
||||
} else
|
||||
cout << "Could not allocate float image " << endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -582,7 +439,6 @@ class multiThreadedAnalogDetector {
|
||||
}
|
||||
|
||||
virtual void StopThreads() {
|
||||
std::cout << "Stopping all threads ..." << std::endl;
|
||||
for (int i = 0; i < nThreads; i++)
|
||||
dets[i]->StopThread();
|
||||
}
|
||||
@ -597,133 +453,76 @@ class multiThreadedAnalogDetector {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
virtual std::vector<int> getThreadsForSc(int sc) {
|
||||
return sc_to_threads[sc];
|
||||
}
|
||||
*/
|
||||
virtual bool pushData(char *&ptr, int sc=0) {
|
||||
//Additional logic implemented to accommodate storage cells
|
||||
virtual bool pushData(char *&ptr) { return dets[ithread]->pushData(ptr); }
|
||||
|
||||
std::unique_lock<std::mutex> lock(map_mutex);
|
||||
|
||||
// Get assigned threads for this storage cell
|
||||
auto& assigned_threads = sc_to_threads[sc];
|
||||
auto& counter = thread_counters_by_sc[sc];
|
||||
|
||||
// Distribute workload among threads using round-robin
|
||||
int selected_thread = assigned_threads[counter % assigned_threads.size()];
|
||||
|
||||
return dets[selected_thread]->pushData(ptr);
|
||||
virtual bool popFree(char *&ptr) {
|
||||
// cout << ithread << endl;
|
||||
return dets[ithread]->popFree(ptr);
|
||||
}
|
||||
|
||||
virtual bool popFree(char *&ptr, int sc=0) {
|
||||
//Additional logic implemented to accommodate storage cells
|
||||
|
||||
std::unique_lock<std::mutex> lock(map_mutex);
|
||||
|
||||
// Get assigned threads for this storage cell
|
||||
auto& assigned_threads = sc_to_threads[sc];
|
||||
auto& counter = thread_counters_by_sc[sc];
|
||||
|
||||
// Distribute workload among threads using round-robin
|
||||
int selected_thread = assigned_threads[counter % assigned_threads.size()];
|
||||
|
||||
return dets[selected_thread]->popFree(ptr);
|
||||
virtual int nextThread() {
|
||||
ithread++;
|
||||
if (ithread == nThreads)
|
||||
ithread = 0;
|
||||
return ithread;
|
||||
}
|
||||
|
||||
virtual int nextThread(int sc=0) {
|
||||
//Additional logic implemented to accommodate storage cells
|
||||
|
||||
auto& counter = thread_counters_by_sc[sc];
|
||||
//counter++;
|
||||
if (++counter == nThreads/nSC)
|
||||
counter = 0;
|
||||
return counter;
|
||||
}
|
||||
|
||||
// Storage cell sensitive
|
||||
virtual double *getPedestal(int sc = 0) {
|
||||
virtual double *getPedestal() {
|
||||
int nx, ny;
|
||||
dets[0]->getDetectorSize(nx, ny);
|
||||
|
||||
if (sc_pedestals.count(sc) && sc_pedestals[sc]) {
|
||||
delete[] sc_pedestals[sc];
|
||||
sc_pedestals[sc] = nullptr;
|
||||
}
|
||||
|
||||
// allocate memory and initialize all values to zero
|
||||
sc_pedestals[sc] = new double[nx * ny](); // parentheses initialize elements to zero
|
||||
//std::fill(sc_pedestals[sc], sc_pedestals[sc] + (nx * ny), 0.0); // explicit zero initialization
|
||||
if (ped)
|
||||
delete[] ped;
|
||||
ped = new double[nx * ny];
|
||||
double *p0 = new double[nx * ny];
|
||||
|
||||
// Get the threads assigned to this storage cell
|
||||
auto const& assigned_threads = sc_to_threads[sc];
|
||||
int num_threads = assigned_threads.size();
|
||||
|
||||
// Only iterate over threads assigned to this storage cell
|
||||
for ( int thread_id : assigned_threads ) {
|
||||
for (int i = 0; i < nThreads; i++) {
|
||||
// inte=(slsInterpolation*)dets[i]->getInterpolation(nb,emi,ema);
|
||||
// cout << i << endl;
|
||||
//p0 = dets[thread_id]->getPedestal(p0);
|
||||
dets[thread_id]->getPedestal(p0);
|
||||
|
||||
if (p0) { /*
|
||||
p0 = dets[i]->getPedestal(p0);
|
||||
if (p0) {
|
||||
if (i == 0) {
|
||||
// If first thread, initialize ped with first thread's values
|
||||
|
||||
for (int ib = 0; ib < nx * ny; ib++) {
|
||||
ped[ib] = p0[ib] / ((double)nThreads);
|
||||
// cout << p0[ib] << " ";
|
||||
}
|
||||
} else {
|
||||
*/
|
||||
// For subsequent threads, accumulate pedestal values
|
||||
// if ( i == 0 ) becomes superfluous if we zero-initialize earlier
|
||||
for (int ib = 0; ib < nx * ny; ib++) {
|
||||
sc_pedestals[sc][ib] += p0[ib] / ((double)num_threads);
|
||||
// cout << p0[ib] << " ";
|
||||
for (int ib = 0; ib < nx * ny; ib++) {
|
||||
ped[ib] += p0[ib] / ((double)nThreads);
|
||||
// cout << p0[ib] << " ";
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
delete[] p0;
|
||||
return sc_pedestals[sc];
|
||||
return ped;
|
||||
};
|
||||
|
||||
// Storage cell sensitive
|
||||
virtual double *getPedestalRMS(int sc = 0) {
|
||||
virtual double *getPedestalRMS() {
|
||||
int nx, ny;
|
||||
dets[0]->getDetectorSize(nx, ny);
|
||||
|
||||
if (sc_pedestals_rms.count(sc) && sc_pedestals_rms[sc]) {
|
||||
delete[] sc_pedestals_rms[sc];
|
||||
sc_pedestals_rms[sc] = nullptr;
|
||||
}
|
||||
|
||||
// allocate memory and initialize all values to zero
|
||||
sc_pedestals_rms[sc] = new double[nx * ny](); // Zero-initialize
|
||||
//std::fill(sc_pedestals_rms[sc], sc_pedestals_rms[sc] + (nx * ny), 0.0); // explicit zero initialization
|
||||
//double *rms = sc_pedestals_rms[sc];
|
||||
// if (ped) delete [] ped;
|
||||
double *rms = new double[nx * ny];
|
||||
double *p0 = new double[nx * ny];
|
||||
|
||||
// Get the threads assigned to this storage cell
|
||||
auto const& assigned_threads = sc_to_threads[sc];
|
||||
int num_threads = assigned_threads.size();
|
||||
|
||||
// Only iterate over threads assigned to this storage cell
|
||||
for (int thread_id : assigned_threads) {
|
||||
for (int i = 0; i < nThreads; i++) {
|
||||
// inte=(slsInterpolation*)dets[i]->getInterpolation(nb,emi,ema);
|
||||
// cout << i << endl;
|
||||
//p0 = dets[thread_id]->getPedestalRMS(p0);
|
||||
dets[thread_id]->getPedestalRMS(p0);
|
||||
|
||||
p0 = dets[i]->getPedestalRMS(p0);
|
||||
if (p0) {
|
||||
for (int ib = 0; ib < nx * ny; ib++) {
|
||||
sc_pedestals_rms[sc][ib] += (p0[ib] * p0[ib]) / ((double)num_threads);
|
||||
if (i == 0) {
|
||||
|
||||
for (int ib = 0; ib < nx * ny; ib++) {
|
||||
rms[ib] = p0[ib] * p0[ib] / ((double)nThreads);
|
||||
// cout << p0[ib] << " ";
|
||||
}
|
||||
} else {
|
||||
for (int ib = 0; ib < nx * ny; ib++) {
|
||||
rms[ib] += p0[ib] * p0[ib] / ((double)nThreads);
|
||||
// cout << p0[ib] << " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
delete[] p0;
|
||||
|
||||
@ -734,117 +533,64 @@ class multiThreadedAnalogDetector {
|
||||
/* rms[ib]=0; */
|
||||
/* } */
|
||||
|
||||
return sc_pedestals_rms[sc];
|
||||
return rms;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets pedestal for given storage cell
|
||||
* \param h pedestal
|
||||
* \param sc storage cell
|
||||
* \returns NULL
|
||||
*/
|
||||
virtual double *setPedestal(double *h = NULL, int sc = 0) {
|
||||
virtual double *setPedestal(double *h = NULL) {
|
||||
// int nb=0;
|
||||
|
||||
int nx, ny;
|
||||
dets[0]->getDetectorSize(nx, ny);
|
||||
if (h == NULL)
|
||||
h = ped;
|
||||
for (auto i : sc_to_threads[sc]) {
|
||||
for (int i = 0; i < nThreads; i++) {
|
||||
dets[i]->setPedestal(h);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
};
|
||||
|
||||
// Storage cell sensitive
|
||||
virtual void *writePedestal(char const* base_imgname) {
|
||||
virtual void *writePedestal(const char *imgname) {
|
||||
|
||||
int nx, ny;
|
||||
dets[0]->getDetectorSize(nx, ny);
|
||||
|
||||
//float *gm = new float[nx * ny];
|
||||
|
||||
// Loop over each storage cell
|
||||
for ( auto const& entry : sc_to_threads ) {
|
||||
int sc = entry.first;
|
||||
std::string imgname = std::string(base_imgname);
|
||||
if (nSC>1)
|
||||
imgname += "_SC" + std::to_string(sc);
|
||||
imgname += ".tiff";
|
||||
|
||||
getPedestal(sc); // Compute pedestal for this storage cell
|
||||
std::vector<float> gm(nx * ny);
|
||||
|
||||
// Copy pedestal data into the float array
|
||||
/*
|
||||
getPedestal();
|
||||
float *gm = new float[nx * ny];
|
||||
if (gm) {
|
||||
for (int ix = 0; ix < nx * ny; ix++) {
|
||||
gm[ix] = sc_pedestals[sc][ix];
|
||||
gm[ix] = ped[ix];
|
||||
}
|
||||
*/
|
||||
std::copy(sc_pedestals[sc], sc_pedestals[sc] + (nx * ny), gm.data());
|
||||
WriteToTiff(gm.data(), imgname.c_str(), nx, ny);
|
||||
|
||||
// Clean up memory
|
||||
if(sc_pedestals[sc]) {
|
||||
delete[] sc_pedestals[sc];
|
||||
sc_pedestals[sc] = nullptr;
|
||||
}
|
||||
}
|
||||
WriteToTiff(gm, imgname, nx, ny);
|
||||
delete[] gm;
|
||||
} else
|
||||
cout << "Could not allocate float image " << endl;
|
||||
|
||||
return NULL;
|
||||
};
|
||||
|
||||
// Storage cell sensitive
|
||||
virtual void *writePedestalRMS(char const* base_imgname) {
|
||||
virtual void *writePedestalRMS(const char *imgname) {
|
||||
|
||||
int nx, ny;
|
||||
dets[0]->getDetectorSize(nx, ny);
|
||||
|
||||
//float *gm = new float[nx * ny];
|
||||
|
||||
// Loop over each stoarge cell
|
||||
for ( auto const& entry : sc_to_threads ) {
|
||||
int sc = entry.first;
|
||||
std::string imgname = std::string(base_imgname);
|
||||
if (nSC>1)
|
||||
imgname += "_SC" + std::to_string(sc);
|
||||
imgname += ".tiff";
|
||||
|
||||
double *rms = getPedestalRMS(sc); // Compute pedestal RMS for this storage cell
|
||||
std::vector<float> gm(nx * ny);
|
||||
|
||||
// Copy rms data into the float array
|
||||
/*
|
||||
double *rms = getPedestalRMS();
|
||||
float *gm = new float[nx * ny];
|
||||
if (gm) {
|
||||
for (int ix = 0; ix < nx * ny; ix++) {
|
||||
gm[ix] = rms[ix];
|
||||
gm[ix] = rms[ix];
|
||||
}
|
||||
*/
|
||||
std::copy(rms, rms + (nx * ny), gm.data());
|
||||
WriteToTiff(gm.data(), imgname.c_str(), nx, ny);
|
||||
|
||||
// Clean up memory
|
||||
//delete[] rms; //This would cause double-free since the pointer is already handled by sc_pedestals_rms[sc]
|
||||
if(sc_pedestals_rms[sc]) {
|
||||
delete[] sc_pedestals_rms[sc];
|
||||
sc_pedestals_rms[sc] = nullptr;
|
||||
}
|
||||
}
|
||||
WriteToTiff(gm, imgname, nx, ny);
|
||||
delete[] gm;
|
||||
delete[] rms;
|
||||
} else
|
||||
cout << "Could not allocate float image " << endl;
|
||||
|
||||
return NULL;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads pedestal and sets it for given storage cell
|
||||
* \param imgname name of pedestal file
|
||||
* \param nb obsolete
|
||||
* \param emin obsolete
|
||||
* \param emax obsolete
|
||||
* \param sc storage cell
|
||||
* \returns setPedestal(NULL, sc)
|
||||
* */
|
||||
virtual void *readPedestal(const char *imgname, int nb = -1,
|
||||
double emin = 1, double emax = 0, int sc = 0) {
|
||||
double emin = 1, double emax = 0) {
|
||||
|
||||
int nx, ny;
|
||||
dets[0]->getDetectorSize(nx, ny);
|
||||
@ -864,68 +610,36 @@ class multiThreadedAnalogDetector {
|
||||
}
|
||||
delete[] gm;
|
||||
|
||||
return setPedestal(NULL, sc);
|
||||
return setPedestal();
|
||||
};
|
||||
|
||||
/** Sets file pointer where to write the clusters to
|
||||
/** sets file pointer where to write the clusters to
|
||||
\param f file pointer
|
||||
\param sc storage cell index
|
||||
\returns current file pointer, or nullptr if invalid
|
||||
\returns current file pointer
|
||||
*/
|
||||
virtual FILE *setFilePointer(FILE *f, int sc = 0) {
|
||||
// Check if the storage cell exists
|
||||
if (sc_to_threads.find(sc) == sc_to_threads.end() || sc_to_threads[sc].empty()) {
|
||||
std::cerr << "Error: Invalid storage cell index " << sc << std::endl;
|
||||
return nullptr;
|
||||
virtual FILE *setFilePointer(FILE *f) {
|
||||
for (int i = 0; i < nThreads; i++) {
|
||||
dets[i]->setFilePointer(f);
|
||||
// dets[i]->setMutex(&fmutex);
|
||||
}
|
||||
|
||||
// Assign file pointer to all threads belonging to this storage cell
|
||||
for (auto i : sc_to_threads[sc]) {
|
||||
if(dets[i]) {
|
||||
dets[i]->setFilePointer(f);
|
||||
// dets[i]->setMutex(&fmutex);
|
||||
} else {
|
||||
std::cerr << "Warning: dets[" << i << "] is null, skipping file pointer set." << std::endl;
|
||||
}
|
||||
}
|
||||
// Return file pointer of the first thread in this storage cell
|
||||
return dets[sc_to_threads[sc][0]] ? dets[sc_to_threads[sc][0]]->getFilePointer() : nullptr;
|
||||
return dets[0]->getFilePointer();
|
||||
};
|
||||
|
||||
/** Gets file pointer where to write the clusters to
|
||||
\param sc storage cell index
|
||||
\returns current file pointer, or nullptr if invalid
|
||||
/** gets file pointer where to write the clusters to
|
||||
\returns current file pointer
|
||||
*/
|
||||
virtual FILE *getFilePointer(int sc = 0) {
|
||||
// Ensure storage cell index is valid
|
||||
if (sc_to_threads.find(sc) == sc_to_threads.end() || sc_to_threads[sc].empty()) {
|
||||
std::cerr << "Error: Invalid storage cell index " << sc << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Return file pointer of the first thread in this storage cell
|
||||
return dets[sc_to_threads[sc][0]] ? dets[sc_to_threads[sc][0]]->getFilePointer() : nullptr;
|
||||
};
|
||||
virtual FILE *getFilePointer() { return dets[0]->getFilePointer(); };
|
||||
|
||||
protected:
|
||||
bool stop;
|
||||
const int nThreads;
|
||||
threadedAnalogDetector *dets[MAXTHREADS];
|
||||
analogDetector<uint16_t> *dd[MAXTHREADS];
|
||||
//int ithread{0}; // Thread index
|
||||
std::vector<int> thread_counters_by_sc{}; // Counters for threads for each storage cell
|
||||
int* image;
|
||||
int* ff;
|
||||
double* ped;
|
||||
//pthread_mutex_t fmutex; //unused
|
||||
std::unordered_map<int,std::vector<int>> sc_to_threads; // Maps storage cell -> vector of assigned thread ids
|
||||
std::mutex map_mutex; // Ensure thread-safe access to the map
|
||||
int nSC{1}; // Number of storage cells
|
||||
|
||||
std::unordered_map<int,int*> sc_images; // Store images per storage cell
|
||||
std::unordered_map<int,double*> sc_pedestals; // Store pedestal arrays per storage cell
|
||||
std::unordered_map<int,double*> sc_pedestals_rms; // Store pedestal RMS arrays per storage cell
|
||||
// at the moment, these maps could be avoided, but this implementation is more robust in allowing future changes
|
||||
int ithread;
|
||||
int *image;
|
||||
int *ff;
|
||||
double *ped;
|
||||
pthread_mutex_t fmutex;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -19,8 +19,8 @@ using namespace std;
|
||||
|
||||
class multiThreadedCountingDetector : public multiThreadedAnalogDetector {
|
||||
public:
|
||||
multiThreadedCountingDetector(singlePhotonDetector *d, int num_threads, int fs = 1000, int num_sc = 1)
|
||||
: multiThreadedAnalogDetector(d, num_threads, fs, num_sc){};
|
||||
multiThreadedCountingDetector(singlePhotonDetector *d, int n, int fs = 1000)
|
||||
: multiThreadedAnalogDetector(d, n, fs){};
|
||||
// virtual
|
||||
// ~multiThreadedCountingDetector{multiThreadedAnalogDetector::~multiThreadedAnalogDetector();};
|
||||
virtual double setNSigma(double n) {
|
||||
|
@ -70,6 +70,7 @@ class multiThreadedInterpolatingDetector
|
||||
if (getInterpolation() == NULL)
|
||||
return multiThreadedAnalogDetector::getImage(nnx, nny, nsx, nsy);
|
||||
// if one interpolates, the whole image is stored in detector 0;
|
||||
int *img;
|
||||
// int nnx, nny, ns;
|
||||
// int nnx, nny, ns;
|
||||
int nn = dets[0]->getImageSize(nnx, nny, nsx, nsy);
|
||||
@ -78,9 +79,9 @@ class multiThreadedInterpolatingDetector
|
||||
image = NULL;
|
||||
}
|
||||
image = new int[nn];
|
||||
int* tmp_img = dets[0]->getImage();
|
||||
img = dets[0]->getImage();
|
||||
for (int i = 0; i < nn; i++) {
|
||||
image[i] = tmp_img[i];
|
||||
image[i] = img[i];
|
||||
}
|
||||
return image;
|
||||
};
|
||||
|
@ -51,6 +51,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
|
||||
|
||||
*/
|
||||
|
||||
singlePhotonDetector(slsDetectorData<uint16_t> *d, int csize = 3,
|
||||
double nsigma = 5, int sign = 1,
|
||||
commonModeSubtraction *cm = NULL, int nped = 1000,
|
||||
@ -59,11 +60,10 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
: analogDetector<uint16_t>(d, sign, cm, nped, nnx, nny, gm, gs),
|
||||
nDark(nd), eventMask(NULL), nSigma(nsigma), eMin(-1), eMax(-1),
|
||||
clusterSize(csize), clusterSizeY(csize), c2(1), c3(1), clusters(NULL),
|
||||
quad(UNDEFINED_QUADRANT), tot(0), quadTot(0), ownsMutex(true) { // The original object owns the mutex {
|
||||
quad(UNDEFINED_QUADRANT), tot(0), quadTot(0) {
|
||||
|
||||
//fm = new pthread_mutex_t;
|
||||
//pthread_mutex_init(fm, NULL);
|
||||
fm = new std::mutex();
|
||||
fm = new pthread_mutex_t;
|
||||
pthread_mutex_init(fm, NULL);
|
||||
|
||||
eventMask = new eventType *[ny];
|
||||
// val=new double*[ny];
|
||||
@ -86,31 +86,24 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
nphFrame = 0;
|
||||
};
|
||||
/**
|
||||
Destructor. Deletes the cluster structure, event mask, and destroys the mutex.
|
||||
destructor. Deletes the cluster structure, the pdestalSubtraction and the
|
||||
image array
|
||||
*/
|
||||
virtual ~singlePhotonDetector() {
|
||||
// std::cout << "#### Debug: Destructing singlePhotonDetector! ####" << std::endl;
|
||||
if (clusters) { delete[] clusters; clusters = nullptr; }
|
||||
for (int i = 0; i < ny; i++) {
|
||||
if (eventMask[i]) { delete[] eventMask[i]; eventMask[i] = nullptr; }
|
||||
}
|
||||
if (eventMask) { delete[] eventMask; eventMask = nullptr; }
|
||||
if (ownsMutex) {
|
||||
if (fm) {
|
||||
//pthread_mutex_destroy(fm); // Destroy the mutex (not necessary with std::mutex)
|
||||
delete fm; // Free the memory allocated for the mutex
|
||||
fm = nullptr; // Set the pointer to nullptr to avoid dangling pointer
|
||||
}
|
||||
}
|
||||
|
||||
delete[] clusters;
|
||||
for (int i = 0; i < ny; i++)
|
||||
delete[] eventMask[i];
|
||||
delete[] eventMask;
|
||||
};
|
||||
|
||||
/**
|
||||
pointer-based copy constructor (cloner)
|
||||
copy constructor
|
||||
\param orig detector to be copied
|
||||
|
||||
*/
|
||||
|
||||
singlePhotonDetector(singlePhotonDetector *orig)
|
||||
: analogDetector<uint16_t>(orig), fm(orig->fm), ownsMutex(false) {
|
||||
: analogDetector<uint16_t>(orig) {
|
||||
|
||||
nDark = orig->nDark;
|
||||
myFile = orig->myFile;
|
||||
@ -133,12 +126,11 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
c3 = sqrt(clusterSizeY * clusterSize);
|
||||
|
||||
clusters = new single_photon_hit[nx * ny];
|
||||
//std::copy(orig->clusters, orig->clusters + (nx * ny), clusters); //possibly superfluous
|
||||
|
||||
// cluster=clusters;
|
||||
|
||||
setClusterSize(clusterSize);
|
||||
//fm = orig->fm;
|
||||
fm = orig->fm;
|
||||
|
||||
quad = UNDEFINED_QUADRANT;
|
||||
tot = 0;
|
||||
@ -151,67 +143,13 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
}
|
||||
|
||||
/**
|
||||
* copy constructor (deep copy), creates a new mutex
|
||||
* stricly, TODO: Implement Rule of Five!
|
||||
* (copy op=, move ctor, and move op= would need to be defined)
|
||||
*/
|
||||
singlePhotonDetector(singlePhotonDetector const& other)
|
||||
: analogDetector<uint16_t>(other), ownsMutex(true) {
|
||||
|
||||
//fm = new pthread_mutex_t; // create a new mutex
|
||||
//pthread_mutex_init(fm, NULL);
|
||||
fm = new std::mutex(); // New unique mutex per copy
|
||||
|
||||
nDark = other.nDark;
|
||||
myFile = other.myFile;
|
||||
|
||||
eventMask = new eventType *[ny];
|
||||
for (int i = 0; i < ny; i++) {
|
||||
eventMask[i] = new eventType[nx];
|
||||
//std::copy(other.eventMask[i], other.eventMask[i] + nx, eventMask[i]);
|
||||
}
|
||||
|
||||
eMin = other.eMin;
|
||||
eMax = other.eMax;
|
||||
|
||||
nSigma = other.nSigma;
|
||||
clusterSize = other.clusterSize;
|
||||
clusterSizeY = other.clusterSizeY;
|
||||
|
||||
c2 = sqrt((clusterSizeY + 1) / 2 * (clusterSize + 1) / 2);
|
||||
c3 = sqrt(clusterSizeY * clusterSize);
|
||||
|
||||
clusters = new single_photon_hit[nx * ny];
|
||||
//std::copy(other.clusters, other.clusters + (nx * ny), clusters);
|
||||
|
||||
setClusterSize(clusterSize);
|
||||
|
||||
quad = other.quad;
|
||||
tot = other.tot;
|
||||
quadTot = other.quadTot;
|
||||
gmap = other.gmap;
|
||||
nphTot = other.nphTot;
|
||||
nphFrame = other.nphFrame;
|
||||
}
|
||||
|
||||
/**
|
||||
Clones the detector structure
|
||||
duplicates the detector structure
|
||||
\returns new single photon detector with same parameters
|
||||
that shares the mutex of the original
|
||||
|
||||
*/
|
||||
virtual singlePhotonDetector* Clone() {
|
||||
virtual singlePhotonDetector *Clone() {
|
||||
return new singlePhotonDetector(this);
|
||||
}
|
||||
/**
|
||||
Copies the detector structure
|
||||
\returns new single photon detector with same parameters
|
||||
that owns a new mutex
|
||||
*/
|
||||
virtual singlePhotonDetector* Copy() {
|
||||
return new singlePhotonDetector(*this); // Calls the copy constructor
|
||||
}
|
||||
|
||||
|
||||
/** sets/gets number of rms threshold to detect photons
|
||||
\param n number of sigma to be set (0 or negative gets)
|
||||
\returns actual number of sigma parameter
|
||||
@ -443,7 +381,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
|
||||
// int ir, ic;
|
||||
eventType ee;
|
||||
double max = 0, tl = 0, tr = 0, bl = 0, br = 0, v = 0;//, *v;
|
||||
double max = 0, tl = 0, tr = 0, bl = 0, br = 0, *v;
|
||||
int cm = 0;
|
||||
int good = 1;
|
||||
int ir, ic;
|
||||
@ -465,8 +403,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
cm = 1;
|
||||
}
|
||||
|
||||
//double *val = new double[ny * nx];
|
||||
std::vector<double> val( ny * nx );
|
||||
double *val = new double[ny * nx];
|
||||
|
||||
for (int iy = ymin; iy < ymax; ++iy) {
|
||||
for (int ix = xmin; ix < xmax; ++ix) {
|
||||
@ -498,34 +435,26 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
(ix + ic) >= 0 && (ix + ic) < nx) {
|
||||
|
||||
|
||||
if ((iy + ir) > iy && (ix + ic) > ix ) {
|
||||
if ((iy + ir) > iy && (ix + ic) > ix ) {
|
||||
|
||||
val[(iy + ir) * nx + ix + ic] =
|
||||
subtractPedestal(data, ix + ic, iy + ir, cm);
|
||||
val[(iy + ir) * nx + ix + ic] =
|
||||
subtractPedestal(data, ix + ic, iy + ir, cm);
|
||||
|
||||
|
||||
}
|
||||
//v = &(val[(iy + ir) * nx + ix + ic]);
|
||||
v = val[(iy + ir) * nx + ix + ic];
|
||||
//tot += *v;
|
||||
tot += v;
|
||||
if (ir <= 0 && ic <= 0)
|
||||
bl += v;
|
||||
//bl += *v;
|
||||
if (ir <= 0 && ic >= 0)
|
||||
br += v;
|
||||
//br += *v;
|
||||
if (ir >= 0 && ic <= 0)
|
||||
tl += v;
|
||||
//tl += *v;
|
||||
if (ir >= 0 && ic >= 0)
|
||||
tr += v;
|
||||
//tr += *v;
|
||||
//if (*v > max) //{
|
||||
//max = *v;
|
||||
if (v > max)
|
||||
max = v;
|
||||
//}
|
||||
}
|
||||
v = &(val[(iy + ir) * nx + ix + ic]);
|
||||
tot += *v;
|
||||
if (ir <= 0 && ic <= 0)
|
||||
bl += *v;
|
||||
if (ir <= 0 && ic >= 0)
|
||||
br += *v;
|
||||
if (ir >= 0 && ic <= 0)
|
||||
tl += *v;
|
||||
if (ir >= 0 && ic >= 0)
|
||||
tr += *v;
|
||||
if (*v > max) //{
|
||||
max = *v;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -595,19 +524,19 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
ic < (clusterSize / 2) + 1; ic++) {
|
||||
if ((iy + ir) >= 0 && (iy + ir) < ny &&
|
||||
(ix + ic) >= 0 && (ix + ic) < nx) {
|
||||
(clusters + nph)
|
||||
(clusters + nph)
|
||||
->set_data(val[(iy + ir) * nx + ix + ic],
|
||||
ic, ir);
|
||||
if (val[(iy + ir) * nx + ix + ic]>max)
|
||||
good=0;
|
||||
}
|
||||
if (val[(iy + ir) * nx + ix + ic]>max)
|
||||
good=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (good==0) {
|
||||
(clusters + nph)->print();
|
||||
cout << max << " " << val[iy * nx + ix] << endl;
|
||||
}
|
||||
//else (clusters + nph)->print();
|
||||
if (good==0) {
|
||||
(clusters + nph)->print();
|
||||
cout << max << " " << val[iy * nx + ix] << endl;
|
||||
}
|
||||
//else (clusters + nph)->print();
|
||||
if (eMin > 0 && tot < eMin)
|
||||
good = 0;
|
||||
if (eMax > 0 && tot > eMax)
|
||||
@ -632,7 +561,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
// cout <<id << " **********************************"<< iframe << " " <<
|
||||
// det->getFrameNumber(data) << " " << nphFrame << endl;
|
||||
writeClusters(det->getFrameNumber(data));
|
||||
//delete[] val;
|
||||
delete[] val;
|
||||
return image;
|
||||
};
|
||||
|
||||
@ -738,14 +667,13 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
void writeClusters(int fn) {
|
||||
if (myFile) {
|
||||
// cout << "++" << endl;
|
||||
//pthread_mutex_lock(fm); // This is dangerous! What if writeClusters() throws? Then the mutex is never unlocked!
|
||||
std::lock_guard<std::mutex> lock(*fm); // safer, RAII-based locking
|
||||
pthread_mutex_lock(fm);
|
||||
// cout <<"**********************************"<< fn << " " <<
|
||||
// nphFrame << endl;
|
||||
writeClusters(myFile, clusters, nphFrame, fn);
|
||||
// for (int i=0; i<nphFrame; i++)
|
||||
// (clusters+i)->write(myFile);
|
||||
//pthread_mutex_unlock(fm); // unsafe
|
||||
pthread_mutex_unlock(fm);
|
||||
// cout << "--" << endl;
|
||||
}
|
||||
};
|
||||
@ -783,14 +711,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
ema = eMax;
|
||||
};
|
||||
|
||||
//void setMutex(pthread_mutex_t *m) { fm = m; };
|
||||
void setMutex(std::mutex* m) {
|
||||
if (ownsMutex && fm) {
|
||||
delete fm; // Cleanup old mutex
|
||||
}
|
||||
fm = m;
|
||||
ownsMutex = false;
|
||||
};
|
||||
void setMutex(pthread_mutex_t *m) { fm = m; };
|
||||
|
||||
protected:
|
||||
int nDark; /**< number of frames to be used at the beginning of the dataset
|
||||
@ -812,9 +733,7 @@ class singlePhotonDetector : public analogDetector<uint16_t> {
|
||||
int nphFrame;
|
||||
|
||||
// double **val;
|
||||
//pthread_mutex_t* fm; // Pointer to the shared mutex
|
||||
std::mutex* fm; // Pointer to the shared (or unique) mutex (safer version)
|
||||
bool ownsMutex; // Flag to indicate ownership
|
||||
pthread_mutex_t *fm;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
28
slsDetectorServers/compileAllServers.sh
Normal file → Executable file
28
slsDetectorServers/compileAllServers.sh
Normal file → Executable file
@ -1,16 +1,19 @@
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
# Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
|
||||
# empty branch = developer branch in updateAPIVersion.sh
|
||||
branch=""
|
||||
det_list=("ctbDetectorServer
|
||||
gotthard2DetectorServer
|
||||
jungfrauDetectorServer
|
||||
mythen3DetectorServer
|
||||
moenchDetectorServer
|
||||
xilinx_ctbDetectorServer"
|
||||
xilinx_ctbDetectorServer"
|
||||
)
|
||||
usage="\nUsage: compileAllServers.sh [server|all(opt)] [branch(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tNo 'branch' input means 'developer branch'"
|
||||
usage="\nUsage: compileAllServers.sh [server|all(opt)] [update_api(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tupdate_api if true updates the api to version in VERSION file"
|
||||
|
||||
update_api=true
|
||||
target=version
|
||||
|
||||
|
||||
|
||||
# arguments
|
||||
if [ $# -eq 0 ]; then
|
||||
@ -34,15 +37,12 @@ elif [ $# -eq 1 ] || [ $# -eq 2 ]; then
|
||||
declare -a det=("${1}")
|
||||
#echo "Compiling only $1"
|
||||
fi
|
||||
# branch
|
||||
|
||||
if [ $# -eq 2 ]; then
|
||||
# arg in list
|
||||
if [[ $det_list == *$2* ]]; then
|
||||
echo -e "Invalid argument 2: $2. $usage"
|
||||
return 1
|
||||
update_api=$2
|
||||
if not $update_api ; then
|
||||
target=clean
|
||||
fi
|
||||
branch+=$2
|
||||
#echo "with branch $branch"
|
||||
fi
|
||||
else
|
||||
echo -e "Too many arguments.$usage"
|
||||
@ -53,6 +53,9 @@ declare -a deterror=("OK" "OK" "OK" "OK" "OK" "OK")
|
||||
|
||||
echo -e "list is ${det[@]}"
|
||||
|
||||
if $update_api; then
|
||||
echo "updating api to $(cat ../VERSION)"
|
||||
fi
|
||||
# compile each server
|
||||
idet=0
|
||||
for i in ${det[@]}
|
||||
@ -62,14 +65,13 @@ do
|
||||
echo -e "Compiling $dir [$file]"
|
||||
cd $dir
|
||||
make clean
|
||||
if make version API_BRANCH=$branch; then
|
||||
if make $target; then
|
||||
deterror[$idet]="OK"
|
||||
else
|
||||
deterror[$idet]="FAIL"
|
||||
fi
|
||||
mv bin/$dir bin/$file
|
||||
git add -f bin/$file
|
||||
cp bin/$file /tftpboot/
|
||||
cd ..
|
||||
echo -e "\n\n"
|
||||
((++idet))
|
||||
|
@ -1,86 +0,0 @@
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
# Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
|
||||
# empty branch = developer branch in updateAPIVersion.sh
|
||||
branch=""
|
||||
det_list=("ctbDetectorServer"
|
||||
"gotthard2DetectorServer"
|
||||
"jungfrauDetectorServer"
|
||||
"mythen3DetectorServer"
|
||||
"moenchDetectorServer"
|
||||
"xilinx_ctbDetectorServer"
|
||||
)
|
||||
usage="\nUsage: compileAllServers.sh [server|all(opt)] [branch(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tNo 'branch' input means 'developer branch'"
|
||||
|
||||
# arguments
|
||||
if [ $# -eq 0 ]; then
|
||||
# no argument, all servers
|
||||
declare -a det=${det_list[@]}
|
||||
echo "Compiling all servers"
|
||||
elif [ $# -eq 1 ] || [ $# -eq 2 ]; then
|
||||
# 'all' servers
|
||||
if [[ $1 == "all" ]]; then
|
||||
declare -a det=${det_list[@]}
|
||||
echo "Compiling all servers"
|
||||
else
|
||||
# only one server
|
||||
# arg not in list
|
||||
if [[ $det_list != *$1* ]]; then
|
||||
echo -e "Invalid argument 1: $1. $usage"
|
||||
return -1
|
||||
fi
|
||||
declare -a det=("${1}")
|
||||
#echo "Compiling only $1"
|
||||
fi
|
||||
# branch
|
||||
if [ $# -eq 2 ]; then
|
||||
# arg in list
|
||||
if [[ $det_list == *$2* ]]; then
|
||||
echo -e "Invalid argument 2: $2. $usage"
|
||||
return -1
|
||||
fi
|
||||
branch+=$2
|
||||
#echo "with branch $branch"
|
||||
fi
|
||||
else
|
||||
echo -e "Too many arguments.$usage"
|
||||
return -1
|
||||
fi
|
||||
|
||||
declare -a deterror=("OK" "OK" "OK" "OK" "OK" "OK")
|
||||
|
||||
echo -e "list is ${det[@]}"
|
||||
|
||||
# compile each server
|
||||
idet=0
|
||||
for i in ${det[@]}
|
||||
do
|
||||
dir=$i
|
||||
file="${i}_developer"
|
||||
echo -e "Compiling $dir [$file]"
|
||||
cd $dir
|
||||
make clean
|
||||
if make API_BRANCH=$branch; then
|
||||
deterror[$idet]="OK"
|
||||
else
|
||||
deterror[$idet]="FAIL"
|
||||
fi
|
||||
mv bin/$dir bin/$file
|
||||
git add -f bin/$file
|
||||
cp bin/$file /tftpboot/
|
||||
cd ..
|
||||
echo -e "\n\n"
|
||||
((++idet))
|
||||
done
|
||||
|
||||
echo -e "Results:"
|
||||
idet=0
|
||||
for i in ${det[@]}
|
||||
do
|
||||
printf "%s\t\t= %s\n" "$i" "${deterror[$idet]}"
|
||||
((++idet))
|
||||
done
|
||||
|
||||
|
||||
|
||||
|
23
slsDetectorServers/compileEigerServer.sh
Normal file → Executable file
23
slsDetectorServers/compileEigerServer.sh
Normal file → Executable file
@ -3,21 +3,31 @@
|
||||
deterror="OK"
|
||||
dir="eigerDetectorServer"
|
||||
file="${dir}_developer"
|
||||
branch=""
|
||||
|
||||
usage="\nUsage: compileAllServers.sh [update_api(opt)]. \n\t update_api if true updates the api to version in VERSION file"
|
||||
|
||||
update_api=true
|
||||
target=version
|
||||
|
||||
# arguments
|
||||
if [ $# -eq 1 ]; then
|
||||
branch+=$1
|
||||
#echo "with branch $branch"
|
||||
update_api=$1
|
||||
if not $update_api ; then
|
||||
target=clean
|
||||
|
||||
fi
|
||||
elif [ ! $# -eq 0 ]; then
|
||||
echo -e "Only one optional argument allowed for branch."
|
||||
echo -e "Only one optional argument allowed for update_api."
|
||||
return -1
|
||||
fi
|
||||
|
||||
if $update_api; then
|
||||
echo "updating api to $(cat ../VERSION)"
|
||||
fi
|
||||
|
||||
echo -e "Compiling $dir [$file]"
|
||||
cd $dir
|
||||
make clean
|
||||
if make version API_BRANCH=$branch; then
|
||||
if make $target; then
|
||||
deterror="OK"
|
||||
else
|
||||
deterror="FAIL"
|
||||
@ -25,7 +35,6 @@ fi
|
||||
|
||||
mv bin/$dir bin/$file
|
||||
git add -f bin/$file
|
||||
cp bin/$file /tftpboot/
|
||||
cd ..
|
||||
echo -e "\n\n"
|
||||
printf "Result:\t\t= %s\n" "${deterror}"
|
||||
|
@ -25,11 +25,10 @@ version: clean versioning $(PROGS)
|
||||
|
||||
boot: $(OBJS)
|
||||
|
||||
version_branch=$(API_BRANCH)
|
||||
version_name=APICTB
|
||||
version_path=slsDetectorServers/ctbDetectorServer
|
||||
versioning:
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
|
||||
|
||||
|
||||
$(PROGS): $(OBJS)
|
||||
|
Binary file not shown.
@ -15,6 +15,7 @@
|
||||
#include "loadPattern.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h> // usleep
|
||||
@ -93,6 +94,10 @@ void basictests() {
|
||||
LOG(logINFOBLUE, ("********* Chip Test Board Virtual Server *********\n"));
|
||||
#else
|
||||
LOG(logINFOBLUE, ("************* Chip Test Board Server *************\n"));
|
||||
initError = enableBlackfinAMCExternalAccessExtension(initErrorMessage);
|
||||
if (initError == FAIL) {
|
||||
return;
|
||||
}
|
||||
initError = defineGPIOpins(initErrorMessage);
|
||||
if (initError == FAIL) {
|
||||
return;
|
||||
@ -438,6 +443,32 @@ uint32_t getDetectorIP() {
|
||||
return res;
|
||||
}
|
||||
|
||||
int enableBlackfinAMCExternalAccessExtension(char *mess) {
|
||||
unsigned int value;
|
||||
const char *file_path = BFIN_AMC_ACCESS_EXTENSION_FNAME;
|
||||
FILE *file = fopen(file_path, "r");
|
||||
if (!file) {
|
||||
strcpy(mess, "Failed to enable blackfin AMC access extension. Could "
|
||||
"not read EBIU_AMBCTL1\n");
|
||||
LOG(logERROR, (mess));
|
||||
return FAIL;
|
||||
}
|
||||
fscanf(file, "%x", &value);
|
||||
fclose(file);
|
||||
|
||||
value |= BFIN_AMC_ACCESS_EXTENSION_ENA_VAL;
|
||||
file = fopen(file_path, "w");
|
||||
if (!file) {
|
||||
strcpy(mess, "Failed to enable blackfin AMC access extension. Could "
|
||||
"not write EBIU_AMBCTL1\n");
|
||||
LOG(logERROR, (mess));
|
||||
return FAIL;
|
||||
}
|
||||
fprintf(file, "0x%x", value);
|
||||
fclose(file);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* initialization */
|
||||
|
||||
void initControlServer() {
|
||||
|
@ -25,11 +25,10 @@ version: clean versioning $(PROGS) #hv9m_blackfin_server
|
||||
|
||||
boot: $(OBJS)
|
||||
|
||||
version_branch=$(API_BRANCH)
|
||||
version_name=APIEIGER
|
||||
version_path=slsDetectorServers/eigerDetectorServer
|
||||
versioning:
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
|
||||
|
||||
|
||||
$(PROGS): $(OBJS)
|
||||
|
@ -24,11 +24,10 @@ version: clean versioning $(PROGS)
|
||||
|
||||
boot: $(OBJS)
|
||||
|
||||
version_branch=$(API_BRANCH)
|
||||
version_name=APIGOTTHARD2
|
||||
version_path=slsDetectorServers/gotthard2DetectorServer
|
||||
versioning:
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
|
||||
|
||||
|
||||
$(PROGS): $(OBJS)
|
||||
|
@ -24,11 +24,10 @@ version: clean versioning $(PROGS)
|
||||
|
||||
boot: $(OBJS)
|
||||
|
||||
version_branch=$(API_BRANCH)
|
||||
version_name=APIJUNGFRAU
|
||||
version_path=slsDetectorServers/jungfrauDetectorServer
|
||||
versioning:
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
|
||||
|
||||
|
||||
$(PROGS): $(OBJS)
|
||||
|
@ -24,11 +24,10 @@ version: clean versioning $(PROGS)
|
||||
|
||||
boot: $(OBJS)
|
||||
|
||||
version_branch=$(API_BRANCH)
|
||||
version_name=APIMOENCH
|
||||
version_path=slsDetectorServers/moenchDetectorServer
|
||||
versioning:
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
|
||||
|
||||
|
||||
$(PROGS): $(OBJS)
|
||||
|
@ -25,11 +25,10 @@ version: clean versioning $(PROGS)
|
||||
|
||||
boot: $(OBJS)
|
||||
|
||||
version_branch=$(API_BRANCH)
|
||||
version_name=APIMYTHEN3
|
||||
version_path=slsDetectorServers/mythen3DetectorServer
|
||||
versioning:
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
|
||||
|
||||
|
||||
$(PROGS): $(OBJS)
|
||||
|
@ -5,6 +5,23 @@
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/** enable support for ARDY signal on interface to FPGA
|
||||
* needed to properly translate avalon_mm_waitrequest in the CTB firmware
|
||||
* https://www.analog.com/media/en/dsp-documentation/processor-manuals/bf537_hwr_Rev3.2.pdf
|
||||
* page 274
|
||||
* */
|
||||
#define BFIN_EBIU_AMBCTL1_B2_ARDY_ENA_OFST (0)
|
||||
#define BFIN_EBIU_AMBCTL1_B2_ARDY_ENA_MSK \
|
||||
(1 << BFIN_EBIU_AMBCTL1_B2_ARDY_ENA_OFST)
|
||||
#define BFIN_EBIU_AMBCTL1_B2_ARDY_POL_OFST (1)
|
||||
#define BFIN_EBIU_AMBCTL1_B2_ARDY_POL_MSK \
|
||||
(1 << BFIN_EBIU_AMBCTL1_B2_ARDY_POL_OFST)
|
||||
|
||||
#define BFIN_AMC_ACCESS_EXTENSION_ENA_VAL \
|
||||
(BFIN_EBIU_AMBCTL1_B2_ARDY_ENA_MSK | BFIN_EBIU_AMBCTL1_B2_ARDY_POL_MSK)
|
||||
#define BFIN_AMC_ACCESS_EXTENSION_FNAME \
|
||||
"/sys/kernel/debug/blackfin/ebiu_amc/EBIU_AMBCTL1"
|
||||
|
||||
/** I2C defines */
|
||||
#define I2C_CLOCK_MHZ (131.25)
|
||||
|
||||
|
@ -113,6 +113,10 @@ void setModuleId(int modid);
|
||||
u_int64_t getDetectorMAC();
|
||||
u_int32_t getDetectorIP();
|
||||
|
||||
#if defined(CHIPTESTBOARDD)
|
||||
int enableBlackfinAMCExternalAccessExtension(char *mess);
|
||||
#endif
|
||||
|
||||
// initialization
|
||||
void initControlServer();
|
||||
void initStopServer();
|
||||
|
@ -36,11 +36,10 @@ version: clean versioning $(PROGS)
|
||||
|
||||
boot: $(OBJS)
|
||||
|
||||
version_branch=$(API_BRANCH)
|
||||
version_name=APIXILINXCTB
|
||||
version_path=slsDetectorServers/xilinx_ctbDetectorServer
|
||||
versioning:
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;`
|
||||
cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;`
|
||||
|
||||
|
||||
$(PROGS): $(OBJS)
|
||||
|
@ -1537,8 +1537,12 @@ void *start_timer(void *arg) {
|
||||
packetSize, packetsPerFrame));
|
||||
|
||||
// Generate Data
|
||||
char imageData[imageSize];
|
||||
char *imageData = (char *)malloc(imageSize);
|
||||
memset(imageData, 0, imageSize);
|
||||
if (imageData == NULL) {
|
||||
LOG(logERROR, ("Can not allocate image.\n"));
|
||||
return NULL;
|
||||
}
|
||||
for (int i = 0; i < imageSize; i += sizeof(uint16_t)) {
|
||||
*((uint16_t *)(imageData + i)) = i;
|
||||
}
|
||||
@ -1561,6 +1565,7 @@ void *start_timer(void *arg) {
|
||||
usleep(expUs);
|
||||
|
||||
int srcOffset = 0;
|
||||
int dataSent = 0;
|
||||
// loop packet
|
||||
for (int i = 0; i != packetsPerFrame; ++i) {
|
||||
|
||||
@ -1577,10 +1582,12 @@ void *start_timer(void *arg) {
|
||||
header->column = detPos[X];
|
||||
|
||||
// fill data
|
||||
int remaining = imageSize - dataSent;
|
||||
int dataSize = remaining < maxDataSize ? remaining : maxDataSize;
|
||||
memcpy(packetData + sizeof(sls_detector_header),
|
||||
imageData + srcOffset,
|
||||
(imageSize < maxDataSize ? imageSize : maxDataSize));
|
||||
srcOffset += maxDataSize;
|
||||
imageData + srcOffset, dataSize);
|
||||
srcOffset += dataSize;
|
||||
dataSent += dataSize;
|
||||
|
||||
sendUDPPacket(0, 0, packetData, packetSize);
|
||||
}
|
||||
|
@ -100,7 +100,6 @@ if(SLS_USE_TEXTCLIENT)
|
||||
target_link_libraries(${val1}
|
||||
slsDetectorStatic
|
||||
pthread
|
||||
rt
|
||||
)
|
||||
SET_SOURCE_FILES_PROPERTIES( src/Caller.cpp PROPERTIES COMPILE_FLAGS "-Wno-unused-variable -Wno-unused-but-set-variable")
|
||||
|
||||
|
@ -21,6 +21,7 @@ class Caller {
|
||||
UdpDestination getUdpEntry();
|
||||
int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand);
|
||||
void WrongNumberOfParameters(size_t expected);
|
||||
std::vector<defs::ROI> parseRoiVector(const std::string &input);
|
||||
|
||||
template <typename V> std::string OutStringHex(const V &value) {
|
||||
if (value.equal())
|
||||
|
@ -2598,11 +2598,7 @@ rx_roi:
|
||||
GET:
|
||||
argc: 0
|
||||
PUT:
|
||||
args:
|
||||
- argc: 2
|
||||
arg_types: [ int, int ]
|
||||
- argc: 4
|
||||
arg_types: [ int, int, int, int ]
|
||||
argc: -1
|
||||
|
||||
ratecorr:
|
||||
is_description: true
|
||||
|
@ -119,6 +119,10 @@ class Detector {
|
||||
|
||||
Result<defs::xy> getModuleSize(Positions pos = {}) const;
|
||||
|
||||
defs::xy getPortPerModuleGeometry() const;
|
||||
|
||||
Result<defs::xy> getPortSize(Positions pos = {}) const;
|
||||
|
||||
/** Gets the actual full detector size. It is the same even if ROI changes
|
||||
*/
|
||||
defs::xy getDetectorSize() const;
|
||||
@ -985,13 +989,14 @@ class Detector {
|
||||
* every minute. Useful in 10G mode. */
|
||||
void setRxArping(bool value, Positions pos = {});
|
||||
|
||||
/** at module level */
|
||||
Result<defs::ROI> getIndividualRxROIs(Positions pos) const;
|
||||
/** Returns multi level ROIs */
|
||||
std::vector<defs::ROI> getRxROI() const;
|
||||
|
||||
defs::ROI getRxROI() const;
|
||||
/** Returns port level ROIs. Max 2 ports and hence max 2 elements per readout */
|
||||
Result<std::array<defs::ROI, 2>> getRxROI(int module_id) const;
|
||||
|
||||
/** only at multi module level without gap pixels */
|
||||
void setRxROI(const defs::ROI value);
|
||||
/** only at multi module level without gap pixels. At most, 1 ROI per UDP port */
|
||||
void setRxROI(const std::vector<defs::ROI> &args);
|
||||
|
||||
void clearRxROI();
|
||||
|
||||
|
@ -21,6 +21,7 @@ class Caller {
|
||||
UdpDestination getUdpEntry();
|
||||
int GetLevelAndInsertIntoArgs(std::string levelSeparatedCommand);
|
||||
void WrongNumberOfParameters(size_t expected);
|
||||
std::vector<defs::ROI> parseRoiVector(const std::string &input);
|
||||
|
||||
template <typename V> std::string OutStringHex(const V &value) {
|
||||
if (value.equal())
|
||||
|
@ -719,49 +719,119 @@ std::string Caller::rx_zmqip(int action) {
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::string Caller::rx_roi(int action) {
|
||||
std::ostringstream os;
|
||||
std::string helpMessage =
|
||||
std::string("[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in "
|
||||
"receiver.\n\t") +
|
||||
"For a list of rois, use '[' and ']; ' to distinguish between "
|
||||
"rois and use comma inside the square brackets.\n\t If one fails to "
|
||||
"use space after semicolon, please use quotes" +
|
||||
"For example: [0,100,0,100]; [200,300,0,100] will set two "
|
||||
"rois.or '[0,100,0,100];[200,300,0,100]' when the vector is a single "
|
||||
"string\n\n\t" +
|
||||
"Only allowed to set at multi module level and without gap "
|
||||
"ixels.\n\n\t" +
|
||||
"One can get rx_roi also at port level, by specifying the module id "
|
||||
"and it will return the roi for each port.\n";
|
||||
if (action == defs::HELP_ACTION) {
|
||||
os << "[xmin] [xmax] [ymin] [ymax]\n\tRegion of interest in "
|
||||
"receiver.\n\tOnly allowed at multi module level and without gap "
|
||||
"pixels."
|
||||
<< '\n';
|
||||
os << helpMessage;
|
||||
} else if (action == defs::GET_ACTION) {
|
||||
if (!args.empty()) {
|
||||
WrongNumberOfParameters(0);
|
||||
}
|
||||
if (det_id == -1) {
|
||||
auto t = det->getRxROI();
|
||||
os << t << '\n';
|
||||
if (det_id != -1) {
|
||||
auto t = det->getRxROI(det_id);
|
||||
os << ToString(t) << '\n';
|
||||
} else {
|
||||
auto t = det->getIndividualRxROIs(std::vector<int>{det_id});
|
||||
os << t << '\n';
|
||||
auto t = det->getRxROI();
|
||||
os << ToString(t) << '\n';
|
||||
}
|
||||
} else if (action == defs::PUT_ACTION) {
|
||||
defs::ROI t;
|
||||
// 2 or 4 arguments
|
||||
if (args.size() != 2 && args.size() != 4) {
|
||||
WrongNumberOfParameters(2);
|
||||
}
|
||||
if (args.size() == 2 || args.size() == 4) {
|
||||
t.xmin = StringTo<int>(args[0]);
|
||||
t.xmax = StringTo<int>(args[1]);
|
||||
}
|
||||
if (args.size() == 4) {
|
||||
t.ymin = StringTo<int>(args[2]);
|
||||
t.ymax = StringTo<int>(args[3]);
|
||||
std::vector<defs::ROI> rois;
|
||||
|
||||
// Support multiple args with bracketed ROIs, or single arg with
|
||||
// semicolon-separated vector
|
||||
bool isVectorInput =
|
||||
std::all_of(args.begin(), args.end(), [](const std::string &a) {
|
||||
return a.find('[') != std::string::npos &&
|
||||
a.find(']') != std::string::npos;
|
||||
});
|
||||
try {
|
||||
// previous format: 2 or 4 separate args
|
||||
if ((args.size() == 2 || args.size() == 4) && !isVectorInput) {
|
||||
defs::ROI t;
|
||||
t.xmin = StringTo<int>(args[0]);
|
||||
t.xmax = StringTo<int>(args[1]);
|
||||
if (args.size() == 4) {
|
||||
t.ymin = StringTo<int>(args[2]);
|
||||
t.ymax = StringTo<int>(args[3]);
|
||||
}
|
||||
rois.emplace_back(t);
|
||||
} else {
|
||||
if (!isVectorInput)
|
||||
WrongNumberOfParameters(2);
|
||||
else {
|
||||
for (const auto &arg : args) {
|
||||
auto subRois = parseRoiVector(arg);
|
||||
rois.insert(rois.end(), subRois.begin(), subRois.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
throw RuntimeError("Could not parse ROI: " + helpMessage);
|
||||
}
|
||||
|
||||
// only multi level
|
||||
if (det_id != -1) {
|
||||
throw RuntimeError("Cannot execute receiver ROI at module level");
|
||||
}
|
||||
det->setRxROI(t);
|
||||
os << t << '\n';
|
||||
|
||||
det->setRxROI(rois);
|
||||
os << ToString(rois) << '\n';
|
||||
} else {
|
||||
throw RuntimeError("Unknown action");
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::vector<defs::ROI> Caller::parseRoiVector(const std::string &input) {
|
||||
std::vector<defs::ROI> rois;
|
||||
std::stringstream ss(input);
|
||||
std::string token;
|
||||
|
||||
while (std::getline(ss, token, ';')) {
|
||||
token.erase(std::remove_if(token.begin(), token.end(), ::isspace),
|
||||
token.end());
|
||||
if (token.empty())
|
||||
continue;
|
||||
if (token.front() != '[' || token.back() != ']') {
|
||||
throw RuntimeError("Each ROI must be enclosed in square brackets: "
|
||||
"[xmin,xmax,ymin,ymax]");
|
||||
}
|
||||
token = token.substr(1, token.size() - 2); // remove brackets
|
||||
std::vector<std::string> parts;
|
||||
std::stringstream inner(token);
|
||||
std::string num;
|
||||
while (std::getline(inner, num, ',')) {
|
||||
parts.push_back(num);
|
||||
}
|
||||
|
||||
if (parts.size() != 4) {
|
||||
throw RuntimeError("ROI must have 4 comma-separated integers");
|
||||
}
|
||||
|
||||
defs::ROI roi;
|
||||
roi.xmin = StringTo<int>(parts[0]);
|
||||
roi.xmax = StringTo<int>(parts[1]);
|
||||
roi.ymin = StringTo<int>(parts[2]);
|
||||
roi.ymax = StringTo<int>(parts[3]);
|
||||
rois.emplace_back(roi);
|
||||
}
|
||||
return rois;
|
||||
}
|
||||
|
||||
std::string Caller::ratecorr(int action) {
|
||||
std::ostringstream os;
|
||||
if (action == defs::HELP_ACTION) {
|
||||
|
@ -201,6 +201,22 @@ Result<defs::xy> Detector::getModuleSize(Positions pos) const {
|
||||
return pimpl->Parallel(&Module::getNumberOfChannels, pos);
|
||||
}
|
||||
|
||||
defs::xy Detector::getPortPerModuleGeometry() const {
|
||||
return pimpl->getPortGeometry();
|
||||
}
|
||||
|
||||
Result<defs::xy> Detector::getPortSize(Positions pos) const {
|
||||
Result<defs::xy> res = pimpl->Parallel(&Module::getNumberOfChannels, pos);
|
||||
defs::xy portGeometry = getPortPerModuleGeometry();
|
||||
for (auto &it : res) {
|
||||
if (portGeometry.x == 2)
|
||||
it.x /= 2;
|
||||
if (portGeometry.y == 2)
|
||||
it.y /= 2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
defs::xy Detector::getDetectorSize() const {
|
||||
return pimpl->getNumberOfChannels();
|
||||
}
|
||||
@ -1367,16 +1383,22 @@ void Detector::setRxArping(bool value, Positions pos) {
|
||||
pimpl->Parallel(&Module::setRxArping, pos, value);
|
||||
}
|
||||
|
||||
Result<defs::ROI> Detector::getIndividualRxROIs(Positions pos) const {
|
||||
return pimpl->Parallel(&Module::getRxROI, pos);
|
||||
std::vector<defs::ROI> Detector::getRxROI() const {
|
||||
return pimpl->getRxROI();
|
||||
}
|
||||
|
||||
defs::ROI Detector::getRxROI() const { return pimpl->getRxROI(); }
|
||||
Result<std::array<defs::ROI, 2>> Detector::getRxROI(int module_id) const {
|
||||
return pimpl->Parallel(&Module::getRxROI, {module_id});
|
||||
}
|
||||
|
||||
void Detector::setRxROI(const defs::ROI value) { pimpl->setRxROI(value); }
|
||||
// RxROIs can be set for all types except CTB. At multi level without gap pixels
|
||||
void Detector::setRxROI(const std::vector<defs::ROI> &args) {
|
||||
pimpl->setRxROI(args);
|
||||
}
|
||||
|
||||
void Detector::clearRxROI() { pimpl->clearRxROI(); }
|
||||
|
||||
|
||||
// File
|
||||
|
||||
Result<defs::fileFormat> Detector::getFileFormat(Positions pos) const {
|
||||
|
@ -130,10 +130,6 @@ void DetectorImpl::initializeDetectorStructure() {
|
||||
shm()->gapPixels = false;
|
||||
// zmqlib default
|
||||
shm()->zmqHwm = -1;
|
||||
shm()->rx_roi.xmin = -1;
|
||||
shm()->rx_roi.xmax = -1;
|
||||
shm()->rx_roi.ymin = -1;
|
||||
shm()->rx_roi.ymax = -1;
|
||||
}
|
||||
|
||||
void DetectorImpl::initializeMembers(bool verify) {
|
||||
@ -539,7 +535,7 @@ void DetectorImpl::readFrameFromReceiver() {
|
||||
bool quadEnable = false;
|
||||
// to flip image
|
||||
bool eiger = false;
|
||||
std::array<int, 4> rxRoi = shm()->rx_roi.getIntArray();
|
||||
std::array<int, 4> rxRoi{}; // TODO: get roi from json header
|
||||
|
||||
std::vector<bool> runningList(zmqSocket.size());
|
||||
std::vector<bool> connectList(zmqSocket.size());
|
||||
@ -1548,31 +1544,6 @@ void DetectorImpl::setDefaultDac(defs::dacIndex index, int defaultValue,
|
||||
Parallel(&Module::setDefaultDac, pos, index, defaultValue, sett);
|
||||
}
|
||||
|
||||
defs::xy DetectorImpl::getPortGeometry() const {
|
||||
defs::xy portGeometry(1, 1);
|
||||
switch (shm()->detType) {
|
||||
case EIGER:
|
||||
portGeometry.x = modules[0]->getNumberofUDPInterfacesFromShm();
|
||||
break;
|
||||
case JUNGFRAU:
|
||||
case MOENCH:
|
||||
portGeometry.y = modules[0]->getNumberofUDPInterfacesFromShm();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return portGeometry;
|
||||
}
|
||||
|
||||
defs::xy DetectorImpl::calculatePosition(int moduleIndex,
|
||||
defs::xy geometry) const {
|
||||
defs::xy pos{};
|
||||
int maxYMods = shm()->numberOfModules.y;
|
||||
pos.y = (moduleIndex % maxYMods) * geometry.y;
|
||||
pos.x = (moduleIndex / maxYMods) * geometry.x;
|
||||
return pos;
|
||||
}
|
||||
|
||||
void DetectorImpl::verifyUniqueDetHost(const uint16_t port,
|
||||
std::vector<int> positions) const {
|
||||
// port for given positions
|
||||
@ -1696,7 +1667,8 @@ void DetectorImpl::verifyUniqueHost(
|
||||
}
|
||||
}
|
||||
|
||||
defs::ROI DetectorImpl::getRxROI() const {
|
||||
std::vector<defs::ROI> DetectorImpl::getRxROI() const {
|
||||
|
||||
if (shm()->detType == CHIPTESTBOARD ||
|
||||
shm()->detType == defs::XILINX_CHIPTESTBOARD) {
|
||||
throw RuntimeError("RxRoi not implemented for this Detector");
|
||||
@ -1704,75 +1676,170 @@ defs::ROI DetectorImpl::getRxROI() const {
|
||||
if (modules.size() == 0) {
|
||||
throw RuntimeError("No Modules added");
|
||||
}
|
||||
// complete detector in roi
|
||||
auto t = Parallel(&Module::getRxROI, {});
|
||||
if (t.equal() && t.front().completeRoi()) {
|
||||
LOG(logDEBUG) << "no roi";
|
||||
return defs::ROI(0, shm()->numberOfChannels.x - 1, 0,
|
||||
shm()->numberOfChannels.y - 1);
|
||||
}
|
||||
|
||||
defs::xy numChansPerMod = modules[0]->getNumberOfChannels();
|
||||
bool is2D = (numChansPerMod.y > 1 ? true : false);
|
||||
defs::xy geometry = getPortGeometry();
|
||||
// return std::vector<defs::ROI>{};
|
||||
return rxRoiTemp;
|
||||
// TODO
|
||||
}
|
||||
|
||||
defs::ROI retval{};
|
||||
for (size_t iModule = 0; iModule != modules.size(); ++iModule) {
|
||||
bool DetectorImpl::roisOverlap(const defs::ROI &a, const defs::ROI &b) const {
|
||||
bool xOverlap = !(a.xmax < b.xmin || a.xmin > b.xmax);
|
||||
bool yOverlap = !(a.ymax < b.ymin || a.ymin > b.ymax);
|
||||
return xOverlap && yOverlap;
|
||||
}
|
||||
|
||||
defs::ROI moduleRoi = modules[iModule]->getRxROI();
|
||||
if (moduleRoi.noRoi()) {
|
||||
LOG(logDEBUG) << iModule << ": no roi";
|
||||
void DetectorImpl::validateROIs(const std::vector<defs::ROI> &rois) {
|
||||
for (size_t i = 0; i < rois.size(); ++i) {
|
||||
const auto &roi = rois[i];
|
||||
|
||||
if (roi.noRoi()) {
|
||||
throw RuntimeError("Invalid Roi of size 0. Roi: " + ToString(roi));
|
||||
}
|
||||
bool is2D = (modules[0]->getNumberOfChannels().y > 1 ? true : false);
|
||||
if (roi.completeRoi()) {
|
||||
std::ostringstream oss;
|
||||
oss << "Did you mean the clear roi command (API: clearRxROI, cmd: "
|
||||
"rx_clearroi) Roi: [ -1, -1 ";
|
||||
oss << (is2D ? ", -1, -1 ]?" : "]?");
|
||||
throw RuntimeError(oss.str());
|
||||
}
|
||||
if (roi.xmin > roi.xmax || roi.ymin > roi.ymax) {
|
||||
throw RuntimeError(
|
||||
"Invalid Roi. xmin/ymin exceeds xmax/ymax. Roi: " +
|
||||
ToString(roi));
|
||||
}
|
||||
|
||||
if (roi.xmin < 0 || roi.xmax >= shm()->numberOfChannels.x) {
|
||||
throw RuntimeError(
|
||||
"ROI x-dimension outside detector bounds. Roi: " +
|
||||
ToString(roi));
|
||||
}
|
||||
|
||||
if (is2D) {
|
||||
if (roi.ymin < 0 || roi.ymax >= shm()->numberOfChannels.y) {
|
||||
throw RuntimeError(
|
||||
"ROI y-dimension outside detector bounds. Roi: " +
|
||||
ToString(roi));
|
||||
}
|
||||
} else {
|
||||
// expand complete roi
|
||||
if (moduleRoi.completeRoi()) {
|
||||
moduleRoi.xmin = 0;
|
||||
moduleRoi.xmax = numChansPerMod.x;
|
||||
if (is2D) {
|
||||
moduleRoi.ymin = 0;
|
||||
moduleRoi.ymax = numChansPerMod.y;
|
||||
}
|
||||
}
|
||||
LOG(logDEBUG) << iModule << ": " << moduleRoi;
|
||||
|
||||
// get roi at detector level
|
||||
defs::xy pos = calculatePosition(iModule, geometry);
|
||||
defs::ROI moduleFullRoi{};
|
||||
moduleFullRoi.xmin = numChansPerMod.x * pos.x + moduleRoi.xmin;
|
||||
moduleFullRoi.xmax = numChansPerMod.x * pos.x + moduleRoi.xmax;
|
||||
if (is2D) {
|
||||
moduleFullRoi.ymin = numChansPerMod.y * pos.y + moduleRoi.ymin;
|
||||
moduleFullRoi.ymax = numChansPerMod.y * pos.y + moduleRoi.ymax;
|
||||
}
|
||||
LOG(logDEBUG) << iModule << ": (full roi)" << moduleFullRoi;
|
||||
|
||||
// get min and max
|
||||
if (retval.xmin == -1 || moduleFullRoi.xmin < retval.xmin) {
|
||||
LOG(logDEBUG) << iModule << ": xmin updated";
|
||||
retval.xmin = moduleFullRoi.xmin;
|
||||
}
|
||||
if (retval.xmax == -1 || moduleFullRoi.xmax > retval.xmax) {
|
||||
LOG(logDEBUG) << iModule << ": xmax updated";
|
||||
retval.xmax = moduleFullRoi.xmax;
|
||||
}
|
||||
if (retval.ymin == -1 || moduleFullRoi.ymin < retval.ymin) {
|
||||
LOG(logDEBUG) << iModule << ": ymin updated";
|
||||
retval.ymin = moduleFullRoi.ymin;
|
||||
}
|
||||
if (retval.ymax == -1 || moduleFullRoi.ymax > retval.ymax) {
|
||||
LOG(logDEBUG) << iModule << ": ymax updated";
|
||||
retval.ymax = moduleFullRoi.ymax;
|
||||
if ((roi.ymin != -1 && roi.ymin != 0) ||
|
||||
(roi.ymax != -1 && roi.ymax != 0)) {
|
||||
throw RuntimeError(
|
||||
"Invalid Y range for 1D detector: should be -1. Roi: " +
|
||||
ToString(roi));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = i + 1; j < rois.size(); ++j) {
|
||||
if (roisOverlap(rois[i], rois[j])) {
|
||||
throw RuntimeError("Invalid Overlapping Rois.");
|
||||
}
|
||||
}
|
||||
LOG(logDEBUG) << iModule << ": (retval): " << retval;
|
||||
}
|
||||
if (retval.ymin == -1) {
|
||||
retval.ymin = 0;
|
||||
retval.ymax = 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
void DetectorImpl::setRxROI(const defs::ROI arg) {
|
||||
defs::xy DetectorImpl::calculatePosition(size_t moduleIndex,
|
||||
const defs::xy &geometry) const {
|
||||
if ((geometry.x != 0 && geometry.x != 1) ||
|
||||
(geometry.y != 0 && geometry.y != 1)) {
|
||||
throw RuntimeError("Invalid geometry configuration. Geometry: " +
|
||||
ToString(geometry));
|
||||
}
|
||||
|
||||
if (moduleIndex >= static_cast<size_t>(geometry.x * geometry.y)) {
|
||||
throw RuntimeError("Module index " + std::to_string(moduleIndex) +
|
||||
" out of bounds.");
|
||||
}
|
||||
|
||||
int x = moduleIndex % geometry.x;
|
||||
int y = moduleIndex / geometry.x;
|
||||
return defs::xy{x, y};
|
||||
}
|
||||
|
||||
defs::xy DetectorImpl::getPortGeometry() const {
|
||||
defs::xy portGeometry(1, 1);
|
||||
switch (shm()->detType) {
|
||||
case EIGER:
|
||||
portGeometry.x = modules[0]->getNumberofUDPInterfacesFromShm();
|
||||
break;
|
||||
case JUNGFRAU:
|
||||
case MOENCH:
|
||||
portGeometry.y = modules[0]->getNumberofUDPInterfacesFromShm();
|
||||
break;
|
||||
case GOTTHARD2: // 2nd port if used is for veto, not data
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return portGeometry;
|
||||
}
|
||||
|
||||
defs::xy DetectorImpl::calculatePosition(int moduleIndex,
|
||||
defs::xy geometry) const {
|
||||
int maxYMods = shm()->numberOfModules.y;
|
||||
int y = (moduleIndex % maxYMods) * geometry.y;
|
||||
int x = (moduleIndex / maxYMods) * geometry.x;
|
||||
return defs::xy{x, y};
|
||||
}
|
||||
|
||||
defs::ROI DetectorImpl::getModuleROI(int moduleIndex) const {
|
||||
const defs::xy modSize = modules[0]->getNumberOfChannels();
|
||||
// calculate module position (not taking into account port geometry)
|
||||
const defs::xy modPos = calculatePosition(moduleIndex, defs::xy{1, 1});
|
||||
return defs::ROI{modSize.x * modPos.x, modSize.x * (modPos.x + 1) - 1,
|
||||
modSize.y * modPos.y,
|
||||
modSize.y * (modPos.y + 1) - 1}; // convert y for 1d?
|
||||
}
|
||||
|
||||
void DetectorImpl::convertGlobalRoiToPortLevel(
|
||||
const defs::ROI &userRoi, const defs::ROI &moduleRoi,
|
||||
std::array<defs::ROI, 2> &portRois) const {
|
||||
const defs::xy modSize = modules[0]->getNumberOfChannels();
|
||||
const defs::xy geometry = getPortGeometry();
|
||||
const int numPorts = geometry.x * geometry.y;
|
||||
if (numPorts > 2) {
|
||||
throw RuntimeError("Only up to 2 ports per module supported.");
|
||||
}
|
||||
|
||||
for (int port = 0; port < numPorts; ++port) {
|
||||
defs::ROI portRoi = moduleRoi;
|
||||
// Calculate port ROI boundaries (split vertically or horizontally)
|
||||
if (geometry.x == 2) {
|
||||
int midX = (moduleRoi.xmin + moduleRoi.xmax) / 2;
|
||||
if (port == 0)
|
||||
portRoi.xmax = midX;
|
||||
else
|
||||
portRoi.xmin = midX + 1;
|
||||
} else if (geometry.y == 2) {
|
||||
int midY = (moduleRoi.ymin + moduleRoi.ymax) / 2;
|
||||
if (port == 0)
|
||||
portRoi.ymax = midY;
|
||||
else
|
||||
portRoi.ymin = midY + 1;
|
||||
}
|
||||
|
||||
// Check if user ROI overlaps with this port ROI
|
||||
if (roisOverlap(userRoi, portRoi)) {
|
||||
defs::ROI clipped{};
|
||||
clipped.xmin = std::max(userRoi.xmin, portRoi.xmin);
|
||||
clipped.xmax = std::min(userRoi.xmax, portRoi.xmax);
|
||||
if (modSize.y > 1) {
|
||||
clipped.ymin = std::max(userRoi.ymin, portRoi.ymin);
|
||||
clipped.ymax = std::min(userRoi.ymax, portRoi.ymax);
|
||||
}
|
||||
|
||||
// Check if port ROI already exists for this port
|
||||
if (!portRois[port].completeRoi()) {
|
||||
throw RuntimeError(
|
||||
"Multiple ROIs specified for the same port " +
|
||||
std::to_string(port) +
|
||||
" with ROI: " + ToString(userRoi));
|
||||
}
|
||||
portRois[port] = clipped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DetectorImpl::setRxROI(const std::vector<defs::ROI> &args) {
|
||||
if (shm()->detType == CHIPTESTBOARD ||
|
||||
shm()->detType == defs::XILINX_CHIPTESTBOARD) {
|
||||
throw RuntimeError("RxRoi not implemented for this Detector");
|
||||
@ -1780,118 +1847,42 @@ void DetectorImpl::setRxROI(const defs::ROI arg) {
|
||||
if (modules.size() == 0) {
|
||||
throw RuntimeError("No Modules added");
|
||||
}
|
||||
if (arg.noRoi()) {
|
||||
throw RuntimeError("Invalid Roi of size 0.");
|
||||
}
|
||||
if (arg.completeRoi()) {
|
||||
throw RuntimeError("Did you mean the clear roi command (API: "
|
||||
"clearRxROI, cmd: rx_clearroi)?");
|
||||
}
|
||||
if (arg.xmin > arg.xmax || arg.ymin > arg.ymax) {
|
||||
throw RuntimeError(
|
||||
"Invalid Receiver Roi. xmin/ymin exceeds xmax/ymax.");
|
||||
}
|
||||
|
||||
defs::xy numChansPerMod = modules[0]->getNumberOfChannels();
|
||||
bool is2D = (numChansPerMod.y > 1 ? true : false);
|
||||
defs::xy geometry = getPortGeometry();
|
||||
validateROIs(args);
|
||||
|
||||
if (!is2D && ((arg.ymin != -1 && arg.ymin != 0) ||
|
||||
(arg.ymax != -1 && arg.ymax != 0))) {
|
||||
throw RuntimeError(
|
||||
"Invalid Receiver roi. Cannot set 2d roi for a 1d detector.");
|
||||
}
|
||||
for (size_t iModule = 0; iModule < modules.size(); ++iModule) {
|
||||
auto moduleGlobalRoi = getModuleROI(iModule);
|
||||
|
||||
if (arg.xmin < 0 || arg.xmax >= shm()->numberOfChannels.x ||
|
||||
(is2D && (arg.ymin < 0 || arg.ymax >= shm()->numberOfChannels.y))) {
|
||||
throw RuntimeError("Invalid Receiver Roi. Outside detector range.");
|
||||
}
|
||||
// at most 2 rois per module (for each port)
|
||||
std::array<defs::ROI, 2> portRois{};
|
||||
|
||||
for (size_t iModule = 0; iModule != modules.size(); ++iModule) {
|
||||
// default init = complete roi
|
||||
defs::ROI moduleRoi{};
|
||||
|
||||
// incomplete roi
|
||||
if (!arg.completeRoi()) {
|
||||
// multi module Gotthard2
|
||||
if (shm()->detType == GOTTHARD2 && size() > 1) {
|
||||
moduleRoi.xmin = arg.xmin / 2;
|
||||
moduleRoi.xmax = arg.xmax / 2;
|
||||
if (iModule == 0) {
|
||||
// all should be even
|
||||
if (arg.xmin % 2 != 0) {
|
||||
++moduleRoi.xmin;
|
||||
}
|
||||
} else if (iModule == 1) {
|
||||
// all should be odd
|
||||
if (arg.xmax % 2 == 0) {
|
||||
--moduleRoi.xmax;
|
||||
}
|
||||
} else {
|
||||
throw RuntimeError("Cannot have more than 2 modules for a "
|
||||
"Gotthard2 detector");
|
||||
}
|
||||
} else {
|
||||
// get module limits
|
||||
defs::xy pos = calculatePosition(iModule, geometry);
|
||||
defs::ROI moduleFullRoi{};
|
||||
moduleFullRoi.xmin = numChansPerMod.x * pos.x;
|
||||
moduleFullRoi.xmax = numChansPerMod.x * (pos.x + 1) - 1;
|
||||
if (is2D) {
|
||||
moduleFullRoi.ymin = numChansPerMod.y * pos.y;
|
||||
moduleFullRoi.ymax = numChansPerMod.y * (pos.y + 1) - 1;
|
||||
}
|
||||
|
||||
// no roi
|
||||
if (arg.xmin > moduleFullRoi.xmax ||
|
||||
arg.xmax < moduleFullRoi.xmin ||
|
||||
(is2D && (arg.ymin > moduleFullRoi.ymax ||
|
||||
arg.ymax < moduleFullRoi.ymin))) {
|
||||
moduleRoi.setNoRoi();
|
||||
}
|
||||
// incomplete module roi
|
||||
else if (arg.xmin > moduleFullRoi.xmin ||
|
||||
arg.xmax < moduleFullRoi.xmax ||
|
||||
(is2D && (arg.ymin > moduleFullRoi.ymin ||
|
||||
arg.ymax < moduleFullRoi.ymax))) {
|
||||
moduleRoi.xmin = (arg.xmin <= moduleFullRoi.xmin)
|
||||
? 0
|
||||
: (arg.xmin % numChansPerMod.x);
|
||||
moduleRoi.xmax = (arg.xmax >= moduleFullRoi.xmax)
|
||||
? numChansPerMod.x - 1
|
||||
: (arg.xmax % numChansPerMod.x);
|
||||
if (is2D) {
|
||||
moduleRoi.ymin = (arg.ymin <= moduleFullRoi.ymin)
|
||||
? 0
|
||||
: (arg.ymin % numChansPerMod.y);
|
||||
moduleRoi.ymax = (arg.ymax >= moduleFullRoi.ymax)
|
||||
? numChansPerMod.y - 1
|
||||
: (arg.ymax % numChansPerMod.y);
|
||||
}
|
||||
}
|
||||
for (const auto &arg : args) {
|
||||
if (roisOverlap(arg, moduleGlobalRoi)) {
|
||||
convertGlobalRoiToPortLevel(arg, moduleGlobalRoi, portRois);
|
||||
}
|
||||
}
|
||||
modules[iModule]->setRxROI(moduleRoi);
|
||||
// print the rois for debugging
|
||||
LOG(logINFOBLUE) << "Module " << iModule << " RxROIs:";
|
||||
for (size_t iPort = 0; iPort != 2; iPort++) {
|
||||
LOG(logINFOBLUE)
|
||||
<< " Port " << iPort << ": " << ToString(portRois[iPort]);
|
||||
}
|
||||
modules[iModule]->setRxROI(portRois);
|
||||
}
|
||||
// updating shm rx_roi for gui purposes
|
||||
shm()->rx_roi = arg;
|
||||
|
||||
rxRoiTemp = args;
|
||||
// metadata
|
||||
if (arg.completeRoi()) {
|
||||
modules[0]->setRxROIMetadata(defs::ROI(0, shm()->numberOfChannels.x - 1,
|
||||
0,
|
||||
shm()->numberOfChannels.y - 1));
|
||||
} else {
|
||||
modules[0]->setRxROIMetadata(arg);
|
||||
modules[0]->setRxROIMetadata(args);
|
||||
}
|
||||
|
||||
void DetectorImpl::clearRxROI() {
|
||||
rxRoiTemp.clear();
|
||||
for (size_t iModule = 0; iModule < modules.size(); ++iModule) {
|
||||
modules[iModule]->setRxROI(std::array<defs::ROI, 2>{});
|
||||
}
|
||||
}
|
||||
|
||||
void DetectorImpl::clearRxROI() {
|
||||
Parallel(&Module::setRxROI, {}, defs::ROI{});
|
||||
shm()->rx_roi.xmin = -1;
|
||||
shm()->rx_roi.ymin = -1;
|
||||
shm()->rx_roi.xmax = -1;
|
||||
shm()->rx_roi.ymax = -1;
|
||||
int DetectorImpl::getNumberOfUdpPortsInRxROI() const {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
void DetectorImpl::getBadChannels(const std::string &fname,
|
||||
|
@ -24,7 +24,7 @@ class detectorData;
|
||||
class Module;
|
||||
|
||||
#define DETECTOR_SHMAPIVERSION 0x190809
|
||||
#define DETECTOR_SHMVERSION 0x220505
|
||||
#define DETECTOR_SHMVERSION 0x250616
|
||||
#define SHORT_STRING_LENGTH 50
|
||||
|
||||
/**
|
||||
@ -65,8 +65,6 @@ struct sharedDetector {
|
||||
bool gapPixels;
|
||||
/** high water mark of listening tcp port (only data) */
|
||||
int zmqHwm;
|
||||
/** in shm for gui purposes */
|
||||
defs::ROI rx_roi{};
|
||||
};
|
||||
|
||||
class DetectorImpl : public virtual slsDetectorDefs {
|
||||
@ -303,9 +301,11 @@ class DetectorImpl : public virtual slsDetectorDefs {
|
||||
std::vector<std::pair<std::string, uint16_t>>
|
||||
verifyUniqueRxHost(const std::vector<std::string> &names) const;
|
||||
|
||||
defs::ROI getRxROI() const;
|
||||
void setRxROI(const defs::ROI arg);
|
||||
defs::xy getPortGeometry() const;
|
||||
std::vector<defs::ROI> getRxROI() const;
|
||||
void setRxROI(const std::vector<defs::ROI> &args);
|
||||
void clearRxROI();
|
||||
int getNumberOfUdpPortsInRxROI() const;
|
||||
|
||||
void getBadChannels(const std::string &fname, Positions pos) const;
|
||||
void setBadChannels(const std::string &fname, Positions pos);
|
||||
@ -422,12 +422,19 @@ class DetectorImpl : public virtual slsDetectorDefs {
|
||||
*/
|
||||
int kbhit();
|
||||
|
||||
defs::xy getPortGeometry() const;
|
||||
defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const;
|
||||
|
||||
void verifyUniqueHost(
|
||||
bool isDet, std::vector<std::pair<std::string, uint16_t>> &hosts) const;
|
||||
|
||||
bool roisOverlap(const defs::ROI &a, const defs::ROI &b) const;
|
||||
void validateROIs(const std::vector<defs::ROI> &rois);
|
||||
defs::xy calculatePosition(size_t moduleIndex,
|
||||
const defs::xy &geometry) const;
|
||||
defs::xy calculatePosition(int moduleIndex, defs::xy geometry) const;
|
||||
defs::ROI getModuleROI(int moduleIndex) const;
|
||||
void convertGlobalRoiToPortLevel(
|
||||
const defs::ROI &userRoi, const defs::ROI &moduleRoi,
|
||||
std::array<defs::ROI, 2> &portRois) const;
|
||||
|
||||
const int detectorIndex{0};
|
||||
SharedMemory<sharedDetector> shm{0, -1};
|
||||
SharedMemory<CtbConfig> ctb_shm{0, -1, CtbConfig::shm_tag()};
|
||||
@ -455,6 +462,8 @@ class DetectorImpl : public virtual slsDetectorDefs {
|
||||
|
||||
void (*dataReady)(detectorData *, uint64_t, uint32_t, void *){nullptr};
|
||||
void *pCallbackArg{nullptr};
|
||||
|
||||
std::vector<defs::ROI> rxRoiTemp;
|
||||
};
|
||||
|
||||
} // namespace sls
|
@ -1521,17 +1521,26 @@ void Module::setRxArping(bool enable) {
|
||||
sendToReceiver(F_SET_RECEIVER_ARPING, static_cast<int>(enable), nullptr);
|
||||
}
|
||||
|
||||
defs::ROI Module::getRxROI() const {
|
||||
return sendToReceiver<slsDetectorDefs::ROI>(F_RECEIVER_GET_RECEIVER_ROI);
|
||||
std::array<defs::ROI, 2> Module::getRxROI() const {
|
||||
return sendToReceiver<std::array<slsDetectorDefs::ROI, 2>>(F_RECEIVER_GET_RECEIVER_ROI);
|
||||
}
|
||||
|
||||
void Module::setRxROI(const slsDetectorDefs::ROI arg) {
|
||||
LOG(logDEBUG) << moduleIndex << ": " << arg;
|
||||
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, arg, nullptr);
|
||||
void Module::setRxROI(const std::array<defs::ROI, 2> &portRois) {
|
||||
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI, portRois, nullptr);
|
||||
}
|
||||
|
||||
void Module::setRxROIMetadata(const slsDetectorDefs::ROI arg) {
|
||||
sendToReceiver(F_RECEIVER_SET_RECEIVER_ROI_METADATA, arg, nullptr);
|
||||
void Module::setRxROIMetadata(const std::vector<slsDetectorDefs::ROI> &args) {
|
||||
LOG(logDEBUG) << "Sending to receiver " << moduleIndex
|
||||
<< " [roi metadata: " << ToString(args) << ']';
|
||||
auto receiver = ReceiverSocket(shm()->rxHostname, shm()->rxTCPPort);
|
||||
receiver.Send(F_RECEIVER_SET_RECEIVER_ROI_METADATA);
|
||||
receiver.setFnum(F_RECEIVER_SET_RECEIVER_ROI_METADATA);
|
||||
receiver.Send(static_cast<int>(args.size()));
|
||||
receiver.Send(args);
|
||||
if (receiver.Receive<int>() == FAIL) {
|
||||
throw ReceiverError("Receiver " + std::to_string(moduleIndex) +
|
||||
" returned error: " + receiver.readErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// File
|
||||
|
@ -301,9 +301,9 @@ class Module : public virtual slsDetectorDefs {
|
||||
std::array<pid_t, NUM_RX_THREAD_IDS> getReceiverThreadIds() const;
|
||||
bool getRxArping() const;
|
||||
void setRxArping(bool enable);
|
||||
defs::ROI getRxROI() const;
|
||||
void setRxROI(const slsDetectorDefs::ROI arg);
|
||||
void setRxROIMetadata(const slsDetectorDefs::ROI arg);
|
||||
std::array<defs::ROI, 2> getRxROI() const;
|
||||
void setRxROI(const std::array<slsDetectorDefs::ROI, 2> &portRois);
|
||||
void setRxROIMetadata(const std::vector<slsDetectorDefs::ROI> &args);
|
||||
|
||||
/**************************************************
|
||||
* *
|
||||
|
@ -17,6 +17,119 @@ namespace sls {
|
||||
using test::GET;
|
||||
using test::PUT;
|
||||
|
||||
TEST_CASE("ctb_acquire_check_file_size", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
|
||||
if (det_type == defs::CHIPTESTBOARD ||
|
||||
det_type == defs::XILINX_CHIPTESTBOARD) {
|
||||
int num_frames_to_acquire = 2;
|
||||
// all the test cases
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::ANALOG_AND_DIGITAL;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::DIGITAL_AND_TRANSCEIVER;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::TRANSCEIVER_ONLY;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
{
|
||||
testCtbAcquireInfo test_ctb_config;
|
||||
test_ctb_config.readout_mode = defs::ANALOG_ONLY;
|
||||
test_ctb_config.dbit_offset = 16;
|
||||
test_ctb_config.dbit_list.clear();
|
||||
test_ctb_config.dbit_reorder = true;
|
||||
REQUIRE_NOTHROW(test_ctb_acquire_with_receiver(
|
||||
test_ctb_config, num_frames_to_acquire, det, caller));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* dacs */
|
||||
|
||||
TEST_CASE("dacname", "[.cmdcall]") {
|
||||
|
@ -17,6 +17,70 @@ namespace sls {
|
||||
using test::GET;
|
||||
using test::PUT;
|
||||
|
||||
TEST_CASE("eiger_acquire_check_file_size", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
|
||||
if (det_type == defs::EIGER) {
|
||||
|
||||
// save previous state
|
||||
testFileInfo prev_file_info = get_file_state(det);
|
||||
testCommonDetAcquireInfo prev_det_config_info =
|
||||
get_common_acquire_config_state(det);
|
||||
|
||||
// save previous specific det type config
|
||||
auto exptime = det.getExptime().tsquash("inconsistent exptime to test");
|
||||
auto n_rows =
|
||||
det.getReadNRows().tsquash("inconsistent number of rows to test");
|
||||
auto dynamic_range =
|
||||
det.getDynamicRange().tsquash("inconsistent dynamic range to test");
|
||||
REQUIRE(false ==
|
||||
det.getTenGiga().tsquash("inconsistent 10Giga to test"));
|
||||
|
||||
// defaults
|
||||
int num_frames_to_acquire = 2;
|
||||
testFileInfo test_file_info;
|
||||
set_file_state(det, test_file_info);
|
||||
testCommonDetAcquireInfo det_config;
|
||||
det_config.num_frames_to_acquire = num_frames_to_acquire;
|
||||
set_common_acquire_config_state(det, det_config);
|
||||
|
||||
// set default specific det type config
|
||||
det.setExptime(std::chrono::microseconds{200});
|
||||
det.setReadNRows(256);
|
||||
det.setDynamicRange(16);
|
||||
|
||||
// acquire
|
||||
test_acquire_with_receiver(caller, det);
|
||||
|
||||
// check frames caught
|
||||
test_frames_caught(det, num_frames_to_acquire);
|
||||
|
||||
// check file size (assuming local pc)
|
||||
{
|
||||
detParameters par(det_type);
|
||||
// data split into half due to 2 udp interfaces per half module
|
||||
int num_chips = (par.nChipX / 2);
|
||||
int bytes_per_pixel = (dynamic_range / 8);
|
||||
size_t expected_image_size =
|
||||
par.nChanX * par.nChanY * num_chips * bytes_per_pixel;
|
||||
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
|
||||
expected_image_size);
|
||||
}
|
||||
|
||||
// restore previous state
|
||||
set_file_state(det, prev_file_info);
|
||||
set_common_acquire_config_state(det, prev_det_config_info);
|
||||
|
||||
// restore previous specific det type config
|
||||
det.setExptime(exptime);
|
||||
det.setReadNRows(n_rows);
|
||||
det.setDynamicRange(dynamic_range);
|
||||
}
|
||||
}
|
||||
|
||||
/** temperature */
|
||||
|
||||
TEST_CASE("temp_fpgaext", "[.cmdcall]") {
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "Caller.h"
|
||||
#include "catch.hpp"
|
||||
#include "sls/Detector.h"
|
||||
#include "sls/logger.h"
|
||||
#include "tests/globals.h"
|
||||
|
||||
namespace sls {
|
||||
@ -88,4 +89,227 @@ void test_onchip_dac_caller(defs::dacIndex index, const std::string &dacname,
|
||||
}
|
||||
}
|
||||
|
||||
testFileInfo get_file_state(const Detector &det) {
|
||||
return testFileInfo{
|
||||
det.getFilePath().tsquash("Inconsistent file path"),
|
||||
det.getFileNamePrefix().tsquash("Inconsistent file prefix"),
|
||||
det.getAcquisitionIndex().tsquash(
|
||||
"Inconsistent file acquisition index"),
|
||||
det.getFileWrite().tsquash("Inconsistent file write state"),
|
||||
det.getFileOverWrite().tsquash("Inconsistent file overwrite state"),
|
||||
det.getFileFormat().tsquash("Inconsistent file format")};
|
||||
}
|
||||
|
||||
void set_file_state(Detector &det, const testFileInfo &file_info) {
|
||||
if (!file_info.file_path.empty())
|
||||
det.setFilePath(file_info.file_path);
|
||||
det.setFileNamePrefix(file_info.file_prefix);
|
||||
det.setAcquisitionIndex(file_info.file_acq_index);
|
||||
det.setFileWrite(file_info.file_write);
|
||||
det.setFileOverWrite(file_info.file_overwrite);
|
||||
det.setFileFormat(file_info.file_format);
|
||||
}
|
||||
|
||||
void test_acquire_binary_file_size(const testFileInfo &file_info,
|
||||
uint64_t num_frames_to_acquire,
|
||||
uint64_t expected_image_size) {
|
||||
assert(file_info.file_format == defs::BINARY);
|
||||
std::string fname = file_info.file_path + "/" + file_info.file_prefix +
|
||||
"_d0_f0_" + std::to_string(file_info.file_acq_index) +
|
||||
".raw";
|
||||
uint64_t expected_file_size =
|
||||
num_frames_to_acquire *
|
||||
(expected_image_size + sizeof(defs::sls_receiver_header));
|
||||
auto actual_file_size = std::filesystem::file_size(fname);
|
||||
REQUIRE(actual_file_size == expected_file_size);
|
||||
}
|
||||
|
||||
void test_frames_caught(const Detector &det, int num_frames_to_acquire) {
|
||||
auto frames_caught = det.getFramesCaught().tsquash(
|
||||
"Inconsistent number of frames caught")[0];
|
||||
REQUIRE(frames_caught == num_frames_to_acquire);
|
||||
}
|
||||
|
||||
void test_acquire_with_receiver(Caller &caller, const Detector &det) {
|
||||
REQUIRE_NOTHROW(caller.call("rx_start", {}, -1, PUT));
|
||||
REQUIRE_NOTHROW(caller.call("start", {}, -1, PUT));
|
||||
bool idle = false;
|
||||
while (!idle) {
|
||||
std::ostringstream oss;
|
||||
REQUIRE_NOTHROW(caller.call("status", {}, -1, GET));
|
||||
auto statusList = det.getDetectorStatus();
|
||||
if (statusList.any(defs::ERROR)) {
|
||||
throw std::runtime_error("error status while acquiring");
|
||||
}
|
||||
if (statusList.contains_only(defs::IDLE, defs::STOPPED)) {
|
||||
idle = true;
|
||||
}
|
||||
}
|
||||
REQUIRE_NOTHROW(caller.call("rx_stop", {}, -1, PUT));
|
||||
}
|
||||
|
||||
testCommonDetAcquireInfo get_common_acquire_config_state(const Detector &det) {
|
||||
return testCommonDetAcquireInfo{
|
||||
det.getTimingMode().tsquash("Inconsistent timing mode"),
|
||||
det.getNumberOfFrames().tsquash("Inconsistent number of frames"),
|
||||
det.getNumberOfTriggers().tsquash("Inconsistent number of triggers"),
|
||||
det.getPeriod().tsquash("Inconsistent period")};
|
||||
}
|
||||
|
||||
void set_common_acquire_config_state(
|
||||
Detector &det, const testCommonDetAcquireInfo &det_config_info) {
|
||||
det.setTimingMode(det_config_info.timing_mode);
|
||||
det.setNumberOfFrames(det_config_info.num_frames_to_acquire);
|
||||
det.setNumberOfTriggers(det_config_info.num_triggers);
|
||||
det.setPeriod(det_config_info.period);
|
||||
}
|
||||
|
||||
testCtbAcquireInfo get_ctb_config_state(const Detector &det) {
|
||||
testCtbAcquireInfo ctb_config_info{
|
||||
det.getReadoutMode().tsquash("inconsistent readout mode to test"),
|
||||
true,
|
||||
det.getNumberOfAnalogSamples().tsquash(
|
||||
"inconsistent number of analog samples to test"),
|
||||
det.getNumberOfDigitalSamples().tsquash(
|
||||
"inconsistent number of digital samples to test"),
|
||||
det.getNumberOfTransceiverSamples().tsquash(
|
||||
"inconsistent number of transceiver samples to test"),
|
||||
0,
|
||||
det.getTenGigaADCEnableMask().tsquash(
|
||||
"inconsistent ten giga adc enable mask to test"),
|
||||
det.getRxDbitOffset().tsquash("inconsistent rx dbit offset to test"),
|
||||
det.getRxDbitList().tsquash("inconsistent rx dbit list to test"),
|
||||
det.getRxDbitReorder().tsquash("inconsistent rx dbit reorder to test"),
|
||||
det.getTransceiverEnableMask().tsquash(
|
||||
"inconsistent transceiver mask to test")};
|
||||
|
||||
if (det.getDetectorType().tsquash("inconsistent detector type to test") ==
|
||||
slsDetectorDefs::CHIPTESTBOARD) {
|
||||
ctb_config_info.ten_giga =
|
||||
det.getTenGiga().tsquash("inconsistent ten giga enable to test");
|
||||
ctb_config_info.adc_enable_1g = det.getADCEnableMask().tsquash(
|
||||
"inconsistent adc enable mask to test");
|
||||
}
|
||||
return ctb_config_info;
|
||||
}
|
||||
|
||||
void set_ctb_config_state(Detector &det,
|
||||
const testCtbAcquireInfo &ctb_config_info) {
|
||||
det.setReadoutMode(ctb_config_info.readout_mode);
|
||||
if (det.getDetectorType().tsquash("inconsistent detector type to test") ==
|
||||
slsDetectorDefs::CHIPTESTBOARD) {
|
||||
det.setTenGiga(ctb_config_info.ten_giga);
|
||||
det.setADCEnableMask(ctb_config_info.adc_enable_1g);
|
||||
}
|
||||
det.setNumberOfAnalogSamples(ctb_config_info.num_adc_samples);
|
||||
det.setNumberOfDigitalSamples(ctb_config_info.num_dbit_samples);
|
||||
det.setNumberOfTransceiverSamples(ctb_config_info.num_trans_samples);
|
||||
det.setTenGigaADCEnableMask(ctb_config_info.adc_enable_10g);
|
||||
det.setRxDbitOffset(ctb_config_info.dbit_offset);
|
||||
det.setRxDbitList(ctb_config_info.dbit_list);
|
||||
det.setRxDbitReorder(ctb_config_info.dbit_reorder);
|
||||
det.setTransceiverEnableMask(ctb_config_info.transceiver_mask);
|
||||
}
|
||||
|
||||
uint64_t calculate_ctb_image_size(const testCtbAcquireInfo &test_info) {
|
||||
uint64_t num_analog_bytes = 0, num_digital_bytes = 0,
|
||||
num_transceiver_bytes = 0;
|
||||
if (test_info.readout_mode == defs::ANALOG_ONLY ||
|
||||
test_info.readout_mode == defs::ANALOG_AND_DIGITAL) {
|
||||
uint32_t adc_enable_mask =
|
||||
(test_info.ten_giga ? test_info.adc_enable_10g
|
||||
: test_info.adc_enable_1g);
|
||||
int num_analog_chans = __builtin_popcount(adc_enable_mask);
|
||||
const int num_bytes_per_sample = 2;
|
||||
num_analog_bytes =
|
||||
num_analog_chans * num_bytes_per_sample * test_info.num_adc_samples;
|
||||
LOG(logDEBUG1) << "[Analog Databytes: " << num_analog_bytes << ']';
|
||||
}
|
||||
|
||||
// digital channels
|
||||
if (test_info.readout_mode == defs::DIGITAL_ONLY ||
|
||||
test_info.readout_mode == defs::ANALOG_AND_DIGITAL ||
|
||||
test_info.readout_mode == defs::DIGITAL_AND_TRANSCEIVER) {
|
||||
int num_digital_samples = test_info.num_dbit_samples;
|
||||
if (test_info.dbit_offset > 0) {
|
||||
uint64_t num_digital_bytes_reserved =
|
||||
num_digital_samples * sizeof(uint64_t);
|
||||
num_digital_bytes_reserved -= test_info.dbit_offset;
|
||||
num_digital_samples = num_digital_bytes_reserved / sizeof(uint64_t);
|
||||
}
|
||||
int num_digital_chans = test_info.dbit_list.size();
|
||||
if (num_digital_chans == 0) {
|
||||
num_digital_chans = 64;
|
||||
}
|
||||
if (!test_info.dbit_reorder) {
|
||||
uint32_t num_bits_per_sample = num_digital_chans;
|
||||
if (num_bits_per_sample % 8 != 0) {
|
||||
num_bits_per_sample += (8 - (num_bits_per_sample % 8));
|
||||
}
|
||||
num_digital_bytes = (num_bits_per_sample / 8) * num_digital_samples;
|
||||
} else {
|
||||
uint32_t num_bits_per_bit = num_digital_samples;
|
||||
if (num_bits_per_bit % 8 != 0) {
|
||||
num_bits_per_bit += (8 - (num_bits_per_bit % 8));
|
||||
}
|
||||
num_digital_bytes = num_digital_chans * (num_bits_per_bit / 8);
|
||||
}
|
||||
LOG(logDEBUG1) << "[Digital Databytes: " << num_digital_bytes << ']';
|
||||
}
|
||||
// transceiver channels
|
||||
if (test_info.readout_mode == defs::TRANSCEIVER_ONLY ||
|
||||
test_info.readout_mode == defs::DIGITAL_AND_TRANSCEIVER) {
|
||||
int num_transceiver_chans =
|
||||
__builtin_popcount(test_info.transceiver_mask);
|
||||
const int num_bytes_per_channel = 8;
|
||||
num_transceiver_bytes = num_transceiver_chans * num_bytes_per_channel *
|
||||
test_info.num_trans_samples;
|
||||
LOG(logDEBUG1) << "[Transceiver Databytes: " << num_transceiver_bytes
|
||||
<< ']';
|
||||
}
|
||||
|
||||
uint64_t image_size =
|
||||
num_analog_bytes + num_digital_bytes + num_transceiver_bytes;
|
||||
LOG(logDEBUG1) << "Expected image size: " << image_size;
|
||||
return image_size;
|
||||
}
|
||||
|
||||
void test_ctb_acquire_with_receiver(const testCtbAcquireInfo &test_info,
|
||||
int64_t num_frames_to_acquire,
|
||||
Detector &det, Caller &caller) {
|
||||
|
||||
// save previous state
|
||||
testFileInfo prev_file_info = get_file_state(det);
|
||||
testCommonDetAcquireInfo prev_det_config_info =
|
||||
// overwrite exptime if not using virtual ctb server
|
||||
get_common_acquire_config_state(det);
|
||||
testCtbAcquireInfo prev_ctb_config_info = get_ctb_config_state(det);
|
||||
|
||||
// defaults
|
||||
testFileInfo test_file_info;
|
||||
set_file_state(det, test_file_info);
|
||||
testCommonDetAcquireInfo det_config;
|
||||
det_config.num_frames_to_acquire = num_frames_to_acquire;
|
||||
set_common_acquire_config_state(det, det_config);
|
||||
|
||||
// set ctb config
|
||||
set_ctb_config_state(det, test_info);
|
||||
|
||||
// acquire
|
||||
REQUIRE_NOTHROW(test_acquire_with_receiver(caller, det));
|
||||
|
||||
// check frames caught
|
||||
REQUIRE_NOTHROW(test_frames_caught(det, num_frames_to_acquire));
|
||||
|
||||
// check file size (assuming local pc)
|
||||
uint64_t expected_image_size = calculate_ctb_image_size(test_info);
|
||||
REQUIRE_NOTHROW(test_acquire_binary_file_size(
|
||||
test_file_info, num_frames_to_acquire, expected_image_size));
|
||||
|
||||
// restore previous state
|
||||
set_file_state(det, prev_file_info);
|
||||
set_common_acquire_config_state(det, prev_det_config_info);
|
||||
set_ctb_config_state(det, prev_ctb_config_info);
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
|
@ -1,9 +1,46 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
#pragma once
|
||||
|
||||
class Caller;
|
||||
#include "sls/Detector.h"
|
||||
#include "sls/sls_detector_defs.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
|
||||
namespace sls {
|
||||
struct testFileInfo {
|
||||
std::string file_path{"/tmp"};
|
||||
std::string file_prefix{"sls_test"};
|
||||
int64_t file_acq_index{0};
|
||||
bool file_write{true};
|
||||
bool file_overwrite{true};
|
||||
slsDetectorDefs::fileFormat file_format{slsDetectorDefs::BINARY};
|
||||
};
|
||||
|
||||
struct testCommonDetAcquireInfo {
|
||||
slsDetectorDefs::timingMode timing_mode{slsDetectorDefs::AUTO_TIMING};
|
||||
int64_t num_frames_to_acquire{2};
|
||||
int64_t num_triggers{1};
|
||||
std::chrono::nanoseconds period{std::chrono::milliseconds{2}};
|
||||
};
|
||||
|
||||
struct testCtbAcquireInfo {
|
||||
defs::readoutMode readout_mode{defs::ANALOG_AND_DIGITAL};
|
||||
bool ten_giga{false};
|
||||
int num_adc_samples{5000};
|
||||
int num_dbit_samples{6000};
|
||||
int num_trans_samples{288};
|
||||
uint32_t adc_enable_1g{0xFFFFFF00};
|
||||
uint32_t adc_enable_10g{0xFF00FFFF};
|
||||
int dbit_offset{0};
|
||||
std::vector<int> dbit_list{0, 12, 2, 43};
|
||||
bool dbit_reorder{false};
|
||||
uint32_t transceiver_mask{0x3};
|
||||
};
|
||||
|
||||
void test_valid_port_caller(const std::string &command,
|
||||
const std::vector<std::string> &arguments,
|
||||
int detector_id, int action);
|
||||
@ -13,4 +50,26 @@ void test_dac_caller(slsDetectorDefs::dacIndex index,
|
||||
void test_onchip_dac_caller(slsDetectorDefs::dacIndex index,
|
||||
const std::string &dacname, int dacvalue);
|
||||
|
||||
testFileInfo get_file_state(const Detector &det);
|
||||
void set_file_state(Detector &det, const testFileInfo &file_info);
|
||||
void test_acquire_binary_file_size(const testFileInfo &file_info,
|
||||
uint64_t num_frames_to_acquire,
|
||||
uint64_t expected_image_size);
|
||||
|
||||
void test_frames_caught(const Detector &det, int num_frames_to_acquire);
|
||||
|
||||
void test_acquire_with_receiver(Caller &caller, const Detector &det);
|
||||
|
||||
testCommonDetAcquireInfo get_common_acquire_config_state(const Detector &det);
|
||||
void set_common_acquire_config_state(
|
||||
Detector &det, const testCommonDetAcquireInfo &det_config_info);
|
||||
|
||||
testCtbAcquireInfo get_ctb_config_state(const Detector &det);
|
||||
void set_ctb_config_state(Detector &det,
|
||||
const testCtbAcquireInfo &ctb_config_info);
|
||||
uint64_t calculate_ctb_image_size(const testCtbAcquireInfo &test_info);
|
||||
void test_ctb_acquire_with_receiver(const testCtbAcquireInfo &test_info,
|
||||
int64_t num_frames_to_acquire,
|
||||
Detector &det, Caller &caller);
|
||||
|
||||
} // namespace sls
|
||||
|
@ -17,6 +17,69 @@ namespace sls {
|
||||
using test::GET;
|
||||
using test::PUT;
|
||||
|
||||
TEST_CASE("gotthard2_acquire_check_file_size", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
|
||||
if (det_type == defs::GOTTHARD2) {
|
||||
|
||||
// save previous state
|
||||
testFileInfo prev_file_info = get_file_state(det);
|
||||
testCommonDetAcquireInfo prev_det_config_info =
|
||||
get_common_acquire_config_state(det);
|
||||
|
||||
// save previous specific det type config
|
||||
auto exptime = det.getExptime().tsquash("inconsistent exptime to test");
|
||||
auto burst_mode =
|
||||
det.getBurstMode().tsquash("inconsistent burst mode to test");
|
||||
auto number_of_bursts = det.getNumberOfBursts().tsquash(
|
||||
"inconsistent number of bursts to test");
|
||||
auto burst_period =
|
||||
det.getBurstPeriod().tsquash("inconsistent burst period to test");
|
||||
|
||||
// defaults
|
||||
int num_frames_to_acquire = 2;
|
||||
testFileInfo test_file_info;
|
||||
set_file_state(det, test_file_info);
|
||||
testCommonDetAcquireInfo det_config;
|
||||
det_config.num_frames_to_acquire = num_frames_to_acquire;
|
||||
set_common_acquire_config_state(det, det_config);
|
||||
|
||||
// set default specific det type config
|
||||
det.setExptime(std::chrono::microseconds{200});
|
||||
det.setBurstMode(defs::CONTINUOUS_EXTERNAL);
|
||||
det.setNumberOfBursts(1);
|
||||
det.setBurstPeriod(std::chrono::milliseconds{0});
|
||||
|
||||
// acquire
|
||||
test_acquire_with_receiver(caller, det);
|
||||
|
||||
// check frames caught
|
||||
test_frames_caught(det, num_frames_to_acquire);
|
||||
|
||||
// check file size (assuming local pc)
|
||||
{
|
||||
detParameters par(det_type);
|
||||
int bytes_per_pixel = det.getDynamicRange().squash() / 8;
|
||||
size_t expected_image_size =
|
||||
par.nChanX * par.nChipX * bytes_per_pixel;
|
||||
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
|
||||
expected_image_size);
|
||||
}
|
||||
// restore previous state
|
||||
set_file_state(det, prev_file_info);
|
||||
set_common_acquire_config_state(det, prev_det_config_info);
|
||||
|
||||
// restore previous specific det type config
|
||||
det.setExptime(exptime);
|
||||
det.setBurstMode(burst_mode);
|
||||
det.setNumberOfBursts(number_of_bursts);
|
||||
det.setBurstPeriod(burst_period);
|
||||
}
|
||||
}
|
||||
|
||||
// time specific measurements for gotthard2
|
||||
TEST_CASE("timegotthard2", "[.cmdcall]") {
|
||||
Detector det;
|
||||
|
@ -15,6 +15,65 @@ namespace sls {
|
||||
using test::GET;
|
||||
using test::PUT;
|
||||
|
||||
TEST_CASE("jungfrau_acquire_check_file_size", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
|
||||
if (det_type == defs::JUNGFRAU) {
|
||||
|
||||
// save previous state
|
||||
testFileInfo prev_file_info = get_file_state(det);
|
||||
testCommonDetAcquireInfo prev_det_config_info =
|
||||
get_common_acquire_config_state(det);
|
||||
|
||||
// save previous specific det type config
|
||||
auto exptime = det.getExptime().tsquash("inconsistent exptime to test");
|
||||
auto num_udp_interfaces = det.getNumberofUDPInterfaces().tsquash(
|
||||
"inconsistent number of udp interfaces");
|
||||
auto n_rows =
|
||||
det.getReadNRows().tsquash("inconsistent number of rows to test");
|
||||
|
||||
// defaults
|
||||
int num_frames_to_acquire = 2;
|
||||
testFileInfo test_file_info;
|
||||
set_file_state(det, test_file_info);
|
||||
testCommonDetAcquireInfo det_config;
|
||||
det_config.num_frames_to_acquire = num_frames_to_acquire;
|
||||
set_common_acquire_config_state(det, det_config);
|
||||
|
||||
// set default specific det type config
|
||||
det.setExptime(std::chrono::microseconds{200});
|
||||
det.setReadNRows(512);
|
||||
|
||||
// acquire
|
||||
test_acquire_with_receiver(caller, det);
|
||||
|
||||
// check frames caught
|
||||
test_frames_caught(det, num_frames_to_acquire);
|
||||
|
||||
// check file size (assuming local pc)
|
||||
{
|
||||
detParameters par(det_type);
|
||||
int bytes_per_pixel = det.getDynamicRange().squash() / 8;
|
||||
// if 2 udp interfaces, data split into half
|
||||
size_t expected_image_size = (par.nChanX * par.nChanY * par.nChipX *
|
||||
par.nChipY * bytes_per_pixel) /
|
||||
num_udp_interfaces;
|
||||
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
|
||||
expected_image_size);
|
||||
}
|
||||
// restore previous state
|
||||
set_file_state(det, prev_file_info);
|
||||
set_common_acquire_config_state(det, prev_det_config_info);
|
||||
|
||||
// restore previous specific det type config
|
||||
det.setExptime(exptime);
|
||||
det.setReadNRows(n_rows);
|
||||
}
|
||||
}
|
||||
|
||||
/* dacs */
|
||||
|
||||
TEST_CASE("Setting and reading back Jungfrau dacs", "[.cmdcall][.dacs]") {
|
||||
|
@ -15,6 +15,66 @@ namespace sls {
|
||||
using test::GET;
|
||||
using test::PUT;
|
||||
|
||||
TEST_CASE("moench_acquire_check_file_size", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
|
||||
if (det_type == defs::MOENCH) {
|
||||
|
||||
// save previous state
|
||||
testFileInfo prev_file_info = get_file_state(det);
|
||||
testCommonDetAcquireInfo prev_det_config_info =
|
||||
get_common_acquire_config_state(det);
|
||||
|
||||
// save previous specific det type config
|
||||
auto exptime = det.getExptime().tsquash("inconsistent exptime to test");
|
||||
auto num_udp_interfaces = det.getNumberofUDPInterfaces().tsquash(
|
||||
"inconsistent number of udp interfaces");
|
||||
auto n_rows =
|
||||
det.getReadNRows().tsquash("inconsistent number of rows to test");
|
||||
|
||||
// defaults
|
||||
int num_frames_to_acquire = 2;
|
||||
testFileInfo test_file_info;
|
||||
set_file_state(det, test_file_info);
|
||||
testCommonDetAcquireInfo det_config;
|
||||
det_config.num_frames_to_acquire = num_frames_to_acquire;
|
||||
set_common_acquire_config_state(det, det_config);
|
||||
|
||||
// set default specific det type config
|
||||
det.setExptime(std::chrono::microseconds{200});
|
||||
det.setReadNRows(400);
|
||||
|
||||
// acquire
|
||||
test_acquire_with_receiver(caller, det);
|
||||
|
||||
// check frames caught
|
||||
test_frames_caught(det, num_frames_to_acquire);
|
||||
|
||||
// check file size (assuming local pc)
|
||||
{
|
||||
detParameters par(det_type);
|
||||
int bytes_per_pixel = det.getDynamicRange().squash() / 8;
|
||||
// if 2 udp interfaces, data split into half
|
||||
size_t expected_image_size = (par.nChanX * par.nChanY * par.nChipX *
|
||||
par.nChipY * bytes_per_pixel) /
|
||||
num_udp_interfaces;
|
||||
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
|
||||
expected_image_size);
|
||||
}
|
||||
|
||||
// restore previous state
|
||||
set_file_state(det, prev_file_info);
|
||||
set_common_acquire_config_state(det, prev_det_config_info);
|
||||
|
||||
// restore previous specific det type config
|
||||
det.setExptime(exptime);
|
||||
det.setReadNRows(n_rows);
|
||||
}
|
||||
}
|
||||
|
||||
/* dacs */
|
||||
|
||||
TEST_CASE("Setting and reading back moench dacs", "[.cmdcall][.dacs]") {
|
||||
|
@ -17,6 +17,74 @@ namespace sls {
|
||||
using test::GET;
|
||||
using test::PUT;
|
||||
|
||||
TEST_CASE("mythen3_acquire_check_file_size", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
auto det_type =
|
||||
det.getDetectorType().tsquash("Inconsistent detector types to test");
|
||||
|
||||
if (det_type == defs::MYTHEN3) {
|
||||
|
||||
// save previous state
|
||||
testFileInfo prev_file_info = get_file_state(det);
|
||||
testCommonDetAcquireInfo prev_det_config_info =
|
||||
get_common_acquire_config_state(det);
|
||||
|
||||
// save previous specific det type config
|
||||
auto exptime =
|
||||
det.getExptimeForAllGates().tsquash("inconsistent exptime to test");
|
||||
auto dynamic_range =
|
||||
det.getDynamicRange().tsquash("inconsistent dynamic range to test");
|
||||
uint32_t counter_mask =
|
||||
det.getCounterMask().tsquash("inconsistent counter mask to test");
|
||||
|
||||
// defaults
|
||||
int num_frames_to_acquire = 2;
|
||||
testFileInfo test_file_info;
|
||||
set_file_state(det, test_file_info);
|
||||
testCommonDetAcquireInfo det_config;
|
||||
det_config.num_frames_to_acquire = num_frames_to_acquire;
|
||||
set_common_acquire_config_state(det, det_config);
|
||||
|
||||
// set default specific det type config
|
||||
det.setExptime(-1, std::chrono::microseconds{200});
|
||||
int test_dynamic_range = 16;
|
||||
det.setDynamicRange(test_dynamic_range);
|
||||
int test_counter_mask = 0x3;
|
||||
int num_counters = __builtin_popcount(test_counter_mask);
|
||||
det.setCounterMask(test_counter_mask);
|
||||
|
||||
// acquire
|
||||
test_acquire_with_receiver(caller, det);
|
||||
|
||||
// check frames caught
|
||||
test_frames_caught(det, num_frames_to_acquire);
|
||||
|
||||
// check file size (assuming local pc)
|
||||
{
|
||||
detParameters par(det_type);
|
||||
int bytes_per_pixel = test_dynamic_range / 8;
|
||||
int num_channels_per_counter = par.nChanX / 3;
|
||||
size_t expected_image_size = num_channels_per_counter *
|
||||
num_counters * par.nChipX *
|
||||
bytes_per_pixel;
|
||||
test_acquire_binary_file_size(test_file_info, num_frames_to_acquire,
|
||||
expected_image_size);
|
||||
}
|
||||
|
||||
// restore previous state
|
||||
set_file_state(det, prev_file_info);
|
||||
set_common_acquire_config_state(det, prev_det_config_info);
|
||||
|
||||
// restore previous specific det type config
|
||||
for (int iGate = 0; iGate < 3; ++iGate) {
|
||||
det.setExptime(iGate, exptime[iGate]);
|
||||
}
|
||||
det.setDynamicRange(dynamic_range);
|
||||
det.setCounterMask(counter_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/* dacs */
|
||||
|
||||
TEST_CASE("Setting and reading back MYTHEN3 dacs", "[.cmdcall][.dacs]") {
|
||||
|
@ -466,7 +466,6 @@ TEST_CASE("rx_arping", "[.cmdcall][.rx]") {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("rx_roi", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
@ -479,33 +478,69 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
|
||||
defs::xy detsize = det.getDetectorSize();
|
||||
|
||||
// 1d
|
||||
if (det_type == defs::GOTTHARD || det_type == defs::GOTTHARD2 ||
|
||||
det_type == defs::MYTHEN3) {
|
||||
if (det_type == defs::GOTTHARD2 || det_type == defs::MYTHEN3) {
|
||||
{
|
||||
std::ostringstream oss;
|
||||
caller.call("rx_roi", {"5", "10"}, -1, PUT, oss);
|
||||
REQUIRE(oss.str() == "rx_roi [5, 10]\n");
|
||||
REQUIRE(oss.str() == "rx_roi [[5, 10]]\n");
|
||||
}
|
||||
{
|
||||
std::ostringstream oss;
|
||||
caller.call("rx_roi", {"10", "15"}, -1, PUT, oss);
|
||||
REQUIRE(oss.str() == "rx_roi [10, 15]\n");
|
||||
REQUIRE(oss.str() == "rx_roi [[10, 15]]\n");
|
||||
}
|
||||
REQUIRE_THROWS(caller.call("rx_roi", {"0", "0"}, -1, PUT));
|
||||
REQUIRE_THROWS(caller.call("rx_roi", {"-1", "-1"}, -1, PUT));
|
||||
REQUIRE_THROWS(
|
||||
caller.call("rx_roi", {"10", "15", "25", "30"}, -1, PUT));
|
||||
// xmin > xmax
|
||||
REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, -1, -1]"}, -1, PUT));
|
||||
// outside detector bounds
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi",
|
||||
{"[95," + std::to_string(detsize.x + 5) + ", -1, -1]"}, -1,
|
||||
PUT));
|
||||
// module level not allowed
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 10, -1, -1]"}, 0, PUT));
|
||||
|
||||
// vector of rois
|
||||
// square brackets missing
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 20, -1, -1; 25, 30, -1, -1]"}, -1, PUT));
|
||||
// invalid roi, 4 parts expected
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 20, -1]; [25, 30, -1, -1]"}, -1, PUT));
|
||||
// overlapping rois
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[0, 10,-1, -1];[5, 15, -1, -1]"}, -1, PUT));
|
||||
|
||||
if (det.size() == 2) {
|
||||
auto moduleSize = det.getModuleSize()[0];
|
||||
std::string stringMin = std::to_string(moduleSize.x);
|
||||
std::string stringMax = std::to_string(moduleSize.x + 1);
|
||||
|
||||
// separated by space is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, -1, -1]", "[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT));
|
||||
std::ostringstream oss;
|
||||
// separated by semicolon is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, -1, -1];[" + stringMin + ", " + stringMax + ", -1, -1]"}, -1, PUT, oss));
|
||||
REQUIRE(oss.str() ==
|
||||
"rx_roi [[5, 10], [" + stringMin + ", " + stringMax + "]]\n");
|
||||
|
||||
}
|
||||
}
|
||||
// 2d
|
||||
// 2d eiger, jungfrau, moench
|
||||
else {
|
||||
{
|
||||
std::ostringstream oss;
|
||||
caller.call("rx_roi", {"10", "15", "1", "5"}, -1, PUT, oss);
|
||||
REQUIRE(oss.str() == "rx_roi [10, 15, 1, 5]\n");
|
||||
REQUIRE(oss.str() == "rx_roi [[10, 15, 1, 5]]\n");
|
||||
}
|
||||
{
|
||||
std::ostringstream oss;
|
||||
caller.call("rx_roi", {"10", "22", "18", "19"}, -1, PUT, oss);
|
||||
REQUIRE(oss.str() == "rx_roi [10, 22, 18, 19]\n");
|
||||
REQUIRE(oss.str() == "rx_roi [[10, 22, 18, 19]]\n");
|
||||
}
|
||||
{
|
||||
std::ostringstream oss;
|
||||
@ -513,14 +548,104 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
|
||||
{"1", std::to_string(detsize.x - 5), "1",
|
||||
std::to_string(detsize.y - 5)},
|
||||
-1, PUT, oss);
|
||||
REQUIRE(oss.str() == std::string("rx_roi [1, ") +
|
||||
REQUIRE(oss.str() == std::string("rx_roi [[1, ") +
|
||||
std::to_string(detsize.x - 5) +
|
||||
std::string(", 1, ") +
|
||||
std::to_string(detsize.y - 5) +
|
||||
std::string("]\n"));
|
||||
std::string("]]\n"));
|
||||
}
|
||||
REQUIRE_THROWS(
|
||||
caller.call("rx_roi", {"0", "0", "0", "0"}, -1, PUT));
|
||||
REQUIRE_THROWS(
|
||||
caller.call("rx_roi", {"-1", "-1", "-1", "-1"}, -1, PUT));
|
||||
// xmin > xmax
|
||||
REQUIRE_THROWS(caller.call("rx_roi", {"[12, 8, 0, 10]"}, -1, PUT));
|
||||
// ymin > ymax
|
||||
REQUIRE_THROWS(caller.call("rx_roi", {"[0, 10, 20, 5]"}, -1, PUT));
|
||||
// outside detector bounds
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[95," + std::to_string(detsize.x + 5) + ", 0, 10]"},
|
||||
-1, PUT));
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi",
|
||||
{"[95, 100, 0, " + std::to_string(detsize.y + 5) + "]"}, -1,
|
||||
PUT));
|
||||
// module level not allowed
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 10, 20, 30]"}, 0, PUT));
|
||||
|
||||
// vector of rois
|
||||
// square brackets missing
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 20, 20, 30; 25, 30, 14, 15]"}, -1, PUT));
|
||||
// invalid roi, 4 parts expected
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[5, 20, 20]; [25, 30, 14, 15]"}, -1, PUT));
|
||||
// overlapping rois
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[0, 10, 0, 10];[5, 15, 0, 10]"}, -1, PUT));
|
||||
REQUIRE_THROWS(caller.call(
|
||||
"rx_roi", {"[0, 10, 0, 10];[0, 10, 9, 11]"}, -1, PUT));
|
||||
|
||||
auto portSize = det.getPortSize()[0];
|
||||
if (det_type == defs::EIGER) {
|
||||
std::string stringMin = std::to_string(portSize.x);
|
||||
std::string stringMax = std::to_string(portSize.x + 1);
|
||||
|
||||
// separated by space is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, 20, 30]", "[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT));
|
||||
std::ostringstream oss;
|
||||
// separated by semicolon is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, 20, 30];[" + stringMin + ", " + stringMax + ", 20, 30]"}, -1, PUT, oss));
|
||||
REQUIRE(oss.str() ==
|
||||
"rx_roi [[5, 10, 20, 30], [" + stringMin + ", " + stringMax + ", 20, 30]]\n");
|
||||
}
|
||||
if (det_type == defs::JUNGFRAU || det_type == defs::MOENCH) {
|
||||
// 2 interfaces or 2 modules
|
||||
if ((det.getNumberofUDPInterfaces().tsquash(
|
||||
"inconsistent number of interfaces") == 2) || (det.size() == 2)) {
|
||||
std::string stringMin = std::to_string(portSize.y);
|
||||
std::string stringMax = std::to_string(portSize.y + 1);
|
||||
if (det.size() == 2) {
|
||||
auto moduleSize = det.getModuleSize()[0];
|
||||
stringMin = std::to_string(moduleSize.y);
|
||||
stringMax = std::to_string(moduleSize.y + 1);
|
||||
}
|
||||
|
||||
// separated by space is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, 20, 30]", "[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT));
|
||||
std::ostringstream oss;
|
||||
// separated by semicolon is allowed
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[5, 10, 20, 30];[25, 28, " + stringMin + ", " + stringMax + "]"}, -1, PUT, oss));
|
||||
REQUIRE(oss.str() ==
|
||||
"rx_roi [[5, 10, 20, 30], [25, 28, " + stringMin + ", " + stringMax + "]]\n");
|
||||
|
||||
// verify individual roi
|
||||
if (det_type == defs::JUNGFRAU) {
|
||||
std::ostringstream oss, oss1;
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[100,500,100,400]"}, -1, PUT, oss));
|
||||
REQUIRE(oss.str() == "rx_roi [[100, 500, 100, 400]]\n");
|
||||
REQUIRE_NOTHROW(
|
||||
caller.call("rx_roi", {}, 0, GET, oss1));
|
||||
REQUIRE(oss1.str() == "rx_roi [[[100, 500, 100, 255], "
|
||||
"[100, 500, 256, 400]]]\n");
|
||||
} else {
|
||||
std::ostringstream oss, oss1;
|
||||
REQUIRE_NOTHROW(caller.call(
|
||||
"rx_roi", {"[100,200,100,300]"}, -1, PUT, oss));
|
||||
REQUIRE(oss.str() == "rx_roi [[100, 200, 100, 300]]\n");
|
||||
REQUIRE_NOTHROW(
|
||||
caller.call("rx_roi", {}, 0, GET, oss1));
|
||||
REQUIRE(oss1.str() == "rx_roi [[[100, 200, 100, 199], "
|
||||
"[100, 200, 200, 300]]]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i != det.size(); ++i) {
|
||||
@ -529,6 +654,7 @@ TEST_CASE("rx_roi", "[.cmdcall]") {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("rx_clearroi", "[.cmdcall]") {
|
||||
Detector det;
|
||||
Caller caller(&det);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <thread>
|
||||
|
||||
#include "tests/globals.h"
|
||||
#include <filesystem>
|
||||
|
||||
namespace sls {
|
||||
|
||||
|
@ -1693,19 +1693,19 @@ int ClientInterface::set_arping(Interface &socket) {
|
||||
}
|
||||
|
||||
int ClientInterface::get_receiver_roi(Interface &socket) {
|
||||
auto retval = impl()->getReceiverROI();
|
||||
LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retval);
|
||||
return socket.sendResult(retval);
|
||||
auto retvals = impl()->getPortROIs();
|
||||
LOG(logDEBUG1) << "Receiver roi retval:" << ToString(retvals);
|
||||
return socket.sendResult(retvals);
|
||||
}
|
||||
|
||||
int ClientInterface::set_receiver_roi(Interface &socket) {
|
||||
auto arg = socket.Receive<ROI>();
|
||||
auto args = socket.Receive<std::array<ROI, 2>>();
|
||||
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
|
||||
functionNotImplemented();
|
||||
LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(arg);
|
||||
LOG(logDEBUG1) << "Set Receiver ROI: " << ToString(args);
|
||||
verifyIdle(socket);
|
||||
try {
|
||||
impl()->setReceiverROI(arg);
|
||||
impl()->setPortROIs(args);
|
||||
} catch (const std::exception &e) {
|
||||
throw RuntimeError("Could not set Receiver ROI [" +
|
||||
std::string(e.what()) + ']');
|
||||
@ -1715,18 +1715,22 @@ int ClientInterface::set_receiver_roi(Interface &socket) {
|
||||
}
|
||||
|
||||
int ClientInterface::set_receiver_roi_metadata(Interface &socket) {
|
||||
auto arg = socket.Receive<ROI>();
|
||||
auto roiSize = socket.Receive<int>();
|
||||
LOG(logDEBUG) << "Number of ReceiverROI metadata: " << roiSize;
|
||||
std::vector<ROI> rois(roiSize);
|
||||
if (roiSize > 0) {
|
||||
socket.Receive(rois);
|
||||
}
|
||||
if (detType == CHIPTESTBOARD || detType == XILINX_CHIPTESTBOARD)
|
||||
functionNotImplemented();
|
||||
LOG(logDEBUG1) << "Set Receiver ROI Metadata: " << ToString(arg);
|
||||
verifyIdle(socket);
|
||||
LOG(logINFO) << "Setting ReceiverROI metadata[" << roiSize << ']';
|
||||
try {
|
||||
impl()->setReceiverROIMetadata(arg);
|
||||
impl()->setMultiROIMetadata(rois);
|
||||
} catch (const std::exception &e) {
|
||||
throw RuntimeError("Could not set ReceiverROI metadata [" +
|
||||
std::string(e.what()) + ']');
|
||||
}
|
||||
|
||||
return socket.Send(OK);
|
||||
}
|
||||
|
||||
|
@ -48,10 +48,10 @@ void DataProcessor::SetUdpPortNumber(const uint16_t portNumber) {
|
||||
|
||||
void DataProcessor::SetActivate(bool enable) { activated = enable; }
|
||||
|
||||
void DataProcessor::SetReceiverROI(ROI roi) {
|
||||
receiverRoi = roi;
|
||||
receiverRoiEnabled = receiverRoi.completeRoi() ? false : true;
|
||||
receiverNoRoi = receiverRoi.noRoi();
|
||||
void DataProcessor::SetPortROI(ROI roi) {
|
||||
portRoi = roi;
|
||||
isPartiallyInRoi = portRoi.completeRoi() ? false : true;
|
||||
isOutsideRoi = portRoi.noRoi();
|
||||
}
|
||||
|
||||
void DataProcessor::SetDataStreamEnable(bool enable) {
|
||||
@ -154,17 +154,17 @@ void DataProcessor::CreateFirstFiles(const std::string &fileNamePrefix,
|
||||
CloseFiles();
|
||||
|
||||
// deactivated (half module/ single port or no roi), dont write file
|
||||
if (!activated || !detectorDataStream || receiverNoRoi) {
|
||||
if (!activated || !detectorDataStream || isOutsideRoi) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HDF5C
|
||||
int nx = generalData->nPixelsX;
|
||||
int ny = generalData->nPixelsY;
|
||||
if (receiverRoiEnabled) {
|
||||
nx = receiverRoi.xmax - receiverRoi.xmin + 1;
|
||||
ny = receiverRoi.ymax - receiverRoi.ymin + 1;
|
||||
if (receiverRoi.ymax == -1 || receiverRoi.ymin == -1) {
|
||||
if (isPartiallyInRoi) {
|
||||
nx = portRoi.xmax - portRoi.xmin + 1;
|
||||
ny = portRoi.ymax - portRoi.ymin + 1;
|
||||
if (portRoi.ymax == -1 || portRoi.ymin == -1) {
|
||||
ny = 1;
|
||||
}
|
||||
}
|
||||
@ -203,7 +203,7 @@ std::string DataProcessor::CreateVirtualFile(
|
||||
const int modulePos, const int numModX, const int numModY,
|
||||
std::mutex *hdf5LibMutex) {
|
||||
|
||||
if (receiverRoiEnabled) {
|
||||
if (isPartiallyInRoi) {
|
||||
throw std::runtime_error(
|
||||
"Skipping virtual hdf5 file since rx_roi is enabled.");
|
||||
}
|
||||
@ -235,7 +235,7 @@ void DataProcessor::LinkFileInMaster(const std::string &masterFileName,
|
||||
const bool silentMode,
|
||||
std::mutex *hdf5LibMutex) {
|
||||
|
||||
if (receiverRoiEnabled) {
|
||||
if (isPartiallyInRoi) {
|
||||
throw std::runtime_error(
|
||||
"Should not be here, roi with hdf5 virtual should throw.");
|
||||
}
|
||||
@ -301,7 +301,7 @@ void DataProcessor::ThreadExecution() {
|
||||
// stream (if time/freq to stream) or free
|
||||
if (streamCurrentFrame) {
|
||||
// copy the complete image back if roi enabled
|
||||
if (receiverRoiEnabled) {
|
||||
if (isPartiallyInRoi) {
|
||||
memImage->size = generalData->imageSize;
|
||||
memcpy(memImage->data, &completeImageToStreamBeforeCropping[0],
|
||||
generalData->imageSize);
|
||||
@ -352,16 +352,20 @@ void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size,
|
||||
if (framePadding && nump < generalData->packetsPerFrame)
|
||||
PadMissingPackets(header, data);
|
||||
|
||||
// rearrange ctb digital bits
|
||||
if (!generalData->ctbDbitList.empty()) {
|
||||
ArrangeDbitData(size, data);
|
||||
} else if (generalData->ctbDbitReorder) {
|
||||
std::vector<int> ctbDbitList(64);
|
||||
std::iota(ctbDbitList.begin(), ctbDbitList.end(), 0);
|
||||
generalData->SetctbDbitList(ctbDbitList);
|
||||
ArrangeDbitData(size, data);
|
||||
} else if (generalData->ctbDbitOffset > 0) {
|
||||
RemoveTrailingBits(size, data);
|
||||
if (generalData->readoutType == slsDetectorDefs::DIGITAL_ONLY ||
|
||||
generalData->readoutType == slsDetectorDefs::ANALOG_AND_DIGITAL ||
|
||||
generalData->readoutType == slsDetectorDefs::DIGITAL_AND_TRANSCEIVER) {
|
||||
// rearrange ctb digital bits
|
||||
if (!generalData->ctbDbitList.empty()) {
|
||||
ArrangeDbitData(size, data);
|
||||
} else if (generalData->ctbDbitReorder) {
|
||||
std::vector<int> ctbDbitList(64);
|
||||
std::iota(ctbDbitList.begin(), ctbDbitList.end(), 0);
|
||||
generalData->SetctbDbitList(ctbDbitList);
|
||||
ArrangeDbitData(size, data);
|
||||
} else if (generalData->ctbDbitOffset > 0) {
|
||||
RemoveTrailingBits(size, data);
|
||||
}
|
||||
}
|
||||
|
||||
// 'stream Image' check has to be done here before crop image
|
||||
@ -377,7 +381,7 @@ void DataProcessor::ProcessAnImage(sls_receiver_header &header, size_t &size,
|
||||
streamCurrentFrame = false;
|
||||
}
|
||||
|
||||
if (receiverRoiEnabled) {
|
||||
if (isPartiallyInRoi) {
|
||||
// copy the complete image to stream before cropping
|
||||
if (streamCurrentFrame) {
|
||||
memcpy(&completeImageToStreamBeforeCropping[0], data,
|
||||
@ -675,20 +679,20 @@ void DataProcessor::ArrangeDbitData(size_t &size, char *data) {
|
||||
memcpy(data + nAnalogDataBytes, result.data(),
|
||||
totalNumBytes * sizeof(uint8_t));
|
||||
|
||||
LOG(logDEBUG1) << "totalNumBytes: " << totalNumBytes
|
||||
LOG(logDEBUG1) << "nDigitalDataBytes: " << totalNumBytes
|
||||
<< " nAnalogDataBytes:" << nAnalogDataBytes
|
||||
<< " ctbDbitOffset:" << ctbDbitOffset
|
||||
<< " nTransceiverDataBytes:" << nTransceiverDataBytes
|
||||
<< " size:" << size;
|
||||
<< " toal size:" << size;
|
||||
}
|
||||
|
||||
void DataProcessor::CropImage(size_t &size, char *data) {
|
||||
LOG(logDEBUG) << "Cropping Image to ROI " << ToString(receiverRoi);
|
||||
LOG(logDEBUG) << "Cropping Image to ROI " << ToString(portRoi);
|
||||
int nPixelsX = generalData->nPixelsX;
|
||||
int xmin = receiverRoi.xmin;
|
||||
int xmax = receiverRoi.xmax;
|
||||
int ymin = receiverRoi.ymin;
|
||||
int ymax = receiverRoi.ymax;
|
||||
int xmin = portRoi.xmin;
|
||||
int xmax = portRoi.xmax;
|
||||
int ymin = portRoi.ymin;
|
||||
int ymax = portRoi.ymax;
|
||||
int xwidth = xmax - xmin + 1;
|
||||
int ywidth = ymax - ymin + 1;
|
||||
if (ymin == -1 || ymax == -1) {
|
||||
|
@ -39,7 +39,7 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
|
||||
|
||||
void SetUdpPortNumber(const uint16_t portNumber);
|
||||
void SetActivate(bool enable);
|
||||
void SetReceiverROI(ROI roi);
|
||||
void SetPortROI(const ROI arg);
|
||||
void SetDataStreamEnable(bool enable);
|
||||
void SetStreamingFrequency(uint32_t value);
|
||||
void SetStreamingTimerInMs(uint32_t value);
|
||||
@ -159,16 +159,16 @@ class DataProcessor : private virtual slsDetectorDefs, public ThreadObject {
|
||||
uint16_t udpPortNumber{0};
|
||||
bool dataStreamEnable;
|
||||
bool activated{false};
|
||||
ROI receiverRoi{};
|
||||
bool receiverRoiEnabled{false};
|
||||
bool receiverNoRoi{false};
|
||||
ROI portRoi{};
|
||||
bool isPartiallyInRoi{false};
|
||||
bool isOutsideRoi{false};
|
||||
std::unique_ptr<char[]> completeImageToStreamBeforeCropping;
|
||||
/** if 0, sending random images with a timer */
|
||||
uint32_t streamingFrequency;
|
||||
uint32_t streamingTimerInMs;
|
||||
uint32_t streamingStartFnum;
|
||||
uint32_t currentFreqCount{0};
|
||||
struct timespec timerbegin{};
|
||||
struct timespec timerbegin {};
|
||||
bool framePadding;
|
||||
std::atomic<bool> startedFlag{false};
|
||||
std::atomic<uint64_t> firstIndex{0};
|
||||
|
@ -53,7 +53,14 @@ void DataStreamer::SetAdditionalJsonHeader(
|
||||
isAdditionalJsonUpdated = true;
|
||||
}
|
||||
|
||||
void DataStreamer::SetReceiverROI(ROI roi) { receiverRoi = roi; }
|
||||
void DataStreamer::SetPortROI(ROI roi) {
|
||||
if (roi.completeRoi()) {
|
||||
portRoi =
|
||||
ROI(0, generalData->nPixelsX - 1, 0, generalData->nPixelsY - 1);
|
||||
} else {
|
||||
portRoi = roi;
|
||||
}
|
||||
}
|
||||
|
||||
void DataStreamer::ResetParametersforNewAcquisition(const std::string &fname) {
|
||||
StopRunning();
|
||||
@ -210,7 +217,7 @@ int DataStreamer::SendDataHeader(sls_detector_header header, uint32_t size,
|
||||
isAdditionalJsonUpdated = false;
|
||||
}
|
||||
zHeader.addJsonHeader = localAdditionalJsonHeader;
|
||||
zHeader.rx_roi = receiverRoi.getIntArray();
|
||||
zHeader.rx_roi = portRoi.getIntArray();
|
||||
|
||||
return zmqSocket->SendHeader(index, zHeader);
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject {
|
||||
void SetNumberofTotalFrames(uint64_t value);
|
||||
void
|
||||
SetAdditionalJsonHeader(const std::map<std::string, std::string> &json);
|
||||
void SetReceiverROI(ROI roi);
|
||||
void SetPortROI(ROI roi);
|
||||
|
||||
void ResetParametersforNewAcquisition(const std::string &fname);
|
||||
/**
|
||||
@ -91,7 +91,7 @@ class DataStreamer : private virtual slsDetectorDefs, public ThreadObject {
|
||||
uint64_t fileIndex{0};
|
||||
bool flipRows{false};
|
||||
std::map<std::string, std::string> additionalJsonHeader;
|
||||
ROI receiverRoi{};
|
||||
ROI portRoi{};
|
||||
|
||||
/** Used by streamer thread to update local copy (reduce number of locks
|
||||
* during streaming) */
|
||||
|
@ -104,11 +104,11 @@ void zmq_free(void *data, void *hint) { delete[] static_cast<char *>(data); }
|
||||
void print_frames(const PortFrameMap &frame_port_map) {
|
||||
LOG(sls::logDEBUG) << "Printing frames";
|
||||
for (const auto &it : frame_port_map) {
|
||||
uint16_t udpPort = it.first;
|
||||
const uint16_t udpPort = it.first;
|
||||
const auto &frame_map = it.second;
|
||||
LOG(sls::logDEBUG) << "UDP port: " << udpPort;
|
||||
for (const auto &frame : frame_map) {
|
||||
uint64_t fnum = frame.first;
|
||||
const uint64_t fnum = frame.first;
|
||||
const auto &msg_list = frame.second;
|
||||
LOG(sls::logDEBUG)
|
||||
<< " acq index: " << fnum << '[' << msg_list.size() << ']';
|
||||
@ -127,30 +127,26 @@ std::set<uint64_t> get_valid_fnums(const PortFrameMap &port_frame_map) {
|
||||
|
||||
// collect all unique frame numbers from all ports
|
||||
std::set<uint64_t> unique_fnums;
|
||||
for (auto it = port_frame_map.begin(); it != port_frame_map.begin(); ++it) {
|
||||
const FrameMap &frame_map = it->second;
|
||||
for (auto frame = frame_map.begin(); frame != frame_map.end();
|
||||
++frame) {
|
||||
unique_fnums.insert(frame->first);
|
||||
for (const auto &it : port_frame_map) {
|
||||
const FrameMap &frame_map = it.second;
|
||||
for (const auto &frame : frame_map) {
|
||||
unique_fnums.insert(frame.first);
|
||||
}
|
||||
}
|
||||
|
||||
// collect valid frame numbers
|
||||
for (auto &fnum : unique_fnums) {
|
||||
bool is_valid = true;
|
||||
for (auto it = port_frame_map.begin(); it != port_frame_map.end();
|
||||
++it) {
|
||||
uint16_t port = it->first;
|
||||
const FrameMap &frame_map = it->second;
|
||||
for (const auto &it : port_frame_map) {
|
||||
const uint16_t port = it.first;
|
||||
const FrameMap &frame_map = it.second;
|
||||
auto frame = frame_map.find(fnum);
|
||||
// invalid: fnum missing in one port
|
||||
if (frame == frame_map.end()) {
|
||||
LOG(sls::logDEBUG)
|
||||
<< "Fnum " << fnum << " is missing in port " << port;
|
||||
// invalid: fnum greater than all in that port
|
||||
auto last_frame = std::prev(frame_map.end());
|
||||
auto last_fnum = last_frame->first;
|
||||
if (fnum > last_fnum) {
|
||||
auto upper_frame = frame_map.upper_bound(fnum);
|
||||
if (upper_frame == frame_map.end()) {
|
||||
LOG(sls::logDEBUG) << "And no larger fnum found. Fnum "
|
||||
<< fnum << " is invalid.\n";
|
||||
is_valid = false;
|
||||
@ -220,18 +216,26 @@ void Correlate(FrameStatus *stat) {
|
||||
// sending all valid fnum data packets
|
||||
for (const auto &fnum : valid_fnums) {
|
||||
ZmqMsgList msg_list;
|
||||
PortFrameMap &port_frame_map = stat->frames;
|
||||
for (auto it = port_frame_map.begin();
|
||||
it != port_frame_map.end(); ++it) {
|
||||
uint16_t port = it->first;
|
||||
const FrameMap &frame_map = it->second;
|
||||
for (const auto &it : stat->frames) {
|
||||
const uint16_t port = it.first;
|
||||
const FrameMap &frame_map = it.second;
|
||||
auto frame = frame_map.find(fnum);
|
||||
if (frame != frame_map.end()) {
|
||||
msg_list.insert(msg_list.end(),
|
||||
stat->frames[port][fnum].begin(),
|
||||
stat->frames[port][fnum].end());
|
||||
// clean up
|
||||
for (zmq_msg_t *msg : stat->frames[port][fnum]) {
|
||||
}
|
||||
}
|
||||
LOG(printHeadersLevel)
|
||||
<< "Sending data packets for fnum " << fnum;
|
||||
zmq_send_multipart(socket, msg_list);
|
||||
// clean up
|
||||
for (const auto &it : stat->frames) {
|
||||
const uint16_t port = it.first;
|
||||
const FrameMap &frame_map = it.second;
|
||||
auto frame = frame_map.find(fnum);
|
||||
if (frame != frame_map.end()) {
|
||||
for (zmq_msg_t *msg : frame->second) {
|
||||
if (msg) {
|
||||
zmq_msg_close(msg);
|
||||
delete msg;
|
||||
@ -240,9 +244,6 @@ void Correlate(FrameStatus *stat) {
|
||||
stat->frames[port].erase(fnum);
|
||||
}
|
||||
}
|
||||
LOG(printHeadersLevel)
|
||||
<< "Sending data packets for fnum " << fnum;
|
||||
zmq_send_multipart(socket, msg_list);
|
||||
}
|
||||
}
|
||||
// sending all end packets
|
||||
@ -256,6 +257,21 @@ void Correlate(FrameStatus *stat) {
|
||||
}
|
||||
}
|
||||
stat->ends.clear();
|
||||
// clean up old frames
|
||||
for (auto &it : stat->frames) {
|
||||
FrameMap &frame_map = it.second;
|
||||
for (auto &frame : frame_map) {
|
||||
for (zmq_msg_t *msg : frame.second) {
|
||||
if (msg) {
|
||||
zmq_msg_close(msg);
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
frame.second.clear();
|
||||
}
|
||||
frame_map.clear();
|
||||
}
|
||||
stat->frames.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ class GeneralData {
|
||||
slsDetectorDefs::frameDiscardPolicy frameDiscardMode{
|
||||
slsDetectorDefs::NO_DISCARD};
|
||||
|
||||
GeneralData() {};
|
||||
virtual ~GeneralData() {};
|
||||
GeneralData(){};
|
||||
virtual ~GeneralData(){};
|
||||
|
||||
// Returns the pixel depth in byte, 4 bits being 0.5 byte
|
||||
float GetPixelDepth() { return float(dynamicRange) / 8; }
|
||||
|
@ -184,7 +184,7 @@ void Implementation::SetupListener(int i) {
|
||||
listener[i]->SetUdpPortNumber(udpPortNum[i]);
|
||||
listener[i]->SetEthernetInterface(eth[i]);
|
||||
listener[i]->SetActivate(activated);
|
||||
listener[i]->SetNoRoi(portRois[i].noRoi());
|
||||
listener[i]->SetIsOutsideRoi(portRois[i].noRoi());
|
||||
listener[i]->SetDetectorDatastream(detectorDataStream[i]);
|
||||
listener[i]->SetSilentMode(silentMode);
|
||||
}
|
||||
@ -194,7 +194,7 @@ void Implementation::SetupDataProcessor(int i) {
|
||||
dataProcessor[i]->SetGeneralData(generalData);
|
||||
dataProcessor[i]->SetUdpPortNumber(udpPortNum[i]);
|
||||
dataProcessor[i]->SetActivate(activated);
|
||||
dataProcessor[i]->SetReceiverROI(portRois[i]);
|
||||
dataProcessor[i]->SetPortROI(portRois[i]);
|
||||
dataProcessor[i]->SetDataStreamEnable(dataStreamEnable);
|
||||
dataProcessor[i]->SetStreamingFrequency(streamingFrequency);
|
||||
dataProcessor[i]->SetStreamingTimerInMs(streamingTimerInMs);
|
||||
@ -216,8 +216,7 @@ void Implementation::SetupDataStreamer(int i) {
|
||||
dataStreamer[i]->SetFlipRows(flipRows);
|
||||
dataStreamer[i]->SetNumberofPorts(numPorts);
|
||||
dataStreamer[i]->SetNumberofTotalFrames(numberOfTotalFrames);
|
||||
dataStreamer[i]->SetReceiverROI(
|
||||
portRois[i].completeRoi() ? GetMaxROIPerPort() : portRois[i]);
|
||||
dataStreamer[i]->SetPortROI(portRois[i]);
|
||||
}
|
||||
|
||||
slsDetectorDefs::xy Implementation::getDetectorSize() const {
|
||||
@ -233,18 +232,13 @@ const slsDetectorDefs::xy Implementation::GetPortGeometry() const {
|
||||
return portGeometry;
|
||||
}
|
||||
|
||||
const slsDetectorDefs::ROI Implementation::GetMaxROIPerPort() const {
|
||||
return slsDetectorDefs::ROI{0, (int)generalData->nPixelsX - 1, 0,
|
||||
(int)generalData->nPixelsY - 1};
|
||||
}
|
||||
|
||||
void Implementation::setDetectorSize(const slsDetectorDefs::xy size) {
|
||||
xy portGeometry = GetPortGeometry();
|
||||
|
||||
std::string log_message = "Detector Size (ports): (";
|
||||
numModules = size;
|
||||
numPorts.x = portGeometry.x * size.x;
|
||||
numPorts.y = portGeometry.y * size.y;
|
||||
numPorts.x = portGeometry.x * numModules.x;
|
||||
numPorts.y = portGeometry.y * numModules.y;
|
||||
if (quadEnable) {
|
||||
numPorts.x = 1;
|
||||
numPorts.y = 2;
|
||||
@ -401,97 +395,27 @@ void Implementation::setArping(const bool i,
|
||||
}
|
||||
}
|
||||
|
||||
slsDetectorDefs::ROI Implementation::getReceiverROI() const {
|
||||
return receiverRoi;
|
||||
std::array<slsDetectorDefs::ROI, 2> Implementation::getPortROIs() const {
|
||||
return portRois;
|
||||
}
|
||||
|
||||
void Implementation::setReceiverROI(const slsDetectorDefs::ROI arg) {
|
||||
receiverRoi = arg;
|
||||
void Implementation::setPortROIs(const std::array<defs::ROI, 2> &args) {
|
||||
portRois = args;
|
||||
|
||||
if (generalData->numUDPInterfaces == 1 ||
|
||||
generalData->detType == slsDetectorDefs::GOTTHARD2) {
|
||||
portRois[0] = arg;
|
||||
} else {
|
||||
slsDetectorDefs::xy nPortDim(generalData->nPixelsX,
|
||||
generalData->nPixelsY);
|
||||
|
||||
for (int iPort = 0; iPort != generalData->numUDPInterfaces; ++iPort) {
|
||||
// default init = complete roi
|
||||
slsDetectorDefs::ROI portRoi{};
|
||||
|
||||
// no roi
|
||||
if (arg.noRoi()) {
|
||||
portRoi.setNoRoi();
|
||||
}
|
||||
|
||||
// incomplete roi
|
||||
else if (!arg.completeRoi()) {
|
||||
// get port limits
|
||||
slsDetectorDefs::ROI portFullRoi{0, nPortDim.x - 1, 0,
|
||||
nPortDim.y - 1};
|
||||
if (iPort == 1) {
|
||||
// left right (eiger)
|
||||
if (GetPortGeometry().x == 2) {
|
||||
portFullRoi.xmin += nPortDim.x;
|
||||
portFullRoi.xmax += nPortDim.x;
|
||||
}
|
||||
// top bottom (jungfrau or moench)
|
||||
else {
|
||||
portFullRoi.ymin += nPortDim.y;
|
||||
portFullRoi.ymax += nPortDim.y;
|
||||
}
|
||||
}
|
||||
LOG(logDEBUG)
|
||||
<< iPort << ": portfullroi:" << ToString(portFullRoi);
|
||||
|
||||
// no roi
|
||||
if (arg.xmin > portFullRoi.xmax ||
|
||||
arg.xmax < portFullRoi.xmin ||
|
||||
arg.ymin > portFullRoi.ymax ||
|
||||
arg.ymax < portFullRoi.ymin) {
|
||||
portRoi.setNoRoi();
|
||||
}
|
||||
|
||||
// incomplete module roi
|
||||
else if (arg.xmin > portFullRoi.xmin ||
|
||||
arg.xmax < portFullRoi.xmax ||
|
||||
arg.ymin > portFullRoi.ymin ||
|
||||
arg.ymax < portFullRoi.ymax) {
|
||||
portRoi.xmin = (arg.xmin <= portFullRoi.xmin)
|
||||
? 0
|
||||
: (arg.xmin % nPortDim.x);
|
||||
portRoi.xmax = (arg.xmax >= portFullRoi.xmax)
|
||||
? nPortDim.x - 1
|
||||
: (arg.xmax % nPortDim.x);
|
||||
portRoi.ymin = (arg.ymin <= portFullRoi.ymin)
|
||||
? 0
|
||||
: (arg.ymin % nPortDim.y);
|
||||
portRoi.ymax = (arg.ymax >= portFullRoi.ymax)
|
||||
? nPortDim.y - 1
|
||||
: (arg.ymax % nPortDim.y);
|
||||
}
|
||||
}
|
||||
portRois[iPort] = portRoi;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i != listener.size(); ++i)
|
||||
listener[i]->SetNoRoi(portRois[i].noRoi());
|
||||
listener[i]->SetIsOutsideRoi(portRois[i].noRoi());
|
||||
for (size_t i = 0; i != dataProcessor.size(); ++i)
|
||||
dataProcessor[i]->SetReceiverROI(portRois[i]);
|
||||
dataProcessor[i]->SetPortROI(portRois[i]);
|
||||
for (size_t i = 0; i != dataStreamer.size(); ++i) {
|
||||
dataStreamer[i]->SetReceiverROI(
|
||||
portRois[i].completeRoi() ? GetMaxROIPerPort() : portRois[i]);
|
||||
}
|
||||
LOG(logINFO) << "receiver roi: " << ToString(receiverRoi);
|
||||
if (generalData->numUDPInterfaces == 2 &&
|
||||
generalData->detType != slsDetectorDefs::GOTTHARD2) {
|
||||
LOG(logINFO) << "port rois: " << ToString(portRois);
|
||||
dataStreamer[i]->SetPortROI(portRois[i]);
|
||||
}
|
||||
LOG(logINFO) << "Rois (per port): " << ToString(portRois);
|
||||
}
|
||||
|
||||
void Implementation::setReceiverROIMetadata(const ROI arg) {
|
||||
receiverRoiMetadata = arg;
|
||||
LOG(logINFO) << "receiver roi Metadata: " << ToString(receiverRoiMetadata);
|
||||
void Implementation::setMultiROIMetadata(
|
||||
const std::vector<slsDetectorDefs::ROI> &args) {
|
||||
multiRoiMetadata = args;
|
||||
LOG(logINFO) << "Multi ROI Metadata: " << ToString(multiRoiMetadata);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
@ -787,8 +711,7 @@ void Implementation::stopReceiver() {
|
||||
summary = (i == 0 ? "\n\tDeactivated Left Port"
|
||||
: "\n\tDeactivated Right Port");
|
||||
} else if (portRois[i].noRoi()) {
|
||||
summary = (i == 0 ? "\n\tNo Roi on Left Port"
|
||||
: "\n\tNo Roi on Right Port");
|
||||
summary = "\n\tNo Roi on Port[" + std::to_string(i) + ']';
|
||||
} else {
|
||||
std::ostringstream os;
|
||||
os << "\n\tMissing Packets\t\t: " << mpMessage
|
||||
@ -958,7 +881,19 @@ void Implementation::StartMasterWriter() {
|
||||
masterAttributes.framePadding = framePadding;
|
||||
masterAttributes.scanParams = scanParams;
|
||||
masterAttributes.totalFrames = numberOfTotalFrames;
|
||||
masterAttributes.receiverRoi = receiverRoiMetadata;
|
||||
// complete ROI
|
||||
if (multiRoiMetadata.empty()) {
|
||||
int nTotalPixelsX = (generalData->nPixelsX * numPorts.x);
|
||||
int nTotalPixelsY = (generalData->nPixelsY * numPorts.y);
|
||||
if (nTotalPixelsY == 1) {
|
||||
masterAttributes.rois.push_back(ROI{0, nTotalPixelsX - 1});
|
||||
} else {
|
||||
masterAttributes.rois.push_back(
|
||||
ROI{0, nTotalPixelsX - 1, 0, nTotalPixelsY - 1});
|
||||
}
|
||||
} else {
|
||||
masterAttributes.rois = multiRoiMetadata;
|
||||
}
|
||||
masterAttributes.exptime = acquisitionTime;
|
||||
masterAttributes.period = acquisitionPeriod;
|
||||
masterAttributes.burstMode = burstMode;
|
||||
@ -1087,8 +1022,8 @@ void Implementation::setNumberofUDPInterfaces(const int n) {
|
||||
|
||||
// fifo
|
||||
SetupFifoStructure();
|
||||
// recalculate port rois
|
||||
setReceiverROI(receiverRoi);
|
||||
// recalculate port rois booleans for listener, processor and streamer
|
||||
setPortROIs(portRois);
|
||||
|
||||
// create threads
|
||||
for (int i = 0; i < generalData->numUDPInterfaces; ++i) {
|
||||
|
@ -58,9 +58,9 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
bool getArping() const;
|
||||
pid_t getArpingProcessId() const;
|
||||
void setArping(const bool i, const std::vector<std::string> ips);
|
||||
ROI getReceiverROI() const;
|
||||
void setReceiverROI(const ROI arg);
|
||||
void setReceiverROIMetadata(const ROI arg);
|
||||
std::array<defs::ROI, 2> getPortROIs() const;
|
||||
void setPortROIs(const std::array<defs::ROI, 2> &args);
|
||||
void setMultiROIMetadata(const std::vector<slsDetectorDefs::ROI> &args);
|
||||
|
||||
/**************************************************
|
||||
* *
|
||||
@ -283,7 +283,6 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
void SetupFifoStructure();
|
||||
|
||||
const xy GetPortGeometry() const;
|
||||
const ROI GetMaxROIPerPort() const;
|
||||
void ResetParametersforNewAcquisition();
|
||||
void CreateUDPSockets();
|
||||
void SetupWriter();
|
||||
@ -308,10 +307,8 @@ class Implementation : private virtual slsDetectorDefs {
|
||||
bool framePadding{true};
|
||||
pid_t parentThreadId;
|
||||
pid_t tcpThreadId;
|
||||
ROI receiverRoi{};
|
||||
std::array<ROI, 2> portRois{};
|
||||
// receiver roi for complete detector for metadata
|
||||
ROI receiverRoiMetadata{};
|
||||
std::vector<ROI> multiRoiMetadata{};
|
||||
|
||||
// file parameters
|
||||
fileFormat fileFormatType{BINARY};
|
||||
|
@ -85,17 +85,17 @@ void Listener::SetEthernetInterface(const std::string e) {
|
||||
|
||||
void Listener::SetActivate(bool enable) {
|
||||
activated = enable;
|
||||
disabledPort = (!activated || !detectorDataStream || noRoi);
|
||||
disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
|
||||
}
|
||||
|
||||
void Listener::SetDetectorDatastream(bool enable) {
|
||||
detectorDataStream = enable;
|
||||
disabledPort = (!activated || !detectorDataStream || noRoi);
|
||||
disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
|
||||
}
|
||||
|
||||
void Listener::SetNoRoi(bool enable) {
|
||||
noRoi = enable;
|
||||
disabledPort = (!activated || !detectorDataStream || noRoi);
|
||||
void Listener::SetIsOutsideRoi(bool enable) {
|
||||
isOutsideRoi = enable;
|
||||
disabledPort = (!activated || !detectorDataStream || isOutsideRoi);
|
||||
}
|
||||
|
||||
void Listener::SetSilentMode(bool enable) { silentMode = enable; }
|
||||
|
@ -43,7 +43,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject {
|
||||
void SetEthernetInterface(const std::string e);
|
||||
void SetActivate(bool enable);
|
||||
void SetDetectorDatastream(bool enable);
|
||||
void SetNoRoi(bool enable);
|
||||
void SetIsOutsideRoi(bool enable);
|
||||
void SetSilentMode(bool enable);
|
||||
|
||||
void ResetParametersforNewAcquisition();
|
||||
@ -116,7 +116,7 @@ class Listener : private virtual slsDetectorDefs, public ThreadObject {
|
||||
std::string eth;
|
||||
bool activated{false};
|
||||
bool detectorDataStream{true};
|
||||
bool noRoi{false};
|
||||
bool isOutsideRoi{false};
|
||||
bool silentMode;
|
||||
bool disabledPort{false};
|
||||
|
||||
|
@ -43,30 +43,30 @@ void MasterAttributes::WriteHDF5Attributes(H5::H5File *fd, H5::Group *group) {
|
||||
WriteCommonHDF5Attributes(fd, group);
|
||||
switch (detType) {
|
||||
case slsDetectorDefs::JUNGFRAU:
|
||||
WriteJungfrauHDF5Attributes(fd, group);
|
||||
WriteJungfrauHDF5Attributes(group);
|
||||
break;
|
||||
case slsDetectorDefs::MOENCH:
|
||||
WriteMoenchHDF5Attributes(fd, group);
|
||||
WriteMoenchHDF5Attributes(group);
|
||||
break;
|
||||
case slsDetectorDefs::EIGER:
|
||||
WriteEigerHDF5Attributes(fd, group);
|
||||
WriteEigerHDF5Attributes(group);
|
||||
break;
|
||||
case slsDetectorDefs::MYTHEN3:
|
||||
WriteMythen3HDF5Attributes(fd, group);
|
||||
WriteMythen3HDF5Attributes(group);
|
||||
break;
|
||||
case slsDetectorDefs::GOTTHARD2:
|
||||
WriteGotthard2HDF5Attributes(fd, group);
|
||||
WriteGotthard2HDF5Attributes(group);
|
||||
break;
|
||||
case slsDetectorDefs::CHIPTESTBOARD:
|
||||
WriteCtbHDF5Attributes(fd, group);
|
||||
WriteCtbHDF5Attributes(group);
|
||||
break;
|
||||
case slsDetectorDefs::XILINX_CHIPTESTBOARD:
|
||||
WriteXilinxCtbHDF5Attributes(fd, group);
|
||||
WriteXilinxCtbHDF5Attributes(group);
|
||||
break;
|
||||
default:
|
||||
throw RuntimeError("Unknown Detector type to get master attributes");
|
||||
}
|
||||
WriteFinalHDF5Attributes(fd, group);
|
||||
WriteFinalHDF5Attributes(group);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -110,17 +110,6 @@ void MasterAttributes::GetCommonBinaryAttributes(
|
||||
w->String(ToString(scanParams).c_str());
|
||||
w->Key("Total Frames");
|
||||
w->Uint64(totalFrames);
|
||||
w->Key("Receiver Roi");
|
||||
w->StartObject();
|
||||
w->Key("xmin");
|
||||
w->Uint(receiverRoi.xmin);
|
||||
w->Key("xmax");
|
||||
w->Uint(receiverRoi.xmax);
|
||||
w->Key("ymin");
|
||||
w->Uint(receiverRoi.ymin);
|
||||
w->Key("ymax");
|
||||
w->Uint(receiverRoi.ymax);
|
||||
w->EndObject();
|
||||
}
|
||||
|
||||
void MasterAttributes::GetFinalBinaryAttributes(
|
||||
@ -287,38 +276,9 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
|
||||
"Total Frames", H5::PredType::STD_U64LE, dataspace);
|
||||
dataset.write(&totalFrames, H5::PredType::STD_U64LE);
|
||||
}
|
||||
// Receiver Roi xmin
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"receiver roi xmin", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&receiverRoi.xmin, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
// Receiver Roi xmax
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"receiver roi xmax", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&receiverRoi.xmax, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
// Receiver Roi ymin
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"receiver roi ymin", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&receiverRoi.ymin, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
// Receiver Roi ymax
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"receiver roi ymax", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&receiverRoi.ymax, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteFinalHDF5Attributes(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteFinalHDF5Attributes(H5::Group *group) {
|
||||
char c[1024]{};
|
||||
// Total Frames in file
|
||||
{
|
||||
@ -339,7 +299,20 @@ void MasterAttributes::WriteFinalHDF5Attributes(H5::H5File *fd,
|
||||
}
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5Exptime(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5ROIs(H5::Group *group) {
|
||||
hsize_t dims[1] = {rois.size()};
|
||||
H5::DataSpace dataspace(1, dims);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 1024);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Receiver Rois", strdatatype, dataspace);
|
||||
std::vector<char[1024]> cRois(rois.size());
|
||||
for (size_t i = 0; i < rois.size(); ++i) {
|
||||
strcpy_safe(cRois[i], ToString(rois[i]));
|
||||
}
|
||||
dataset.write(cRois.data(), strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5Exptime(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::DataSet dataset =
|
||||
@ -349,7 +322,7 @@ void MasterAttributes::WriteHDF5Exptime(H5::H5File *fd, H5::Group *group) {
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5Period(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5Period(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::DataSet dataset =
|
||||
@ -359,7 +332,7 @@ void MasterAttributes::WriteHDF5Period(H5::H5File *fd, H5::Group *group) {
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5DynamicRange(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Dynamic Range", H5::PredType::NATIVE_INT, dataspace);
|
||||
@ -372,30 +345,28 @@ void MasterAttributes::WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group) {
|
||||
attribute.write(strdatatype, c);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5TenGiga(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5TenGiga(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Ten Giga Enable", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&tenGiga, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5NumUDPInterfaces(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5NumUDPInterfaces(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Number of UDP Interfaces", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&numUDPInterfaces, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5ReadNRows(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5ReadNRows(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Number of rows", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&readNRows, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5ThresholdEnergy(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5ThresholdEnergy(H5::Group *group) {
|
||||
char c[1024]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
@ -409,8 +380,7 @@ void MasterAttributes::WriteHDF5ThresholdEnergy(H5::H5File *fd,
|
||||
attribute.write(strdatatype, c);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5ThresholdEnergies(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5ThresholdEnergies(H5::Group *group) {
|
||||
char c[1024]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 1024);
|
||||
@ -420,7 +390,7 @@ void MasterAttributes::WriteHDF5ThresholdEnergies(H5::H5File *fd,
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5SubExpTime(H5::Group *group) {
|
||||
char c[1024]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
@ -430,7 +400,7 @@ void MasterAttributes::WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group) {
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5SubPeriod(H5::Group *group) {
|
||||
char c[1024]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
@ -440,15 +410,14 @@ void MasterAttributes::WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group) {
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5SubQuad(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5SubQuad(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Quad", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&quad, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5RateCorrections(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5RateCorrections(H5::Group *group) {
|
||||
char c[1024]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 1024);
|
||||
@ -458,14 +427,14 @@ void MasterAttributes::WriteHDF5RateCorrections(H5::H5File *fd,
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5CounterMask(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5CounterMask(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Counter Mask", H5::PredType::STD_U32LE, dataspace);
|
||||
dataset.write(&counterMask, H5::PredType::STD_U32LE);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5ExptimeArray(H5::Group *group) {
|
||||
for (int i = 0; i != 3; ++i) {
|
||||
char c[1024]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
@ -477,8 +446,7 @@ void MasterAttributes::WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group) {
|
||||
}
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5GateDelayArray(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5GateDelayArray(H5::Group *group) {
|
||||
for (int i = 0; i != 3; ++i) {
|
||||
char c[1024]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
@ -490,14 +458,14 @@ void MasterAttributes::WriteHDF5GateDelayArray(H5::H5File *fd,
|
||||
}
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5Gates(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5Gates(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Gates", H5::PredType::STD_U32LE, dataspace);
|
||||
dataset.write(&gates, H5::PredType::STD_U32LE);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5BurstMode(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::DataSet dataset =
|
||||
@ -507,82 +475,77 @@ void MasterAttributes::WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group) {
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5AdcMask(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5AdcMask(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("ADC Mask", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&adcmask, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5AnalogFlag(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5AnalogFlag(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Analog Flag", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&analog, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5AnalogSamples(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5AnalogSamples(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Analog Samples", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&analogSamples, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5DigitalFlag(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5DigitalFlag(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Digital Flag", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&digital, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5DigitalSamples(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5DigitalSamples(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Digital Samples", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&digitalSamples, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5DbitOffset(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Dbit Offset", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&dbitoffset, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5DbitReorder(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5DbitReorder(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Dbit Reorder", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&dbitreorder, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5DbitList(H5::H5File *fd, H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5DbitList(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Dbit Bitset List", H5::PredType::STD_U64LE, dataspace);
|
||||
dataset.write(&dbitlist, H5::PredType::STD_U64LE);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5TransceiverMask(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5TransceiverMask(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Transceiver Mask", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&transceiverMask, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5TransceiverFlag(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5TransceiverFlag(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Transceiver Flag", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&transceiver, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5TransceiverSamples(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
void MasterAttributes::WriteHDF5TransceiverSamples(H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Transceiver Samples", H5::PredType::NATIVE_INT, dataspace);
|
||||
@ -592,6 +555,13 @@ void MasterAttributes::WriteHDF5TransceiverSamples(H5::H5File *fd,
|
||||
|
||||
void MasterAttributes::GetJungfrauBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
|
||||
w->Key("Receiver Rois");
|
||||
w->StartArray();
|
||||
for (const slsDetectorDefs::ROI &roi : rois) {
|
||||
std::string roi_str = ToString(roi);
|
||||
w->String(roi_str.c_str());
|
||||
}
|
||||
w->EndArray();
|
||||
w->Key("Exptime");
|
||||
w->String(ToString(exptime).c_str());
|
||||
w->Key("Period");
|
||||
@ -603,17 +573,24 @@ void MasterAttributes::GetJungfrauBinaryAttributes(
|
||||
}
|
||||
|
||||
#ifdef HDF5C
|
||||
void MasterAttributes::WriteJungfrauHDF5Attributes(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5Exptime(fd, group);
|
||||
MasterAttributes::WriteHDF5Period(fd, group);
|
||||
MasterAttributes::WriteHDF5NumUDPInterfaces(fd, group);
|
||||
MasterAttributes::WriteHDF5ReadNRows(fd, group);
|
||||
void MasterAttributes::WriteJungfrauHDF5Attributes(H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5ROIs(group);
|
||||
MasterAttributes::WriteHDF5Exptime(group);
|
||||
MasterAttributes::WriteHDF5Period(group);
|
||||
MasterAttributes::WriteHDF5NumUDPInterfaces(group);
|
||||
MasterAttributes::WriteHDF5ReadNRows(group);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MasterAttributes::GetMoenchBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
|
||||
w->Key("Receiver Rois");
|
||||
w->StartArray();
|
||||
for (const slsDetectorDefs::ROI &roi : rois) {
|
||||
std::string roi_str = ToString(roi);
|
||||
w->String(roi_str.c_str());
|
||||
}
|
||||
w->EndArray();
|
||||
w->Key("Exptime");
|
||||
w->String(ToString(exptime).c_str());
|
||||
w->Key("Period");
|
||||
@ -625,17 +602,24 @@ void MasterAttributes::GetMoenchBinaryAttributes(
|
||||
}
|
||||
|
||||
#ifdef HDF5C
|
||||
void MasterAttributes::WriteMoenchHDF5Attributes(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5Exptime(fd, group);
|
||||
MasterAttributes::WriteHDF5Period(fd, group);
|
||||
MasterAttributes::WriteHDF5NumUDPInterfaces(fd, group);
|
||||
MasterAttributes::WriteHDF5ReadNRows(fd, group);
|
||||
void MasterAttributes::WriteMoenchHDF5Attributes(H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5ROIs(group);
|
||||
MasterAttributes::WriteHDF5Exptime(group);
|
||||
MasterAttributes::WriteHDF5Period(group);
|
||||
MasterAttributes::WriteHDF5NumUDPInterfaces(group);
|
||||
MasterAttributes::WriteHDF5ReadNRows(group);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MasterAttributes::GetEigerBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
|
||||
w->Key("Receiver Rois");
|
||||
w->StartArray();
|
||||
for (const slsDetectorDefs::ROI &roi : rois) {
|
||||
std::string roi_str = ToString(roi);
|
||||
w->String(roi_str.c_str());
|
||||
}
|
||||
w->EndArray();
|
||||
w->Key("Dynamic Range");
|
||||
w->Uint(dynamicRange);
|
||||
w->Key("Ten Giga");
|
||||
@ -659,23 +643,30 @@ void MasterAttributes::GetEigerBinaryAttributes(
|
||||
}
|
||||
|
||||
#ifdef HDF5C
|
||||
void MasterAttributes::WriteEigerHDF5Attributes(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5DynamicRange(fd, group);
|
||||
MasterAttributes::WriteHDF5TenGiga(fd, group);
|
||||
MasterAttributes::WriteHDF5Exptime(fd, group);
|
||||
MasterAttributes::WriteHDF5Period(fd, group);
|
||||
MasterAttributes::WriteHDF5ThresholdEnergy(fd, group);
|
||||
MasterAttributes::WriteHDF5SubExpTime(fd, group);
|
||||
MasterAttributes::WriteHDF5SubPeriod(fd, group);
|
||||
MasterAttributes::WriteHDF5SubQuad(fd, group);
|
||||
MasterAttributes::WriteHDF5ReadNRows(fd, group);
|
||||
MasterAttributes::WriteHDF5RateCorrections(fd, group);
|
||||
void MasterAttributes::WriteEigerHDF5Attributes(H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5ROIs(group);
|
||||
MasterAttributes::WriteHDF5DynamicRange(group);
|
||||
MasterAttributes::WriteHDF5TenGiga(group);
|
||||
MasterAttributes::WriteHDF5Exptime(group);
|
||||
MasterAttributes::WriteHDF5Period(group);
|
||||
MasterAttributes::WriteHDF5ThresholdEnergy(group);
|
||||
MasterAttributes::WriteHDF5SubExpTime(group);
|
||||
MasterAttributes::WriteHDF5SubPeriod(group);
|
||||
MasterAttributes::WriteHDF5SubQuad(group);
|
||||
MasterAttributes::WriteHDF5ReadNRows(group);
|
||||
MasterAttributes::WriteHDF5RateCorrections(group);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MasterAttributes::GetMythen3BinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
|
||||
w->Key("Receiver Rois");
|
||||
w->StartArray();
|
||||
for (const slsDetectorDefs::ROI &roi : rois) {
|
||||
std::string roi_str = ToString(roi);
|
||||
w->String(roi_str.c_str());
|
||||
}
|
||||
w->EndArray();
|
||||
w->Key("Dynamic Range");
|
||||
w->Uint(dynamicRange);
|
||||
w->Key("Ten Giga");
|
||||
@ -699,21 +690,28 @@ void MasterAttributes::GetMythen3BinaryAttributes(
|
||||
}
|
||||
|
||||
#ifdef HDF5C
|
||||
void MasterAttributes::WriteMythen3HDF5Attributes(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5DynamicRange(fd, group);
|
||||
MasterAttributes::WriteHDF5TenGiga(fd, group);
|
||||
MasterAttributes::WriteHDF5Period(fd, group);
|
||||
MasterAttributes::WriteHDF5CounterMask(fd, group);
|
||||
MasterAttributes::WriteHDF5ExptimeArray(fd, group);
|
||||
MasterAttributes::WriteHDF5GateDelayArray(fd, group);
|
||||
MasterAttributes::WriteHDF5Gates(fd, group);
|
||||
MasterAttributes::WriteHDF5ThresholdEnergies(fd, group);
|
||||
void MasterAttributes::WriteMythen3HDF5Attributes(H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5ROIs(group);
|
||||
MasterAttributes::WriteHDF5DynamicRange(group);
|
||||
MasterAttributes::WriteHDF5TenGiga(group);
|
||||
MasterAttributes::WriteHDF5Period(group);
|
||||
MasterAttributes::WriteHDF5CounterMask(group);
|
||||
MasterAttributes::WriteHDF5ExptimeArray(group);
|
||||
MasterAttributes::WriteHDF5GateDelayArray(group);
|
||||
MasterAttributes::WriteHDF5Gates(group);
|
||||
MasterAttributes::WriteHDF5ThresholdEnergies(group);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MasterAttributes::GetGotthard2BinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w) {
|
||||
w->Key("Receiver Rois");
|
||||
w->StartArray();
|
||||
for (const slsDetectorDefs::ROI &roi : rois) {
|
||||
std::string roi_str = ToString(roi);
|
||||
w->String(roi_str.c_str());
|
||||
}
|
||||
w->EndArray();
|
||||
w->Key("Exptime");
|
||||
w->String(ToString(exptime).c_str());
|
||||
w->Key("Period");
|
||||
@ -723,11 +721,11 @@ void MasterAttributes::GetGotthard2BinaryAttributes(
|
||||
}
|
||||
|
||||
#ifdef HDF5C
|
||||
void MasterAttributes::WriteGotthard2HDF5Attributes(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5Exptime(fd, group);
|
||||
MasterAttributes::WriteHDF5Period(fd, group);
|
||||
MasterAttributes::WriteHDF5BurstMode(fd, group);
|
||||
void MasterAttributes::WriteGotthard2HDF5Attributes(H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5ROIs(group);
|
||||
MasterAttributes::WriteHDF5Exptime(group);
|
||||
MasterAttributes::WriteHDF5Period(group);
|
||||
MasterAttributes::WriteHDF5BurstMode(group);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -764,22 +762,21 @@ void MasterAttributes::GetCtbBinaryAttributes(
|
||||
}
|
||||
|
||||
#ifdef HDF5C
|
||||
void MasterAttributes::WriteCtbHDF5Attributes(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5Exptime(fd, group);
|
||||
MasterAttributes::WriteHDF5Period(fd, group);
|
||||
MasterAttributes::WriteHDF5TenGiga(fd, group);
|
||||
MasterAttributes::WriteHDF5AdcMask(fd, group);
|
||||
MasterAttributes::WriteHDF5AnalogFlag(fd, group);
|
||||
MasterAttributes::WriteHDF5AnalogSamples(fd, group);
|
||||
MasterAttributes::WriteHDF5DigitalFlag(fd, group);
|
||||
MasterAttributes::WriteHDF5DigitalSamples(fd, group);
|
||||
MasterAttributes::WriteHDF5DbitOffset(fd, group);
|
||||
MasterAttributes::WriteHDF5DbitReorder(fd, group);
|
||||
MasterAttributes::WriteHDF5DbitList(fd, group);
|
||||
MasterAttributes::WriteHDF5TransceiverMask(fd, group);
|
||||
MasterAttributes::WriteHDF5TransceiverFlag(fd, group);
|
||||
MasterAttributes::WriteHDF5TransceiverSamples(fd, group);
|
||||
void MasterAttributes::WriteCtbHDF5Attributes(H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5Exptime(group);
|
||||
MasterAttributes::WriteHDF5Period(group);
|
||||
MasterAttributes::WriteHDF5TenGiga(group);
|
||||
MasterAttributes::WriteHDF5AdcMask(group);
|
||||
MasterAttributes::WriteHDF5AnalogFlag(group);
|
||||
MasterAttributes::WriteHDF5AnalogSamples(group);
|
||||
MasterAttributes::WriteHDF5DigitalFlag(group);
|
||||
MasterAttributes::WriteHDF5DigitalSamples(group);
|
||||
MasterAttributes::WriteHDF5DbitOffset(group);
|
||||
MasterAttributes::WriteHDF5DbitReorder(group);
|
||||
MasterAttributes::WriteHDF5DbitList(group);
|
||||
MasterAttributes::WriteHDF5TransceiverMask(group);
|
||||
MasterAttributes::WriteHDF5TransceiverFlag(group);
|
||||
MasterAttributes::WriteHDF5TransceiverSamples(group);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -814,21 +811,20 @@ void MasterAttributes::GetXilinxCtbBinaryAttributes(
|
||||
}
|
||||
|
||||
#ifdef HDF5C
|
||||
void MasterAttributes::WriteXilinxCtbHDF5Attributes(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5Exptime(fd, group);
|
||||
MasterAttributes::WriteHDF5Period(fd, group);
|
||||
MasterAttributes::WriteHDF5AdcMask(fd, group);
|
||||
MasterAttributes::WriteHDF5AnalogFlag(fd, group);
|
||||
MasterAttributes::WriteHDF5AnalogSamples(fd, group);
|
||||
MasterAttributes::WriteHDF5DigitalFlag(fd, group);
|
||||
MasterAttributes::WriteHDF5DigitalSamples(fd, group);
|
||||
MasterAttributes::WriteHDF5DbitOffset(fd, group);
|
||||
MasterAttributes::WriteHDF5DbitReorder(fd, group);
|
||||
MasterAttributes::WriteHDF5DbitList(fd, group);
|
||||
MasterAttributes::WriteHDF5TransceiverMask(fd, group);
|
||||
MasterAttributes::WriteHDF5TransceiverFlag(fd, group);
|
||||
MasterAttributes::WriteHDF5TransceiverSamples(fd, group);
|
||||
void MasterAttributes::WriteXilinxCtbHDF5Attributes(H5::Group *group) {
|
||||
MasterAttributes::WriteHDF5Exptime(group);
|
||||
MasterAttributes::WriteHDF5Period(group);
|
||||
MasterAttributes::WriteHDF5AdcMask(group);
|
||||
MasterAttributes::WriteHDF5AnalogFlag(group);
|
||||
MasterAttributes::WriteHDF5AnalogSamples(group);
|
||||
MasterAttributes::WriteHDF5DigitalFlag(group);
|
||||
MasterAttributes::WriteHDF5DigitalSamples(group);
|
||||
MasterAttributes::WriteHDF5DbitOffset(group);
|
||||
MasterAttributes::WriteHDF5DbitReorder(group);
|
||||
MasterAttributes::WriteHDF5DbitList(group);
|
||||
MasterAttributes::WriteHDF5TransceiverMask(group);
|
||||
MasterAttributes::WriteHDF5TransceiverFlag(group);
|
||||
MasterAttributes::WriteHDF5TransceiverSamples(group);
|
||||
}
|
||||
#endif
|
||||
} // namespace sls
|
||||
|
@ -57,7 +57,7 @@ class MasterAttributes {
|
||||
uint32_t transceiverMask{0};
|
||||
uint32_t transceiver{0};
|
||||
uint32_t transceiverSamples{0};
|
||||
slsDetectorDefs::ROI receiverRoi{};
|
||||
std::vector<slsDetectorDefs::ROI> rois{};
|
||||
uint32_t counterMask{0};
|
||||
std::array<ns, 3> exptimeArray{};
|
||||
std::array<ns, 3> gateDelayArray{};
|
||||
@ -80,77 +80,78 @@ class MasterAttributes {
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
#ifdef HDF5C
|
||||
void WriteCommonHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteFinalHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5Exptime(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5Period(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5TenGiga(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5NumUDPInterfaces(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5ReadNRows(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5ThresholdEnergy(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5ThresholdEnergies(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5SubQuad(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5RateCorrections(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5CounterMask(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5GateDelayArray(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5Gates(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5AdcMask(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5AnalogFlag(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5AnalogSamples(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DigitalFlag(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DigitalSamples(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DbitOffset(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DbitList(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5DbitReorder(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5TransceiverMask(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5TransceiverFlag(H5::H5File *fd, H5::Group *group);
|
||||
void WriteHDF5TransceiverSamples(H5::H5File *fd, H5::Group *group);
|
||||
void WriteFinalHDF5Attributes(H5::Group *group);
|
||||
void WriteHDF5ROIs(H5::Group *group);
|
||||
void WriteHDF5Exptime(H5::Group *group);
|
||||
void WriteHDF5Period(H5::Group *group);
|
||||
void WriteHDF5DynamicRange(H5::Group *group);
|
||||
void WriteHDF5TenGiga(H5::Group *group);
|
||||
void WriteHDF5NumUDPInterfaces(H5::Group *group);
|
||||
void WriteHDF5ReadNRows(H5::Group *group);
|
||||
void WriteHDF5ThresholdEnergy(H5::Group *group);
|
||||
void WriteHDF5ThresholdEnergies(H5::Group *group);
|
||||
void WriteHDF5SubExpTime(H5::Group *group);
|
||||
void WriteHDF5SubPeriod(H5::Group *group);
|
||||
void WriteHDF5SubQuad(H5::Group *group);
|
||||
void WriteHDF5RateCorrections(H5::Group *group);
|
||||
void WriteHDF5CounterMask(H5::Group *group);
|
||||
void WriteHDF5ExptimeArray(H5::Group *group);
|
||||
void WriteHDF5GateDelayArray(H5::Group *group);
|
||||
void WriteHDF5Gates(H5::Group *group);
|
||||
void WriteHDF5BurstMode(H5::Group *group);
|
||||
void WriteHDF5AdcMask(H5::Group *group);
|
||||
void WriteHDF5AnalogFlag(H5::Group *group);
|
||||
void WriteHDF5AnalogSamples(H5::Group *group);
|
||||
void WriteHDF5DigitalFlag(H5::Group *group);
|
||||
void WriteHDF5DigitalSamples(H5::Group *group);
|
||||
void WriteHDF5DbitOffset(H5::Group *group);
|
||||
void WriteHDF5DbitList(H5::Group *group);
|
||||
void WriteHDF5DbitReorder(H5::Group *group);
|
||||
void WriteHDF5TransceiverMask(H5::Group *group);
|
||||
void WriteHDF5TransceiverFlag(H5::Group *group);
|
||||
void WriteHDF5TransceiverSamples(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetJungfrauBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
#ifdef HDF5C
|
||||
void WriteJungfrauHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteJungfrauHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetEigerBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
#ifdef HDF5C
|
||||
void WriteEigerHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteEigerHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetMythen3BinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
#ifdef HDF5C
|
||||
void WriteMythen3HDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteMythen3HDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetGotthard2BinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
#ifdef HDF5C
|
||||
void WriteGotthard2HDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteGotthard2HDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetMoenchBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
#ifdef HDF5C
|
||||
void WriteMoenchHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteMoenchHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void
|
||||
GetCtbBinaryAttributes(rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
#ifdef HDF5C
|
||||
void WriteCtbHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteCtbHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
|
||||
void GetXilinxCtbBinaryAttributes(
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
#ifdef HDF5C
|
||||
void WriteXilinxCtbHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
void WriteXilinxCtbHDF5Attributes(H5::Group *group);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -47,8 +47,8 @@ class GeneralDataTest : public GeneralData {
|
||||
// dummy DataProcessor class for testing
|
||||
class DataProcessorTest : public DataProcessor {
|
||||
public:
|
||||
DataProcessorTest() : DataProcessor(0) {};
|
||||
~DataProcessorTest() {};
|
||||
DataProcessorTest() : DataProcessor(0){};
|
||||
~DataProcessorTest(){};
|
||||
void ArrangeDbitData(size_t &size, char *data) {
|
||||
DataProcessor::ArrangeDbitData(size, data);
|
||||
}
|
||||
|
@ -88,6 +88,7 @@ message(STATUS "RAPID: ${SLS_INTERNAL_RAPIDJSON_DIR}")
|
||||
target_link_libraries(slsSupportObject
|
||||
PUBLIC
|
||||
slsProjectOptions
|
||||
${STD_FS_LIB} # from helpers.cmake
|
||||
|
||||
PRIVATE
|
||||
slsProjectWarnings
|
||||
|
@ -113,10 +113,12 @@ template <typename T, size_t Capacity> class StaticVector {
|
||||
// auto begin() noexcept -> decltype(data_.begin()) { return data_.begin();
|
||||
// }
|
||||
const_iterator begin() const noexcept { return data_.begin(); }
|
||||
iterator end() noexcept { return &data_[current_size]; }
|
||||
const_iterator end() const noexcept { return &data_[current_size]; }
|
||||
iterator end() noexcept { return data_.begin() + current_size; }
|
||||
const_iterator end() const noexcept { return data_.begin() + current_size; }
|
||||
const_iterator cbegin() const noexcept { return data_.cbegin(); }
|
||||
const_iterator cend() const noexcept { return &data_[current_size]; }
|
||||
const_iterator cend() const noexcept {
|
||||
return data_.cbegin() + current_size;
|
||||
}
|
||||
|
||||
void size_check(size_type s) const {
|
||||
if (s > Capacity) {
|
||||
|
@ -47,6 +47,8 @@ std::string ToString(const defs::polarity s);
|
||||
std::string ToString(const defs::timingInfoDecoder s);
|
||||
std::string ToString(const defs::collectionMode s);
|
||||
|
||||
std::string ToString(bool value);
|
||||
|
||||
std::string ToString(const slsDetectorDefs::xy &coord);
|
||||
std::ostream &operator<<(std::ostream &os, const slsDetectorDefs::xy &coord);
|
||||
std::string ToString(const slsDetectorDefs::ROI &roi);
|
||||
@ -347,4 +349,5 @@ std::vector<T> StringTo(const std::vector<std::string> &strings) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace sls
|
||||
|
@ -11,7 +11,7 @@ class Version {
|
||||
private:
|
||||
std::string version_;
|
||||
std::string date_;
|
||||
const std::string defaultBranch_ = "developer";
|
||||
inline static const std::string defaultVersion_[] = {"developer", "0.0.0"};
|
||||
|
||||
public:
|
||||
explicit Version(const std::string &s);
|
||||
|
@ -237,7 +237,8 @@ class slsDetectorDefs {
|
||||
return (xmin == -1 && xmax == -1 && ymin == -1 && ymax == -1);
|
||||
}
|
||||
constexpr bool noRoi() const {
|
||||
return (xmin == 0 && xmax == 0 && ymin == 0 && ymax == 0);
|
||||
return ((xmin == 0 && xmax == 0) &&
|
||||
((ymin == 0 && ymax == 0) || (ymin == -1 && ymax == -1)));
|
||||
}
|
||||
void setNoRoi() {
|
||||
xmin = 0;
|
||||
|
@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-other
|
||||
// Copyright (C) 2021 Contributors to the SLS Detector Package
|
||||
/** API versions */
|
||||
#define APILIB "developer 0x241122"
|
||||
#define APIRECEIVER "developer 0x241122"
|
||||
#define APICTB "developer 0x250310"
|
||||
#define APIGOTTHARD2 "developer 0x250310"
|
||||
#define APIMOENCH "developer 0x250310"
|
||||
#define APIEIGER "developer 0x250310"
|
||||
#define APIXILINXCTB "developer 0x250311"
|
||||
#define APIJUNGFRAU "developer 0x250318"
|
||||
#define APIMYTHEN3 "developer 0x250409"
|
||||
#define APILIB "0.0.0 0x250523"
|
||||
#define APIRECEIVER "0.0.0 0x250523"
|
||||
#define APICTB "0.0.0 0x250523"
|
||||
#define APIGOTTHARD2 "0.0.0 0x250523"
|
||||
#define APIMOENCH "0.0.0 0x250523"
|
||||
#define APIEIGER "0.0.0 0x250523"
|
||||
#define APIXILINXCTB "0.0.0 0x250523"
|
||||
#define APIJUNGFRAU "0.0.0 0x250523"
|
||||
#define APIMYTHEN3 "0.0.0 0x250523"
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
namespace sls {
|
||||
|
||||
std::string ToString(bool value) { return value ? "1" : "0"; }
|
||||
|
||||
std::string ToString(const slsDetectorDefs::xy &coord) {
|
||||
std::ostringstream oss;
|
||||
oss << '[' << coord.x << ", " << coord.y << ']';
|
||||
|
@ -21,7 +21,8 @@ Version::Version(const std::string &s) {
|
||||
}
|
||||
|
||||
bool Version::hasSemanticVersioning() const {
|
||||
return version_ != defaultBranch_;
|
||||
|
||||
return (version_ != defaultVersion_[0]) && (version_ != defaultVersion_[1]);
|
||||
}
|
||||
|
||||
std::string Version::getVersion() const { return version_; }
|
||||
|
@ -14,6 +14,7 @@ target_sources(tests PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-TypeTraits.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-UdpRxSocket.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-logger.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-Version.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test-ZmqSocket.cpp
|
||||
)
|
||||
|
||||
|
@ -8,10 +8,10 @@
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace sls {
|
||||
using sls::StaticVector;
|
||||
|
||||
TEST_CASE("StaticVector is a container") {
|
||||
REQUIRE(is_container<StaticVector<int, 7>>::value == true);
|
||||
REQUIRE(sls::is_container<StaticVector<int, 7>>::value == true);
|
||||
}
|
||||
|
||||
TEST_CASE("Comparing StaticVector containers") {
|
||||
@ -90,10 +90,17 @@ TEST_CASE("Copy construct from array") {
|
||||
REQUIRE(fcc == arr);
|
||||
}
|
||||
|
||||
TEST_CASE("Construct from a smaller StaticVector") {
|
||||
StaticVector<int, 3> sv{1, 2, 3};
|
||||
StaticVector<int, 5> sv2{sv};
|
||||
REQUIRE(sv == sv2);
|
||||
}
|
||||
|
||||
TEST_CASE("Free function and method gives the same iterators") {
|
||||
StaticVector<int, 3> fcc{1, 2, 3};
|
||||
REQUIRE(std::begin(fcc) == fcc.begin());
|
||||
}
|
||||
|
||||
SCENARIO("StaticVectors can be sized and resized", "[support]") {
|
||||
|
||||
GIVEN("A default constructed container") {
|
||||
@ -246,23 +253,23 @@ SCENARIO("Sorting, removing and other manipulation of a container",
|
||||
REQUIRE(a[3] == 90);
|
||||
}
|
||||
}
|
||||
// WHEN("Sorting is done using free function for begin and end") {
|
||||
// std::sort(begin(a), end(a));
|
||||
// THEN("it also works") {
|
||||
// REQUIRE(a[0] == 12);
|
||||
// REQUIRE(a[1] == 12);
|
||||
// REQUIRE(a[2] == 14);
|
||||
// REQUIRE(a[3] == 90);
|
||||
// }
|
||||
// }
|
||||
// WHEN("Erasing elements of a certain value") {
|
||||
// a.erase(std::remove(begin(a), end(a), 12));
|
||||
// THEN("all elements of that value are removed") {
|
||||
// REQUIRE(a.size() == 2);
|
||||
// REQUIRE(a[0] == 14);
|
||||
// REQUIRE(a[1] == 90);
|
||||
// }
|
||||
// }
|
||||
WHEN("Sorting is done using free function for begin and end") {
|
||||
std::sort(std::begin(a), std::end(a));
|
||||
THEN("it also works") {
|
||||
REQUIRE(a[0] == 12);
|
||||
REQUIRE(a[1] == 12);
|
||||
REQUIRE(a[2] == 14);
|
||||
REQUIRE(a[3] == 90);
|
||||
}
|
||||
}
|
||||
WHEN("Erasing elements of a certain value") {
|
||||
a.erase(std::remove(std::begin(a), std::end(a), 12));
|
||||
THEN("all elements of that value are removed") {
|
||||
REQUIRE(a.size() == 2);
|
||||
REQUIRE(a[0] == 14);
|
||||
REQUIRE(a[1] == 90);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,5 +341,3 @@ TEST_CASE("StaticVector stream") {
|
||||
oss << vec;
|
||||
REQUIRE(oss.str() == "[33, 85667, 2]");
|
||||
}
|
||||
|
||||
} // namespace sls
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user