Compare commits

...

16 Commits

Author SHA1 Message Date
2b9ce9a26e Merge branch '2406-more-minor-stuff' into 'main'
v1.0.0_rc.11

See merge request jungfraujoch/nextgendcu!73
2024-06-30 17:48:35 +02:00
3035d9e144 v1.0.0_rc.11 2024-06-30 17:48:35 +02:00
53b5a304d3 Merge branch '2406-openapi-python-client' into 'main'
Minor modifications to jfjoch_writer and OpenAPI

See merge request jungfraujoch/nextgendcu!72
2024-06-28 20:44:51 +02:00
30a92d8eb9 Minor modifications to jfjoch_writer and OpenAPI 2024-06-28 20:44:51 +02:00
81df571961 Merge branch '2406-after-crmx' into 'main'
Modifications after CristallinaMX beamtime

See merge request jungfraujoch/nextgendcu!71
2024-06-27 20:26:11 +02:00
1717e171b9 Modifications after CristallinaMX beamtime 2024-06-27 20:26:11 +02:00
4e59930972 Merge branch '2406-crmx' into 'main'
Release 1.0.0_rc.9

See merge request jungfraujoch/nextgendcu!70
2024-06-20 11:26:40 +02:00
a32c7274a6 Release 1.0.0_rc.9 2024-06-20 11:26:40 +02:00
8809b8d0d5 Merge branch '2405-writer-metadata' into 'main'
Extra metadata in HDF5 writer completed file stream

See merge request jungfraujoch/nextgendcu!69
2024-06-05 18:18:12 +02:00
86b3934387 Extra metadata in HDF5 writer completed file stream 2024-06-05 18:18:12 +02:00
7d9dcf2721 Merge branch '2405-maxiv-day-5' into 'main'
Updates after MAX IV experiment

See merge request jungfraujoch/nextgendcu!68
2024-06-03 10:56:43 +02:00
953c3fa972 Updates after MAX IV experiment 2024-06-03 10:56:43 +02:00
5d7a4e1ff2 Merge branch '2405-maxiv-day-3-2' into 'main'
PreviewImage: remove mutex

See merge request jungfraujoch/nextgendcu!67
2024-05-23 22:58:52 +02:00
f85b87bfd2 PreviewImage: remove mutex 2024-05-23 22:58:52 +02:00
500222bdcc Merge branch '2405-maxiv-day-3' into 'main'
Minor modifications

See merge request jungfraujoch/nextgendcu!66
2024-05-23 17:11:14 +02:00
c4d677f05b Minor modifications 2024-05-23 17:11:14 +02:00
178 changed files with 4018 additions and 2083 deletions

View File

@@ -251,6 +251,7 @@ synthesis:vivado_pcie_100g:
- fpga/pcie_driver/jfjoch_fpga.h
tags:
- vivado
retry: 1
artifacts:
paths:
- "jfjoch_fpga_pcie_100g.mcs"
@@ -284,6 +285,7 @@ synthesis:vivado_pcie_8x10g:
allow_failure: true
tags:
- vivado
retry: 1
artifacts:
paths:
- "jfjoch_fpga_pcie_8x10g.mcs"
@@ -316,11 +318,8 @@ release:
- export PACKAGE_VERSION=`head -n1 VERSION`
- export PACKAGE_REGISTRY_URL="${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/jungfraujoch/${PACKAGE_VERSION}"
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm "${PACKAGE_REGISTRY_URL}/jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm "${PACKAGE_REGISTRY_URL}/jfjoch-driver-dkms.el8.noarch.rpm"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm "${PACKAGE_REGISTRY_URL}/jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm "${PACKAGE_REGISTRY_URL}/jfjoch-writer.el8.x86_64.rpm"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm "${PACKAGE_REGISTRY_URL}/jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm "${PACKAGE_REGISTRY_URL}/jfjoch.el8.x86_64.rpm"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch_driver.tar.gz "${PACKAGE_REGISTRY_URL}/jfjoch_driver.tar.gz"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch_frontend.tar.gz "${PACKAGE_REGISTRY_URL}/jfjoch_frontend.tar.gz"'
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file jfjoch_fpga_pcie_100g.mcs "${PACKAGE_REGISTRY_URL}/jfjoch_fpga_pcie_100g.mcs"'
@@ -331,9 +330,6 @@ release:
--assets-link "{\"name\":\"jfjoch_frontend.tar.gz\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch_frontend.tar.gz\"}"
--assets-link "{\"name\":\"jfjoch_fpga_pcie_8x10g.mcs\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch_fpga_pcie_8x10g.mcs\"}"
--assets-link "{\"name\":\"jfjoch_fpga_pcie_100g.mcs\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch_fpga_pcie_100g.mcs\"}"
--assets-link "{\"name\":\"jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm\"}"
--assets-link "{\"name\":\"jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm\"}"
--assets-link "{\"name\":\"jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm\"}"
--assets-link "{\"name\":\"jfjoch.el8.x86_64.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch.el8.x86_64.rpm\"}"
--assets-link "{\"name\":\"jfjoch-writer.el8.x86_64.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-writer.el8.x86_64.rpm\"}"
--assets-link "{\"name\":\"jfjoch-driver-dkms.el8.noarch.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-driver-dkms.el8.noarch.rpm\"}"
--assets-link "{\"name\":\"jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-${PACKAGE_VERSION}-1.el8.x86_64.rpm\",\"link_type\":\"package\"}"
--assets-link "{\"name\":\"jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-writer-${PACKAGE_VERSION}-1.el8.x86_64.rpm\",\"link_type\":\"package\"}"
--assets-link "{\"name\":\"jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm\",\"url\":\"${PACKAGE_REGISTRY_URL}/jfjoch-driver-dkms-${PACKAGE_VERSION}-1.el8.noarch.rpm\",\"link_type\":\"package\"}"

View File

@@ -134,7 +134,12 @@ IF (NOT JFJOCH_WRITER_ONLY)
INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/fpga/pcie_driver/
DESTINATION /usr/src/jfjoch-1.0.0
COMPONENT driver-dkms
FILES_MATCHING PATTERN "*.c" PATTERN "*.h" PATTERN "Makefile" PATTERN "dkms.conf")
FILES_MATCHING PATTERN "dkms.conf")
INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/fpga/pcie_driver/
DESTINATION /usr/src/jfjoch-1.0.0/src
COMPONENT driver-dkms
FILES_MATCHING PATTERN "*.c" PATTERN "*.h" PATTERN "Makefile")
FILE(MAKE_DIRECTORY ${CMAKE_SOURCE_DIR}/frontend_ui/build/)
INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/frontend_ui/build/ DESTINATION share/jfjoch/frontend COMPONENT jfjoch )
@@ -161,6 +166,7 @@ SET(CPACK_RPM_DRIVER-DKMS_PACKAGE_REQUIRES "dkms, gcc, bash, sed")
SET(CPACK_RPM_DRIVER-DKMS_PACKAGE_ARCHITECTURE "noarch")
SET(CPACK_RPM_DRIVER-DKMS_POST_INSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/fpga/pcie_driver/postinstall.sh)
SET(CPACK_RPM_DRIVER-DKMS_PRE_UNINSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/fpga/pcie_driver/preuninstall.sh)
SET(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/src)
# Set The Vendor Name
SET(CPACK_PACKAGE_VENDOR "Paul Scherrer Institut")

View File

@@ -7,6 +7,7 @@ Citation: F. Leonarski, M. Bruckner, C. Lopez-Cuenca, A. Mozzanica, H.-C. Stadle
The project is supported by :
* Innosuisse via Innovation Project "NextGenDCU high data rate acquisition system for X-ray detectors in structural biology applications" (101.535.1 IP-ENG; Apr 2023 - Sep 2025).
* ETH Domain via Open Research Data Contribute project (Jan - Dec 2023)
* AMD University Program with donation of licenses of Ethernet IP cores and Vivado software
## License

View File

@@ -1 +1 @@
1.0.0_rc.6
1.0.0_rc.11

View File

