mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-06-13 21:37:13 +02:00
Compare commits
5 Commits
developer
...
dev/fix_m3
Author | SHA1 | Date | |
---|---|---|---|
dae88ad689 | |||
7c232cbd48 | |||
f4219ac879 | |||
e54ffa9904 | |||
d174d9a2ec |
64
.github/workflows/build_wheel.yml
vendored
64
.github/workflows/build_wheel.yml
vendored
@ -1,64 +0,0 @@
|
||||
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
|
@ -42,7 +42,6 @@ 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,8 +6,6 @@ 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,12 +28,6 @@ Welcome to slsDetectorPackage's documentation!
|
||||
receiver_api
|
||||
examples
|
||||
|
||||
.. toctree::
|
||||
:caption: how to
|
||||
:maxdepth: 2
|
||||
|
||||
multidet
|
||||
|
||||
.. toctree::
|
||||
:caption: Python API
|
||||
:maxdepth: 2
|
||||
|
@ -1,228 +0,0 @@
|
||||
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,47 +123,6 @@ 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
|
||||
--------------------
|
||||
|
@ -100,6 +100,7 @@ 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")
|
||||
|
||||
|
@ -168,19 +168,11 @@ void MasterAttributes::GetFinalBinaryAttributes(
|
||||
#ifdef HDF5C
|
||||
void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
char c[1024]{};
|
||||
// version
|
||||
{
|
||||
double version = BINARY_WRITER_VERSION;
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::Attribute attribute = fd->createAttribute(
|
||||
"Version", H5::PredType::NATIVE_DOUBLE, dataspace);
|
||||
attribute.write(H5::PredType::NATIVE_DOUBLE, &version);
|
||||
}
|
||||
char c[HSTR_LEN]{};
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
// timestamp
|
||||
{
|
||||
time_t t = std::time(nullptr);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Timestamp", strdatatype, dataspace);
|
||||
@ -190,7 +182,6 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
|
||||
// detector type
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Detector Type", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(detType));
|
||||
@ -199,26 +190,18 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
|
||||
// timing mode
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Timing Mode", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(timingMode));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
// TODO: make this into an array?
|
||||
// geometry x
|
||||
// geometry
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Geometry in x axis", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&geometry.x, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
// geometry y
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Geometry in y axis", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&geometry.y, H5::PredType::NATIVE_INT);
|
||||
"Geometry", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(geometry));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
// Image Size
|
||||
{
|
||||
@ -227,7 +210,6 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
|
||||
"Image Size", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&imageSize, H5::PredType::NATIVE_INT);
|
||||
H5::DataSpace dataspaceAttr = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::Attribute attribute =
|
||||
dataset.createAttribute("Unit", strdatatype, dataspaceAttr);
|
||||
strcpy_safe(c, "bytes");
|
||||
@ -238,15 +220,9 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Number of pixels in x axis", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&nPixels.x, H5::PredType::NATIVE_INT);
|
||||
}
|
||||
// npixels y
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Number of pixels in y axis", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&nPixels.y, H5::PredType::NATIVE_INT);
|
||||
"Pixels", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(nPixels));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
// Maximum frames per file
|
||||
{
|
||||
@ -258,7 +234,6 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
|
||||
// Frame Discard Policy
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::DataSet dataset = group->createDataSet("Frame Discard Policy",
|
||||
strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(frameDiscardMode));
|
||||
@ -274,7 +249,6 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
|
||||
// Scan Parameters
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Scan Parameters", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(scanParams));
|
||||
@ -287,39 +261,18 @@ void MasterAttributes::WriteCommonHDF5Attributes(H5::H5File *fd,
|
||||
"Total Frames", H5::PredType::STD_U64LE, dataspace);
|
||||
dataset.write(&totalFrames, H5::PredType::STD_U64LE);
|
||||
}
|
||||
// Receiver Roi xmin
|
||||
// Receiver Roi
|
||||
{
|
||||
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);
|
||||
"receiver roi", H5::PredType::NATIVE_INT, dataspace);
|
||||
strcpy_safe(c, ToString(receiverRoi));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteFinalHDF5Attributes(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
char c[1024]{};
|
||||
// Total Frames in file
|
||||
{
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
@ -334,6 +287,7 @@ void MasterAttributes::WriteFinalHDF5Attributes(H5::H5File *fd,
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet("Additional JSON Header",
|
||||
strdatatype, dataspace);
|
||||
char c[sizeof(strdatatype)]{};
|
||||
strcpy_safe(c, ToString(additionalJsonHeader));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
@ -341,20 +295,20 @@ void MasterAttributes::WriteFinalHDF5Attributes(H5::H5File *fd,
|
||||
|
||||
void MasterAttributes::WriteHDF5Exptime(H5::H5File *fd, H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Exposure Time", strdatatype, dataspace);
|
||||
char c[1024]{};
|
||||
char c[HSTR_LEN]{};
|
||||
strcpy_safe(c, ToString(exptime));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5Period(H5::H5File *fd, H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Acquisition Period", strdatatype, dataspace);
|
||||
char c[1024]{};
|
||||
char c[HSTR_LEN]{};
|
||||
strcpy_safe(c, ToString(period));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
@ -365,10 +319,10 @@ void MasterAttributes::WriteHDF5DynamicRange(H5::H5File *fd, H5::Group *group) {
|
||||
"Dynamic Range", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&dynamicRange, H5::PredType::NATIVE_INT);
|
||||
H5::DataSpace dataspaceAttr = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::Attribute attribute =
|
||||
dataset.createAttribute("Unit", strdatatype, dataspaceAttr);
|
||||
char c[1024] = "bits";
|
||||
char c[HSTR_LEN] = "bits";
|
||||
attribute.write(strdatatype, c);
|
||||
}
|
||||
|
||||
@ -396,13 +350,13 @@ void MasterAttributes::WriteHDF5ReadNRows(H5::H5File *fd, H5::Group *group) {
|
||||
|
||||
void MasterAttributes::WriteHDF5ThresholdEnergy(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
char c[1024]{};
|
||||
char c[HSTR_LEN]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::DataSet dataset = group->createDataSet(
|
||||
"Threshold Energy", H5::PredType::NATIVE_INT, dataspace);
|
||||
dataset.write(&thresholdEnergyeV, H5::PredType::NATIVE_INT);
|
||||
H5::DataSpace dataspaceAttr = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::Attribute attribute =
|
||||
dataset.createAttribute("Unit", strdatatype, dataspaceAttr);
|
||||
strcpy_safe(c, "eV");
|
||||
@ -411,9 +365,9 @@ void MasterAttributes::WriteHDF5ThresholdEnergy(H5::H5File *fd,
|
||||
|
||||
void MasterAttributes::WriteHDF5ThresholdEnergies(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
char c[1024]{};
|
||||
char c[HSTR_LEN]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 1024);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Threshold Energies", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(thresholdAllEnergyeV));
|
||||
@ -421,9 +375,9 @@ void MasterAttributes::WriteHDF5ThresholdEnergies(H5::H5File *fd,
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group) {
|
||||
char c[1024]{};
|
||||
char c[HSTR_LEN]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Sub Exposure Time", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(subExptime));
|
||||
@ -431,9 +385,9 @@ void MasterAttributes::WriteHDF5SubExpTime(H5::H5File *fd, H5::Group *group) {
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5SubPeriod(H5::H5File *fd, H5::Group *group) {
|
||||
char c[1024]{};
|
||||
char c[HSTR_LEN]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Sub Period", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(subPeriod));
|
||||
@ -449,9 +403,9 @@ void MasterAttributes::WriteHDF5SubQuad(H5::H5File *fd, H5::Group *group) {
|
||||
|
||||
void MasterAttributes::WriteHDF5RateCorrections(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
char c[1024]{};
|
||||
char c[HSTR_LEN]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 1024);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Rate Corrections", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(ratecorr));
|
||||
@ -466,28 +420,24 @@ void MasterAttributes::WriteHDF5CounterMask(H5::H5File *fd, H5::Group *group) {
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5ExptimeArray(H5::H5File *fd, H5::Group *group) {
|
||||
for (int i = 0; i != 3; ++i) {
|
||||
char c[1024]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Exposure Time1", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(exptimeArray[i]));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
char c[HSTR_LEN]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Exposure Times", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(exptimeArray));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5GateDelayArray(H5::H5File *fd,
|
||||
H5::Group *group) {
|
||||
for (int i = 0; i != 3; ++i) {
|
||||
char c[1024]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Gate Delay1", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(gateDelayArray[i]));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
char c[HSTR_LEN]{};
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Gate Delays", strdatatype, dataspace);
|
||||
strcpy_safe(c, ToString(gateDelayArray));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
||||
void MasterAttributes::WriteHDF5Gates(H5::H5File *fd, H5::Group *group) {
|
||||
@ -499,10 +449,10 @@ void MasterAttributes::WriteHDF5Gates(H5::H5File *fd, H5::Group *group) {
|
||||
|
||||
void MasterAttributes::WriteHDF5BurstMode(H5::H5File *fd, H5::Group *group) {
|
||||
H5::DataSpace dataspace = H5::DataSpace(H5S_SCALAR);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, 256);
|
||||
H5::StrType strdatatype(H5::PredType::C_S1, HSTR_LEN);
|
||||
H5::DataSet dataset =
|
||||
group->createDataSet("Burst Mode", strdatatype, dataspace);
|
||||
char c[1024]{};
|
||||
char c[HSTR_LEN]{};
|
||||
strcpy_safe(c, ToString(burstMode));
|
||||
dataset.write(c, strdatatype);
|
||||
}
|
||||
|
@ -151,7 +151,13 @@ class MasterAttributes {
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> *w);
|
||||
#ifdef HDF5C
|
||||
void WriteXilinxCtbHDF5Attributes(H5::H5File *fd, H5::Group *group);
|
||||
#endif
|
||||
private:
|
||||
#ifdef HDF5C
|
||||
static const int HSTR_LEN = 1024;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace sls
|
||||
|
@ -19,8 +19,8 @@ namespace sls {
|
||||
// files
|
||||
|
||||
// versions
|
||||
#define HDF5_WRITER_VERSION (6.7) // 1 decimal places
|
||||
#define BINARY_WRITER_VERSION (7.3) // 1 decimal places
|
||||
#define HDF5_WRITER_VERSION (7.0)
|
||||
#define BINARY_WRITER_VERSION (7.3)
|
||||
|
||||
#define MAX_FRAMES_PER_FILE 20000
|
||||
#define SHORT_MAX_FRAMES_PER_FILE 100000
|
||||
|
@ -47,8 +47,6 @@ 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);
|
||||
|
@ -5,13 +5,6 @@
|
||||
|
||||
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 << ']';
|
||||
|
@ -16,17 +16,6 @@ namespace sls {
|
||||
|
||||
using namespace sls::time;
|
||||
|
||||
TEST_CASE("Convert bool to string", "[support]") {
|
||||
REQUIRE(ToString(true) == "1");
|
||||
REQUIRE(ToString(false) == "0");
|
||||
}
|
||||
|
||||
TEST_CASE("Convert string to bool", "[support]") {
|
||||
REQUIRE(StringTo<bool>("1") == true);
|
||||
REQUIRE(StringTo<bool>("0") == false);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Integer conversions", "[support]") {
|
||||
REQUIRE(ToString(0) == "0");
|
||||
REQUIRE(ToString(1) == "1");
|
||||
|
@ -20,7 +20,6 @@ from utils_for_test import (
|
||||
cleanSharedmemory,
|
||||
startProcessInBackground,
|
||||
startProcessInBackgroundWithLogFile,
|
||||
checkLogForErrors,
|
||||
startDetectorVirtualServer,
|
||||
loadConfig,
|
||||
ParseArguments
|
||||
@ -35,9 +34,6 @@ def startFrameSynchronizerPullSocket(name, fp):
|
||||
fname = PULL_SOCKET_PREFIX_FNAME + name + '.txt'
|
||||
cmd = ['python', '-u', 'frameSynchronizerPullSocket.py']
|
||||
startProcessInBackgroundWithLogFile(cmd, fp, fname)
|
||||
time.sleep(1)
|
||||
checkLogForErrors(fp, fname)
|
||||
|
||||
|
||||
|
||||
def startFrameSynchronizer(num_mods, fp):
|
||||
@ -48,14 +44,16 @@ def startFrameSynchronizer(num_mods, fp):
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
def acquire(fp, det):
|
||||
def acquire(fp):
|
||||
Log(LogLevel.INFO, 'Acquiring')
|
||||
Log(LogLevel.INFO, 'Acquiring', fp)
|
||||
det.acquire()
|
||||
d = Detector()
|
||||
d.acquire()
|
||||
|
||||
|
||||
def testFramesCaught(name, det, num_frames):
|
||||
fnum = det.rx_framescaught[0]
|
||||
def testFramesCaught(name, num_frames):
|
||||
d = Detector()
|
||||
fnum = d.rx_framescaught[0]
|
||||
if fnum != num_frames:
|
||||
raise RuntimeException(f"{name} caught only {fnum}. Expected {num_frames}")
|
||||
|
||||
@ -63,7 +61,7 @@ def testFramesCaught(name, det, num_frames):
|
||||
Log(LogLevel.INFOGREEN, f'Frames caught test passed for {name}', fp)
|
||||
|
||||
|
||||
def testZmqHeadetTypeCount(name, det, num_mods, num_frames, fp):
|
||||
def testZmqHeadetTypeCount(name, num_mods, num_frames, fp):
|
||||
|
||||
Log(LogLevel.INFO, f"Testing Zmq Header type count for {name}")
|
||||
Log(LogLevel.INFO, f"Testing Zmq Header type count for {name}", fp)
|
||||
@ -90,7 +88,8 @@ def testZmqHeadetTypeCount(name, det, num_mods, num_frames, fp):
|
||||
continue
|
||||
|
||||
# test if file contents matches expected counts
|
||||
num_ports_per_module = 1 if name == "gotthard2" else det.numinterfaces
|
||||
d = Detector()
|
||||
num_ports_per_module = 1 if name == "gotthard2" else d.numinterfaces
|
||||
total_num_frame_parts = num_ports_per_module * num_mods * num_frames
|
||||
for htype, expected_count in [("header", num_mods), ("series_end", num_mods), ("module", total_num_frame_parts)]:
|
||||
if htype_counts[htype] != expected_count:
|
||||
@ -112,10 +111,10 @@ def startTestsForAll(args, fp):
|
||||
startDetectorVirtualServer(server, args.num_mods, fp)
|
||||
startFrameSynchronizerPullSocket(server, fp)
|
||||
startFrameSynchronizer(args.num_mods, fp)
|
||||
d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=args.num_mods, num_frames=args.num_frames)
|
||||
acquire(fp, d)
|
||||
testFramesCaught(server, d, args.num_frames)
|
||||
testZmqHeadetTypeCount(server, d, args.num_mods, args.num_frames, fp)
|
||||
loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=args.num_mods, num_frames=args.num_frames)
|
||||
acquire(fp)
|
||||
testFramesCaught(server, args.num_frames)
|
||||
testZmqHeadetTypeCount(server, args.num_mods, args.num_frames, fp)
|
||||
Log(LogLevel.INFO, '\n')
|
||||
except Exception as e:
|
||||
raise RuntimeException(f'Synchronizer Tests failed') from e
|
||||
|
@ -104,7 +104,7 @@ def startProcessInBackground(cmd, fp):
|
||||
raise RuntimeException(f'Failed to start {cmd}:{str(e)}') from e
|
||||
|
||||
|
||||
def startProcessInBackgroundWithLogFile(cmd, fp, log_file_name: str):
|
||||
def startProcessInBackgroundWithLogFile(cmd, fp, log_file_name):
|
||||
Log(LogLevel.INFOBLUE, 'Starting up ' + ' '.join(cmd) + '. Log: ' + log_file_name)
|
||||
Log(LogLevel.INFOBLUE, 'Starting up ' + ' '.join(cmd) + '. Log: ' + log_file_name, fp)
|
||||
try:
|
||||
@ -114,22 +114,6 @@ def startProcessInBackgroundWithLogFile(cmd, fp, log_file_name: str):
|
||||
raise RuntimeException(f'Failed to start {cmd}:{str(e)}') from e
|
||||
|
||||
|
||||
def checkLogForErrors(fp, log_file_path: str):
|
||||
try:
|
||||
with open(log_file_path, 'r') as log_file:
|
||||
for line in log_file:
|
||||
if 'Error' in line:
|
||||
Log(LogLevel.ERROR, f"Error found in log: {line.strip()}")
|
||||
Log(LogLevel.ERROR, f"Error found in log: {line.strip()}", fp)
|
||||
raise RuntimeException("Error found in log file")
|
||||
except FileNotFoundError:
|
||||
print(f"Log file not found: {log_file_path}")
|
||||
raise
|
||||
except Exception as e:
|
||||
print(f"Exception while reading log: {e}")
|
||||
raise
|
||||
|
||||
|
||||
def runProcessWithLogFile(name, cmd, fp, log_file_name):
|
||||
Log(LogLevel.INFOBLUE, 'Running ' + name + '. Log: ' + log_file_name)
|
||||
Log(LogLevel.INFOBLUE, 'Running ' + name + '. Log: ' + log_file_name, fp)
|
||||
@ -156,7 +140,7 @@ def startDetectorVirtualServer(name :str, num_mods, fp):
|
||||
for i in range(num_mods):
|
||||
port_no = SERVER_START_PORTNO + (i * 2)
|
||||
cmd = [name + 'DetectorServer_virtual', '-p', str(port_no)]
|
||||
startProcessInBackgroundWithLogFile(cmd, fp, "/tmp/virtual_det_" + name + str(i) + ".txt")
|
||||
startProcessInBackground(cmd, fp)
|
||||
match name:
|
||||
case 'jungfrau':
|
||||
time.sleep(7)
|
||||
@ -217,8 +201,6 @@ def loadConfig(name, rx_hostname, settingsdir, fp, num_mods = 1, num_frames = 1)
|
||||
d.frames = num_frames
|
||||
except Exception as e:
|
||||
raise RuntimeException(f'Could not load config for {name}. Error: {str(e)}') from e
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def ParseArguments(description, default_num_mods=1):
|
||||
|
Reference in New Issue
Block a user