@@ -4,6 +4,8 @@
#include <nlohmann/json.hpp>
#include "JFJochBrokerHttp.h"
#include "gen/model/Error_message.h"
#include "../preview/JFJochTIFF.h"
#include "../common/GitInfo.h"
// From https://en.cppreference.com/w/cpp/string/byte/tolower
inline std::string str_tolower(std::string s) {
@@ -22,6 +24,10 @@ inline SpotFindingSettings Convert(const org::openapitools::server::model::Spot_
ret.enable = input.isEnable();
ret.indexing = input.isIndexing();
ret.indexing_tolerance = input.getIndexingTolerance();
if (input.filterPowderRingsIsSet())
ret.filter_spots_powder_ring = input.isFilterPowderRings();
if (input.minSpotCountPowderRingIsSet())
ret.min_spot_count_powder_ring = input.getMinSpotCountPowderRing();
return ret;
}
@@ -36,6 +42,8 @@ inline org::openapitools::server::model::Spot_finding_settings Convert(const Spo
ret.setEnable(input.enable);
ret.setIndexing(input.indexing);
ret.setIndexingTolerance(input.indexing_tolerance);
ret.setFilterPowderRings(input.filter_spots_powder_ring);
ret.setMinSpotCountPowderRing(input.min_spot_count_powder_ring);
return ret;
}
@@ -45,6 +53,7 @@ inline org::openapitools::server::model::Measurement_statistics Convert(const Me
if (!input.file_prefix.empty())
ret.setFilePrefix(input.file_prefix);
ret.setExperimentGroup(input.experiment_group);
ret.setImagesExpected(input.images_expected);
ret.setImagesCollected(input.images_collected);
ret.setImagesSent(input.images_sent);
@@ -68,7 +77,7 @@ inline org::openapitools::server::model::Measurement_statistics Convert(const Me
if (input.bkg_estimate)
ret.setBkgEstimate(input.bkg_estimate.value());
ret.setUnitCell(input.unit_cell);
ret.setRunNumber(input.run_number);
return ret;
}
@@ -185,10 +194,10 @@ inline org::openapitools::server::model::Detector_status Convert(const DetectorS
output.setHighVoltageV(input.high_voltage_V);
switch (input.power_state) {
case DetectorPowerState::ON:
output.setPowerchip("On");
output.setPowerchip("PowerOn");
break;
case DetectorPowerState::OFF:
output.setPowerchip("Off");
output.setPowerchip("PowerOff");
break;
case DetectorPowerState::PARTIAL:
output.setPowerchip("Partial");
@@ -317,6 +326,7 @@ inline PreviewJPEGSettings Convert(const org::openapitools::server::model::Previ
ret.saturation_value = input.getSaturation();
ret.show_roi = input.isShowRoi();
ret.show_indexed = input.isShowIndexed();
ret.show_user_mask = input.isShowUserMask();
if (input.resolutionRingIsSet())
ret.resolution_ring = input.getResolutionRing();
return ret;
@@ -328,6 +338,13 @@ inline DatasetSettings Convert(const org::openapitools::server::model::Dataset_s
ret.ImagesPerTrigger(input.getImagesPerTrigger());
ret.NumTriggers(input.getNtrigger());
if (input.runNumberIsSet())
ret.RunNumber(input.getRunNumber());
if (input.runNameIsSet())
ret.RunName(input.getRunName());
ret.ExperimentGroup(input.getExperimentGroup());
if (!input.fpgaOutputIsSet())
ret.FPGAOutputMode(FPGAPixelOutput::Auto);
else {
@@ -346,13 +363,13 @@ inline DatasetSettings Convert(const org::openapitools::server::model::Dataset_s
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Unknown output format");
}
ret.Summation(input.getSummation());
if (input.imageTimeUsIsSet())
ret.ImageTime(std::chrono::microseconds(input.getImageTimeUs()));
ret.BeamX_pxl(input.getBeamXPxl());
ret.BeamY_pxl(input.getBeamYPxl());
ret.DetectorDistance_mm(input.getDetectorDistanceMm());
ret.PhotonEnergy_keV(input.getPhotonEnergyKeV());
ret.PhotonEnergyMultiplayer(input.getPhotonEnergyMultiplier());
ret.PhotonEnergy_keV(input.getIncidentEnergyKeV());
ret.PhotonEnergyMultiplayer(input.getEnergyMultiplier());
ret.FilePrefix(input.getFilePrefix());
@@ -387,12 +404,15 @@ inline DatasetSettings Convert(const org::openapitools::server::model::Dataset_s
if (input.transmissionIsSet())
ret.AttenuatorTransmission(input.getTransmission());
if (input.omegaIsSet()) {
ret.OmegaStep(input.getOmega().getStep());
ret.OmegaStart(input.getOmega().getStart());
if (input.getOmega().getVector().size() == 3) {
auto v = input.getOmega().getVector();
ret.OmegaAxis(Coord(v[0], v[1], v[2]));
if (input.goniometerIsSet()) {
ret.Goniometer(GoniometerAxis{
.name = input.getGoniometer().getName(),
.increment = input.getGoniometer().getStep(),
.start = input.getGoniometer().getStart()
});
if (input.getGoniometer().getVector().size() == 3) {
auto v = input.getGoniometer().getVector();
ret.RotationAxis(Coord(v[0], v[1], v[2]));
}
}
@@ -455,8 +475,21 @@ void JFJochBrokerHttp::status_get(Pistache::Http::ResponseWriter &response) {
ProcessOutput(Convert(state_machine.GetStatus()), response);
}
void JFJochBrokerHttp::wait_till_done_post(Pistache::Http::ResponseWriter &response) {
auto state = state_machine.WaitTillMeasurementDone(std::chrono::seconds(5));
void JFJochBrokerHttp::wait_till_done_post(const std::optional<int32_t> &timeout,
Pistache::Http::ResponseWriter &response) {
JFJochState state;
if (!timeout)
state = state_machine.WaitTillMeasurementDone(std::chrono::minutes(1));
else if ((timeout.value() > 3600) || (timeout.value() < 0)) {
response.send(Pistache::Http::Code::Bad_Request);
return;
} else if (timeout.value() == 0)
state = state_machine.GetState();
else
state = state_machine.WaitTillMeasurementDone(std::chrono::seconds(timeout.value()));
switch (state) {
case JFJochState::Idle:
response.send(Pistache::Http::Code::Ok);
@@ -655,18 +688,33 @@ void JFJochBrokerHttp::preview_image_tiff_get(Pistache::Http::ResponseWriter &re
void JFJochBrokerHttp::config_internal_generator_image_put(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter &response) {
int64_t image_number = 0;
auto number_query = request.query().get("number");
auto number_query = request.query().get("id");
if (number_query)
image_number = std::stoi(number_query.value());
if ((image_number < 0) || (image_number > 127))
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "image_number must be in range 0-127");
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "id must be in range 0-127");
state_machine.LoadInternalGeneratorImage(request.body().data(), request.body().size(), image_number);
logger.Info("Internal generator image #{} loaded", image_number);
response.send(Pistache::Http::Code::Ok);
}
void JFJochBrokerHttp::config_internal_generator_image_tiff_put(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter &response) {
int64_t image_number = 0;
auto number_query = request.query().get("id");
if (number_query)
image_number = std::stoi(number_query.value());
if ((image_number < 0) || (image_number > 127))
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "id must be in range 0-127");
state_machine.LoadInternalGeneratorImageTIFF(request.body(), image_number);
response.send(Pistache::Http::Code::Ok);
}
void JFJochBrokerHttp::roi_box_get(Pistache::Http::ResponseWriter &response) {
ProcessOutput(Convert(state_machine.GetBoxROI()), response);
}
@@ -782,3 +830,23 @@ void JFJochBrokerHttp::plot_strong_pixel_get(const std::optional<int32_t> &binni
Pistache::Http::ResponseWriter &response) {
GenericPlot(PlotType::StrongPixels, binning, response);
}
void JFJochBrokerHttp::config_mask_tiff_get(Pistache::Http::ResponseWriter &response) {
std::string s = state_machine.GetFullPixelMaskTIFF();
response.send(Pistache::Http::Code::Ok, s, Pistache::Http::Mime::MediaType::fromString("image/tiff"));
}
void JFJochBrokerHttp::config_user_mask_tiff_get(Pistache::Http::ResponseWriter &response) {
std::string s = state_machine.GetUserPixelMaskTIFF();
response.send(Pistache::Http::Code::Ok, s, Pistache::Http::Mime::MediaType::fromString("image/tiff"));
}
void JFJochBrokerHttp::config_user_mask_tiff_put(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter &response) {
state_machine.SetUserPixelMask(request.body());
response.send(Pistache::Http::Code::Ok);
}
void JFJochBrokerHttp::version_get(Pistache::Http::ResponseWriter &response) {
response.send(Pistache::Http::Code::Ok, jfjoch_version(), MIME(Text, Plain));
}

View File

@@ -90,7 +90,7 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi {
void status_get(Pistache::Http::ResponseWriter &response) override;
void wait_till_done_post(Pistache::Http::ResponseWriter &response) override;
void wait_till_done_post(const std::optional<int32_t> &timeoutMs, Pistache::Http::ResponseWriter &response) override;
void trigger_post(Pistache::Http::ResponseWriter &response) override;
void pedestal_post(Pistache::Http::ResponseWriter &response) override;
@@ -118,6 +118,16 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi {
void xfel_event_code_get(Pistache::Http::ResponseWriter &response) override;
void xfel_pulse_id_get(Pistache::Http::ResponseWriter &response) override;
void config_mask_tiff_get(Pistache::Http::ResponseWriter &response) override;
void config_user_mask_tiff_get(Pistache::Http::ResponseWriter &response) override;
void config_user_mask_tiff_put(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter &response) override;
void config_internal_generator_image_tiff_put(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter &response) override;
void GetStaticFile(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
std::pair<Pistache::Http::Code, std::string> handleOperationException(const std::exception &ex) const noexcept override;
@@ -133,6 +143,9 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi {
to_json(j, output);
response.send(Pistache::Http::Code::Ok, j.dump(), MIME(Application, Json));
}
void version_get(Pistache::Http::ResponseWriter &response) override;
public:
JFJochBrokerHttp(const DiffractionExperiment& experiment, std::shared_ptr<Pistache::Rest::Router> &rtr);
void AddDetectorSetup(const DetectorSetup &setup);

View File

@@ -2,6 +2,8 @@
#include "JFJochBrokerParser.h"
#include "../common/NetworkAddressConvert.h"
#include "../frame_serialize/ZMQStream2Pusher.h"
#include "../frame_serialize/DumpCBORToFilePusher.h"
inline bool CHECK_ARRAY(const nlohmann::json &j, const std::string& tag) {
if (j.contains(tag)) {
@@ -183,6 +185,7 @@ inline int64_t TimeToUs(const std::string &unit) {
inline std::chrono::microseconds GET_TIME(const nlohmann::json &j, const std::string& tag) {
if (j.contains(tag)) {
// If no units provided for time, this is always microsecond
if (j[tag].is_number())
return std::chrono::microseconds (std::lround(j[tag].get<double>() * 1000.0 * 1000.0));
else if (j[tag].is_string()) {
@@ -283,7 +286,8 @@ DetectorSetup ParseDetectorSetup(const nlohmann::json &j) {
setup.UDPInterfaceCount(GET_I64(j, "udp_interface_count", 2))
.SensorThickness_um(GET_FLOAT(j, "sensor_thickness_um", 320.0f))
.PixelSize_um(GET_FLOAT(j, "pixel_size_um", 75.0f))
.SensorMaterial(GET_STR(j, "sensor_material", "Si"));
.SensorMaterial(GET_STR(j, "sensor_material", "Si"))
.SerialNumber(GET_STR(j, "serial_number",""));
if (j.contains("tx_delay"))
setup.TxDelay(GET_I64_ARR(j, "tx_delay"));
@@ -299,24 +303,55 @@ void ParseDetectorSetup(const nlohmann::json &j, const std::string& tag, JFJochB
throw JFJochException(JFJochExceptionCategory::JSON, "Detector setup not found");
}
void ParseImagePusher(const nlohmann::json &input, std::unique_ptr<ImagePusher> &image_pusher) {
std::string pusher_type = ParseString(input, "stream_type", "zmq");
if (pusher_type == "zmq") {
int32_t zmq_send_watermark = ParseInt32(input, "zmq_send_watermark", 100);
int32_t zmq_send_buffer_size = ParseInt32(input, "zmq_send_buffer_size", -1);
auto tmp = std::make_unique<ZMQStream2Pusher>(ParseStringArray(input, "zmq_image_addr"),
zmq_send_watermark,
zmq_send_buffer_size);
std::string preview_addr = ParseString(input, "zmq_preview_addr", "");
if (!preview_addr.empty())
tmp->PreviewSocket(preview_addr);
if (input.contains("zmq_preview_period"))
tmp->PreviewCounterPeriod(GET_TIME(input, "zmq_preview_period"));
std::string writer_notification_addr = ParseString(input, "zmq_writer_notification_addr", "");
if (!writer_notification_addr.empty())
tmp->WriterNotificationSocket(writer_notification_addr);
image_pusher = std::move(tmp);
} else if (pusher_type == "dump_cbor") {
image_pusher = std::make_unique<DumpCBORToFilePusher>();
} else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"stream_type allowed: zmq (default), dump_cbor");
}
void ParseFacilityConfiguration(const nlohmann::json &input, const std::string& tag, DiffractionExperiment &experiment) {
if (CHECK_OBJECT(input, tag)) {
auto j = input[tag];
experiment.SourceName(GET_STR(j, "source_name"));
experiment.SourceNameShort(GET_STR(j, "source_name_short"));
experiment.SourceType(GET_STR(j, "source_type", ""));
experiment.InstrumentName(GET_STR(j, "instrument_name"));
experiment.InstrumentNameShort(GET_STR(j, "instrument_name_short"));
experiment.PulsedSource(GET_BOOL(j, "pulsed_source", false));
if (j.contains("omega_axis")) {
if (j["omega_axis"].is_array() && (j["omega_axis"].size() == 3))
experiment.DefaultOmegaAxis(Coord(j["omega_axis"][0].get<float>(),
j["omega_axis"][1].get<float>(),
j["omega_axis"][2].get<float>()));
if (j.contains("rotation_axis")) {
if (j["rotation_axis"].is_array() && (j["rotation_axis"].size() == 3))
experiment.DefaultRotationAxis(Coord(j["rotation_axis"][0].get<float>(),
j["rotation_axis"][1].get<float>(),
j["rotation_axis"][2].get<float>()));
else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"omega_axis must be float array of 3");
"rotation_axis must be float array of 3");
}
if (j.contains("pedestal_g0_frames"))
@@ -325,12 +360,11 @@ void ParseFacilityConfiguration(const nlohmann::json &input, const std::string&
experiment.PedestalG1Frames(GET_I64(j, "pedestal_g1_frames"));
if (j.contains("pedestal_g2_frames"))
experiment.PedestalG2Frames(GET_I64(j, "pedestal_g2_frames"));
if (j.contains("detector_trigger_delay_us"))
experiment.DetectorDelay(GET_TIME(j, "detector_trigger_delay_us"));
if (j.contains("detector_trigger_delay"))
experiment.DetectorDelay(GET_TIME(j, "detector_trigger_delay"));
experiment.FrameTime(GET_TIME(j, "frame_time"), GET_TIME(j, "count_time"));
experiment.FrameTime(GET_TIME(j, "frame_time_us"), GET_TIME(j, "count_time_us"));
if (j.contains("preview_period_us"))
experiment.PreviewPeriod(GET_TIME(j, "preview_period_us"));
experiment.UseInternalPacketGenerator(GET_BOOL(j, "internal_frame_generator", false));
if (experiment.IsUsingInternalPacketGen())
experiment.ConversionOnFPGA(false);

View File

@@ -14,6 +14,7 @@ DetectorGeometry ParseDetectorGeometry(const nlohmann::json &j);
DetectorSetup ParseDetectorSetup(const nlohmann::json &j);
void ParseDetectorSetup(const nlohmann::json &j, const std::string& tag, JFJochBrokerHttp& broker);
void ParseFacilityConfiguration(const nlohmann::json &j, const std::string& tag, DiffractionExperiment &experiment);
void ParseImagePusher(const nlohmann::json &j, std::unique_ptr<ImagePusher> &image_pusher);
void ParseAcquisitionDeviceGroup(const nlohmann::json &input, const std::string& tag, AcquisitionDeviceGroup &aq_devices);
std::vector<std::string> ParseStringArray(const nlohmann::json &input, const std::string& tag);

View File

@@ -5,15 +5,17 @@
JFJochServices::JFJochServices(Logger &in_logger) : logger(in_logger) {}
void JFJochServices::Start(const DiffractionExperiment& experiment, const JFCalibration &calibration) {
void JFJochServices::Start(const DiffractionExperiment& experiment,
const PixelMask &pixel_mask,
const JFCalibration &calibration) {
logger.Info("Measurement start for: {}", experiment.GetFilePrefix());
if (receiver != nullptr) {
logger.Info(" ... receiver start");
if (experiment.GetDetectorMode() == DetectorMode::Conversion)
receiver->Start(experiment, &calibration);
receiver->Start(experiment, pixel_mask, &calibration);
else
receiver->Start(experiment, nullptr);
receiver->Start(experiment, pixel_mask, nullptr);
if (detector && !experiment.IsUsingInternalPacketGen()) {
logger.Info(" ... detector start");

View File

@@ -23,7 +23,9 @@ public:
void On(const DiffractionExperiment& experiment);
void Off();
void ConfigureDetector(const DiffractionExperiment& experiment);
void Start(const DiffractionExperiment& experiment, const JFCalibration &calibration);
void Start(const DiffractionExperiment& experiment,
const PixelMask &pixel_mask,
const JFCalibration &calibration);
JFJochServicesOutput Stop();
void Cancel();
void Trigger();

View File

@@ -3,7 +3,7 @@
#include <thread>
#include "JFJochStateMachine.h"
#include "../preview/WriteTIFF.h"
#include "../preview/JFJochTIFF.h"
void ApplyDetectorSettings(DiffractionExperiment& experiment, const DetectorSettings &settings) {
auto tmp = experiment;
@@ -66,8 +66,10 @@ void ApplyRadialIntegrationSettings(DiffractionExperiment& experiment, const Rad
}
JFJochStateMachine::JFJochStateMachine(JFJochServices &in_services, Logger &in_logger)
: services(in_services), logger(in_logger),
data_processing_settings(DiffractionExperiment::DefaultDataProcessingSettings()) {
: services(in_services),
logger(in_logger),
data_processing_settings(DiffractionExperiment::DefaultDataProcessingSettings()),
pixel_mask(experiment) {
}
@@ -126,6 +128,7 @@ void JFJochStateMachine::TakePedestalInternalAll(std::unique_lock<std::mutex> &u
}
}
services.ConfigureDetector(experiment);
pixel_mask.LoadDetectorBadPixelMask(calibration->CalculateMask());
} catch (const std::exception &e) {
logger.Error("Pedestal sequence error {}", e.what());
state = JFJochState::Error;
@@ -158,7 +161,7 @@ void JFJochStateMachine::TakePedestalInternalG0(std::unique_lock<std::mutex> &ul
state = JFJochState::Pedestal;
services.ConfigureDetector(local_experiment);
services.Start(local_experiment, *calibration);
services.Start(local_experiment, pixel_mask, *calibration);
services.Trigger();
@@ -197,7 +200,7 @@ void JFJochStateMachine::TakePedestalInternalG1(std::unique_lock<std::mutex> &ul
state = JFJochState::Pedestal;
services.ConfigureDetector(local_experiment);
services.Start(local_experiment, *calibration);
services.Start(local_experiment, pixel_mask, *calibration);
services.Trigger();
@@ -236,7 +239,7 @@ void JFJochStateMachine::TakePedestalInternalG2(std::unique_lock<std::mutex> &ul
state = JFJochState::Pedestal;
services.ConfigureDetector(local_experiment);
services.Start(local_experiment, *calibration);
services.Start(local_experiment, pixel_mask, *calibration);
services.Trigger();
@@ -321,12 +324,12 @@ void JFJochStateMachine::Start(const DatasetSettings& settings) {
else
experiment.StorageCellStart(0);
experiment.IncrementSeriesID();
experiment.IncrementRunNumber();
try {
state = JFJochState::Busy;
services.SetSpotFindingSettings(GetSpotFindingSettings());
services.Start(experiment, *calibration);
services.Start(experiment, pixel_mask, *calibration);
state = JFJochState::Measuring;
measurement = std::async(std::launch::async, &JFJochStateMachine::MeasurementThread, this);
@@ -337,12 +340,6 @@ void JFJochStateMachine::Start(const DatasetSettings& settings) {
}
}
void JFJochStateMachine::WaitTillMeasurementDone() {
std::unique_lock<std::mutex> ul(m);
c.wait(ul, [&] { return !IsRunning(); });
}
void JFJochStateMachine::MeasurementThread() {
try {
auto tmp_output = services.Stop();
@@ -398,6 +395,9 @@ void JFJochStateMachine::SetFullMeasurementOutput(const JFJochServicesOutput &ou
MeasurementStatistics tmp{}; // reset last measurement statistics
tmp.file_prefix = experiment.GetFilePrefix();
tmp.run_number = experiment.GetRunNumber();
tmp.experiment_group = experiment.GetExperimentGroup();
tmp.detector_width = experiment.GetXPixelsNum();
tmp.detector_height = experiment.GetYPixelsNum();
tmp.detector_pixel_depth = experiment.GetPixelDepth();
@@ -424,6 +424,9 @@ void JFJochStateMachine::ClearAndSetMeasurementStatistics() {
MeasurementStatistics tmp{};
tmp.file_prefix = experiment.GetFilePrefix();
tmp.run_number = experiment.GetRunNumber();
tmp.experiment_group = experiment.GetExperimentGroup();
tmp.detector_height = experiment.GetXPixelsNum();
tmp.detector_width = experiment.GetYPixelsNum();
tmp.detector_pixel_depth = experiment.GetPixelDepth();
@@ -445,6 +448,9 @@ std::optional<MeasurementStatistics> JFJochStateMachine::GetMeasurementStatistic
MeasurementStatistics tmp;
tmp.file_prefix = experiment.GetFilePrefix();
tmp.run_number = experiment.GetRunNumber();
tmp.experiment_group = experiment.GetExperimentGroup();
tmp.detector_width = experiment.GetXPixelsNum();
tmp.detector_height = experiment.GetYPixelsNum();
tmp.detector_pixel_depth = experiment.GetPixelDepth();
@@ -562,6 +568,7 @@ void JFJochStateMachine::AddDetectorSetup(const DetectorSetup &setup) {
experiment.Detector(setup);
gain_calibration = setup.GetGainCalibration();
current_detector_setup = 0;
pixel_mask = PixelMask(setup);
}
detector_setup.emplace_back(setup);
}
@@ -599,6 +606,7 @@ void JFJochStateMachine::SelectDetector(int64_t id) {
try {
experiment.Detector(detector_setup[id]);
gain_calibration = detector_setup[id].GetGainCalibration();
pixel_mask = PixelMask(detector_setup[id]);
state = JFJochState::Inactive;
current_detector_setup = id;
} catch (JFJochException &e) {
@@ -645,6 +653,14 @@ bool JFJochStateMachine::IsRunning() const {
}
}
JFJochState JFJochStateMachine::WaitTillMeasurementDone() {
std::unique_lock<std::mutex> ul(m);
c.wait(ul, [&] { return !IsRunning(); });
return state;
}
JFJochState JFJochStateMachine::WaitTillMeasurementDone(std::chrono::milliseconds timeout) {
std::unique_lock<std::mutex> ul(m);
@@ -705,6 +721,21 @@ void JFJochStateMachine::LoadInternalGeneratorImage(const void *data, size_t siz
services.LoadInternalGeneratorImage(experiment, image, image_number);
}
void JFJochStateMachine::LoadInternalGeneratorImageTIFF(const std::string &s, uint64_t image_number) {
std::unique_lock<std::mutex> ul(m);
if (state != JFJochState::Idle)
throw WrongDAQStateException ("Can change internal generator image only when detector in Idle state");
uint32_t cols, lines;
auto v = ReadTIFFFromString16(s, cols, lines);
if (((cols == experiment.GetXPixelsNum()) && (lines == experiment.GetYPixelsNum()))
|| ((cols == RAW_MODULE_SIZE) && (lines == RAW_MODULE_LINES * experiment.GetModulesNum())))
services.LoadInternalGeneratorImage(experiment, v, image_number);
else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Image size doesn't match current detector");
}
void JFJochStateMachine::SetBoxROI(const std::vector<ROIBox> &input) {
std::unique_lock<std::mutex> ul(m);
@@ -744,3 +775,33 @@ std::vector<uint64_t> JFJochStateMachine::GetXFELEventCode() const {
services.GetXFELEventCode(ret);
return ret;
}
std::string JFJochStateMachine::GetFullPixelMaskTIFF() const {
std::unique_lock<std::mutex> ul(m);
std::vector v = pixel_mask.GetMask(experiment);
return WriteTIFFToString(v.data(), experiment.GetXPixelsNum(), experiment.GetYPixelsNum(),
sizeof(uint32_t), false);
}
std::string JFJochStateMachine::GetUserPixelMaskTIFF() const {
std::unique_lock<std::mutex> ul(m);
std::vector v = pixel_mask.GetUserMask(experiment);
return WriteTIFFToString(v.data(), experiment.GetXPixelsNum(), experiment.GetYPixelsNum(),
sizeof(uint32_t), false);
}
void JFJochStateMachine::SetUserPixelMask(const std::string &s) {
std::unique_lock<std::mutex> ul(m);
if (state != JFJochState::Idle)
throw WrongDAQStateException ("User mask can be only modified in Idle state");
try {
uint32_t cols, lines;
auto v = ReadTIFFFromString32(s, cols, lines);
pixel_mask.LoadUserMask(experiment, v);
} catch (const JFJochException &e) {
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Problem handling user mask " + std::string(e.what()));
}
}

View File

@@ -37,6 +37,9 @@ struct DetectorList {
struct MeasurementStatistics {
std::string file_prefix;
std::string experiment_group;
int64_t run_number;
int64_t images_expected;
int64_t images_collected;
int64_t images_sent;
@@ -98,6 +101,8 @@ class JFJochStateMachine {
volatile JFJochState state = JFJochState::Inactive;
volatile bool cancel_sequence = false;
std::unique_ptr<JFCalibration> calibration;
PixelMask pixel_mask;
std::vector<JFModuleGainCalibration> gain_calibration;
std::vector<DetectorSetup> detector_setup;
int64_t current_detector_setup;
@@ -136,7 +141,7 @@ public:
void Pedestal();
void Deactivate();
void Start(const DatasetSettings& settings);
void WaitTillMeasurementDone();
JFJochState WaitTillMeasurementDone();
JFJochState WaitTillMeasurementDone(std::chrono::milliseconds timeout);
void Trigger();
@@ -172,6 +177,7 @@ public:
std::string GetPedestalTIFF(size_t gain_level, size_t sc) const;
void LoadInternalGeneratorImage(const void *data, size_t size, uint64_t image_number);
void LoadInternalGeneratorImageTIFF(const std::string &s, uint64_t image_number);
// Not thread safe - only for configuration in serial context
DiffractionExperiment& NotThreadSafe_Experiment();
@@ -187,6 +193,10 @@ public:
std::vector<uint64_t> GetXFELPulseID() const;
std::vector<uint64_t> GetXFELEventCode() const;
std::string GetFullPixelMaskTIFF() const;
std::string GetUserPixelMaskTIFF() const;
void SetUserPixelMask(const std::string &v);
};

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -37,12 +37,16 @@ void DefaultApi::setupRoutes() {
Routes::Get(*router, base + "/config/detector", Routes::bind(&DefaultApi::config_detector_get_handler, this));
Routes::Put(*router, base + "/config/detector", Routes::bind(&DefaultApi::config_detector_put_handler, this));
Routes::Put(*router, base + "/config/internal_generator_image", Routes::bind(&DefaultApi::config_internal_generator_image_put_handler, this));
Routes::Put(*router, base + "/config/internal_generator_image.tiff", Routes::bind(&DefaultApi::config_internal_generator_image_tiff_put_handler, this));
Routes::Get(*router, base + "/config/mask.tiff", Routes::bind(&DefaultApi::config_mask_tiff_get_handler, this));
Routes::Get(*router, base + "/config/rad_int", Routes::bind(&DefaultApi::config_rad_int_get_handler, this));
Routes::Put(*router, base + "/config/rad_int", Routes::bind(&DefaultApi::config_rad_int_put_handler, this));
Routes::Get(*router, base + "/config/select_detector", Routes::bind(&DefaultApi::config_select_detector_get_handler, this));
Routes::Put(*router, base + "/config/select_detector", Routes::bind(&DefaultApi::config_select_detector_put_handler, this));
Routes::Get(*router, base + "/config/spot_finding", Routes::bind(&DefaultApi::config_spot_finding_get_handler, this));
Routes::Put(*router, base + "/config/spot_finding", Routes::bind(&DefaultApi::config_spot_finding_put_handler, this));
Routes::Get(*router, base + "/config/user_mask.tiff", Routes::bind(&DefaultApi::config_user_mask_tiff_get_handler, this));
Routes::Put(*router, base + "/config/user_mask.tiff", Routes::bind(&DefaultApi::config_user_mask_tiff_put_handler, this));
Routes::Post(*router, base + "/deactivate", Routes::bind(&DefaultApi::deactivate_post_handler, this));
Routes::Get(*router, base + "/detector/status", Routes::bind(&DefaultApi::detector_status_get_handler, this));
Routes::Post(*router, base + "/initialize", Routes::bind(&DefaultApi::initialize_post_handler, this));
@@ -75,6 +79,7 @@ void DefaultApi::setupRoutes() {
Routes::Get(*router, base + "/statistics/data_collection", Routes::bind(&DefaultApi::statistics_data_collection_get_handler, this));
Routes::Get(*router, base + "/status", Routes::bind(&DefaultApi::status_get_handler, this));
Routes::Post(*router, base + "/trigger", Routes::bind(&DefaultApi::trigger_post_handler, this));
Routes::Get(*router, base + "/version", Routes::bind(&DefaultApi::version_get_handler, this));
Routes::Post(*router, base + "/wait_till_done", Routes::bind(&DefaultApi::wait_till_done_post_handler, this));
Routes::Get(*router, base + "/xfel/event_code", Routes::bind(&DefaultApi::xfel_event_code_get_handler, this));
Routes::Get(*router, base + "/xfel/pulse_id", Routes::bind(&DefaultApi::xfel_pulse_id_get_handler, this));
@@ -192,6 +197,45 @@ void DefaultApi::config_internal_generator_image_put_handler(const Pistache::Res
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::config_internal_generator_image_tiff_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
try {
this->config_internal_generator_image_tiff_put(request, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::config_mask_tiff_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->config_mask_tiff_get(response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::config_rad_int_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
@@ -351,6 +395,45 @@ void DefaultApi::config_spot_finding_put_handler(const Pistache::Rest::Request &
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::config_user_mask_tiff_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->config_user_mask_tiff_get(response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::config_user_mask_tiff_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
try {
this->config_user_mask_tiff_put(request, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::deactivate_post_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
@@ -1172,12 +1255,42 @@ void DefaultApi::trigger_post_handler(const Pistache::Rest::Request &, Pistache:
}
}
void DefaultApi::wait_till_done_post_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
void DefaultApi::version_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->wait_till_done_post(response);
this->version_get(response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
} catch (std::exception &e) {
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::wait_till_done_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the query params
auto timeoutQuery = request.query().get("timeout");
std::optional<int32_t> timeout;
if(timeoutQuery.has_value()){
int32_t valueQuery_instance;
if(fromStringValue(timeoutQuery.value(), valueQuery_instance)){
timeout = valueQuery_instance;
}
}
try {
this->wait_till_done_post(timeout, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -61,12 +61,16 @@ private:
void config_detector_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_detector_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_internal_generator_image_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_internal_generator_image_tiff_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_mask_tiff_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_rad_int_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_rad_int_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_select_detector_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_select_detector_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_spot_finding_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_spot_finding_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_user_mask_tiff_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void config_user_mask_tiff_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void deactivate_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void detector_status_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void initialize_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
@@ -99,6 +103,7 @@ private:
void statistics_data_collection_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void status_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void trigger_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void version_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void wait_till_done_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void xfel_event_code_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void xfel_pulse_id_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
@@ -150,6 +155,20 @@ private:
/// </remarks>
virtual void config_internal_generator_image_put(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Load TIFF image for internal FPGA generator
/// </summary>
/// <remarks>
/// Load image for internal FPGA generator. This can only happen in Idle state of the detector. Requires TIFF with 16-bit integer numbers of size of detector in raw/converted coordinates (depending on detector settings).
/// </remarks>
virtual void config_internal_generator_image_tiff_put(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Get mask of the detector
/// </summary>
/// <remarks>
/// Get full pixel mask of the detector See NXmx standard for meaning of pixel values
/// </remarks>
virtual void config_mask_tiff_get(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Get radial integration configuration
/// </summary>
/// <remarks>
@@ -195,6 +214,20 @@ private:
/// <param name="spotFindingSettings"> (optional)</param>
virtual void config_spot_finding_put(const org::openapitools::server::model::Spot_finding_settings &spotFindingSettings, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Get user mask of the detector
/// </summary>
/// <remarks>
/// Get user pixel mask of the detector in the actual detector coordinates: 0 - good pixel, 1 - masked
/// </remarks>
virtual void config_user_mask_tiff_get(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Upload user mask of the detector
/// </summary>
/// <remarks>
/// Should be in &#x60;Idle&#x60; state. Upload user mask of the detector - this is for example to account for beam stop shadow or misbehaving regions. If detector is conversion mode the mask can be both in raw (1024x512; stacked modules) or converted coordinates. In the latter case - module gaps are ignored and don&#39;t need to be assigned value. Mask is expected as TIFF (4-byte; unsigned). 0 - good pixel, other value - masked User mask is stored in NXmx pixel mask (bit 8), as well as used in spot finding and azimuthal integration. User mask is not automatically applied - i.e. pixels with user mask will have a valid pixel value in the images.
/// </remarks>
virtual void config_user_mask_tiff_put(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Prepare detector to turn off
/// </summary>
/// <remarks>
@@ -436,12 +469,20 @@ private:
/// </remarks>
virtual void trigger_post(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
///
/// </summary>
/// <remarks>
///
/// </remarks>
virtual void version_get(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Wait for acquisition done
/// </summary>
/// <remarks>
/// Block execution of external script till initialization, data collection or pedestal is finished. Running this command does not affect (cancel) running data collection, it is only to ensure synchronous execution of other software. To not block web server for a long period of time, the procedure is provided with a timeout of 5 seconds.
/// Block execution of external script till initialization, data collection or pedestal is finished. Running this command does not affect (cancel) running data collection, it is only to ensure synchronous execution of other software. To not block web server for a indefinite period of time, the procedure is provided with a timeout. Extending timeout is possible, but requires to ensure safety that client will not close the connection and retry the connection.
/// </remarks>
virtual void wait_till_done_post(Pistache::Http::ResponseWriter &response) = 0;
/// <param name="timeout">Timeout in seconds (0 &#x3D;&#x3D; immediate response) (optional, default to 60)</param>
virtual void wait_till_done_post(const std::optional<int32_t> &timeout, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Return XFEL event codes for the current data acquisition
/// </summary>

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -25,12 +25,12 @@ Dataset_settings::Dataset_settings()
m_Images_per_triggerIsSet = false;
m_Ntrigger = 1L;
m_NtriggerIsSet = false;
m_Summation = 1L;
m_SummationIsSet = false;
m_Image_time_us = 0L;
m_Image_time_usIsSet = false;
m_Beam_x_pxl = 0.0f;
m_Beam_y_pxl = 0.0f;
m_Detector_distance_mm = 0.0f;
m_Photon_energy_keV = 0.0f;
m_Incident_energy_keV = 0.0f;
m_File_prefix = "";
m_File_prefixIsSet = false;
m_Images_per_file = 1000L;
@@ -38,6 +38,7 @@ Dataset_settings::Dataset_settings()
m_Space_group_number = 0L;
m_Space_group_numberIsSet = false;
m_Sample_name = "";
m_Sample_nameIsSet = false;
m_Fpga_output = "auto";
m_Fpga_outputIsSet = false;
m_Compression = "bslz4";
@@ -46,15 +47,19 @@ Dataset_settings::Dataset_settings()
m_Total_fluxIsSet = false;
m_Transmission = 0.0f;
m_TransmissionIsSet = false;
m_OmegaIsSet = false;
m_Header_appendix = "";
m_GoniometerIsSet = false;
m_Header_appendixIsSet = false;
m_Image_appendix = "";
m_Image_appendixIsSet = false;
m_Photon_energy_multiplier = 1.0f;
m_Photon_energy_multiplierIsSet = false;
m_Energy_multiplier = 1.0f;
m_Energy_multiplierIsSet = false;
m_Data_reduction_factor_serialmx = 1.0f;
m_Data_reduction_factor_serialmxIsSet = false;
m_Run_number = 0L;
m_Run_numberIsSet = false;
m_Run_name = "";
m_Run_nameIsSet = false;
m_Experiment_group = "";
m_Experiment_groupIsSet = false;
m_Unit_cellIsSet = false;
}
@@ -107,21 +112,16 @@ bool Dataset_settings::validate(std::stringstream& msg, const std::string& pathP
}
if (summationIsSet())
if (imageTimeUsIsSet())
{
const int64_t& value = m_Summation;
const std::string currentValuePath = _pathPrefix + ".summation";
const int64_t& value = m_Image_time_us;
const std::string currentValuePath = _pathPrefix + ".imageTimeUs";
if (value < 1ll)
if (value < 0ll)
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 1;";
}
if (value > 256ll)
{
success = false;
msg << currentValuePath << ": must be less than or equal to 256;";
msg << currentValuePath << ": must be greater than or equal to 0;";
}
}
@@ -141,9 +141,9 @@ bool Dataset_settings::validate(std::stringstream& msg, const std::string& pathP
}
/* Photon_energy_keV */ {
const float& value = m_Photon_energy_keV;
const std::string currentValuePath = _pathPrefix + ".photonEnergyKeV";
/* Incident_energy_keV */ {
const float& value = m_Incident_energy_keV;
const std::string currentValuePath = _pathPrefix + ".incidentEnergyKeV";
if (value < static_cast<float>(0))
@@ -206,10 +206,10 @@ bool Dataset_settings::validate(std::stringstream& msg, const std::string& pathP
}
if (photonEnergyMultiplierIsSet())
if (energyMultiplierIsSet())
{
const float& value = m_Photon_energy_multiplier;
const std::string currentValuePath = _pathPrefix + ".photonEnergyMultiplier";
const float& value = m_Energy_multiplier;
const std::string currentValuePath = _pathPrefix + ".energyMultiplier";
if (value < static_cast<float>(0.015625))
@@ -243,7 +243,21 @@ bool Dataset_settings::validate(std::stringstream& msg, const std::string& pathP
}
}
if (runNumberIsSet())
{
const int64_t& value = m_Run_number;
const std::string currentValuePath = _pathPrefix + ".runNumber";
if (value < 0ll)
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
}
return success;
}
@@ -259,7 +273,7 @@ bool Dataset_settings::operator==(const Dataset_settings& rhs) const
((!ntriggerIsSet() && !rhs.ntriggerIsSet()) || (ntriggerIsSet() && rhs.ntriggerIsSet() && getNtrigger() == rhs.getNtrigger())) &&
((!summationIsSet() && !rhs.summationIsSet()) || (summationIsSet() && rhs.summationIsSet() && getSummation() == rhs.getSummation())) &&
((!imageTimeUsIsSet() && !rhs.imageTimeUsIsSet()) || (imageTimeUsIsSet() && rhs.imageTimeUsIsSet() && getImageTimeUs() == rhs.getImageTimeUs())) &&
(getBeamXPxl() == rhs.getBeamXPxl())
&&
@@ -270,7 +284,7 @@ bool Dataset_settings::operator==(const Dataset_settings& rhs) const
(getDetectorDistanceMm() == rhs.getDetectorDistanceMm())
&&
(getPhotonEnergyKeV() == rhs.getPhotonEnergyKeV())
(getIncidentEnergyKeV() == rhs.getIncidentEnergyKeV())
&&
@@ -282,8 +296,8 @@ bool Dataset_settings::operator==(const Dataset_settings& rhs) const
((!spaceGroupNumberIsSet() && !rhs.spaceGroupNumberIsSet()) || (spaceGroupNumberIsSet() && rhs.spaceGroupNumberIsSet() && getSpaceGroupNumber() == rhs.getSpaceGroupNumber())) &&
(getSampleName() == rhs.getSampleName())
&&
((!sampleNameIsSet() && !rhs.sampleNameIsSet()) || (sampleNameIsSet() && rhs.sampleNameIsSet() && getSampleName() == rhs.getSampleName())) &&
((!fpgaOutputIsSet() && !rhs.fpgaOutputIsSet()) || (fpgaOutputIsSet() && rhs.fpgaOutputIsSet() && getFpgaOutput() == rhs.getFpgaOutput())) &&
@@ -298,7 +312,7 @@ bool Dataset_settings::operator==(const Dataset_settings& rhs) const
((!transmissionIsSet() && !rhs.transmissionIsSet()) || (transmissionIsSet() && rhs.transmissionIsSet() && getTransmission() == rhs.getTransmission())) &&
((!omegaIsSet() && !rhs.omegaIsSet()) || (omegaIsSet() && rhs.omegaIsSet() && getOmega() == rhs.getOmega())) &&
((!goniometerIsSet() && !rhs.goniometerIsSet()) || (goniometerIsSet() && rhs.goniometerIsSet() && getGoniometer() == rhs.getGoniometer())) &&
((!headerAppendixIsSet() && !rhs.headerAppendixIsSet()) || (headerAppendixIsSet() && rhs.headerAppendixIsSet() && getHeaderAppendix() == rhs.getHeaderAppendix())) &&
@@ -307,12 +321,21 @@ bool Dataset_settings::operator==(const Dataset_settings& rhs) const
((!imageAppendixIsSet() && !rhs.imageAppendixIsSet()) || (imageAppendixIsSet() && rhs.imageAppendixIsSet() && getImageAppendix() == rhs.getImageAppendix())) &&
((!photonEnergyMultiplierIsSet() && !rhs.photonEnergyMultiplierIsSet()) || (photonEnergyMultiplierIsSet() && rhs.photonEnergyMultiplierIsSet() && getPhotonEnergyMultiplier() == rhs.getPhotonEnergyMultiplier())) &&
((!energyMultiplierIsSet() && !rhs.energyMultiplierIsSet()) || (energyMultiplierIsSet() && rhs.energyMultiplierIsSet() && getEnergyMultiplier() == rhs.getEnergyMultiplier())) &&
((!dataReductionFactorSerialmxIsSet() && !rhs.dataReductionFactorSerialmxIsSet()) || (dataReductionFactorSerialmxIsSet() && rhs.dataReductionFactorSerialmxIsSet() && getDataReductionFactorSerialmx() == rhs.getDataReductionFactorSerialmx())) &&
((!runNumberIsSet() && !rhs.runNumberIsSet()) || (runNumberIsSet() && rhs.runNumberIsSet() && getRunNumber() == rhs.getRunNumber())) &&
((!runNameIsSet() && !rhs.runNameIsSet()) || (runNameIsSet() && rhs.runNameIsSet() && getRunName() == rhs.getRunName())) &&
((!experimentGroupIsSet() && !rhs.experimentGroupIsSet()) || (experimentGroupIsSet() && rhs.experimentGroupIsSet() && getExperimentGroup() == rhs.getExperimentGroup())) &&
((!unitCellIsSet() && !rhs.unitCellIsSet()) || (unitCellIsSet() && rhs.unitCellIsSet() && getUnitCell() == rhs.getUnitCell()))
;
@@ -330,19 +353,20 @@ void to_json(nlohmann::json& j, const Dataset_settings& o)
j["images_per_trigger"] = o.m_Images_per_trigger;
if(o.ntriggerIsSet())
j["ntrigger"] = o.m_Ntrigger;
if(o.summationIsSet())
j["summation"] = o.m_Summation;
if(o.imageTimeUsIsSet())
j["image_time_us"] = o.m_Image_time_us;
j["beam_x_pxl"] = o.m_Beam_x_pxl;
j["beam_y_pxl"] = o.m_Beam_y_pxl;
j["detector_distance_mm"] = o.m_Detector_distance_mm;
j["photon_energy_keV"] = o.m_Photon_energy_keV;
j["incident_energy_keV"] = o.m_Incident_energy_keV;
if(o.filePrefixIsSet())
j["file_prefix"] = o.m_File_prefix;
if(o.imagesPerFileIsSet())
j["images_per_file"] = o.m_Images_per_file;
if(o.spaceGroupNumberIsSet())
j["space_group_number"] = o.m_Space_group_number;
j["sample_name"] = o.m_Sample_name;
if(o.sampleNameIsSet())
j["sample_name"] = o.m_Sample_name;
if(o.fpgaOutputIsSet())
j["fpga_output"] = o.m_Fpga_output;
if(o.compressionIsSet())
@@ -351,16 +375,22 @@ void to_json(nlohmann::json& j, const Dataset_settings& o)
j["total_flux"] = o.m_Total_flux;
if(o.transmissionIsSet())
j["transmission"] = o.m_Transmission;
if(o.omegaIsSet())
j["omega"] = o.m_Omega;
if(o.goniometerIsSet())
j["goniometer"] = o.m_Goniometer;
if(o.headerAppendixIsSet())
j["header_appendix"] = o.m_Header_appendix;
if(o.imageAppendixIsSet())
j["image_appendix"] = o.m_Image_appendix;
if(o.photonEnergyMultiplierIsSet())
j["photon_energy_multiplier"] = o.m_Photon_energy_multiplier;
if(o.energyMultiplierIsSet())
j["energy_multiplier"] = o.m_Energy_multiplier;
if(o.dataReductionFactorSerialmxIsSet())
j["data_reduction_factor_serialmx"] = o.m_Data_reduction_factor_serialmx;
if(o.runNumberIsSet())
j["run_number"] = o.m_Run_number;
if(o.runNameIsSet())
j["run_name"] = o.m_Run_name;
if(o.experimentGroupIsSet())
j["experiment_group"] = o.m_Experiment_group;
if(o.unitCellIsSet())
j["unit_cell"] = o.m_Unit_cell;
@@ -378,15 +408,15 @@ void from_json(const nlohmann::json& j, Dataset_settings& o)
j.at("ntrigger").get_to(o.m_Ntrigger);
o.m_NtriggerIsSet = true;
}
if(j.find("summation") != j.end())
if(j.find("image_time_us") != j.end())
{
j.at("summation").get_to(o.m_Summation);
o.m_SummationIsSet = true;
j.at("image_time_us").get_to(o.m_Image_time_us);
o.m_Image_time_usIsSet = true;
}
j.at("beam_x_pxl").get_to(o.m_Beam_x_pxl);
j.at("beam_y_pxl").get_to(o.m_Beam_y_pxl);
j.at("detector_distance_mm").get_to(o.m_Detector_distance_mm);
j.at("photon_energy_keV").get_to(o.m_Photon_energy_keV);
j.at("incident_energy_keV").get_to(o.m_Incident_energy_keV);
if(j.find("file_prefix") != j.end())
{
j.at("file_prefix").get_to(o.m_File_prefix);
@@ -402,7 +432,11 @@ void from_json(const nlohmann::json& j, Dataset_settings& o)
j.at("space_group_number").get_to(o.m_Space_group_number);
o.m_Space_group_numberIsSet = true;
}
j.at("sample_name").get_to(o.m_Sample_name);
if(j.find("sample_name") != j.end())
{
j.at("sample_name").get_to(o.m_Sample_name);
o.m_Sample_nameIsSet = true;
}
if(j.find("fpga_output") != j.end())
{
j.at("fpga_output").get_to(o.m_Fpga_output);
@@ -423,10 +457,10 @@ void from_json(const nlohmann::json& j, Dataset_settings& o)
j.at("transmission").get_to(o.m_Transmission);
o.m_TransmissionIsSet = true;
}
if(j.find("omega") != j.end())
if(j.find("goniometer") != j.end())
{
j.at("omega").get_to(o.m_Omega);
o.m_OmegaIsSet = true;
j.at("goniometer").get_to(o.m_Goniometer);
o.m_GoniometerIsSet = true;
}
if(j.find("header_appendix") != j.end())
{
@@ -438,16 +472,31 @@ void from_json(const nlohmann::json& j, Dataset_settings& o)
j.at("image_appendix").get_to(o.m_Image_appendix);
o.m_Image_appendixIsSet = true;
}
if(j.find("photon_energy_multiplier") != j.end())
if(j.find("energy_multiplier") != j.end())
{
j.at("photon_energy_multiplier").get_to(o.m_Photon_energy_multiplier);
o.m_Photon_energy_multiplierIsSet = true;
j.at("energy_multiplier").get_to(o.m_Energy_multiplier);
o.m_Energy_multiplierIsSet = true;
}
if(j.find("data_reduction_factor_serialmx") != j.end())
{
j.at("data_reduction_factor_serialmx").get_to(o.m_Data_reduction_factor_serialmx);
o.m_Data_reduction_factor_serialmxIsSet = true;
}
if(j.find("run_number") != j.end())
{
j.at("run_number").get_to(o.m_Run_number);
o.m_Run_numberIsSet = true;
}
if(j.find("run_name") != j.end())
{
j.at("run_name").get_to(o.m_Run_name);
o.m_Run_nameIsSet = true;
}
if(j.find("experiment_group") != j.end())
{
j.at("experiment_group").get_to(o.m_Experiment_group);
o.m_Experiment_groupIsSet = true;
}
if(j.find("unit_cell") != j.end())
{
j.at("unit_cell").get_to(o.m_Unit_cell);
@@ -490,22 +539,22 @@ void Dataset_settings::unsetNtrigger()
{
m_NtriggerIsSet = false;
}
int64_t Dataset_settings::getSummation() const
int64_t Dataset_settings::getImageTimeUs() const
{
return m_Summation;
return m_Image_time_us;
}
void Dataset_settings::setSummation(int64_t const value)
void Dataset_settings::setImageTimeUs(int64_t const value)
{
m_Summation = value;
m_SummationIsSet = true;
m_Image_time_us = value;
m_Image_time_usIsSet = true;
}
bool Dataset_settings::summationIsSet() const
bool Dataset_settings::imageTimeUsIsSet() const
{
return m_SummationIsSet;
return m_Image_time_usIsSet;
}
void Dataset_settings::unsetSummation()
void Dataset_settings::unsetImage_time_us()
{
m_SummationIsSet = false;
m_Image_time_usIsSet = false;
}
float Dataset_settings::getBeamXPxl() const
{
@@ -531,13 +580,13 @@ void Dataset_settings::setDetectorDistanceMm(float const value)
{
m_Detector_distance_mm = value;
}
float Dataset_settings::getPhotonEnergyKeV() const
float Dataset_settings::getIncidentEnergyKeV() const
{
return m_Photon_energy_keV;
return m_Incident_energy_keV;
}
void Dataset_settings::setPhotonEnergyKeV(float const value)
void Dataset_settings::setIncidentEnergyKeV(float const value)
{
m_Photon_energy_keV = value;
m_Incident_energy_keV = value;
}
std::string Dataset_settings::getFilePrefix() const
{
@@ -597,6 +646,15 @@ std::string Dataset_settings::getSampleName() const
void Dataset_settings::setSampleName(std::string const& value)
{
m_Sample_name = value;
m_Sample_nameIsSet = true;
}
bool Dataset_settings::sampleNameIsSet() const
{
return m_Sample_nameIsSet;
}
void Dataset_settings::unsetSample_name()
{
m_Sample_nameIsSet = false;
}
std::string Dataset_settings::getFpgaOutput() const
{
@@ -666,28 +724,28 @@ void Dataset_settings::unsetTransmission()
{
m_TransmissionIsSet = false;
}
org::openapitools::server::model::Rotation_axis Dataset_settings::getOmega() const
org::openapitools::server::model::Rotation_axis Dataset_settings::getGoniometer() const
{
return m_Omega;
return m_Goniometer;
}
void Dataset_settings::setOmega(org::openapitools::server::model::Rotation_axis const& value)
void Dataset_settings::setGoniometer(org::openapitools::server::model::Rotation_axis const& value)
{
m_Omega = value;
m_OmegaIsSet = true;
m_Goniometer = value;
m_GoniometerIsSet = true;
}
bool Dataset_settings::omegaIsSet() const
bool Dataset_settings::goniometerIsSet() const
{
return m_OmegaIsSet;
return m_GoniometerIsSet;
}
void Dataset_settings::unsetOmega()
void Dataset_settings::unsetGoniometer()
{
m_OmegaIsSet = false;
m_GoniometerIsSet = false;
}
std::string Dataset_settings::getHeaderAppendix() const
nlohmann::json Dataset_settings::getHeaderAppendix() const
{
return m_Header_appendix;
}
void Dataset_settings::setHeaderAppendix(std::string const& value)
void Dataset_settings::setHeaderAppendix(nlohmann::json const& value)
{
m_Header_appendix = value;
m_Header_appendixIsSet = true;
@@ -700,11 +758,11 @@ void Dataset_settings::unsetHeader_appendix()
{
m_Header_appendixIsSet = false;
}
std::string Dataset_settings::getImageAppendix() const
nlohmann::json Dataset_settings::getImageAppendix() const
{
return m_Image_appendix;
}
void Dataset_settings::setImageAppendix(std::string const& value)
void Dataset_settings::setImageAppendix(nlohmann::json const& value)
{
m_Image_appendix = value;
m_Image_appendixIsSet = true;
@@ -717,22 +775,22 @@ void Dataset_settings::unsetImage_appendix()
{
m_Image_appendixIsSet = false;
}
float Dataset_settings::getPhotonEnergyMultiplier() const
float Dataset_settings::getEnergyMultiplier() const
{
return m_Photon_energy_multiplier;
return m_Energy_multiplier;
}
void Dataset_settings::setPhotonEnergyMultiplier(float const value)
void Dataset_settings::setEnergyMultiplier(float const value)
{
m_Photon_energy_multiplier = value;
m_Photon_energy_multiplierIsSet = true;
m_Energy_multiplier = value;
m_Energy_multiplierIsSet = true;
}
bool Dataset_settings::photonEnergyMultiplierIsSet() const
bool Dataset_settings::energyMultiplierIsSet() const
{
return m_Photon_energy_multiplierIsSet;
return m_Energy_multiplierIsSet;
}
void Dataset_settings::unsetPhoton_energy_multiplier()
void Dataset_settings::unsetEnergy_multiplier()
{
m_Photon_energy_multiplierIsSet = false;
m_Energy_multiplierIsSet = false;
}
float Dataset_settings::getDataReductionFactorSerialmx() const
{
@@ -751,6 +809,57 @@ void Dataset_settings::unsetData_reduction_factor_serialmx()
{
m_Data_reduction_factor_serialmxIsSet = false;
}
int64_t Dataset_settings::getRunNumber() const
{
return m_Run_number;
}
void Dataset_settings::setRunNumber(int64_t const value)
{
m_Run_number = value;
m_Run_numberIsSet = true;
}
bool Dataset_settings::runNumberIsSet() const
{
return m_Run_numberIsSet;
}
void Dataset_settings::unsetRun_number()
{
m_Run_numberIsSet = false;
}
std::string Dataset_settings::getRunName() const
{
return m_Run_name;
}
void Dataset_settings::setRunName(std::string const& value)
{
m_Run_name = value;
m_Run_nameIsSet = true;
}
bool Dataset_settings::runNameIsSet() const
{
return m_Run_nameIsSet;
}
void Dataset_settings::unsetRun_name()
{
m_Run_nameIsSet = false;
}
std::string Dataset_settings::getExperimentGroup() const
{
return m_Experiment_group;
}
void Dataset_settings::setExperimentGroup(std::string const& value)
{
m_Experiment_group = value;
m_Experiment_groupIsSet = true;
}
bool Dataset_settings::experimentGroupIsSet() const
{
return m_Experiment_groupIsSet;
}
void Dataset_settings::unsetExperiment_group()
{
m_Experiment_groupIsSet = false;
}
org::openapitools::server::model::Dataset_settings_unit_cell Dataset_settings::getUnitCell() const
{
return m_Unit_cell;

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -19,6 +19,7 @@
#define Dataset_settings_H_
#include <nlohmann/json.hpp>
#include "Rotation_axis.h"
#include <string>
#include "Dataset_settings_unit_cell.h"
@@ -75,12 +76,12 @@ public:
bool ntriggerIsSet() const;
void unsetNtrigger();
/// <summary>
/// FPGA frame summation. For summation above two 32-bit pixel format will be used, unless explicitly specified. Frame summation factor applies only to conversion mode (assumed as 1 for raw data). In XFEL mode: summation happens for frames collected with multiple triggers. Ignored for storage cells (assumed as 1).
/// Image time. If not provided (or zero value) the frame time is assumed as default. Image time must be multiple of frame time; max value is 256 * frame_time. In XFEL mode: summation happens for frames collected with multiple triggers. Ignored for storage cells and if raw data are saved.
/// </summary>
int64_t getSummation() const;
void setSummation(int64_t const value);
bool summationIsSet() const;
void unsetSummation();
int64_t getImageTimeUs() const;
void setImageTimeUs(int64_t const value);
bool imageTimeUsIsSet() const;
void unsetImage_time_us();
/// <summary>
/// /entry/detector/beam_center_x in NXmx Beam center in X direction [pixels]
/// </summary>
@@ -97,10 +98,10 @@ public:
float getDetectorDistanceMm() const;
void setDetectorDistanceMm(float const value);
/// <summary>
/// Used to calculate /entry/beam/incident_wavelength in NXmx Incident photon energy in keV
/// Used to calculate /entry/beam/incident_wavelength in NXmx Incident particle (photon, electron) energy in keV
/// </summary>
float getPhotonEnergyKeV() const;
void setPhotonEnergyKeV(float const value);
float getIncidentEnergyKeV() const;
void setIncidentEnergyKeV(float const value);
/// <summary>
/// Prefix for filenames. If left empty, no file will be saved.
/// </summary>
@@ -127,6 +128,8 @@ public:
/// </summary>
std::string getSampleName() const;
void setSampleName(std::string const& value);
bool sampleNameIsSet() const;
void unsetSample_name();
/// <summary>
/// FPGA output data type
/// </summary>
@@ -158,31 +161,31 @@ public:
/// <summary>
///
/// </summary>
org::openapitools::server::model::Rotation_axis getOmega() const;
void setOmega(org::openapitools::server::model::Rotation_axis const& value);
bool omegaIsSet() const;
void unsetOmega();
org::openapitools::server::model::Rotation_axis getGoniometer() const;
void setGoniometer(org::openapitools::server::model::Rotation_axis const& value);
bool goniometerIsSet() const;
void unsetGoniometer();
/// <summary>
/// Header appendix, added as user_data to start message
/// Header appendix, added as user_data/user to start message (can be any valid JSON)
/// </summary>
std::string getHeaderAppendix() const;
void setHeaderAppendix(std::string const& value);
nlohmann::json getHeaderAppendix() const;
void setHeaderAppendix(nlohmann::json const& value);
bool headerAppendixIsSet() const;
void unsetHeader_appendix();
/// <summary>
/// Image appendix, added as user_data to image message
/// Image appendix, added as user_data to image message (can be any valid JSON)
/// </summary>
std::string getImageAppendix() const;
void setImageAppendix(std::string const& value);
nlohmann::json getImageAppendix() const;
void setImageAppendix(nlohmann::json const& value);
bool imageAppendixIsSet() const;
void unsetImage_appendix();
/// <summary>
/// For JUNGFRAU conversion it is possible to multiply energy by a given factor to get fractional/multiplied photon counts
/// For JUNGFRAU conversion it is possible to multiply incident energy by a given factor to get fractional/multiplied particle counts
/// </summary>
float getPhotonEnergyMultiplier() const;
void setPhotonEnergyMultiplier(float const value);
bool photonEnergyMultiplierIsSet() const;
void unsetPhoton_energy_multiplier();
float getEnergyMultiplier() const;
void setEnergyMultiplier(float const value);
bool energyMultiplierIsSet() const;
void unsetEnergy_multiplier();
/// <summary>
/// Rate at which non-indexed images are accepted to be forwarded to writer. Value of 1.0 (default) means that all images are written. Values below zero mean that non-indexed images will be accepted with a given probability.
/// </summary>
@@ -191,6 +194,27 @@ public:
bool dataReductionFactorSerialmxIsSet() const;
void unsetData_reduction_factor_serialmx();
/// <summary>
/// Number of run within an experimental session. Transferred over CBOR stream as \&quot;series ID\&quot;, though not saved in HDF5 file. It is highly recommended to keep this number unique for each data collection during experimental series. If not provided, the number will be automatically incremented.
/// </summary>
int64_t getRunNumber() const;
void setRunNumber(int64_t const value);
bool runNumberIsSet() const;
void unsetRun_number();
/// <summary>
/// Unique ID of run. Transferred over CBOR stream as \&quot;unique series ID\&quot;, though not saved in HDF5 file. It is highly recommended to keep this name unique for each data collection during experimental series. If not provided, the name will be automatically generated as number + colon + file_prefix.
/// </summary>
std::string getRunName() const;
void setRunName(std::string const& value);
bool runNameIsSet() const;
void unsetRun_name();
/// <summary>
/// Name of group owning the data (e.g. p-group or proposal number). Transferred over CBOR stream, though not saved in HDF5 file.
/// </summary>
std::string getExperimentGroup() const;
void setExperimentGroup(std::string const& value);
bool experimentGroupIsSet() const;
void unsetExperiment_group();
/// <summary>
///
/// </summary>
org::openapitools::server::model::Dataset_settings_unit_cell getUnitCell() const;
@@ -205,15 +229,15 @@ protected:
bool m_Images_per_triggerIsSet;
int64_t m_Ntrigger;
bool m_NtriggerIsSet;
int64_t m_Summation;
bool m_SummationIsSet;
int64_t m_Image_time_us;
bool m_Image_time_usIsSet;
float m_Beam_x_pxl;
float m_Beam_y_pxl;
float m_Detector_distance_mm;
float m_Photon_energy_keV;
float m_Incident_energy_keV;
std::string m_File_prefix;
bool m_File_prefixIsSet;
@@ -222,7 +246,7 @@ protected:
int64_t m_Space_group_number;
bool m_Space_group_numberIsSet;
std::string m_Sample_name;
bool m_Sample_nameIsSet;
std::string m_Fpga_output;
bool m_Fpga_outputIsSet;
std::string m_Compression;
@@ -231,16 +255,22 @@ protected:
bool m_Total_fluxIsSet;
float m_Transmission;
bool m_TransmissionIsSet;
org::openapitools::server::model::Rotation_axis m_Omega;
bool m_OmegaIsSet;
std::string m_Header_appendix;
org::openapitools::server::model::Rotation_axis m_Goniometer;
bool m_GoniometerIsSet;
nlohmann::json m_Header_appendix;
bool m_Header_appendixIsSet;
std::string m_Image_appendix;
nlohmann::json m_Image_appendix;
bool m_Image_appendixIsSet;
float m_Photon_energy_multiplier;
bool m_Photon_energy_multiplierIsSet;
float m_Energy_multiplier;
bool m_Energy_multiplierIsSet;
float m_Data_reduction_factor_serialmx;
bool m_Data_reduction_factor_serialmxIsSet;
int64_t m_Run_number;
bool m_Run_numberIsSet;
std::string m_Run_name;
bool m_Run_nameIsSet;
std::string m_Experiment_group;
bool m_Experiment_groupIsSet;
org::openapitools::server::model::Dataset_settings_unit_cell m_Unit_cell;
bool m_Unit_cellIsSet;

View File

@@ -1,133 +0,0 @@
/**
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
#include "Dataset_settings_roi_sum_area.h"
#include "Helpers.h"
#include <sstream>
namespace org::openapitools::server::model
{
Dataset_settings_roi_sum_area::Dataset_settings_roi_sum_area()
{
m_X_min = 0L;
m_X_max = 0L;
m_Y_min = 0L;
m_Y_max = 0L;
}
void Dataset_settings_roi_sum_area::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
bool Dataset_settings_roi_sum_area::validate(std::stringstream& msg) const
{
return validate(msg, "");
}
bool Dataset_settings_roi_sum_area::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Dataset_settings_roi_sum_area" : pathPrefix;
return success;
}
bool Dataset_settings_roi_sum_area::operator==(const Dataset_settings_roi_sum_area& rhs) const
{
return
(getXMin() == rhs.getXMin())
&&
(getXMax() == rhs.getXMax())
&&
(getYMin() == rhs.getYMin())
&&
(getYMax() == rhs.getYMax())
;
}
bool Dataset_settings_roi_sum_area::operator!=(const Dataset_settings_roi_sum_area& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Dataset_settings_roi_sum_area& o)
{
j = nlohmann::json();
j["x_min"] = o.m_X_min;
j["x_max"] = o.m_X_max;
j["y_min"] = o.m_Y_min;
j["y_max"] = o.m_Y_max;
}
void from_json(const nlohmann::json& j, Dataset_settings_roi_sum_area& o)
{
j.at("x_min").get_to(o.m_X_min);
j.at("x_max").get_to(o.m_X_max);
j.at("y_min").get_to(o.m_Y_min);
j.at("y_max").get_to(o.m_Y_max);
}
int64_t Dataset_settings_roi_sum_area::getXMin() const
{
return m_X_min;
}
void Dataset_settings_roi_sum_area::setXMin(int64_t const value)
{
m_X_min = value;
}
int64_t Dataset_settings_roi_sum_area::getXMax() const
{
return m_X_max;
}
void Dataset_settings_roi_sum_area::setXMax(int64_t const value)
{
m_X_max = value;
}
int64_t Dataset_settings_roi_sum_area::getYMin() const
{
return m_Y_min;
}
void Dataset_settings_roi_sum_area::setYMin(int64_t const value)
{
m_Y_min = value;
}
int64_t Dataset_settings_roi_sum_area::getYMax() const
{
return m_Y_max;
}
void Dataset_settings_roi_sum_area::setYMax(int64_t const value)
{
m_Y_max = value;
}
} // namespace org::openapitools::server::model

View File

@@ -1,97 +0,0 @@
/**
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/*
* Dataset_settings_roi_sum_area.h
*
* Rectangle for ROI summation
*/
#ifndef Dataset_settings_roi_sum_area_H_
#define Dataset_settings_roi_sum_area_H_
#include <nlohmann/json.hpp>
namespace org::openapitools::server::model
{
/// <summary>
/// Rectangle for ROI summation
/// </summary>
class Dataset_settings_roi_sum_area
{
public:
Dataset_settings_roi_sum_area();
virtual ~Dataset_settings_roi_sum_area() = default;
/// <summary>
/// Validate the current data in the model. Throws a ValidationException on failure.
/// </summary>
void validate() const;
/// <summary>
/// Validate the current data in the model. Returns false on error and writes an error
/// message into the given stringstream.
/// </summary>
bool validate(std::stringstream& msg) const;
/// <summary>
/// Helper overload for validate. Used when one model stores another model and calls it's validate.
/// Not meant to be called outside that case.
/// </summary>
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
bool operator==(const Dataset_settings_roi_sum_area& rhs) const;
bool operator!=(const Dataset_settings_roi_sum_area& rhs) const;
/////////////////////////////////////////////
/// Dataset_settings_roi_sum_area members
/// <summary>
///
/// </summary>
int64_t getXMin() const;
void setXMin(int64_t const value);
/// <summary>
///
/// </summary>
int64_t getXMax() const;
void setXMax(int64_t const value);
/// <summary>
///
/// </summary>
int64_t getYMin() const;
void setYMin(int64_t const value);
/// <summary>
///
/// </summary>
int64_t getYMax() const;
void setYMax(int64_t const value);
friend void to_json(nlohmann::json& j, const Dataset_settings_roi_sum_area& o);
friend void from_json(const nlohmann::json& j, Dataset_settings_roi_sum_area& o);
protected:
int64_t m_X_min;
int64_t m_X_max;
int64_t m_Y_min;
int64_t m_Y_max;
};
} // namespace org::openapitools::server::model
#endif /* Dataset_settings_roi_sum_area_H_ */

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -23,6 +23,10 @@ Measurement_statistics::Measurement_statistics()
{
m_File_prefix = "";
m_File_prefixIsSet = false;
m_Run_number = 0L;
m_Run_numberIsSet = false;
m_Experiment_group = "";
m_Experiment_groupIsSet = false;
m_Images_expected = 0L;
m_Images_expectedIsSet = false;
m_Images_collected = 0L;
@@ -75,7 +79,7 @@ bool Measurement_statistics::validate(std::stringstream& msg, const std::string&
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Measurement_statistics" : pathPrefix;
if (collectionEfficiencyIsSet())
{
const float& value = m_Collection_efficiency;
@@ -121,6 +125,12 @@ bool Measurement_statistics::operator==(const Measurement_statistics& rhs) const
((!filePrefixIsSet() && !rhs.filePrefixIsSet()) || (filePrefixIsSet() && rhs.filePrefixIsSet() && getFilePrefix() == rhs.getFilePrefix())) &&
((!runNumberIsSet() && !rhs.runNumberIsSet()) || (runNumberIsSet() && rhs.runNumberIsSet() && getRunNumber() == rhs.getRunNumber())) &&
((!experimentGroupIsSet() && !rhs.experimentGroupIsSet()) || (experimentGroupIsSet() && rhs.experimentGroupIsSet() && getExperimentGroup() == rhs.getExperimentGroup())) &&
((!imagesExpectedIsSet() && !rhs.imagesExpectedIsSet()) || (imagesExpectedIsSet() && rhs.imagesExpectedIsSet() && getImagesExpected() == rhs.getImagesExpected())) &&
@@ -178,6 +188,10 @@ void to_json(nlohmann::json& j, const Measurement_statistics& o)
j = nlohmann::json();
if(o.filePrefixIsSet())
j["file_prefix"] = o.m_File_prefix;
if(o.runNumberIsSet())
j["run_number"] = o.m_Run_number;
if(o.experimentGroupIsSet())
j["experiment_group"] = o.m_Experiment_group;
if(o.imagesExpectedIsSet())
j["images_expected"] = o.m_Images_expected;
if(o.imagesCollectedIsSet())
@@ -218,6 +232,16 @@ void from_json(const nlohmann::json& j, Measurement_statistics& o)
j.at("file_prefix").get_to(o.m_File_prefix);
o.m_File_prefixIsSet = true;
}
if(j.find("run_number") != j.end())
{
j.at("run_number").get_to(o.m_Run_number);
o.m_Run_numberIsSet = true;
}
if(j.find("experiment_group") != j.end())
{
j.at("experiment_group").get_to(o.m_Experiment_group);
o.m_Experiment_groupIsSet = true;
}
if(j.find("images_expected") != j.end())
{
j.at("images_expected").get_to(o.m_Images_expected);
@@ -313,6 +337,40 @@ void Measurement_statistics::unsetFile_prefix()
{
m_File_prefixIsSet = false;
}
int64_t Measurement_statistics::getRunNumber() const
{
return m_Run_number;
}
void Measurement_statistics::setRunNumber(int64_t const value)
{
m_Run_number = value;
m_Run_numberIsSet = true;
}
bool Measurement_statistics::runNumberIsSet() const
{
return m_Run_numberIsSet;
}
void Measurement_statistics::unsetRun_number()
{
m_Run_numberIsSet = false;
}
std::string Measurement_statistics::getExperimentGroup() const
{
return m_Experiment_group;
}
void Measurement_statistics::setExperimentGroup(std::string const& value)
{
m_Experiment_group = value;
m_Experiment_groupIsSet = true;
}
bool Measurement_statistics::experimentGroupIsSet() const
{
return m_Experiment_groupIsSet;
}
void Measurement_statistics::unsetExperiment_group()
{
m_Experiment_groupIsSet = false;
}
int64_t Measurement_statistics::getImagesExpected() const
{
return m_Images_expected;

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -66,6 +66,20 @@ public:
bool filePrefixIsSet() const;
void unsetFile_prefix();
/// <summary>
/// Number of data collection run. This can be either automatically incremented or provided externally for each data collection.
/// </summary>
int64_t getRunNumber() const;
void setRunNumber(int64_t const value);
bool runNumberIsSet() const;
void unsetRun_number();
/// <summary>
/// Name of group owning the data (e.g. p-group or proposal number).
/// </summary>
std::string getExperimentGroup() const;
void setExperimentGroup(std::string const& value);
bool experimentGroupIsSet() const;
void unsetExperiment_group();
/// <summary>
///
/// </summary>
int64_t getImagesExpected() const;
@@ -176,6 +190,10 @@ public:
protected:
std::string m_File_prefix;
bool m_File_prefixIsSet;
int64_t m_Run_number;
bool m_Run_numberIsSet;
std::string m_Experiment_group;
bool m_Experiment_groupIsSet;
int64_t m_Images_expected;
bool m_Images_expectedIsSet;
int64_t m_Images_collected;

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -1,106 +0,0 @@
/**
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
#include "Plot_request.h"
#include "Helpers.h"
#include <sstream>
namespace org::openapitools::server::model
{
Plot_request::Plot_request()
{
m_Binning = 0L;
m_BinningIsSet = false;
}
void Plot_request::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
bool Plot_request::validate(std::stringstream& msg) const
{
return validate(msg, "");
}
bool Plot_request::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Plot_request" : pathPrefix;
return success;
}
bool Plot_request::operator==(const Plot_request& rhs) const
{
return
((!binningIsSet() && !rhs.binningIsSet()) || (binningIsSet() && rhs.binningIsSet() && getBinning() == rhs.getBinning()))
;
}
bool Plot_request::operator!=(const Plot_request& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Plot_request& o)
{
j = nlohmann::json();
if(o.binningIsSet())
j["binning"] = o.m_Binning;
}
void from_json(const nlohmann::json& j, Plot_request& o)
{
if(j.find("binning") != j.end())
{
j.at("binning").get_to(o.m_Binning);
o.m_BinningIsSet = true;
}
}
int64_t Plot_request::getBinning() const
{
return m_Binning;
}
void Plot_request::setBinning(int64_t const value)
{
m_Binning = value;
m_BinningIsSet = true;
}
bool Plot_request::binningIsSet() const
{
return m_BinningIsSet;
}
void Plot_request::unsetBinning()
{
m_BinningIsSet = false;
}
} // namespace org::openapitools::server::model

View File

@@ -1,78 +0,0 @@
/**
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
/*
* Plot_request.h
*
*
*/
#ifndef Plot_request_H_
#define Plot_request_H_
#include <nlohmann/json.hpp>
namespace org::openapitools::server::model
{
/// <summary>
///
/// </summary>
class Plot_request
{
public:
Plot_request();
virtual ~Plot_request() = default;
/// <summary>
/// Validate the current data in the model. Throws a ValidationException on failure.
/// </summary>
void validate() const;
/// <summary>
/// Validate the current data in the model. Returns false on error and writes an error
/// message into the given stringstream.
/// </summary>
bool validate(std::stringstream& msg) const;
/// <summary>
/// Helper overload for validate. Used when one model stores another model and calls it's validate.
/// Not meant to be called outside that case.
/// </summary>
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
bool operator==(const Plot_request& rhs) const;
bool operator!=(const Plot_request& rhs) const;
/////////////////////////////////////////////
/// Plot_request members
/// <summary>
///
/// </summary>
int64_t getBinning() const;
void setBinning(int64_t const value);
bool binningIsSet() const;
void unsetBinning();
friend void to_json(nlohmann::json& j, const Plot_request& o);
friend void from_json(const nlohmann::json& j, Plot_request& o);
protected:
int64_t m_Binning;
bool m_BinningIsSet;
};
} // namespace org::openapitools::server::model
#endif /* Plot_request_H_ */

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -26,11 +26,13 @@ Preview_settings::Preview_settings()
m_Show_spotsIsSet = false;
m_Show_roi = false;
m_Show_roiIsSet = false;
m_Jpeg_quality = 0L;
m_Jpeg_quality = 100L;
m_Jpeg_qualityIsSet = false;
m_Show_indexed = false;
m_Show_indexedIsSet = false;
m_Resolution_ring = 0.0f;
m_Show_user_mask = false;
m_Show_user_maskIsSet = false;
m_Resolution_ring = 0.1f;
m_Resolution_ringIsSet = false;
}
@@ -92,7 +94,7 @@ bool Preview_settings::validate(std::stringstream& msg, const std::string& pathP
}
}
if (resolutionRingIsSet())
{
const float& value = m_Resolution_ring;
@@ -136,6 +138,9 @@ bool Preview_settings::operator==(const Preview_settings& rhs) const
((!showIndexedIsSet() && !rhs.showIndexedIsSet()) || (showIndexedIsSet() && rhs.showIndexedIsSet() && isShowIndexed() == rhs.isShowIndexed())) &&
((!showUserMaskIsSet() && !rhs.showUserMaskIsSet()) || (showUserMaskIsSet() && rhs.showUserMaskIsSet() && isShowUserMask() == rhs.isShowUserMask())) &&
((!resolutionRingIsSet() && !rhs.resolutionRingIsSet()) || (resolutionRingIsSet() && rhs.resolutionRingIsSet() && getResolutionRing() == rhs.getResolutionRing()))
;
@@ -158,6 +163,8 @@ void to_json(nlohmann::json& j, const Preview_settings& o)
j["jpeg_quality"] = o.m_Jpeg_quality;
if(o.showIndexedIsSet())
j["show_indexed"] = o.m_Show_indexed;
if(o.showUserMaskIsSet())
j["show_user_mask"] = o.m_Show_user_mask;
if(o.resolutionRingIsSet())
j["resolution_ring"] = o.m_Resolution_ring;
@@ -186,6 +193,11 @@ void from_json(const nlohmann::json& j, Preview_settings& o)
j.at("show_indexed").get_to(o.m_Show_indexed);
o.m_Show_indexedIsSet = true;
}
if(j.find("show_user_mask") != j.end())
{
j.at("show_user_mask").get_to(o.m_Show_user_mask);
o.m_Show_user_maskIsSet = true;
}
if(j.find("resolution_ring") != j.end())
{
j.at("resolution_ring").get_to(o.m_Resolution_ring);
@@ -270,6 +282,23 @@ void Preview_settings::unsetShow_indexed()
{
m_Show_indexedIsSet = false;
}
bool Preview_settings::isShowUserMask() const
{
return m_Show_user_mask;
}
void Preview_settings::setShowUserMask(bool const value)
{
m_Show_user_mask = value;
m_Show_user_maskIsSet = true;
}
bool Preview_settings::showUserMaskIsSet() const
{
return m_Show_user_maskIsSet;
}
void Preview_settings::unsetShow_user_mask()
{
m_Show_user_maskIsSet = false;
}
float Preview_settings::getResolutionRing() const
{
return m_Resolution_ring;

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -91,6 +91,13 @@ public:
bool showIndexedIsSet() const;
void unsetShow_indexed();
/// <summary>
/// Show user mask
/// </summary>
bool isShowUserMask() const;
void setShowUserMask(bool const value);
bool showUserMaskIsSet() const;
void unsetShow_user_mask();
/// <summary>
///
/// </summary>
float getResolutionRing() const;
@@ -111,6 +118,8 @@ protected:
bool m_Jpeg_qualityIsSet;
bool m_Show_indexed;
bool m_Show_indexedIsSet;
bool m_Show_user_mask;
bool m_Show_user_maskIsSet;
float m_Resolution_ring;
bool m_Resolution_ringIsSet;

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -21,6 +21,8 @@ namespace org::openapitools::server::model
Rotation_axis::Rotation_axis()
{
m_Name = "omega";
m_NameIsSet = false;
m_Step = 0.0f;
m_Start = 0.0f;
m_StartIsSet = false;
@@ -47,6 +49,20 @@ bool Rotation_axis::validate(std::stringstream& msg, const std::string& pathPref
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Rotation_axis" : pathPrefix;
if (nameIsSet())
{
const std::string& value = m_Name;
const std::string currentValuePath = _pathPrefix + ".name";
if (value.length() < 1)
{
success = false;
msg << currentValuePath << ": must be at least 1 characters long;";
}
}
if (vectorIsSet())
{
@@ -87,6 +103,9 @@ bool Rotation_axis::operator==(const Rotation_axis& rhs) const
return
((!nameIsSet() && !rhs.nameIsSet()) || (nameIsSet() && rhs.nameIsSet() && getName() == rhs.getName())) &&
(getStep() == rhs.getStep())
&&
@@ -107,6 +126,8 @@ bool Rotation_axis::operator!=(const Rotation_axis& rhs) const
void to_json(nlohmann::json& j, const Rotation_axis& o)
{
j = nlohmann::json();
if(o.nameIsSet())
j["name"] = o.m_Name;
j["step"] = o.m_Step;
if(o.startIsSet())
j["start"] = o.m_Start;
@@ -117,6 +138,11 @@ void to_json(nlohmann::json& j, const Rotation_axis& o)
void from_json(const nlohmann::json& j, Rotation_axis& o)
{
if(j.find("name") != j.end())
{
j.at("name").get_to(o.m_Name);
o.m_NameIsSet = true;
}
j.at("step").get_to(o.m_Step);
if(j.find("start") != j.end())
{
@@ -131,6 +157,23 @@ void from_json(const nlohmann::json& j, Rotation_axis& o)
}
std::string Rotation_axis::getName() const
{
return m_Name;
}
void Rotation_axis::setName(std::string const& value)
{
m_Name = value;
m_NameIsSet = true;
}
bool Rotation_axis::nameIsSet() const
{
return m_NameIsSet;
}
void Rotation_axis::unsetName()
{
m_NameIsSet = false;
}
float Rotation_axis::getStep() const
{
return m_Step;

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -19,6 +19,7 @@
#define Rotation_axis_H_
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
@@ -58,6 +59,13 @@ public:
/////////////////////////////////////////////
/// Rotation_axis members
/// <summary>
/// Name of rotation axis (e.g., omega, phi)
/// </summary>
std::string getName() const;
void setName(std::string const& value);
bool nameIsSet() const;
void unsetName();
/// <summary>
/// Angle step in degrees
/// </summary>
@@ -81,6 +89,8 @@ public:
friend void to_json(nlohmann::json& j, const Rotation_axis& o);
friend void from_json(const nlohmann::json& j, Rotation_axis& o);
protected:
std::string m_Name;
bool m_NameIsSet;
float m_Step;
float m_Start;

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -23,6 +23,10 @@ Spot_finding_settings::Spot_finding_settings()
{
m_Enable = true;
m_Indexing = true;
m_Filter_powder_rings = false;
m_Filter_powder_ringsIsSet = false;
m_Min_spot_count_powder_ring = 0L;
m_Min_spot_count_powder_ringIsSet = false;
m_Signal_to_noise_threshold = 0.0f;
m_Photon_count_threshold = 0L;
m_Min_pix_per_spot = 0L;
@@ -52,7 +56,21 @@ bool Spot_finding_settings::validate(std::stringstream& msg, const std::string&
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Spot_finding_settings" : pathPrefix;
if (minSpotCountPowderRingIsSet())
{
const int64_t& value = m_Min_spot_count_powder_ring;
const std::string currentValuePath = _pathPrefix + ".minSpotCountPowderRing";
if (value < 5ll)
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 5;";
}
}
/* Signal_to_noise_threshold */ {
const float& value = m_Signal_to_noise_threshold;
@@ -142,6 +160,12 @@ bool Spot_finding_settings::operator==(const Spot_finding_settings& rhs) const
(isIndexing() == rhs.isIndexing())
&&
((!filterPowderRingsIsSet() && !rhs.filterPowderRingsIsSet()) || (filterPowderRingsIsSet() && rhs.filterPowderRingsIsSet() && isFilterPowderRings() == rhs.isFilterPowderRings())) &&
((!minSpotCountPowderRingIsSet() && !rhs.minSpotCountPowderRingIsSet()) || (minSpotCountPowderRingIsSet() && rhs.minSpotCountPowderRingIsSet() && getMinSpotCountPowderRing() == rhs.getMinSpotCountPowderRing())) &&
(getSignalToNoiseThreshold() == rhs.getSignalToNoiseThreshold())
&&
@@ -176,6 +200,10 @@ void to_json(nlohmann::json& j, const Spot_finding_settings& o)
j = nlohmann::json();
j["enable"] = o.m_Enable;
j["indexing"] = o.m_Indexing;
if(o.filterPowderRingsIsSet())
j["filter_powder_rings"] = o.m_Filter_powder_rings;
if(o.minSpotCountPowderRingIsSet())
j["min_spot_count_powder_ring"] = o.m_Min_spot_count_powder_ring;
j["signal_to_noise_threshold"] = o.m_Signal_to_noise_threshold;
j["photon_count_threshold"] = o.m_Photon_count_threshold;
j["min_pix_per_spot"] = o.m_Min_pix_per_spot;
@@ -190,6 +218,16 @@ void from_json(const nlohmann::json& j, Spot_finding_settings& o)
{
j.at("enable").get_to(o.m_Enable);
j.at("indexing").get_to(o.m_Indexing);
if(j.find("filter_powder_rings") != j.end())
{
j.at("filter_powder_rings").get_to(o.m_Filter_powder_rings);
o.m_Filter_powder_ringsIsSet = true;
}
if(j.find("min_spot_count_powder_ring") != j.end())
{
j.at("min_spot_count_powder_ring").get_to(o.m_Min_spot_count_powder_ring);
o.m_Min_spot_count_powder_ringIsSet = true;
}
j.at("signal_to_noise_threshold").get_to(o.m_Signal_to_noise_threshold);
j.at("photon_count_threshold").get_to(o.m_Photon_count_threshold);
j.at("min_pix_per_spot").get_to(o.m_Min_pix_per_spot);
@@ -216,6 +254,40 @@ void Spot_finding_settings::setIndexing(bool const value)
{
m_Indexing = value;
}
bool Spot_finding_settings::isFilterPowderRings() const
{
return m_Filter_powder_rings;
}
void Spot_finding_settings::setFilterPowderRings(bool const value)
{
m_Filter_powder_rings = value;
m_Filter_powder_ringsIsSet = true;
}
bool Spot_finding_settings::filterPowderRingsIsSet() const
{
return m_Filter_powder_ringsIsSet;
}
void Spot_finding_settings::unsetFilter_powder_rings()
{
m_Filter_powder_ringsIsSet = false;
}
int64_t Spot_finding_settings::getMinSpotCountPowderRing() const
{
return m_Min_spot_count_powder_ring;
}
void Spot_finding_settings::setMinSpotCountPowderRing(int64_t const value)
{
m_Min_spot_count_powder_ring = value;
m_Min_spot_count_powder_ringIsSet = true;
}
bool Spot_finding_settings::minSpotCountPowderRingIsSet() const
{
return m_Min_spot_count_powder_ringIsSet;
}
void Spot_finding_settings::unsetMin_spot_count_powder_ring()
{
m_Min_spot_count_powder_ringIsSet = false;
}
float Spot_finding_settings::getSignalToNoiseThreshold() const
{
return m_Signal_to_noise_threshold;

View File

@@ -2,8 +2,8 @@
* Jungfraujoch
* Jungfraujoch Broker Web API
*
* The version of the OpenAPI document: 1.0.1
*
* The version of the OpenAPI document: 1.0.0_rc.11
* Contact: filip.leonarski@psi.ch
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
@@ -58,16 +58,30 @@ public:
/// Spot_finding_settings members
/// <summary>
/// Enable spot finding
/// Enable spot finding. This is temporary setting, i.e. can be changed anytime during data collection. Even if disabled spot finding information will still be send and written, though always with zero spots.
/// </summary>
bool isEnable() const;
void setEnable(bool const value);
/// <summary>
/// Enable indexing
/// Enable indexing. This is temporary setting, i.e. can be changed anytime during data collection.
/// </summary>
bool isIndexing() const;
void setIndexing(bool const value);
/// <summary>
/// Filter spots which form powder rings (e.g., ice rings)
/// </summary>
bool isFilterPowderRings() const;
void setFilterPowderRings(bool const value);
bool filterPowderRingsIsSet() const;
void unsetFilter_powder_rings();
/// <summary>
/// Minimum number of spots to consider a thin resolution shell (0.01 A^-1) a powder ring and filter out.
/// </summary>
int64_t getMinSpotCountPowderRing() const;
void setMinSpotCountPowderRing(int64_t const value);
bool minSpotCountPowderRingIsSet() const;
void unsetMin_spot_count_powder_ring();
/// <summary>
///
/// </summary>
float getSignalToNoiseThreshold() const;
@@ -110,6 +124,10 @@ protected:
bool m_Indexing;
bool m_Filter_powder_rings;
bool m_Filter_powder_ringsIsSet;
int64_t m_Min_spot_count_powder_ring;
bool m_Min_spot_count_powder_ringIsSet;
float m_Signal_to_noise_threshold;
int64_t m_Photon_count_threshold;

View File

@@ -2,7 +2,9 @@ openapi: 3.0.3
info:
title: Jungfraujoch
description: Jungfraujoch Broker Web API
version: 1.0.1
version: 1.0.0_rc.11
contact:
email: filip.leonarski@psi.ch
components:
schemas:
rotation_axis:
@@ -11,6 +13,11 @@ components:
required:
- step
properties:
name:
type: string
default: omega
minLength: 1
description: Name of rotation axis (e.g., omega, phi)
step:
type: number
format: float
@@ -37,8 +44,7 @@ components:
- beam_x_pxl
- beam_y_pxl
- detector_distance_mm
- photon_energy_keV
- sample_name
- incident_energy_keV
properties:
images_per_trigger:
type: integer
@@ -56,17 +62,16 @@ components:
minimum: 1
description: |
Number of TTL trigger that the detector is expected to receive during data collection
summation:
image_time_us:
type: integer
format: int64
minimum: 1
maximum: 256
default: 1
minimum: 0
description: |
FPGA frame summation. For summation above two 32-bit pixel format will be used, unless explicitly specified.
Frame summation factor applies only to conversion mode (assumed as 1 for raw data).
Image time.
If not provided (or zero value) the frame time is assumed as default.
Image time must be multiple of frame time; max value is 256 * frame_time.
In XFEL mode: summation happens for frames collected with multiple triggers.
Ignored for storage cells (assumed as 1).
Ignored for storage cells and if raw data are saved.
beam_x_pxl:
type: number
format: float
@@ -86,13 +91,13 @@ components:
description:
/entry/detector/distance in NXmx
Detector distance [mm]
photon_energy_keV:
incident_energy_keV:
type: number
format: float
minimum: 0
description: |
Used to calculate /entry/beam/incident_wavelength in NXmx
Incident photon energy in keV
Incident particle (photon, electron) energy in keV
file_prefix:
type: string
default: ""
@@ -111,6 +116,7 @@ components:
maximum: 194
sample_name:
type: string
default: ""
description: |
/entry/sample/name in NXmx
Sample name
@@ -148,21 +154,19 @@ components:
description: |
/entry/instrument/attenuator/attenuator_transmission
Transmission of attenuator (filter) [no units]
omega:
goniometer:
$ref: "#/components/schemas/rotation_axis"
header_appendix:
type: string
description: Header appendix, added as user_data to start message
description: Header appendix, added as user_data/user to start message (can be any valid JSON)
image_appendix:
type: string
description: Image appendix, added as user_data to image message
photon_energy_multiplier:
description: Image appendix, added as user_data to image message (can be any valid JSON)
energy_multiplier:
type: number
format: float
default: 1.0
minimum: 0.015625
maximum: 4.0
description: For JUNGFRAU conversion it is possible to multiply energy by a given factor to get fractional/multiplied photon counts
description: For JUNGFRAU conversion it is possible to multiply incident energy by a given factor to get fractional/multiplied particle counts
data_reduction_factor_serialmx:
type: number
format: float
@@ -173,6 +177,27 @@ components:
Rate at which non-indexed images are accepted to be forwarded to writer.
Value of 1.0 (default) means that all images are written.
Values below zero mean that non-indexed images will be accepted with a given probability.
run_number:
type: integer
format: int64
minimum: 0
description: |
Number of run within an experimental session.
Transferred over CBOR stream as "series ID", though not saved in HDF5 file.
It is highly recommended to keep this number unique for each data collection during experimental series.
If not provided, the number will be automatically incremented.
run_name:
type: string
description: |
Unique ID of run.
Transferred over CBOR stream as "unique series ID", though not saved in HDF5 file.
It is highly recommended to keep this name unique for each data collection during experimental series.
If not provided, the name will be automatically generated as number + colon + file_prefix.
experiment_group:
type: string
description: |
Name of group owning the data (e.g. p-group or proposal number).
Transferred over CBOR stream, though not saved in HDF5 file.
unit_cell:
type: object
description: Units of angstrom and degree
@@ -235,7 +260,7 @@ components:
powerchip:
type: string
description: Power on of ASICs
enum: ["On", "Off", "Partial"]
enum: ["PowerOn", "PowerOff", "Partial"]
server_version:
type: string
description: Detector server (on read-out boards) version
@@ -333,11 +358,23 @@ components:
enable:
type: boolean
default: true
description: Enable spot finding
description: |
Enable spot finding. This is temporary setting, i.e. can be changed anytime during data collection.
Even if disabled spot finding information will still be send and written, though always with zero spots.
indexing:
type: boolean
default: true
description: Enable indexing
description: |
Enable indexing. This is temporary setting, i.e. can be changed anytime during data collection.
filter_powder_rings:
type: boolean
default: false
description: Filter spots which form powder rings (e.g., ice rings)
min_spot_count_powder_ring:
type: integer
format: int64
minimum: 5
description: Minimum number of spots to consider a thin resolution shell (0.01 A^-1) a powder ring and filter out.
signal_to_noise_threshold:
type: number
format: float
@@ -447,6 +484,15 @@ components:
properties:
file_prefix:
type: string
run_number:
type: integer
format: int64
description: |
Number of data collection run. This can be either automatically incremented or provided externally for each data collection.
experiment_group:
type: string
description: |
Name of group owning the data (e.g. p-group or proposal number).
images_expected:
type: integer
format: int64
@@ -620,14 +666,21 @@ components:
type: integer
description: "Quality of JPEG image (100 - highest; 0 - lowest)"
format: int64
default: 100
minimum: 0
maximum: 100
show_indexed:
type: boolean
description: "Preview indexed images only"
default: false
show_user_mask:
type: boolean
description: "Show user mask"
default: false
resolution_ring:
type: number
format: float
default: 0.1
minimum: 0.1
maximum: 100.0
error_message:
@@ -800,22 +853,37 @@ paths:
/wait_till_done:
post:
summary: Wait for acquisition done
parameters:
- in: query
name: timeout
required: false
schema:
type: integer
default: 60
minimum: 0
maximum: 3600
description: Timeout in seconds (0 == immediate response)
description: |
Block execution of external script till initialization, data collection or pedestal is finished.
Running this command does not affect (cancel) running data collection, it is only to ensure synchronous execution of other software.
To not block web server for a long period of time, the procedure is provided with a timeout of 5 seconds.
To not block web server for a indefinite period of time, the procedure is provided with a timeout.
Extending timeout is possible, but requires to ensure safety that client will not close the connection and retry the connection.
responses:
"200":
description: Detector in `Idle` state, another data collection can start immediately
"400":
description: Timeout parameter out of bounds
"500":
description: Error within Jungfraujoch code - see output message.
content:
application/json:
schema:
$ref: '#/components/schemas/error_message'
"502":
description: Detector is inactive mode
"504":
description: 5 second timeout reached, need to restart operation
description: Timeout reached, need to restart operation
/trigger:
post:
@@ -967,9 +1035,9 @@ paths:
Requires binary blob with 16-bit integer numbers of size of detector in raw/converted coordinates
(depending on detector settings).
parameters:
- name: number
- name: id
in: query
description: Image number to upload
description: Image id to upload
required: false
schema:
type: integer
@@ -992,6 +1060,38 @@ paths:
schema:
type: string
description: Exception error
/config/internal_generator_image.tiff:
put:
summary: Load TIFF image for internal FPGA generator
description: |
Load image for internal FPGA generator. This can only happen in Idle state of the detector.
Requires TIFF with 16-bit integer numbers of size of detector in raw/converted coordinates
(depending on detector settings).
parameters:
- in: query
name: id
description: Image ID to upload
required: false
schema:
type: integer
minimum: 0
maximum: 127
requestBody:
content:
image/tiff:
schema:
type: string
format: binary
responses:
"200":
description: Everything OK
"400":
description: Input parsing or validation error
content:
text/plain:
schema:
type: string
description: Exception error
/config/select_detector:
put:
summary: Select detector
@@ -1564,6 +1664,63 @@ paths:
format: binary
"404":
description: No preview image recorded so far
/config/mask.tiff:
get:
summary: Get mask of the detector
description: |
Get full pixel mask of the detector
See NXmx standard for meaning of pixel values
responses:
"200":
description: Pixel mask in TIFF format (4 byte; unsigned)
content:
image/tiff:
schema:
type: string
format: binary
/config/user_mask.tiff:
get:
summary: Get user mask of the detector
description: "Get user pixel mask of the detector in the actual detector coordinates: 0 - good pixel, 1 - masked"
responses:
"200":
description: User mask in TIFF format (4 byte; unsigned)
content:
image/tiff:
schema:
type: string
format: binary
put:
summary: Upload user mask of the detector
description: |
Should be in `Idle` state.
Upload user mask of the detector - this is for example to account for beam stop shadow or misbehaving regions.
If detector is conversion mode the mask can be both in raw (1024x512; stacked modules) or converted coordinates.
In the latter case - module gaps are ignored and don't need to be assigned value.
Mask is expected as TIFF (4-byte; unsigned).
0 - good pixel, other value - masked
User mask is stored in NXmx pixel mask (bit 8), as well as used in spot finding and azimuthal integration.
User mask is not automatically applied - i.e. pixels with user mask will have a valid pixel value in the images.
requestBody:
content:
application/octet-stream:
schema:
type: string
format: binary
responses:
"200":
description: All good
content:
image/tiff:
schema:
type: string
format: binary
"500":
description: Error within Jungfraujoch code - see output message.
content:
application/json:
schema:
$ref: '#/components/schemas/error_message'
/preview/pedestal.tiff:
get:
parameters:
@@ -1588,4 +1745,14 @@ paths:
type: string
format: binary
"404":
description: No calibration recorded so far
description: No calibration recorded so far
/version:
get:
responses:
"200":
description: Release number of Jungfraujoch
content:
text/plain:
schema:
type: string
example: 1.0.0

View File

@@ -12,8 +12,6 @@
#include "JFJochBrokerHttp.h"
#include "JFJochBrokerParser.h"
#include "../frame_serialize/ZMQStream2Pusher.h"
#include "../frame_serialize/DumpCBORToFilePusher.h"
static Pistache::Http::Endpoint *httpEndpoint;
@@ -81,25 +79,7 @@ int main (int argc, char **argv) {
if (aq_devices.size() > 0) {
experiment.DataStreams(aq_devices.size());
std::string pusher_type = ParseString(input, "stream_type", "zmq");
if (pusher_type == "zmq") {
int32_t zmq_send_watermark = ParseInt32(input, "zmq_send_watermark", 100);
int32_t zmq_send_buffer_size = ParseInt32(input, "zmq_send_buffer_size", -1);
auto tmp = std::make_unique<ZMQStream2Pusher>(ParseStringArray(input, "zmq_image_addr"),
zmq_send_watermark,
zmq_send_buffer_size);
std::string preview_addr = ParseString(input, "zmq_preview_addr", "");
if (!preview_addr.empty())
tmp->PreviewSocket(preview_addr);
image_pusher = std::move(tmp);
} else if (pusher_type == "dump_cbor") {
image_pusher = std::make_unique<DumpCBORToFilePusher>();
} else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"stream_type allowed: zmq (default), dump_cbor");
ParseImagePusher(input, image_pusher);
int32_t send_buffer_size_MiB = ParseInt32(input, "send_buffer_size_MiB", 2048);
receiver = std::make_unique<JFJochReceiverService>(aq_devices, logger, *image_pusher, send_buffer_size_MiB);
@@ -115,9 +95,9 @@ int main (int argc, char **argv) {
logger.Info("Source {} Instrument {} Default rotation axis {:.2f},{:.2f},{:.2f}",
experiment.GetSourceName(), experiment.GetInstrumentName(),
experiment.GetDefaultOmegaAxis().x,
experiment.GetDefaultOmegaAxis().y,
experiment.GetDefaultOmegaAxis().z);
experiment.GetDefaultRotationAxis().x,
experiment.GetDefaultRotationAxis().y,
experiment.GetDefaultRotationAxis().z);
Pistache::Address addr(Pistache::Ipv4::any(), Pistache::Port(http_port));

File diff suppressed because one or more lines are too long

View File

@@ -17,8 +17,11 @@ int32_t get_gpu_count() {
void set_gpu(int32_t dev_id) {
auto dev_count = get_gpu_count();
if ((dev_id < 0) || (dev_id >= dev_count))
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Device ID cannot be negative");
// Ignore if no GPU present
if (dev_count > 0) {
if ((dev_id < 0) || (dev_id >= dev_count))
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Device ID cannot be negative");
cuda_err(cudaSetDevice(dev_id));
}
cuda_err(cudaSetDevice(dev_id));
}
}

View File

@@ -19,12 +19,10 @@ DatasetSettings::DatasetSettings() {
file_prefix = "test";
ntrigger = 1;
images_per_trigger = 1;
summation = 1;
fpga_pixel_output = FPGAPixelOutput::Auto;
space_group_number = 0; // not set
compression = CompressionAlgorithm::BSHUF_LZ4;
photon_energy_multiplier = 1.0f;
omega_start = 0.0f;
images_per_file = 1000;
data_reduction_factor_serialmx = 1.0;
}
@@ -151,40 +149,34 @@ DatasetSettings &DatasetSettings::TotalFlux(const std::optional<float> &input) {
return *this;
}
DatasetSettings &DatasetSettings::OmegaStep(const std::optional<float> &input) {
DatasetSettings &DatasetSettings::Goniometer(const std::optional<GoniometerAxis> &input) {
if (input) {
check_finite("Omega step", input.value());
check_finite("Rotation angle increment", input->increment);
if (input->increment == 0.0f)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Angle increment cannot be zero");
check_finite("Rotation angle start", input->start);
goniometer = input;
}
if (input && (input == 0.0f))
omega_step.reset();
else
omega_step = input;
return *this;
}
DatasetSettings &DatasetSettings::OmegaStart(float input) {
check_finite("Omega start", input);
omega_start = input;
return *this;
}
DatasetSettings &DatasetSettings::OmegaAxis(const std::optional<Coord> &c) {
DatasetSettings &DatasetSettings::RotationAxis(const std::optional<Coord> &c) {
if (c) {
if (c->Length() == 0.0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Cannot use empty vector for omega");
omega_rotation_axis = c->Normalize();
rotation_axis = c->Normalize();
} else
omega_rotation_axis = c;
rotation_axis = c;
return *this;
}
DatasetSettings &DatasetSettings::HeaderAppendix(const std::string &input) {
DatasetSettings &DatasetSettings::HeaderAppendix(const nlohmann::json &input) {
header_appendix = input;
return *this;
}
DatasetSettings &DatasetSettings::ImageAppendix(const std::string &input) {
DatasetSettings &DatasetSettings::ImageAppendix(const nlohmann::json &input) {
image_appendix = input;
return *this;
}
@@ -198,13 +190,6 @@ DatasetSettings &DatasetSettings::PhotonEnergyMultiplayer(float input) {
return *this;
}
DatasetSettings &DatasetSettings::Summation(int64_t input) {
check_min("Summation", input, 1);
check_max("Summation", input, MAX_FPGA_SUMMATION);
summation = input;
return *this;
}
DatasetSettings &DatasetSettings::FPGAOutputMode(FPGAPixelOutput input) {
switch (input) {
case FPGAPixelOutput::Auto:
@@ -228,23 +213,19 @@ std::optional<float> DatasetSettings::GetTotalFlux() const {
return total_flux;
}
std::optional<float> DatasetSettings::GetOmegaStep() const {
return omega_step;
std::optional<GoniometerAxis> DatasetSettings::GetGoniometer() const {
return goniometer;
}
float DatasetSettings::GetOmegaStart() const {
return omega_start;
std::optional<Coord> DatasetSettings::GetRotationAxis() const {
return rotation_axis;
}
std::optional<Coord> DatasetSettings::GetOmegaAxis() const {
return omega_rotation_axis;
}
std::string DatasetSettings::GetHeaderAppendix() const {
const nlohmann::json& DatasetSettings::GetHeaderAppendix() const {
return header_appendix;
}
std::string DatasetSettings::GetImageAppendix() const {
const nlohmann::json& DatasetSettings::GetImageAppendix() const {
return image_appendix;
}
@@ -260,10 +241,6 @@ int64_t DatasetSettings::GetSpaceGroupNumber() const {
return space_group_number;
}
int64_t DatasetSettings::GetSummation() const {
return summation;
}
FPGAPixelOutput DatasetSettings::GetFPGAOutputMode() const {
return fpga_pixel_output;
}
@@ -332,3 +309,49 @@ DatasetSettings &DatasetSettings::DataReductionFactorSerialMX(float input) {
float DatasetSettings::GetDataReductionFactorSerialMX() const {
return data_reduction_factor_serialmx;
}
DatasetSettings &DatasetSettings::RunNumber(const std::optional<uint64_t> &input) {
if (input) {
check_min("Run number", input, 0);
check_max("Run number", input, INT64_MAX);
}
run_number = input;
return *this;
}
DatasetSettings & DatasetSettings::RunName(const std::optional<std::string> &input) {
if (input && input.value().empty())
run_name = {};
else
run_name = input;
return *this;
}
DatasetSettings &DatasetSettings::ExperimentGroup(const std::string &input) {
group = input;
return *this;
}
std::optional<uint64_t> DatasetSettings::GetRunNumber() const {
return run_number;
}
std::optional<std::string> DatasetSettings::GetRunName() const {
return run_name;
}
std::string DatasetSettings::GetExperimentGroup() const {
return group;
}
std::optional<std::chrono::microseconds> DatasetSettings::GetImageTime() const {
return image_time;
}
DatasetSettings &DatasetSettings::ImageTime(const std::optional<std::chrono::microseconds> input) {
if (input && (input.value().count() == 0))
image_time = {};
else
image_time = input;
return *this;
}

View File

@@ -21,7 +21,6 @@ class DatasetSettings {
int64_t ntrigger;
FPGAPixelOutput fpga_pixel_output;
int64_t summation;
float beam_x_pxl;
float beam_y_pxl;
@@ -40,14 +39,18 @@ class DatasetSettings {
std::optional<float> total_flux;
std::optional<float> attenuator_transmission;
std::optional<float> omega_step;
float omega_start;
std::string image_appendix;
std::string header_appendix;
std::optional<GoniometerAxis> goniometer;
nlohmann::json image_appendix;
nlohmann::json header_appendix;
std::optional<Coord> omega_rotation_axis;
std::optional<Coord> rotation_axis;
float data_reduction_factor_serialmx;
std::optional<std::chrono::microseconds> image_time;
std::optional<uint64_t> run_number;
std::optional<std::string> run_name;
std::string group;
public:
DatasetSettings();
@@ -65,28 +68,28 @@ public:
DatasetSettings& SampleName(std::string input);
DatasetSettings& AttenuatorTransmission(const std::optional<float> &input);
DatasetSettings& TotalFlux(const std::optional<float> &input);
DatasetSettings& OmegaStep(const std::optional<float> &input);
DatasetSettings& OmegaStart(float input);
DatasetSettings& OmegaAxis(const std::optional<Coord> &c);
DatasetSettings& HeaderAppendix(const std::string& input);
DatasetSettings& ImageAppendix(const std::string& input);
DatasetSettings& Goniometer(const std::optional<GoniometerAxis>& input);
DatasetSettings& RotationAxis(const std::optional<Coord> &c);
DatasetSettings& HeaderAppendix(const nlohmann::json& input);
DatasetSettings& ImageAppendix(const nlohmann::json& input);
DatasetSettings& PhotonEnergyMultiplayer(float input);
DatasetSettings& Summation(int64_t input);
DatasetSettings& FPGAOutputMode(FPGAPixelOutput input);
DatasetSettings& ImagesPerFile(int64_t input);
DatasetSettings& DataReductionFactorSerialMX(float input);
DatasetSettings& RunNumber(const std::optional<uint64_t> &run_number);
DatasetSettings& RunName(const std::optional<std::string> &input);
DatasetSettings& ExperimentGroup(const std::string &group);
DatasetSettings& ImageTime(const std::optional<std::chrono::microseconds> input);
std::optional<float> GetAttenuatorTransmission() const;
std::optional<float> GetTotalFlux() const;
std::optional<float> GetOmegaStep() const;
float GetOmegaStart() const;
std::optional<Coord> GetOmegaAxis() const;
std::string GetHeaderAppendix() const;
std::string GetImageAppendix() const;
std::optional<GoniometerAxis> GetGoniometer() const;
std::optional<Coord> GetRotationAxis() const;
const nlohmann::json& GetHeaderAppendix() const;
const nlohmann::json& GetImageAppendix() const;
float GetPhotonEnergyMultiplier() const;
std::optional<UnitCell> GetUnitCell() const;
int64_t GetSpaceGroupNumber() const;
int64_t GetSummation() const;
FPGAPixelOutput GetFPGAOutputMode() const;
std::string GetSampleName() const;
float GetPhotonEnergy_keV() const;
@@ -104,6 +107,11 @@ public:
int64_t GetImageNumPerTrigger() const;
int64_t GetImagesPerFile() const;
float GetDataReductionFactorSerialMX() const;
std::optional<uint64_t> GetRunNumber() const;
std::optional<std::string> GetRunName() const;
std::string GetExperimentGroup() const;
std::optional<std::chrono::microseconds> GetImageTime() const;
};
#endif //JUNGFRAUJOCH_DATASETSETTINGS_H

View File

@@ -12,10 +12,12 @@
#define CONVERTED_MODULE_SIZE (CONVERTED_MODULE_LINES * CONVERTED_MODULE_COLS)
#define JUNGFRAU_PACKET_SIZE_BYTES (8192)
#define MIN_COUNT_TIME_IN_US 5
#define MIN_FRAME_TIME_HALF_SPEED_IN_US 1000
#define MIN_FRAME_TIME_FULL_SPEED_IN_US 470
#define MAX_FRAME_TIME 2000
#define MAX_COUNT_TIME_IN_US 1980
#define MIN_COUNT_TIME_IN_US 3
#define MIN_STORAGE_CELL_DELAY_IN_NS 2100
#define READOUT_TIME_IN_US 20

View File

@@ -148,3 +148,12 @@ void DetectorSetup::SetTrimFiles(const std::vector<std::string> &filenames) {
const std::vector<std::string> &DetectorSetup::GetTrimFileNames() const {
return trim_file_names;
}
std::string DetectorSetup::GetSerialNumber() const {
return serial_number;
}
DetectorSetup &DetectorSetup::SerialNumber(const std::string &input) {
serial_number = input;
return *this;
}

View File

@@ -10,6 +10,7 @@ enum class DetectorType {EIGER, JUNGFRAU};
class DetectorSetup {
std::string description;
std::string serial_number;
DetectorGeometry geometry;
std::vector<std::string> det_modules_hostname;
std::vector<std::string> gain_file_names;
@@ -41,6 +42,7 @@ public:
DetectorSetup& SensorThickness_um(float input);
DetectorSetup& PixelSize_um(float input);
DetectorSetup& HighVoltage(int32_t input);
DetectorSetup& SerialNumber(const std::string &input);
[[nodiscard]] DetectorType GetDetectorType() const;
[[nodiscard]] const DetectorGeometry& GetGeometry() const;
@@ -56,6 +58,7 @@ public:
[[nodiscard]] const std::vector<std::string> &GetGainFileNames() const;
[[nodiscard]] const std::vector<std::string> &GetTrimFileNames() const;
[[nodiscard]] int32_t GetHighVoltage() const;
[[nodiscard]] std::string GetSerialNumber() const;
};

View File

@@ -10,6 +10,7 @@
#include "RawToConvertedGeometry.h"
#include "../fpga/pcie_driver/jfjoch_fpga.h"
#include "../include/spdlog/fmt/fmt.h"
#include "GitInfo.h"
using namespace std::literals::chrono_literals;
@@ -29,8 +30,6 @@ DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup)
internal_fpga_packet_generator = false;
internal_fpga_packet_generator_images = 1;
debug_pixel_mask = false;
ndatastreams = 1;
frame_time = std::chrono::microseconds(MIN_FRAME_TIME_HALF_SPEED_IN_US);
@@ -68,6 +67,8 @@ DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup)
mode = DetectorMode::Conversion;
max_spot_count = MAX_SPOT_COUNT;
summation = 1;
}
// setter functions
@@ -102,10 +103,13 @@ DiffractionExperiment &DiffractionExperiment::NumTriggers(int64_t input) {
DiffractionExperiment &DiffractionExperiment::FrameTime(std::chrono::microseconds in_frame_time,
std::chrono::microseconds in_count_time) {
check_min("Frame time (us)", in_frame_time.count(), MIN_FRAME_TIME_FULL_SPEED_IN_US);
check_max("Frame time (us)", in_frame_time.count(), MAX_FRAME_TIME);
check_max("Count time (us)", in_count_time.count(), in_frame_time.count() - READOUT_TIME_IN_US);
if (in_count_time.count() != 0) {
check_min("Count time (us)", in_count_time.count(), MIN_COUNT_TIME_IN_US);
check_max("Count time (us)", in_count_time.count(), MAX_COUNT_TIME_IN_US);
} else {
check_max("Count time (us)", in_frame_time.count() - READOUT_TIME_IN_US,
MAX_COUNT_TIME_IN_US);
}
frame_time = in_frame_time;
@@ -684,6 +688,7 @@ void DiffractionExperiment::CheckDataProcessingSettings(const SpotFindingSetting
check_min("Spot finding low resolution limit", settings.low_resolution_limit, 1.0);
check_max("Spot finding low resolution limit", settings.low_resolution_limit, 50.0);
}
check_min("min spot count for powder ring detection", settings.min_spot_count_powder_ring, 5);
check_min("indexing tolerance", settings.indexing_tolerance, 0.0);
check_max("indexing tolerance", settings.indexing_tolerance, 1.0);
}
@@ -730,6 +735,7 @@ void DiffractionExperiment::FillMessage(StartMessage &message) const {
message.source_name = GetSourceName();
message.source_name_short = GetSourceNameShort();
message.source_type = GetSourceType();
message.instrument_name = GetInstrumentName();
message.instrument_name_short = GetInstrumentNameShort();
@@ -739,14 +745,16 @@ void DiffractionExperiment::FillMessage(StartMessage &message) const {
message.countrate_correction_enabled = false;
message.flatfield_enabled = false;
if (GetOmegaStep())
message.omega = GoniometerAxis{.increment = GetOmegaStep().value(), .start = GetOmegaStart(),
.axis = {GetOmegaAxis().x, GetOmegaAxis().y, GetOmegaAxis().z}};
else
message.omega = GoniometerAxis{.increment = 0.0f};
auto goniometer = dataset.GetGoniometer();
if (goniometer) {
message.goniometer = goniometer;
message.rotation_axis[0] = GetRotationAxis().x;
message.rotation_axis[1] = GetRotationAxis().y;
message.rotation_axis[2] = GetRotationAxis().z;
}
message.series_id = GetSeriesID();
message.series_unique_id = GetSeriesIDString();
message.run_number = GetRunNumber();
message.run_name = GetRunName();
message.gain_file_names = detector.GetGainFileNames();
@@ -754,6 +762,9 @@ void DiffractionExperiment::FillMessage(StartMessage &message) const {
message.roi_names.emplace_back(x);
message.data_reduction_factor_serialmx = GetDataReductionFactorSerialMX();
message.experiment_group = dataset.GetExperimentGroup();
message.jfjoch_release = jfjoch_version();
message.detector_serial_number = detector.GetSerialNumber();
}
float DiffractionExperiment::GetPixelSize_mm() const {
@@ -770,6 +781,11 @@ DiffractionExperiment &DiffractionExperiment::SourceNameShort(std::string input)
return *this;
}
DiffractionExperiment &DiffractionExperiment::SourceType(std::string input) {
source_type = input;
return *this;
}
DiffractionExperiment &DiffractionExperiment::InstrumentName(std::string input) {
instrument_name = input;
return *this;
@@ -788,6 +804,10 @@ std::string DiffractionExperiment::GetSourceNameShort() const {
return source_name_short;
}
std::string DiffractionExperiment::GetSourceType() const {
return source_type;
}
std::string DiffractionExperiment::GetInstrumentName() const {
return instrument_name;
}
@@ -865,7 +885,9 @@ std::chrono::nanoseconds DiffractionExperiment::GetStorageCellDelay() const {
}
DiffractionExperiment &DiffractionExperiment::Summation(int64_t input) {
dataset.Summation(input);
check_min("Summation factor", input, 1);
check_max("Summation factor", input, MAX_FPGA_SUMMATION);
summation = input;
return *this;
}
@@ -881,7 +903,7 @@ int64_t DiffractionExperiment::GetSummation() const {
if (GetStorageCellNumber() > 1)
return 1;
else
return dataset.GetSummation();
return summation;
}
}
@@ -950,22 +972,13 @@ std::optional<float> DiffractionExperiment::GetTotalFlux() const {
return dataset.GetTotalFlux();
}
DiffractionExperiment &DiffractionExperiment::OmegaStep(const std::optional<float> &input) {
dataset.OmegaStep(input);
DiffractionExperiment &DiffractionExperiment::Goniometer(const std::optional<GoniometerAxis> &input) {
dataset.Goniometer(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::OmegaStart(float input) {
dataset.OmegaStart(input);
return *this;
}
std::optional<float> DiffractionExperiment::GetOmegaStep() const {
return dataset.GetOmegaStep();
}
float DiffractionExperiment::GetOmegaStart() const {
return dataset.GetOmegaStart();
std::optional<GoniometerAxis> DiffractionExperiment::GetGoniometer() const {
return dataset.GetGoniometer();
}
DiffractionExperiment &DiffractionExperiment::UsingGainHG0(bool input) {
@@ -986,63 +999,64 @@ bool DiffractionExperiment::IsUsingGainHG0() const {
return use_gain_hg0;
}
DiffractionExperiment &DiffractionExperiment::HeaderAppendix(const std::string &input) {
DiffractionExperiment &DiffractionExperiment::HeaderAppendix(const nlohmann::json &input) {
dataset.HeaderAppendix(input);
return *this;
}
DiffractionExperiment &DiffractionExperiment::ImageAppendix(const std::string &input) {
DiffractionExperiment &DiffractionExperiment::ImageAppendix(const nlohmann::json &input) {
dataset.ImageAppendix(input);
return *this;
}
std::string DiffractionExperiment::GetHeaderAppendix() const {
const nlohmann::json& DiffractionExperiment::GetHeaderAppendix() const {
return dataset.GetHeaderAppendix();
}
std::string DiffractionExperiment::GetImageAppendix() const {
const nlohmann::json& DiffractionExperiment::GetImageAppendix() const {
return dataset.GetImageAppendix();
}
DiffractionExperiment &DiffractionExperiment::OmegaAxis(const Coord &c) {
dataset.OmegaAxis(c);
DiffractionExperiment &DiffractionExperiment::RotationAxis(const std::optional<Coord> &c) {
dataset.RotationAxis(c);
return *this;
}
DiffractionExperiment &DiffractionExperiment::OmegaAxis() {
dataset.OmegaAxis({});
return *this;
}
Coord DiffractionExperiment::GetOmegaAxis() const {
auto tmp = dataset.GetOmegaAxis();
Coord DiffractionExperiment::GetRotationAxis() const {
auto tmp = dataset.GetRotationAxis();
if (tmp)
return tmp.value();
else
return default_omega_axis;
}
DiffractionExperiment &DiffractionExperiment::DefaultOmegaAxis(const Coord &c) {
DiffractionExperiment &DiffractionExperiment::DefaultRotationAxis(const Coord &c) {
if (c.Length() == 0.0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Cannot use empty vector for omega axis");
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Cannot use empty vector for goniometer axis");
default_omega_axis = c.Normalize();
return *this;
}
Coord DiffractionExperiment::GetDefaultOmegaAxis() const {
Coord DiffractionExperiment::GetDefaultRotationAxis() const {
return default_omega_axis;
}
uint64_t DiffractionExperiment::GetSeriesID() const {
uint64_t DiffractionExperiment::GetRunNumber() const {
if (dataset.GetRunNumber())
return dataset.GetRunNumber().value();
return series_id;
}
std::string DiffractionExperiment::GetSeriesIDString() const {
return std::to_string(series_id) + ": " + dataset.GetFilePrefix();
std::string DiffractionExperiment::GetRunName() const {
auto run_name = dataset.GetRunName();
if (run_name)
return run_name.value();
else
return std::to_string(series_id) + ":" + dataset.GetFilePrefix();
}
DiffractionExperiment &DiffractionExperiment::IncrementSeriesID() {
DiffractionExperiment &DiffractionExperiment::IncrementRunNumber() {
series_id++;
return *this;
}
@@ -1069,6 +1083,7 @@ bool DiffractionExperiment::IsConversionOnFPGA() const {
}
DiffractionExperiment &DiffractionExperiment::DetectorDelay(std::chrono::nanoseconds input) {
check_min("Detector delay (us)", input.count(), 0);
detector_delay = input;
return *this;
}
@@ -1128,6 +1143,19 @@ int64_t DiffractionExperiment::GetInternalPacketGeneratorImages() const {
DiffractionExperiment &DiffractionExperiment::ImportDatasetSettings(const DatasetSettings &input) {
auto tmp = dataset;
dataset = input;
auto image_time = input.GetImageTime();
if (image_time) {
if (image_time->count() % GetFrameTime().count() != 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Image time must be multiple of frame time");
if (GetFrameTime().count() == 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Frame time cannot be zero");
this->Summation(image_time.value() / GetFrameTime());
} else
summation = 1;
if (GetFrameNum() >= MAX_FRAMES) {
dataset = tmp;
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
@@ -1185,3 +1213,7 @@ DiffractionExperiment &DiffractionExperiment::DataReductionFactorSerialMX(float
dataset.DataReductionFactorSerialMX(input);
return *this;
}
std::string DiffractionExperiment::GetExperimentGroup() const {
return dataset.GetExperimentGroup();
}

View File

@@ -78,11 +78,11 @@ class DiffractionExperiment {
std::string source_name;
std::string source_name_short;
std::string source_type;
std::string instrument_name;
std::string instrument_name_short;
bool pulsed_source;
bool debug_pixel_mask;
Coord default_omega_axis;
bool conversion_on_fpga;
@@ -98,6 +98,10 @@ class DiffractionExperiment {
ROIMap roi_mask;
int64_t max_spot_count;
int64_t summation;
std::string detector_update_zmq_addr;
public:
// Public methods are atomic
DiffractionExperiment();
@@ -133,14 +137,15 @@ public:
DiffractionExperiment& StorageCellStart(int64_t input = 15);
DiffractionExperiment& SourceName(std::string input);
DiffractionExperiment& SourceType(std::string input);
DiffractionExperiment& SourceNameShort(std::string input);
DiffractionExperiment& InstrumentName(std::string input);
DiffractionExperiment& InstrumentNameShort(std::string input);
DiffractionExperiment& DefaultOmegaAxis(const Coord &c);
DiffractionExperiment& DefaultRotationAxis(const Coord &c);
DiffractionExperiment& UsingGainHG0(bool input);
DiffractionExperiment& FixedGainG1(bool input);
DiffractionExperiment& IncrementSeriesID();
DiffractionExperiment& IncrementRunNumber();
DiffractionExperiment& ConversionOnFPGA(bool input);
DiffractionExperiment& PulsedSource(bool input);
@@ -157,12 +162,10 @@ public:
DiffractionExperiment& SampleName(std::string input);
DiffractionExperiment& AttenuatorTransmission(const std::optional<float> &input);
DiffractionExperiment& TotalFlux(const std::optional<float> &input);
DiffractionExperiment& OmegaStep(const std::optional<float> &input);
DiffractionExperiment& OmegaStart(float input);
DiffractionExperiment& OmegaAxis(const Coord &c);
DiffractionExperiment& OmegaAxis();
DiffractionExperiment& HeaderAppendix(const std::string& input);
DiffractionExperiment& ImageAppendix(const std::string& input);
DiffractionExperiment& Goniometer(const std::optional<GoniometerAxis> &input);
DiffractionExperiment& RotationAxis(const std::optional<Coord> &c);
DiffractionExperiment& HeaderAppendix(const nlohmann::json& input);
DiffractionExperiment& ImageAppendix(const nlohmann::json& input);
DiffractionExperiment& PhotonEnergyMultiplayer(float input);
DiffractionExperiment& Summation(int64_t input);
DiffractionExperiment& FPGAOutputMode(FPGAPixelOutput input);
@@ -253,6 +256,7 @@ public:
float GetPixelSize_mm() const;
std::string GetSourceName() const;
std::string GetSourceType() const;
std::string GetSourceNameShort() const;
std::string GetInstrumentName() const;
std::string GetInstrumentNameShort() const;
@@ -269,13 +273,13 @@ public:
int64_t GetUDPInterfaceCount() const;
std::vector<DetectorModuleConfig> GetDetectorModuleConfig(const std::vector<AcquisitionDeviceNetConfig>& net_config) const;
Coord GetDefaultOmegaAxis() const;
Coord GetDefaultRotationAxis() const;
bool IsFixedGainG1() const;
bool IsUsingGainHG0() const;
uint64_t GetSeriesID() const;
std::string GetSeriesIDString() const;
uint64_t GetRunNumber() const;
std::string GetRunName() const;
bool IsConversionOnFPGA() const;
const DetectorSetup& GetDetectorSetup() const;
@@ -288,11 +292,11 @@ public:
std::optional<float> GetAttenuatorTransmission() const;
std::optional<float> GetTotalFlux() const;
std::optional<float> GetOmegaStep() const;
float GetOmegaStart() const;
Coord GetOmegaAxis() const;
std::string GetHeaderAppendix() const;
std::string GetImageAppendix() const;
std::optional<GoniometerAxis> GetGoniometer() const;
Coord GetRotationAxis() const;
const nlohmann::json& GetHeaderAppendix() const;
const nlohmann::json& GetImageAppendix() const;
float GetPhotonEnergyMultiplier() const;
std::optional<UnitCell> GetUnitCell() const;
std::string GetUnitCellString() const;
@@ -321,6 +325,7 @@ public:
int64_t GetImagesPerFile() const;
float GetDataReductionFactorSerialMX() const;
std::string GetExperimentGroup() const;
};
#endif //DIFFRACTIONEXPERIMENT_H

View File

@@ -12,7 +12,7 @@ PixelMask::PixelMask(const DetectorSetup &detector)
PixelMask::PixelMask(const DiffractionExperiment& experiment)
: PixelMask(experiment.GetDetectorSetup()) {}
void PixelMask::LoadDetectorBadPixelMask(const std::vector<uint32_t> &input_mask, uint8_t bit) {
void PixelMask::LoadMask(const std::vector<uint32_t> &input_mask, uint8_t bit) {
if (input_mask.size() != mask.size())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Input match doesn't fit the detector ");
@@ -25,7 +25,11 @@ void PixelMask::LoadDetectorBadPixelMask(const std::vector<uint32_t> &input_mask
}
}
std::vector<uint32_t> PixelMask::GetMask(const DiffractionExperiment &experiment) {
void PixelMask::LoadDetectorBadPixelMask(const std::vector<uint32_t> &input_mask) {
LoadMask(input_mask, ErrorPixelBit);
}
std::vector<uint32_t> PixelMask::GetMask(const DiffractionExperiment &experiment, bool conv) const {
std::vector<uint32_t> mask_out = mask;
// apply edge mask
@@ -39,7 +43,7 @@ std::vector<uint32_t> PixelMask::GetMask(const DiffractionExperiment &experiment
|| (line == RAW_MODULE_LINES - 1)
|| (col == 0)
|| (col == RAW_MODULE_COLS - 1))
mask_out[pixel] |= (1 << 30);
mask_out[pixel] |= (1 << ModuleEdgePixelBit);
}
if (experiment.GetMaskChipEdges()) {
@@ -47,33 +51,39 @@ std::vector<uint32_t> PixelMask::GetMask(const DiffractionExperiment &experiment
|| (col == 511) || (col == 512)
|| (col == 767) || (col == 768)
|| (line == 255) || (line== 256))
mask_out[pixel] |= (1 << 31);
mask_out[pixel] |= (1 << ChipGapPixelBit);
}
}
}
}
if (experiment.GetDetectorMode() == DetectorMode::Conversion) {
std::vector<uint32_t> tmp(experiment.GetPixelsNum(), 1); // nonfuctional areas (i.e. gaps) are filled with 1
if (conv && (experiment.GetDetectorMode() == DetectorMode::Conversion)) {
std::vector<uint32_t> tmp(experiment.GetPixelsNum(), 1<<ModuleGapPixelBit); // nonfunctional areas (i.e. gaps) are filled with 1
RawToConvertedGeometry<uint32_t, uint32_t>(experiment, tmp.data(), mask_out.data());
return tmp;
} else
return mask_out;
}
std::vector<uint32_t> PixelMask::GetUserMask(const DiffractionExperiment &experiment, bool conv) const {
std::vector<uint32_t> ret = GetMask(experiment, conv);
for (auto &i: ret)
i = ((i & (1 << UserMaskedPixelBit)) != 0) ? 1 : 0;
return ret;
}
void PixelMask::LoadUserMask(const DiffractionExperiment &experiment,
const std::vector<uint32_t> &in_mask,
uint8_t bit) {
const std::vector<uint32_t> &in_mask) {
if (experiment.GetModulesNum() != nmodules)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Mismatch in module size");
if (in_mask.size() == nmodules * RAW_MODULE_SIZE) {
LoadDetectorBadPixelMask(in_mask, bit);
LoadMask(in_mask, UserMaskedPixelBit);
} else if (in_mask.size() == experiment.GetPixelsNum()) {
std::vector<uint32_t> raw_mask(nmodules * RAW_MODULE_SIZE);
ConvertedToRawGeometry(experiment, raw_mask.data(), in_mask.data());
LoadDetectorBadPixelMask(in_mask, bit);
LoadMask(raw_mask, UserMaskedPixelBit);
} else
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Size of input user mask invalid");

View File

@@ -9,12 +9,21 @@
class PixelMask {
size_t nmodules;
std::vector<uint32_t> mask;
void LoadMask(const std::vector<uint32_t>& mask, uint8_t bit);
public:
// NXmx bits
constexpr static const uint8_t ModuleGapPixelBit = 0;
constexpr static const uint8_t ErrorPixelBit = 1;
constexpr static const uint8_t UserMaskedPixelBit = 8;
constexpr static const uint8_t ChipGapPixelBit = 31;
constexpr static const uint8_t ModuleEdgePixelBit = 30;
PixelMask(const DetectorSetup& detector);
PixelMask(const DiffractionExperiment& experiment);
void LoadUserMask(const DiffractionExperiment& experiment, const std::vector<uint32_t>& mask, uint8_t bit);
void LoadDetectorBadPixelMask(const std::vector<uint32_t>& mask, uint8_t bit);
std::vector<uint32_t> GetMask(const DiffractionExperiment& experiment);
void LoadUserMask(const DiffractionExperiment& experiment, const std::vector<uint32_t>& mask);
void LoadDetectorBadPixelMask(const std::vector<uint32_t>& mask);
std::vector<uint32_t> GetMask(const DiffractionExperiment& experiment, bool conv = true) const;
std::vector<uint32_t> GetUserMask(const DiffractionExperiment& experiment, bool conv = true) const;
};

View File

@@ -7,9 +7,12 @@
#include <cstdint>
#include <string>
enum class PlotType {BkgEstimate, RadInt, RadIntPerTimePoint, SpotCount, IndexingRate, IndexingRatePerTimePoint,
ErrorPixels, ImageCollectionEfficiency, ReceiverDelay, ReceiverFreeSendBuf, StrongPixels,
ROISum, ROIMaxCount, ROIPixels};
enum class PlotType {
BkgEstimate, RadInt, RadIntPerTimePoint, SpotCount, SpotCountInRings,
IndexingRate, IndexingRatePerTimePoint,
ErrorPixels, ImageCollectionEfficiency, ReceiverDelay, ReceiverFreeSendBuf, StrongPixels,
ROISum, ROIMaxCount, ROIPixels
};
struct PlotRequest {
PlotType type;

View File

@@ -7,6 +7,7 @@
#include <map>
#include <mutex>
#include <cmath>
#include <optional>
#include "Plot.h"
@@ -37,6 +38,11 @@ template <class T> class StatusVector {
return ret;
}
public:
void AddElement(uint32_t id, std::optional<T> val) {
if (val.has_value())
AddElement(id, val.value());
}
void AddElement(uint32_t id, T val) {
std::unique_lock<std::mutex> ul(m);
if (id >= content.size()) {

View File

@@ -65,14 +65,14 @@ void DetectorWrapper::Initialize(const DiffractionExperiment& experiment,
det.setSourceUDPIP(sls::IpAddr(cfg.ipv4_src_addr_1), {i});
det.setSourceUDPMAC(sls::MacAddr(BASE_DETECTOR_MAC + i * 2), {i});
det.setDestinationUDPPort(cfg.udp_dest_port_1, i);
det.setDestinationUDPPort(cfg.udp_dest_port_1 + 2 * i, i);
det.setDestinationUDPIP(sls::IpAddr(cfg.ipv4_dest_addr_1), {i});
det.setDestinationUDPMAC(sls::MacAddr(cfg.mac_addr_dest_1), {i});
if (experiment.GetUDPInterfaceCount() == 2) {
det.setSourceUDPIP2(sls::IpAddr(cfg.ipv4_src_addr_2), {i});
det.setSourceUDPMAC2(sls::MacAddr(BASE_DETECTOR_MAC + i * 2 + 1), {i});
det.setDestinationUDPPort2(cfg.udp_dest_port_2, i);
det.setDestinationUDPPort2(cfg.udp_dest_port_2 + 2 * i + 1, i);
det.setDestinationUDPIP2(sls::IpAddr(cfg.ipv4_dest_addr_2), {i});
det.setDestinationUDPMAC2(sls::MacAddr(cfg.mac_addr_dest_2), {i});
}
@@ -91,7 +91,7 @@ void DetectorWrapper::Initialize(const DiffractionExperiment& experiment,
throw JFJochException(JFJochExceptionCategory::Detector,
"Discrepancy in module number between DAQ and detector");
}
det.setDynamicRange(16);
det.setTenGiga(true);
auto trim_files = experiment.GetDetectorSetup().GetTrimFileNames();
@@ -100,8 +100,8 @@ void DetectorWrapper::Initialize(const DiffractionExperiment& experiment,
auto &cfg = mod_cfg[i];
det.setDestinationUDPPort(cfg.udp_dest_port_1, 2 * i);
det.setDestinationUDPPort2(cfg.udp_dest_port_1, 2 * i + 1);
det.setDestinationUDPPort(cfg.udp_dest_port_1 + 2 * i, 2 * i);
det.setDestinationUDPPort2(cfg.udp_dest_port_1 + 2 * i + 1, 2 * i + 1);
det.setSourceUDPIP(sls::IpAddr(cfg.ipv4_src_addr_1), {2 * i, 2 * i + 1});
det.setDestinationUDPIP(sls::IpAddr(cfg.ipv4_dest_addr_1), {2 * i, 2 * i + 1});
det.setDestinationUDPMAC(sls::MacAddr(cfg.mac_addr_dest_1), {2 * i, 2 * i + 1});

View File

@@ -8,13 +8,13 @@
"pedestal_g0_frames": 2000,
"pedestal_g1_frames": 300,
"pedestal_g2_frames": 300,
"frame_time_us": "500 us",
"count_time_us": "480 us",
"preview_period_us": "1 s",
"frame_time": "500 us",
"count_time": "480 us",
"detector_ipv4": "10.10.85.0"
},
"frontend_directory":"/home/jungfrau/nextgendcu/frontend/build",
"numa_policy": "n2g2",
"zmq_preview_period": "1 s",
"zmq_image_addr": ["tcp://0.0.0.0:5500", "tcp://0.0.0.0:5501", "tcp://0.0.0.0:5502", "tcp://0.0.0.0:5503"],
"receiver_threads": 64,
"receiver": {

View File

@@ -8,15 +8,16 @@
"pedestal_g0_frames": 2000,
"pedestal_g1_frames": 300,
"pedestal_g2_frames": 300,
"frame_time_us": "10 ms",
"count_time_us": "10 us",
"preview_period_us": "1 s",
"frame_time": "10 ms",
"count_time": "10 us",
"detector_ipv4": "10.3.30.155",
"pulsed_source": true
},
"frontend_directory":"/home/jungfrau/nextgendcu/frontend/build",
"numa_policy": "n2g4",
"zmq_image_addr": ["tcp://0.0.0.0:5500"],
"zmq_preview_period": "1 s",
"receiver_threads": 64,
"receiver": {
"type": "pcie",

View File

@@ -8,9 +8,8 @@
"pedestal_g0_frames": 0,
"pedestal_g1_frames": 0,
"pedestal_g2_frames": 0,
"frame_time_us": "1000 us",
"count_time_us": "980 us",
"preview_period_us": "1 s",
"frame_time": "1000 us",
"count_time": "980 us",
"detector_ipv4": "10.10.85.20",
"internal_frame_generator": true
},
@@ -20,6 +19,9 @@
},
"frontend_directory": "../../frontend_ui/build/",
"zmq_image_addr": ["tcp://0.0.0.0:5500"],
"zmq_preview_addr": "tcp://0.0.0.0:5501",
"zmq_preview_period": "1 s",
"zmq_writer_notification_addr": "ipc://*",
"detectors": [
{
"standard_geometry": {

View File

@@ -75,6 +75,7 @@ void host_writer(STREAM_512 &data_in,
state = 0;
ap_uint<16> req_handle;
ap_uint<16> req_handle_send = HANDLE_START;
ap_uint<64> req_host_offset;
while (data_in.empty()) {
@@ -240,7 +241,9 @@ void host_writer(STREAM_512 &data_in,
host_memory_out << packet_out;
if (send_images) {
write_completion(m_axis_completion, req_handle, data_collection_id);
if (req_handle_send != HANDLE_START)
write_completion(m_axis_completion, req_handle_send, data_collection_id);
req_handle_send = req_handle;
internal_packets_processed += cmpl.packet_count;
packets_processed = internal_packets_processed;
}
@@ -252,6 +255,21 @@ void host_writer(STREAM_512 &data_in,
data_in >> packet;
#ifdef JFJOCH_HLS_NOSYNTH
while (!host_memory_out.empty())
std::this_thread::sleep_for(std::chrono::milliseconds(1));
#else
{
// wait for 5 ms (ensure that PCIe buffer is clean)
#pragma HLS PROTOCOL
for (int i = 0; i < 5 * 200 * 1000; i++)
ap_wait();
}
#endif
if (req_handle_send != HANDLE_START)
write_completion(m_axis_completion, req_handle_send, data_collection_id);
write_completion(m_axis_completion, HANDLE_END, data_collection_id);
idle = 1;

View File

@@ -13,13 +13,18 @@
struct spot_finder_packet {
ap_uint<768> data;
ap_uint<32> mask;
ap_uint<32> strong_pixel;
ap_int<32> count_threshold;
ap_uint<32> snr_threshold;
ap_uint<1> user;
ap_uint<1> last;
};
void spot_finder_in_stream(STREAM_768 &data_in,
hls::stream<ap_uint<32>> &mask_in,
hls::stream<spot_finder_packet> &data_out) {
hls::stream<spot_finder_packet> &data_out,
volatile ap_int<32> &in_count_threshold,
volatile ap_uint<32> &in_snr_threshold) {
ap_uint<32> mask;
packet_768_t packet_in;
{
@@ -33,12 +38,53 @@ void spot_finder_in_stream(STREAM_768 &data_in,
while (!packet_in.user) {
#pragma HLS PIPELINE II=1
mask_in >> mask;
data_out << spot_finder_packet{.data = packet_in.data, .mask = mask, .user = packet_in.user, .last = packet_in.last};
data_out << spot_finder_packet{
.data = packet_in.data,
.mask = mask,
.strong_pixel = 0,
.count_threshold = in_count_threshold,
.snr_threshold = in_snr_threshold,
.user = packet_in.user,
.last = packet_in.last
};
data_in >> packet_in;
}
data_out << spot_finder_packet{.data = packet_in.data, .mask = 0, .user = packet_in.user, .last = packet_in.last};
}
void spot_finder_out_stream(hls::stream<spot_finder_packet> &data_in,
STREAM_768 &data_out,
hls::stream<ap_axiu<32,1,1,1>> &strong_pixel_out) {
spot_finder_packet packet_in;
{
#pragma HLS PROTOCOL fixed
data_in >> packet_in;
ap_wait();
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
ap_wait();
}
data_in >> packet_in;
while (!packet_in.user) {
ap_uint<32> count_threshold = packet_in.count_threshold;
ap_uint<32> snr_threshold_u32 = packet_in.snr_threshold;
for (int i = 0; i < RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) {
#pragma HLS PIPELINE II=1
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
strong_pixel_out << ap_axiu<32,1,1,1>{.data = packet_in.strong_pixel, .user = 0};
data_in >> packet_in;
}
// Save module statistics
strong_pixel_out << ap_axiu<32,1,1,1>{.data = count_threshold, .user = 0};
strong_pixel_out << ap_axiu<32,1,1,1>{.data = snr_threshold_u32, .user = 0};
for (int i = 0; i < 14;i++)
strong_pixel_out << ap_axiu<32,1,1,1>{.data = 0, .user = 0};
}
strong_pixel_out << ap_axiu<32,1,1,1>{.data = 0, .user = 1};
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
}
ap_int<SUM_BITWIDTH> calc_sum(ap_int<24> val[32], ap_uint<32> mask) {
#pragma HLS PIPELINE II=1
ap_int<SUM_BITWIDTH> ret = 0;
@@ -73,6 +119,8 @@ void spot_finder_prepare(hls::stream<spot_finder_packet> &data_in,
hls::stream<ap_int<SUM_BITWIDTH>> &sum_out,
hls::stream<ap_int<SUM2_BITWIDTH>> &sum2_out,
hls::stream<ap_int<VALID_BITWIDTH>> &valid_out) {
ap_uint<32> strong_pixel;
spot_finder_packet packet;
{
#pragma HLS PROTOCOL fixed
@@ -95,6 +143,7 @@ void spot_finder_prepare(hls::stream<spot_finder_packet> &data_in,
for (ap_uint<15> i = 0; i < RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) {
#pragma HLS PIPELINE II=1
data_out << packet;
ap_int<24> val[32];
unpack32(packet.data, val);
ap_uint<32> mask = packet.mask;
@@ -167,31 +216,28 @@ ap_uint<32> spot_finder_count_threshold(ap_int<24> val[32], ap_int<32> &count_th
}
void spot_finder_apply_threshold(hls::stream<spot_finder_packet> &data_in,
STREAM_768 &data_out,
hls::stream<spot_finder_packet> &data_out,
hls::stream<ap_int<SUM_BITWIDTH>> &sum_in,
hls::stream<ap_int<SUM2_BITWIDTH>> &sum2_in,
hls::stream<ap_int<VALID_BITWIDTH>> &valid_in,
hls::stream<ap_axiu<32,1,1,1>> &strong_pixel_out,
volatile ap_int<32> &in_count_threshold,
volatile ap_uint<32> &in_snr_threshold) {
hls::stream<ap_int<VALID_BITWIDTH>> &valid_in) {
ap_uint<32> strong_pixel_prev;
spot_finder_packet packet_in;
{
#pragma HLS PROTOCOL fixed
data_in >> packet_in;
ap_wait();
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
data_out << packet_in;
ap_wait();
}
ap_int<SUM_BITWIDTH> sum[32];
ap_int<SUM2_BITWIDTH> sum2[32];
ap_int<VALID_BITWIDTH> valid[32];
data_in >> packet_in;
while (!packet_in.user) {
ap_int<32> count_threshold = in_count_threshold;
ap_uint<32> snr_threshold_u32 = in_snr_threshold;
ap_int<32> count_threshold = packet_in.count_threshold;
ap_uint<32> snr_threshold_u32 = packet_in.snr_threshold;
float_uint32 thr;
thr.u = snr_threshold_u32;
ap_ufixed<10,8, AP_RND_CONV> snr_threshold = thr.f;
@@ -212,34 +258,28 @@ void spot_finder_apply_threshold(hls::stream<spot_finder_packet> &data_in,
valid_in >> valid[i % 32];
}
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
ap_int<24> data_unpacked[32];
unpack32(packet_in.data, data_unpacked);
ap_uint<32> strong_pixel = spot_finder_count_threshold(data_unpacked, count_threshold) &
spot_finder_snr_threshold(data_unpacked, snr_threshold_2,
sum[i % 32], sum2[i % 32], valid[i % 32]);
strong_pixel = strong_pixel & packet_in.mask;
spot_finder_snr_threshold(data_unpacked, snr_threshold_2,
sum[i % 32], sum2[i % 32], valid[i % 32]);
if ((snr_threshold == 0) && (count_threshold <= 0))
strong_pixel = 0;
strong_pixel_out << ap_axiu<32,1,1,1>{.data = strong_pixel, .user = 0};
strong_pixel = strong_pixel & packet_in.mask;
packet_in.mask |= strong_pixel; // mask strong pixels
packet_in.strong_pixel |= strong_pixel; // add strong pixels to the output
data_out << packet_in;
data_in >> packet_in;
}
// Save module statistics
strong_pixel_out << ap_axiu<32,1,1,1>{.data = count_threshold, .user = 0};
strong_pixel_out << ap_axiu<32,1,1,1>{.data = snr_threshold_u32, .user = 0};
for (int i = 0; i < 14;i++)
strong_pixel_out << ap_axiu<32,1,1,1>{.data = 0, .user = 0};
}
strong_pixel_out << ap_axiu<32,1,1,1>{.data = 0, .user = 1};
data_out << packet_768_t{.data = packet_in.data, .user = packet_in.user, .last = packet_in.last};
data_out << packet_in;
}
void spot_finder(STREAM_768 &data_in,
hls::stream<ap_uint<32>> &mask_in,
STREAM_768 &data_out,
@@ -256,22 +296,38 @@ void spot_finder(STREAM_768 &data_in,
hls::stream<spot_finder_packet, 2> data_0;
hls::stream<spot_finder_packet, 1080> data_1;
hls::stream<spot_finder_packet, 8> data_2;
hls::stream<spot_finder_packet, 1080> data_3;
hls::stream<spot_finder_packet, 8> data_4;
#pragma HLS BIND_STORAGE variable=data_1 type=fifo impl=bram
#pragma HLS BIND_STORAGE variable=data_3 type=fifo impl=bram
hls::stream<ap_int<SUM_BITWIDTH>, 24> sum_0;
hls::stream<ap_int<SUM2_BITWIDTH>, 24> sum2_0;
hls::stream<ap_int<VALID_BITWIDTH>, 24> valid_0;
hls::stream<ap_int<SUM_BITWIDTH>, 24> sum_1;
hls::stream<ap_int<SUM2_BITWIDTH>, 24> sum2_1;
hls::stream<ap_int<VALID_BITWIDTH>, 24> valid_1;
#ifndef JFJOCH_HLS_NOSYNTH
spot_finder_in_stream(data_in, mask_in, data_0);
spot_finder_in_stream(data_in, mask_in, data_0, in_count_threshold, in_snr_threshold);
spot_finder_prepare(data_0, data_1, sum_0, sum2_0, valid_0);
spot_finder_apply_threshold(data_1, data_out, sum_0, sum2_0, valid_0, strong_pixel_out,
in_count_threshold, in_snr_threshold);
spot_finder_apply_threshold(data_1, data_2, sum_0, sum2_0, valid_0);
spot_finder_prepare(data_2, data_3, sum_1, sum2_1, valid_1);
spot_finder_apply_threshold(data_3, data_4, sum_1, sum2_1, valid_1);
spot_finder_out_stream(data_4, data_out, strong_pixel_out);
#else
std::vector<std::thread> spot_finder_cores;
spot_finder_cores.emplace_back([&] {spot_finder_in_stream(data_in, mask_in, data_0);});
spot_finder_cores.emplace_back([&] {spot_finder_in_stream(data_in, mask_in, data_0, in_count_threshold,
in_snr_threshold);});
spot_finder_cores.emplace_back([&] {spot_finder_prepare(data_0, data_1, sum_0, sum2_0, valid_0);});
spot_finder_cores.emplace_back([&] {spot_finder_apply_threshold(data_1, data_out, sum_0, sum2_0, valid_0,
strong_pixel_out, in_count_threshold,
in_snr_threshold);});
spot_finder_cores.emplace_back([&] {spot_finder_apply_threshold(data_1, data_2, sum_0, sum2_0, valid_0);});
spot_finder_cores.emplace_back([&] {spot_finder_prepare(data_2, data_3, sum_1, sum2_1, valid_1);});
spot_finder_cores.emplace_back([&] {spot_finder_apply_threshold(data_3, data_4, sum_1, sum2_1, valid_1);});
spot_finder_cores.emplace_back([&] {spot_finder_out_stream(data_4, data_out, strong_pixel_out);});
for (auto &i : spot_finder_cores)
i.join();
#endif

View File

@@ -74,8 +74,8 @@ void spot_finder_mask(STREAM_768 &data_in,
|| (((col == 0) || (col == 8) || (col == 16) || (col == 24)) && (j == 0))
|| (pixel_val[j] == INT24_MIN)
|| (pixel_val[j] == INT24_MAX)
|| ((d[j] != 0) && (d[j] < min_d_value))
|| ((d[j] != 0) && (d[j] > max_d_value)))
|| (d[j] < min_d_value)
|| (d[j] > max_d_value))
mask_val[j] = 0;
else
mask_val[j] = 1;

View File

@@ -177,11 +177,9 @@ struct jfjoch_drvdata {
// however getting things from the queue happens in system call and can be executed in parallel
// therefore this part is protected by mutex (it is assumed that waiting for interrupts can take seconds,
// process has to be able to sleep while holding the lock => spinlock would not work)
// the mutex is also protecting work_compl_count variable
struct mutex work_compl_read_mutex;
DECLARE_KFIFO(work_compl, u32, MAX_FPGA_BUFFER); // protected by work_compl_read_mutex
wait_queue_head_t work_compl_wait_queue; // used for read completion queue method to wait for interrupt, ISR has wake-up call
u32 work_compl_count; // protected by work_compl_read_mutex
atomic_t active_handles;
};
@@ -220,7 +218,6 @@ void jfjoch_set_ipv4_addr(struct jfjoch_drvdata *drvdata, const u32 *addr);
void jfjoch_get_ipv4_addr(struct jfjoch_drvdata *drvdata, u32 *addr);
int jfjoch_load_calibration(struct jfjoch_drvdata *drvdata, struct LoadCalibrationConfig *config);
int jfjoch_run_frame_gen(struct jfjoch_drvdata *drvdata, struct FrameGeneratorConfig *config);
u32 jfjoch_get_c2h_descriptors(struct jfjoch_drvdata *drvdata);
void jfjoch_set_spot_finder_parameters(struct jfjoch_drvdata *drvdata, struct SpotFinderParameters *params);
void jfjoch_get_spot_finder_parameters(struct jfjoch_drvdata *drvdata, struct SpotFinderParameters *params);
u32 jfjoch_get_data_source(struct jfjoch_drvdata *drvdata);
@@ -236,7 +233,6 @@ void jfjoch_get_env_data(struct jfjoch_drvdata *drvdata, struct DeviceStatus *en
void jfjoch_reset(struct jfjoch_drvdata *drvdata);
void jfjoch_write_register(struct jfjoch_drvdata *drvdata, uint32_t addr, uint32_t val);
uint32_t jfjoch_read_register(struct jfjoch_drvdata *drvdata, uint32_t addr);
int jfjoch_register_sysfs(struct jfjoch_drvdata *drvdata);

View File

@@ -75,7 +75,7 @@ typedef __u64 uint64_t;
#define INT24_MIN (-8388608)
// INT32_MAX is written explicitly, as the constant is not present in kernel
#define MAX_FRAMES (2147483647/(MAX_MODULES_FPGA*DMA_DESCRIPTORS_PER_MODULE))
#define MAX_FRAMES (2147483647)
#pragma pack(push)
#pragma pack(4)

View File

@@ -16,13 +16,8 @@ void jfjoch_start(struct jfjoch_drvdata *drvdata) {
mutex_lock(&drvdata->work_compl_read_mutex);
while(!kfifo_is_empty(&drvdata->work_compl))
tmp2 = kfifo_get(&drvdata->work_compl, &tmp1);
// Reset work completion queue
drvdata->work_compl_count = 0;
mutex_unlock(&drvdata->work_compl_read_mutex);
// Set PCIe beats counters
iowrite32((1 << 1), drvdata->bar0 + PCIE_OFFSET + (1<<12) + 0xC0);
iowrite32((1 << 2), drvdata->bar0 + PCIE_OFFSET + (1<<12) + 0xC0);
@@ -69,28 +64,14 @@ int jfjoch_send_wr(struct jfjoch_drvdata *drvdata, u32 handle) {
}
int jfjoch_read_wc(struct jfjoch_drvdata *drvdata, u32 *output) {
struct device *const dev = &drvdata->pdev->dev;
int ret, tmp, i;
u32 curr_compl_count, handle;
u32 data_collection_id;
int ret, tmp;
mutex_lock(&drvdata->work_compl_read_mutex);
ret = wait_event_interruptible_timeout(drvdata->work_compl_wait_queue, !kfifo_is_empty(&drvdata->work_compl), HZ);
if (ret > 0) {
if (ret > 0)
tmp = kfifo_get(&drvdata->work_compl, output);
handle = (*output) & 0xFFFF;
data_collection_id = (*output >> 16) & 0xFFFF;
if (handle == HANDLE_START) {
drvdata->work_compl_count = 0;
curr_compl_count = 0;
} else if ((handle != HANDLE_END) && (data_collection_id != DATA_COLLECTION_ID_PURGE)) {
curr_compl_count = drvdata->work_compl_count;
drvdata->work_compl_count++;
}
}
mutex_unlock(&drvdata->work_compl_read_mutex);
if (ret < 0)
@@ -98,27 +79,9 @@ int jfjoch_read_wc(struct jfjoch_drvdata *drvdata, u32 *output) {
else if ((ret == 0) || (tmp == 0))
return -EAGAIN;
// Guarantee that data are in host memory
if ((handle != HANDLE_START) && (handle != HANDLE_END)) {
u32 descriptors = ioread32(drvdata->bar0 + PCIE_OFFSET + (1 << 12) + 0x48);
i = 0;
while ((descriptors < curr_compl_count * DMA_DESCRIPTORS_PER_MODULE) && (i < 100)) {
udelay(10);
descriptors = ioread32(drvdata->bar0 + PCIE_OFFSET + (1 << 12) + 0x48);
i++;
}
if (descriptors < DMA_DESCRIPTORS_PER_MODULE * curr_compl_count) {
dev_err(dev, "Late completion count SW %u, HW %u HANDLE %x", curr_compl_count, descriptors, handle);
return -EIO;
} else if (i > 0) {
dev_warn(dev, "Late completion count SW %u, HW %u HANDLE %x delay %d", curr_compl_count, descriptors, handle, i);
}
}
return 0;
}
int jfjoch_set_config(struct jfjoch_drvdata *drvdata, const struct DataCollectionConfig *config) {
if (config->nframes > MAX_FRAMES)
return -EINVAL;
@@ -409,10 +372,6 @@ int jfjoch_run_frame_gen(struct jfjoch_drvdata *drvdata, struct FrameGeneratorCo
return 0;
}
u32 jfjoch_get_c2h_descriptors(struct jfjoch_drvdata *drvdata) {
return ioread32(drvdata->bar0 + PCIE_OFFSET + (1<<12) + 0x48);
}
void jfjoch_set_spot_finder_parameters(struct jfjoch_drvdata *drvdata, struct SpotFinderParameters *params) {
memcpy_toio((drvdata->bar0) + ACTION_CONFIG_OFFSET + ADDR_SPOT_FINDER_THRESHOLD,
params,

View File

@@ -154,11 +154,6 @@ long jfjoch_cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
if (copy_from_user(&frame_generator_config, (char *) arg, sizeof(struct FrameGeneratorConfig)) != 0)
return -EFAULT;
return jfjoch_run_frame_gen(drvdata, &frame_generator_config);
case IOCTL_JFJOCH_C2H_DMA_DESC:
exchange[0] = jfjoch_get_c2h_descriptors(drvdata);
if (copy_to_user((char *) arg, exchange, sizeof(u32)) != 0)
return -EFAULT;
return 0;
case IOCTL_JFJOCH_READ_REGISTER:
// This is the most powerful option from security point of view and can only be performed by root
if (!capable(CAP_SYS_ADMIN))

View File

@@ -34,8 +34,7 @@
#define IOCTL_JFJOCH_GET_IPV4 _IOR(IOCTL_JFJOCH_MAGIC, 18, uint32_t)
// 19-21 are reserved
#define IOCTL_JFJOCH_RUN_FRAME_GEN _IOW(IOCTL_JFJOCH_MAGIC, 23, struct FrameGeneratorConfig)
#define IOCTL_JFJOCH_C2H_DMA_DESC _IOR(IOCTL_JFJOCH_MAGIC, 24, uint32_t)
// 25 is reserved
// 24-25 are reserved
#define IOCTL_JFJOCH_READ_REGISTER _IOWR(IOCTL_JFJOCH_MAGIC, 26, struct RegisterConfig )
#define IOCTL_JFJOCH_SET_SPOTFIN_PAR _IOW(IOCTL_JFJOCH_MAGIC, 27, struct SpotFinderParameters)
#define IOCTL_JFJOCH_SET_DATA_SOURCE _IOW(IOCTL_JFJOCH_MAGIC, 28, uint32_t)

View File

@@ -54,12 +54,13 @@ int jfjoch_check_version(struct pci_dev *pdev) {
release_level = ioread32(drvdata->bar0 + ACTION_CONFIG_OFFSET + ADDR_RELEASE_LEVEL);
if (action_type != JFJOCH_FPGA_MAGIC) {
dev_err(dev, "Mismatch in JFJoch action type (%x)\n", action_type);
dev_err(dev, "Very likely the FPGA is not flashed with Jungfraujoch design, given that action type register value is wrong (%x).\n", action_type);
return -EINVAL;
}
if (release_level != JFJOCH_FPGA_RELEASE) {
dev_err(dev, "Mismatch in JFJoch release level (%x)\n", release_level);
dev_err(dev, "Jungfraujoch FPGA is flashed with design made with release %x, while driver is compiled with release %x.\n", release_level, JFJOCH_FPGA_RELEASE);
dev_err(dev, "Given FPGA releases have braking changes in FPGA-driver interface (register map, data structure size, etc.)\n it is not safe and not supported at the moment to operate multiple releases with one driver.\n");
return -EINVAL;
}
return 0;

View File

@@ -441,9 +441,9 @@ namespace {
else if (key == "data")
ProcessImageData(value, message.image);
else if (key == "series_unique_id")
message.series_unique_id = GetCBORString(value);
message.run_name = GetCBORString(value);
else if (key == "series_id")
message.series_id = GetCBORUInt(value);
message.run_number = GetCBORUInt(value);
else if (key == "real_time") {
auto r = GetRational(value);
message.exptime = r.first;
@@ -452,10 +452,17 @@ namespace {
auto r = GetRational(value);
message.timestamp = r.first;
message.timestamp_base = r.second;
} else if (key == "user_data")
message.user_data = GetCBORString(value);
else if (key == "spots")
} else if (key == "user_data") {
const std::string s = GetCBORString(value);
try {
message.user_data = nlohmann::json::parse(s);
} catch (...) {
message.user_data = s;
}
} else if (key == "spots")
GetCBORSpots(message, value);
else if (key == "spot_count_in_rings")
message.spot_count_in_rings = GetCBORUInt(value);
else if (key == "az_int_profile")
GetCBORFloatArray(value, message.az_int_profile);
else if (key == "indexing_result")
@@ -526,30 +533,38 @@ namespace {
cborErr(cbor_value_leave_container(&value, &array_value));
}
void ProcessGoniometerOmega(StartMessage &message, CborValue &value) {
GoniometerAxis ProcessGoniometerOmega(std::string &name, CborValue &value) {
GoniometerAxis ret;
ret.name = name;
CborValue map_value;
cborErr(cbor_value_enter_container(&value, &map_value));
while (!cbor_value_at_end(&map_value)) {
auto key = GetCBORString(map_value);
if (key == "increment")
message.omega.increment = GetCBORFloat(map_value);
ret.increment = GetCBORFloat(map_value);
else if (key == "start")
message.omega.start = GetCBORFloat(map_value);
ret.start = GetCBORFloat(map_value);
else
cbor_value_advance(&value);
}
cborErr(cbor_value_leave_container(&value, &map_value));
return ret;
}
void ProcessGoniometerMap(StartMessage &message, CborValue &value) {
CborValue map_value;
if (GetCBORMapLen(value) > 1)
throw JFJochException(JFJochExceptionCategory::CBORError, "Max one rotation angle allowed");
cborErr(cbor_value_enter_container(&value, &map_value));
while (!cbor_value_at_end(&map_value)) {
GoniometerAxis axis;
auto key = GetCBORString(map_value);
if (key == "omega")
ProcessGoniometerOmega(message, map_value);
message.goniometer = ProcessGoniometerOmega(key, map_value);
}
cborErr(cbor_value_leave_container(&value, &map_value));
}
@@ -613,6 +628,8 @@ namespace {
message.sample_name = j["sample_name"];
if (j.contains("source_name"))
message.source_name = j["source_name"];
if (j.contains("source_type"))
message.source_type = j["source_type"];
if (j.contains("source_name_short"))
message.source_name_short = j["source_name_short"];
if (j.contains("instrument_name"))
@@ -623,10 +640,10 @@ namespace {
message.total_flux = j["total_flux"];
if (j.contains("attenuator_transmission"))
message.attenuator_transmission = j["attenuator_transmission"];
if (j.contains("omega_rotation_axis") && j["omega_rotation_axis"].is_array() &&
(j["omega_rotation_axis"].size() == 3)) {
if (j.contains("rotation_axis") && j["rotation_axis"].is_array() &&
(j["rotation_axis"].size() == 3)) {
for (int i = 0; i < 3; i++)
message.omega.axis[i] = j["omega_rotation_axis"][i];
message.rotation_axis[i] = j["rotation_axis"][i];
}
if (j.contains("space_group_number"))
message.space_group_number = j["space_group_number"];
@@ -638,6 +655,14 @@ namespace {
message.write_master_file = j["write_master_file"];
if (j.contains("data_reduction_factor_serialmx"))
message.data_reduction_factor_serialmx = j["data_reduction_factor_serialmx"];
if (j.contains("experiment_group"))
message.experiment_group = j["experiment_group"];
if (j.contains("jfjoch_release"))
message.jfjoch_release = j["jfjoch_release"];
if (j.contains("socket_number"))
message.socket_number = j["socket_number"];
if (j.contains("writer_notification_zmq_addr"))
message.writer_notification_zmq_addr = j["writer_notification_zmq_addr"];
} catch (const std::exception &e) {
throw JFJochException(JFJochExceptionCategory::CBORError,
"Cannot parse user_data as valid JSON " + std::string(e.what()));
@@ -693,9 +718,9 @@ namespace {
else if (key == "detector_serial_number")
message.detector_serial_number = GetCBORString(value);
else if (key == "series_unique_id")
message.series_unique_id = GetCBORString(value);
message.run_name = GetCBORString(value);
else if (key == "series_id")
message.series_id = GetCBORUInt(value);
message.run_number = GetCBORUInt(value);
else if (key == "pixel_mask")
ProcessPixelMaskElement(message, value);
else if (key == "channels")
@@ -815,9 +840,9 @@ namespace {
if (key == "end_date")
message.end_date = GetCBORString(value);
else if (key == "series_unique_id")
message.series_unique_id = GetCBORString(value);
message.run_name = GetCBORString(value);
else if (key == "series_id")
message.series_id = GetCBORUInt(value);
message.run_number = GetCBORUInt(value);
else if (key == "max_image_number")
message.max_image_number = GetCBORUInt(value);
else if (key == "images_collected")

View File

@@ -215,10 +215,10 @@ inline void CBOR_ENC_AXIS(CborEncoder &encoder, const char* key, const float det
cborErr(cbor_encoder_close_container(&encoder, &arrayEncoder));
}
inline void CBOR_ENC_GONIOMETER(CborEncoder &encoder, const char* key, const GoniometerAxis &g) {
inline void CBOR_ENC_GONIOMETER(CborEncoder &encoder, const GoniometerAxis &g) {
CborEncoder mapEncoder;
cborErr(cbor_encode_text_stringz(&encoder, key));
cborErr(cbor_encode_text_stringz(&encoder, g.name.c_str()));
cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, 2));
CBOR_ENC(mapEncoder, "increment", g.increment);
CBOR_ENC(mapEncoder, "start", g.start);
@@ -228,11 +228,12 @@ inline void CBOR_ENC_GONIOMETER(CborEncoder &encoder, const char* key, const Gon
inline void CBOR_ENC_GONIOMETER_MAP(CborEncoder &encoder, const char* key, const StartMessage &msg) {
CborEncoder mapEncoder;
cborErr(cbor_encode_text_stringz(&encoder, key));
cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, 1));
CBOR_ENC_GONIOMETER(mapEncoder, "omega", msg.omega);
cborErr(cbor_encoder_close_container(&encoder, &mapEncoder));
if (msg.goniometer) {
cborErr(cbor_encode_text_stringz(&encoder, key));
cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, 1));
CBOR_ENC_GONIOMETER(mapEncoder, msg.goniometer.value());
cborErr(cbor_encoder_close_container(&encoder, &mapEncoder));
}
}
inline void CBOR_ENC(CborEncoder &encoder, const char* key, const std::vector<std::string> &v) {
@@ -302,6 +303,8 @@ inline void CBOR_ENC_START_USER_DATA(CborEncoder& encoder, const char* key,
j["images_per_file"] = message.images_per_file;
j["source_name"] = message.source_name;
j["source_name_short"] = message.source_name_short;
if (!message.source_type.empty())
j["source_type"] = message.source_type;
j["instrument_name"] = message.instrument_name;
j["instrument_name_short"] = message.instrument_name_short;
j["sample_name"] = message.sample_name;
@@ -310,7 +313,7 @@ inline void CBOR_ENC_START_USER_DATA(CborEncoder& encoder, const char* key,
j["attenuator_transmission"] = message.attenuator_transmission.value();
if (message.total_flux)
j["total_flux"] = message.total_flux.value();
j["omega_rotation_axis"] = {message.omega.axis[0], message.omega.axis[1], message.omega.axis[2]};
j["rotation_axis"] = {message.rotation_axis[0], message.rotation_axis[1], message.rotation_axis[2]};
j["space_group_number"] = message.space_group_number;
j["roi_names"] = message.roi_names;
j["gain_file_names"] = message.gain_file_names;
@@ -318,6 +321,12 @@ inline void CBOR_ENC_START_USER_DATA(CborEncoder& encoder, const char* key,
j["write_master_file"] = message.write_master_file.value();
if (message.data_reduction_factor_serialmx)
j["data_reduction_factor_serialmx"] = message.data_reduction_factor_serialmx.value();
j["experiment_group"] = message.experiment_group;
j["jfjoch_release"] = message.jfjoch_release;
if (message.socket_number)
j["socket_number"] = message.socket_number.value();
j["writer_notification_zmq_addr"] = message.writer_notification_zmq_addr;
auto str = j.dump();
@@ -367,8 +376,8 @@ void CBORStream2Serializer::SerializeSequenceStart(const StartMessage& message)
CBOR_ENC(mapEncoder, "pixel_mask_enabled", message.pixel_mask_enabled);
CBOR_ENC(mapEncoder, "detector_description", message.detector_description);
CBOR_ENC(mapEncoder, "detector_serial_number", message.detector_serial_number);
CBOR_ENC(mapEncoder, "series_unique_id", message.series_unique_id);
CBOR_ENC(mapEncoder, "series_id", message.series_id);
CBOR_ENC(mapEncoder, "series_unique_id", message.run_name);
CBOR_ENC(mapEncoder, "series_id", message.run_number);
CBOR_ENC_AXIS(mapEncoder, "detector_translation", message.detector_translation);
CBOR_ENC_GONIOMETER_MAP(mapEncoder, "goniometer", message);
@@ -413,8 +422,8 @@ void CBORStream2Serializer::SerializeSequenceEnd(const EndMessage& message) {
CBOR_ENC(mapEncoder, "type", "end");
CBOR_ENC(mapEncoder, "magic_number", user_data_magic_number);
CBOR_ENC(mapEncoder, "series_unique_id", message.series_unique_id);
CBOR_ENC(mapEncoder, "series_id", message.series_id);
CBOR_ENC(mapEncoder, "series_unique_id", message.run_name);
CBOR_ENC(mapEncoder, "series_id", message.run_number);
CBOR_ENC(mapEncoder, "end_date", message.end_date);
CBOR_ENC(mapEncoder, "max_image_number", message.max_image_number);
@@ -439,8 +448,8 @@ void CBORStream2Serializer::SerializeImage(const DataMessage& message) {
CBOR_ENC(mapEncoder, "type", "image");
CBOR_ENC(mapEncoder, "magic_number", user_data_magic_number);
CBOR_ENC(mapEncoder, "series_unique_id", message.series_unique_id);
CBOR_ENC(mapEncoder, "series_id", message.series_id);
CBOR_ENC(mapEncoder, "series_unique_id", message.run_name);
CBOR_ENC(mapEncoder, "series_id", message.run_number);
CBOR_ENC(mapEncoder, "image_id", message.number);
CBOR_ENC(mapEncoder, "original_image_id", message.original_number);
@@ -450,6 +459,8 @@ void CBORStream2Serializer::SerializeImage(const DataMessage& message) {
CBOR_ENC_RATIONAL(mapEncoder, "end_time", message.timestamp + message.exptime, message.timestamp_base);
CBOR_ENC(mapEncoder, "spots", message.spots);
CBOR_ENC(mapEncoder, "spot_count_in_rings", message.spot_count_in_rings);
CBOR_ENC(mapEncoder, "az_int_profile", message.az_int_profile);
CBOR_ENC(mapEncoder, "indexing_result", message.indexing_result);
if (!message.indexing_lattice.empty())
@@ -467,7 +478,7 @@ void CBORStream2Serializer::SerializeImage(const DataMessage& message) {
CBOR_ENC(mapEncoder, "bkg_estimate", message.bkg_estimate);
CBOR_ENC(mapEncoder, "adu_histogram", message.adu_histogram);
CBOR_ENC(mapEncoder, "roi_integrals", message.roi);
CBOR_ENC(mapEncoder, "user_data", message.user_data);
CBOR_ENC(mapEncoder, "user_data", message.user_data.dump());
CBOR_ENC(mapEncoder, "data", message.image);
cborErr(cbor_encoder_close_container(&encoder, &mapEncoder));

View File

@@ -21,6 +21,7 @@ ADD_LIBRARY(ImagePusher STATIC
ImagePusher.cpp ImagePusher.h
TestImagePusher.cpp TestImagePusher.h
ZMQStream2Pusher.cpp ZMQStream2Pusher.h
ZMQWriterNotificationPuller.cpp ZMQWriterNotificationPuller.h
DumpCBORToFilePusher.cpp
DumpCBORToFilePusher.h)

View File

@@ -15,3 +15,9 @@ void PrepareCBORImage(DataMessage& message,
message.image.algorithm = experiment.GetCompressionAlgorithm();
message.image.channel = "default";
}
void ImagePusher::Finalize() {}
std::string ImagePusher::GetWriterNotificationSocketAddress() const {
return "socket1234";
}

View File

@@ -11,6 +11,7 @@
#include "CBORStream2Serializer.h"
#include "JFJochMessages.h"
#include "../common/ZeroCopyReturnValue.h"
#include "../common/Logger.h"
void PrepareCBORImage(DataMessage& message,
const DiffractionExperiment &experiment,
@@ -24,6 +25,9 @@ public:
virtual void SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number,
ZeroCopyReturnValue *z) = 0;
virtual bool SendCalibration(const CompressedImage& message) = 0;
virtual void Finalize(); // Ensure that all streams are closed, can throw exception
virtual std::string GetWriterNotificationSocketAddress() const;
virtual ~ImagePusher() = default;
};

View File

@@ -10,6 +10,8 @@
#include <optional>
#include <cstring>
#include <stdexcept>
#include <nlohmann/json.hpp>
#include "../compression/CompressionAlgorithmEnum.h"
#include "../common/SpotToSave.h"
#include "../common/UnitCell.h"
@@ -45,6 +47,7 @@ struct DataMessage {
float image_collection_efficiency;
std::vector<SpotToSave> spots;
std::optional<uint64_t> spot_count_in_rings = 0;
std::vector<float> az_int_profile;
float bkg_estimate;
@@ -61,14 +64,14 @@ struct DataMessage {
uint32_t exptime;
uint32_t exptime_base;
std::string series_unique_id;
uint64_t series_id;
std::string run_name;
uint64_t run_number;
uint64_t saturated_pixel_count;
uint64_t error_pixel_count;
uint64_t strong_pixel_count;
std::string user_data;
nlohmann::json user_data;
std::optional<uint64_t> jf_info;
std::optional<uint64_t> receiver_aq_dev_delay;
@@ -84,9 +87,9 @@ struct DataMessage {
};
struct GoniometerAxis {
std::string name;
float increment;
float start;
float axis[3];
};
struct StartMessage {
@@ -137,15 +140,18 @@ struct StartMessage {
std::string detector_description;
std::string detector_serial_number;
std::string series_unique_id;
uint64_t series_id;
std::string run_name;
uint64_t run_number;
std::vector<std::string> gain_file_names;
std::vector<std::string> roi_names;
GoniometerAxis omega;
std::optional<GoniometerAxis> goniometer;
float rotation_axis[3];
float detector_translation[3];
std::string source_type;
std::string source_name;
std::string source_name_short;
std::string instrument_name;
@@ -167,9 +173,15 @@ struct StartMessage {
pixel_mask.emplace_back(std::move(image));
}
std::string user_data;
nlohmann::json user_data;
std::optional<float> data_reduction_factor_serialmx;
std::string experiment_group;
std::string jfjoch_release;
std::optional<uint64_t> socket_number; // This is number of socket in ZeroMQ
std::string writer_notification_zmq_addr; // Socket to inform detector on writer done
};
struct EndMessage {
@@ -181,8 +193,8 @@ struct EndMessage {
std::optional<std::string> end_date;
std::string series_unique_id;
uint64_t series_id;
std::string run_name;
uint64_t run_number;
std::map<std::string, std::vector<float>> az_int_result;
std::map<std::string, std::vector<uint64_t>> adu_histogram;

View File

@@ -13,55 +13,60 @@ There are minor differences at the moment:
## Start message
| Field name | Type | Description | Present in DECTRIS format |
|---------------------------|---------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|:-------------------------:|
| type | String | value "start" | X |
| magic_number | uint64 | Number used to describe version of the Jungfraujoch data interface - to allow to detect inconsistency between sender and receiver | |
| detector_distance | float | Detector distance \[m\] | |
| detector_translation | float | Detector translation vector \[m\] | X |
| beam_center_x | float | Beam center in X direction \[pixels\] | X |
| beam_center_y | float | Beam center in Y direction \[pixels\] | X |
| number_of_images | uint64 | Number of images in the series | X |
| image_size_x | uint64 | Image width \[pixels\] | X |
| image_size_y | uint64 | Image height \[pixels\] | X |
| incident_energy | float | X-ray energy \[eV\] | X |
| incident_wavelength | float | X-ray wavelength \[Angstrom\] | X |
| frame_time | float | Frame time, if multiple frames per trigger \[s\] | X |
| count_time | float | Exposure time \[s\] | X |
| saturation_value | int64 | Maximum valid sample value | X |
| error_value | int64 | Value used in images to describe pixels that are in error state or missing | |
| pixel_size_x | float | Pixel width \[m\] | X |
| pixel_size_y | float | Pixel height \[m\] | X |
| sensor_thickness | float | Sensor thickness \[m\] | X |
| sensor_material | string | Sensor material | X |
| arm_data | data | Approximate date of arming | X |
| pixel_mask_enabled | bool | Pixel mask applied on images | X |
| detector_description | string | Name of the detector | X |
| series_unique_id | string | Unique text ID of the series | X |
| series_id | uint64 | Unique numeric ID of the series | X |
| goniometer | Map | See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/stream_v2) - only "omega" axis is supported | X |
| pixel_mask | Map(string -> Image) | Pixel mask - multiple in case of storage cells | X |
| channels | Array(string) | List of image channels | X |
| max_spot_count | uint64 | Maximum number of spots identified in spot finding | |
| storage_cell_number | uint64 | Number of storage cells used by JUNGFRAU | |
| image_dtype | string | Pixel bit type (e.g. uint16) | X |
| unit_cell | Array(6 * float) (optional) | Unit cell of the system: a, b, c \[angstrom\] and alpha, beta, gamma \[degree\] | |
| az_int_bin_number | uint64 | Number of azimuthal integration bins | |
| az_int_bin_to_q | Array(float) | Q value for each azimuthal integration bin \[angstrom^-1\] | |
| summation | uint64 | Factor of frame summation | |
| user_data | string | JSON string that can contain the following fields (among others): | X |
| - source_name | string | Facility name | |
| - source_name_short | string | Facility name (short) | |
| - instrument_name | string | Instrument name | |
| - instrument_name_short | string | Instrument name (short | |
| - attenuator_transmission | float (optional) | Attenuator transmission \[\] | |
| - total_flux | float (optional) | Total flux \[ph/s\] | |
| - data_file_count | uint64 | Number of used data files | |
| - file_prefix | string | File prefix | |
| - sample_name | string | Name of the sample | |
| - omega_rotation_axis | Array(float) | Omega rotation axis (array of size 3) | |
| - space_group_number | uint64 | Space group number | |
| - write_master_file | bool | With multiple sockets, it selects which socket will provide master file | |
| Field name | Type | Description | Present in DECTRIS format |
|--------------------------------|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------|:-------------------------:|
| type | String | value "start" | X |
| magic_number | uint64 | Number used to describe version of the Jungfraujoch data interface - to allow to detect inconsistency between sender and receiver | |
| detector_distance | float | Detector distance \[m\] | |
| detector_translation | float | Detector translation vector \[m\] | X |
| beam_center_x | float | Beam center in X direction \[pixels\] | X |
| beam_center_y | float | Beam center in Y direction \[pixels\] | X |
| number_of_images | uint64 | Number of images in the series | X |
| image_size_x | uint64 | Image width \[pixels\] | X |
| image_size_y | uint64 | Image height \[pixels\] | X |
| incident_energy | float | X-ray energy \[eV\] | X |
| incident_wavelength | float | X-ray wavelength \[Angstrom\] | X |
| frame_time | float | Frame time, if multiple frames per trigger \[s\] | X |
| count_time | float | Exposure time \[s\] | X |
| saturation_value | int64 | Maximum valid sample value | X |
| error_value | int64 | Value used in images to describe pixels that are in error state or missing | |
| pixel_size_x | float | Pixel width \[m\] | X |
| pixel_size_y | float | Pixel height \[m\] | X |
| sensor_thickness | float | Sensor thickness \[m\] | X |
| sensor_material | string | Sensor material | X |
| arm_data | data | Approximate date of arming | X |
| pixel_mask_enabled | bool | Pixel mask applied on images | X |
| detector_description | string | Name of the detector | X |
| series_unique_id | string | Unique text ID of the series (run_name parameter) | X |
| series_id | uint64 | Unique numeric ID of the series (run_number parameter) | X |
| goniometer | Map | See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/stream_v2) - only one axis is supported | X |
| pixel_mask | Map(string -> Image) | Pixel mask - multiple in case of storage cells | X |
| channels | Array(string) | List of image channels | X |
| max_spot_count | uint64 | Maximum number of spots identified in spot finding | |
| storage_cell_number | uint64 | Number of storage cells used by JUNGFRAU | |
| image_dtype | string | Pixel bit type (e.g. uint16) | X |
| unit_cell | Array(6 * float) (optional) | Unit cell of the system: a, b, c \[angstrom\] and alpha, beta, gamma \[degree\] | |
| az_int_bin_number | uint64 | Number of azimuthal integration bins | |
| az_int_bin_to_q | Array(float) | Q value for each azimuthal integration bin \[angstrom^-1\] | |
| summation | uint64 | Factor of frame summation | |
| user_data | string | JSON serialized to string that can contain the following fields: | X |
| - user | any valid JSON | Value of header_appendix provided at collection start to Jungfraujoch | |
| - source_name | string | Facility name | |
| - source_name_short | string | Facility name (short) | |
| - source_type | string (optional) | Type of X-ray source (use NXsource/type values, for example "Synchrotron X-ray Source" or "Free-Electron Laser") | |
| - instrument_name | string | Instrument name | |
| - instrument_name_short | string | Instrument name (short) | |
| - attenuator_transmission | float (optional) | Attenuator transmission \[\] | |
| - total_flux | float (optional) | Total flux \[ph/s\] | |
| - data_file_count | uint64 | Number of used data files | |
| - file_prefix | string | File prefix | |
| - sample_name | string | Name of the sample | |
| - rotation_axis | Array(float) | Rotation axis vector (array of size 3) | |
| - space_group_number | uint64 | Space group number | |
| - write_master_file | bool | With multiple sockets, it selects which socket will provide master file | |
| - writer_notification_zmq_addr | string | ZeroMQ address to inform `jfjoch_broker` about writers that finished operation | |
| - socket_number | uint64 | Number of ZeroMQ socket (on `jfjoch_broker` side) used for transmission | |
| - experiment_group | string | ID of instrument user, e.g., p-group (SLS/SwissFEL) or proposal number | |
See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/stream_v2) for definition of Image as MultiDimArray with optional compression.
@@ -71,8 +76,8 @@ See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/s
|----------------------------|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------|:-------------------------:|:--------:|
| type | String | value "image" | X | |
| magic_number | uint64 | Number used to describe version of the Jungfraujoch data interface - to allow to detect inconsistency between sender and receiver | | |
| series_unique_id | string | Unique text ID of the series | X | |
| series_id | uint64 | Unique numeric ID of the series | X | |
| series_unique_id | string | Unique text ID of the series (run_name parameter) | X | |
| series_id | uint64 | Unique numeric ID of the series (run_number parameter) | X | |
| image_id | uint64 | Number of image within the series | X | |
| real_time | Rational | Exposure time | X | |
| start_time | Rational | Exposure start time (highly approximate) | X | |
@@ -85,8 +90,8 @@ See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/s
| az_int_profile | Array(float) | Azimuthal integration results, use az_int_bin_to_q from start message for legend | | |
| indexing_result | bool | Indexing successful | | |
| indexing_lattice | Array(float * 9) (optional) | Indexing result real lattice; present only if indexed | | |
| xfel_pulse_id | uint64 | Bunch ID (for SwissFEL) | | X |
| xfel_event_code | uint64 | Event code (for SwissFEL) | | X |
| xfel_pulse_id | uint64 | Bunch ID (for pulsed source, e.g., SwissFEL) | | X |
| xfel_event_code | uint64 | Event code (for pulsed source, e.g., SwissFEL) | | X |
| jf_info | uint64 | Detector info field | | |
| receiver_aq_dev_delay | uint64 | Receiver internal delay | | |
| receiver_free_send_buf | uint64 | Receiver internal number of available send buffers | | |
@@ -100,7 +105,7 @@ See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/s
| corr_beam_x_pxl | float | Difference between provided and calculated beam center X (pixels) - requires indexing | | X |
| corr_beam_y_pxl | float | Difference between provided and calculated beam center Y (pixels) - requires indexing | | X |
| corr_det_dist_mm | float | Difference between provided and calculated detector distance (mm) - requires indexing | | X |
| user_data | string | Optional user defined text information | | |
| user_data | string | Optional user defined text information - this is image_appendix serialized to JSON format | | |
| roi_sum | int64 | Sum of ROI rectangle \[photons\] | | X |
| image | Map(string -> Image) | Image | | |
@@ -110,8 +115,8 @@ See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/s
|----------------------------|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------|:-------------------------:|
| type | String | value "end" | X |
| magic_number | uint64 | Number used to describe version of the Jungfraujoch data interface - to allow to detect inconsistency between sender and receiver | |
| series_unique_id | string | Unique text ID of the series | X |
| series_id | uint64 | Unique numeric ID of the series | X |
| series_unique_id | string | Unique text ID of the series (run_name parameter) | X |
| series_id | uint64 | Unique numeric ID of the series (run_number parameter) | X |
| end_date | date | Approximate end date | |
| max_image_number | uint64 | Number of image with the highest number (this is counted from 1 - to distinguish zero images and one image) | |
| images_collected | uint64 | Number of image collected | |
@@ -130,20 +135,21 @@ See [DECTRIS documentation](https://github.com/dectris/documentation/tree/main/s
| magic_number | uint64 | Number used to describe version of the Jungfraujoch data interface - to allow to detect inconsistency between sender and receiver | |
| data | Map(string -> Image) | Calibration map (only single pedestal array per message) | |
# User data
In many cases there is an interest from facilities to forward more metadata, than available explicitly in the Jungfraujoch.
For this reason two fields can be provided: `header_appendix` (sent with start message) and `image_appendix` (send with image message).
To increase flexibility, both appendices can contain any valid JSON message.
These appendices are serialized into string and stored in CBOR messages as `user_data`.
Notably for start message, `user_data` contain more information (non-DECTRIS compliant metadata).
Therefore `user_data` is serialized by Jungfraujoch as CBOR object. There is member `user` which contains `header_appendix`.
# Image transfer
Images can be forwarded by Jungraujoch through few interfaces. All of them are ZeroMQ based at the moment, though they differ with serialization layer.
All interfaces are subclasses of `ImagePusher` class. The following options are available:
Images can be forwarded by Jungraujoch through ZeroMQ interfaces with serialization compatible with DECTRIS Stream2 serialization.
This is using PUSH ZeroMQ socket(s). Multiple sockets can be used, in this case images will be split according to file number to which they belong. All sockets will forward start and end messages. Only first socket will forward calibration messages.
## ZMQStream2Pusher
Pushes images using Stream2 serialization. This is using PUSH ZeroMQ sockets. Behavior is as following:
* Start message is sent with timeout of 5s. If within the time the message cannot be put in the outgoing queue or there is no connected puller exception is thrown - this is to stop data collection in absence of writer.
* Images are sent in non-blocking way and without timeout. If message cannot be sent `false` is returned for the send call - need to be reported or handled in calling function.
* End message is sent with timeout of 5s. If message cannot be sent `false` is returned for the send call - need to be reported or handled in calling function.
## ZMQStream2PusherGroup
Same as above, but multiple ZeroMQ sockets are used and images are distributed on a round-robin basis between the sockets based on the image number.
Behavior for errors is the same as for `ZMQStream2Pusher`.
## TestImagePusher
This interface is used for automated tests. It reads incoming images and compares one image with the reference data provided.
Behavior is as following:
* Start message is sent with timeout of 5s. If within the time the message cannot be put in the outgoing queue or there is no connected puller exception is thrown - stop data collection with error due to absence of a writer.
* Images are sent in non-blocking way and without timeout.
* End message is sent with timeout of 5s. No error is reported

View File

@@ -55,17 +55,17 @@ void ZMQStream2Pusher::StartDataCollection(StartMessage& message) {
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Images per file cannot be zero or negative");
images_per_file = message.images_per_file;
run_number = message.run_number;
run_name = message.run_name;
serializer.SerializeSequenceStart(message);
for (auto &s: socket) {
if (!s->Send(serialization_buffer.data(), serializer.GetBufferSize(), true))
throw JFJochException(JFJochExceptionCategory::ZeroMQ, "Timeout on pushing start message on addr "
+ s->GetEndpointName());
if (message.write_master_file) {
for (int i = 0; i < socket.size(); i++) {
message.socket_number = i;
if (i > 0)
message.write_master_file = false;
serializer.SerializeSequenceStart(message);
}
serializer.SerializeSequenceStart(message);
if (!socket[i]->Send(serialization_buffer.data(), serializer.GetBufferSize(), true))
throw JFJochException(JFJochExceptionCategory::ZeroMQ, "Timeout on pushing start message on addr "
+ socket[i]->GetEndpointName());
}
if (preview_socket)
@@ -115,3 +115,36 @@ std::string ZMQStream2Pusher::GetPreviewAddress() {
else
return "";
}
void ZMQStream2Pusher::Finalize() {
if (writer_notification_socket) {
for (int i = 0; i < socket.size(); i++) {
auto n = writer_notification_socket->Receive(run_number, run_name);
if (!n)
throw JFJochException(JFJochExceptionCategory::FileWriteError, "No notification received from writer");
else if (n->socket_number >= socket.size())
throw JFJochException(JFJochExceptionCategory::FileWriteError, "Wrong socket number provided in the message");
else if (!n->ok)
throw JFJochException(JFJochExceptionCategory::FileWriteError, "Writer (socket "
+ socket[n->socket_number]->GetEndpointName()
+ ") finished with error");
}
}
}
std::string ZMQStream2Pusher::GetWriterNotificationSocketAddress() const {
if (writer_notification_socket)
return writer_notification_socket->GetEndpointName();
else
return "";
}
ZMQStream2Pusher &ZMQStream2Pusher::WriterNotificationSocket(const std::string &addr) {
writer_notification_socket = std::make_unique<ZMQWriterNotificationPuller>(addr);
return *this;
}
ZMQStream2Pusher &ZMQStream2Pusher::PreviewCounterPeriod(std::chrono::microseconds input) {
preview_counter.Period(input);
return *this;
}

View File

@@ -8,6 +8,7 @@
#include "ImagePusher.h"
#include "../common/ZMQWrappers.h"
#include "../preview/PreviewCounter.h"
#include "ZMQWriterNotificationPuller.h"
class ZMQStream2Pusher : public ImagePusher {
std::vector<uint8_t> serialization_buffer;
@@ -18,13 +19,19 @@ class ZMQStream2Pusher : public ImagePusher {
std::unique_ptr<ZMQSocket> preview_socket;
PreviewCounter preview_counter;
std::unique_ptr<ZMQWriterNotificationPuller> writer_notification_socket;
int64_t images_per_file = 1;
uint64_t run_number = 0;
std::string run_name;
public:
explicit ZMQStream2Pusher(const std::vector<std::string>& addr,
int32_t send_buffer_high_watermark = -1,
int32_t send_buffer_size = -1);
ZMQStream2Pusher& PreviewSocket(const std::string& addr);
ZMQStream2Pusher& WriterNotificationSocket(const std::string& addr);
ZMQStream2Pusher& PreviewCounterPeriod(std::chrono::microseconds input);
std::string GetPreviewAddress();
std::vector<std::string> GetAddress();
@@ -37,6 +44,9 @@ public:
// Thread-safe
void SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number, ZeroCopyReturnValue *z) override;
bool SendImage(const uint8_t *image_data, size_t image_size, int64_t image_number) override;
void Finalize() override;
std::string GetWriterNotificationSocketAddress() const override;
};
#endif //JUNGFRAUJOCH_ZMQSTREAM2PUSHER_H

View File

@@ -0,0 +1,34 @@
// Copyright (2019-2024) Paul Scherrer Institute
#include "ZMQWriterNotificationPuller.h"
#include "nlohmann/json.hpp"
ZMQWriterNotificationPuller::ZMQWriterNotificationPuller(const std::string &addr, std::chrono::milliseconds timeout)
: socket(ZMQSocketType::Pull) {
socket.ReceiveTimeout(timeout);
socket.Bind(addr);
}
std::optional<ZMQWriterNotificationOutput> ZMQWriterNotificationPuller::Receive(uint64_t run_number, const std::string &run_name) {
ZMQMessage msg;
// Loop to ensure that messages with wrong run_number or run_name are filtered
while (socket.Receive(msg)) {
try {
nlohmann::json j = nlohmann::json::parse(std::string((char *) msg.data(), msg.size()));
if ((j["run_number"] == run_number) && (j["run_name"] == run_name)) {
ZMQWriterNotificationOutput ret{};
ret.ok = j["ok"];
ret.processed_images = j["processed_images"];
ret.socket_number = j["socket_number"];
return ret;
}
} catch (const std::exception &e) {
// Cannot parse properly
}
}
return {};
}
std::string ZMQWriterNotificationPuller::GetEndpointName() {
return socket.GetEndpointName();
}

Some files were not shown because too many files have changed in this diff Show More