Improve plotting

This commit is contained in:
2024-03-31 23:08:19 +02:00
parent 8cad89d649
commit 30e775d8a2
122 changed files with 4640 additions and 1149 deletions

View File

@@ -186,6 +186,16 @@ void AcquisitionDevice::InitializeSpotFinderResolutionMap(const float *data, siz
void AcquisitionDevice::InitializeROIMap(const uint16_t *map, size_t module_number) {}
void AcquisitionDevice::InitializeROIMap(const DiffractionExperiment& experiment) {
std::vector<uint16_t> tmp(RAW_MODULE_SIZE);
auto offset = experiment.GetFirstModuleOfDataStream(data_stream);
size_t modules = experiment.GetModulesNum(data_stream);
for (int m = 0; m < modules; m++) {
experiment.ExportROIMask(tmp.data(), offset + m);
InitializeROIMap(tmp.data(), m);
}
}
void AcquisitionDevice::MapBuffersStandard(size_t c2h_buffer_count, int16_t numa_node) {
try {
for (int i = 0; i < c2h_buffer_count; i++)

View File

@@ -97,6 +97,7 @@ public:
virtual void InitializeIntegrationMap(const uint16_t *map, const float *weights, size_t module_number);
virtual void InitializeSpotFinderResolutionMap(const float *data, size_t module_number);
virtual void InitializeROIMap(const uint16_t *map, size_t module_number);
void InitializeROIMap(const DiffractionExperiment &experiment);
const AcquisitionCounters& Counters() const;

View File

@@ -278,6 +278,7 @@ void HLSSimulatedDevice::HLSMainThread() {
STREAM_768 stream_768_2;
STREAM_768 stream_768_3;
STREAM_768 stream_768_4;
STREAM_768 stream_768_5;
STREAM_512 data_0;
hls::stream<ap_axiu<512, 1, 1, 1>, 2> data_1;
@@ -290,7 +291,6 @@ void HLSSimulatedDevice::HLSMainThread() {
STREAM_512 data_8;
STREAM_512 data_9;
STREAM_512 data_10;
STREAM_576 data_11;
STREAM_512 data_12;
STREAM_512 data_13;
@@ -480,7 +480,7 @@ void HLSSimulatedDevice::HLSMainThread() {
hls_cores.emplace_back([&] { eiger_reorder(data_8, data_9, axi_compl[5], axi_compl[6]);});
// 6. Apply pedestal & gain corrections
hls_cores.emplace_back([&] { jf_conversion(data_9, data_11,
hls_cores.emplace_back([&] { jf_conversion(data_9, stream_768_0,
axi_compl[6], axi_compl[7],
hbm.data(),
hbm.data(),
@@ -497,10 +497,10 @@ void HLSSimulatedDevice::HLSMainThread() {
hbm_if_size); });
// 7. Frame summation
hls_cores.emplace_back([&] { frame_summation(data_11, stream_768_0, axi_compl[7], axi_compl[8], frame_summation_idle);});
hls_cores.emplace_back([&] { frame_summation(stream_768_0, stream_768_1, axi_compl[7], axi_compl[8], frame_summation_idle);});
// 8. Integration of pixels
hls_cores.emplace_back([&] { integration(stream_768_0, stream_768_1, integration_result_0, axi_compl[8], axi_compl[9],
hls_cores.emplace_back([&] { integration(stream_768_1, stream_768_2, integration_result_0, axi_compl[8], axi_compl[9],
hbm.data(), hbm.data(), hbm.data(), hbm.data(), integration_idle, hbm_if_size);});
hls_cores.emplace_back([&] { axis_64_to_512(integration_result_0, integration_result_1);});
@@ -512,8 +512,8 @@ void HLSSimulatedDevice::HLSMainThread() {
ap_uint<32> min_pix_per_spot = spot_finder_parameters.min_pix_per_spot;
hls_cores.emplace_back([&] {
spot_finder_mask(stream_768_1,
stream_768_2,
spot_finder_mask(stream_768_2,
stream_768_3,
spot_finder_mask_0,
axi_compl[9],
axi_compl[10],
@@ -526,7 +526,7 @@ void HLSSimulatedDevice::HLSMainThread() {
});
hls_cores.emplace_back([&] {
spot_finder(stream_768_2, spot_finder_mask_0, stream_768_3, spot_finder_result_0, tmp_count_threshold, tmp_snr_threshold);
spot_finder(stream_768_3, spot_finder_mask_0, stream_768_4, spot_finder_result_0, tmp_count_threshold, tmp_snr_threshold);
logger_hls.Info("spot_finder done");
});
@@ -546,8 +546,8 @@ void HLSSimulatedDevice::HLSMainThread() {
});
hls_cores.emplace_back([&] {
roi_calc(stream_768_3,
stream_768_4,
roi_calc(stream_768_4,
stream_768_5,
roi_calc_result_0,
axi_compl[10],
axi_compl[11],
@@ -558,7 +558,7 @@ void HLSSimulatedDevice::HLSMainThread() {
});
// 10. Reduce/extend 24-bit stream
hls_cores.emplace_back([&] { stream_24bit_conv(stream_768_4, data_12, stream_conv_idle);});
hls_cores.emplace_back([&] { stream_24bit_conv(stream_768_5, data_12, stream_conv_idle);});
// 11. Prepare data to write to host memory
hls_cores.emplace_back([&] {
@@ -618,8 +618,7 @@ void HLSSimulatedDevice::HLSMainThread() {
if (!data_10.empty())
throw std::runtime_error("data_10 queue not empty");
if (!data_11.empty())
throw std::runtime_error("data_11 queue not empty");
if (!data_12.empty())
throw std::runtime_error("data_12 queue not empty");
@@ -633,13 +632,19 @@ void HLSSimulatedDevice::HLSMainThread() {
}
if (!stream_768_0.empty())
throw std::runtime_error("Stream_768_0 queue not empty");
throw std::runtime_error("stream_768_0 queue not empty");
if (!stream_768_1.empty())
throw std::runtime_error("Stream_768_1 queue not empty");
throw std::runtime_error("stream_768_1 queue not empty");
if (!stream_768_2.empty())
throw std::runtime_error("Stream_768_2 queue not empty");
throw std::runtime_error("stream_768_2 queue not empty");
if (!stream_768_3.empty())
throw std::runtime_error("stream_768_3 queue not empty");
if (!stream_768_4.empty())
throw std::runtime_error("stream_768_4 queue not empty");
if (!hbm_handles.empty())
throw std::runtime_error("Handles queue not empty");

View File

@@ -222,17 +222,16 @@ inline org::openapitools::server::model::Detector_list Convert(const DetectorLis
return ret;
}
inline org::openapitools::server::model::Plot Convert(const Plot& input) {
org::openapitools::server::model::Plot output;
output.setX(input.x);
output.setY(input.y);
return output;
}
inline org::openapitools::server::model::Plots Convert(const MultiLinePlot& input) {
std::vector<org::openapitools::server::model::Plot> tmp(input.size());
for (int i = 0; i < input.size(); i++) {
tmp[i].setTitle(input[i].title);
tmp[i].setX(input[i].x);
tmp[i].setY(input[i].y);
}
inline org::openapitools::server::model::Radial_integration_plots_inner Convert(const RadialIntegrationProfileStruct& input) {
org::openapitools::server::model::Radial_integration_plots_inner output;
output.setTitle(input.title);
output.setPlot(Convert(input.plot));
org::openapitools::server::model::Plots output;
output.setPlot(tmp);
return output;
}
@@ -267,11 +266,58 @@ inline org::openapitools::server::model::Rad_int_settings Convert(const RadialIn
return ret;
}
inline std::vector<ROIBox> Convert(const org::openapitools::server::model::Roi_box_list& input) {
std::vector<ROIBox> ret;
for (const auto &i: input.getRois())
ret.emplace_back(ROIBox(i.getName(), i.getMinXPxl(), i.getMaxXPxl(), i.getMinYPxl(), i.getMaxYPxl()));
return ret;
}
inline std::vector<ROICircle> Convert(const org::openapitools::server::model::Roi_circle_list& input) {
std::vector<ROICircle> ret;
for (const auto &i: input.getRois())
ret.emplace_back(ROICircle(i.getName(), i.getCenterXPxl(), i.getCenterYPxl(), i.getRadiusPxl()));
return ret;
}
inline org::openapitools::server::model::Roi_circle_list Convert(const std::vector<ROICircle> &input) {
org::openapitools::server::model::Roi_circle_list ret{};
std::vector<org::openapitools::server::model::Roi_circle> tmp;
for (const auto &i: input) {
org::openapitools::server::model::Roi_circle elem;
elem.setName(i.GetName());
elem.setCenterXPxl(i.GetX());
elem.setCenterYPxl(i.GetY());
elem.setRadiusPxl(i.GetRadius_pxl());
tmp.emplace_back(elem);
}
ret.setRois(tmp);
return ret;
}
inline org::openapitools::server::model::Roi_box_list Convert(const std::vector<ROIBox> &input) {
org::openapitools::server::model::Roi_box_list ret{};
std::vector<org::openapitools::server::model::Roi_box> tmp;
for (const auto &i: input) {
org::openapitools::server::model::Roi_box elem;
elem.setName(i.GetName());
elem.setMinXPxl(i.GetXMin());
elem.setMaxXPxl(i.GetXMax());
elem.setMinYPxl(i.GetYMin());
elem.setMaxYPxl(i.GetYMax());
tmp.emplace_back(elem);
}
ret.setRois(tmp);
return ret;
}
inline PreviewJPEGSettings Convert(const org::openapitools::server::model::Preview_settings& input) {
PreviewJPEGSettings ret{};
ret.show_spots = input.isShowSpots();
ret.jpeg_quality = input.getJpegQuality();
ret.saturation_value = input.getSaturation();
ret.show_roi = input.isShowRoi();
return ret;
}
@@ -280,6 +326,7 @@ inline org::openapitools::server::model::Preview_settings Convert(const PreviewJ
ret.setJpegQuality(settings.jpeg_quality);
ret.setSaturation(settings.saturation_value);
ret.setShowSpots(settings.show_spots);
ret.setShowRoi(settings.show_roi);
return ret;
}
@@ -358,14 +405,6 @@ inline DatasetSettings Convert(const org::openapitools::server::model::Dataset_s
}
}
if (input.roiSumAreaIsSet()) {
ret.ROISummation(ROIRectangle{
.x_min = static_cast<size_t>(input.getRoiSumArea().getXMin()),
.x_max = static_cast<size_t>(input.getRoiSumArea().getXMax()),
.y_min = static_cast<size_t>(input.getRoiSumArea().getYMin()),
.y_max = static_cast<size_t>(input.getRoiSumArea().getYMax())
});
}
ret.SpaceGroupNumber(input.getSpaceGroupNumber());
ret.SampleName(input.getSampleName());
ret.HeaderAppendix(input.getHeaderAppendix());
@@ -493,15 +532,6 @@ void JFJochBrokerHttp::config_spot_finding_put(
response.send(Pistache::Http::Code::Ok);
}
void JFJochBrokerHttp::plot_saturated_pixel_post(const org::openapitools::server::model::Plot_request &plotRequest,
Pistache::Http::ResponseWriter &response) {
PlotRequest req{.type = PlotType::SaturatedPixels, .binning = 0};
if (plotRequest.binningIsSet())
req.binning = plotRequest.getBinning();
auto plot = state_machine.GetPlots(req);
ProcessOutput(Convert(plot), response);
}
void JFJochBrokerHttp::plot_bkg_estimate_post(const org::openapitools::server::model::Plot_request &plotRequest,
Pistache::Http::ResponseWriter &response) {
PlotRequest req{.type = PlotType::BkgEstimate, .binning = 0};
@@ -534,19 +564,9 @@ void JFJochBrokerHttp::plot_rad_int_get(Pistache::Http::ResponseWriter &response
}
void JFJochBrokerHttp::plot_rad_int_per_file_get(Pistache::Http::ResponseWriter &response) {
auto rad_int = state_machine.GetRadialIntegrationProfiles();
nlohmann::json j;
for (const auto &i: rad_int.profiles) {
auto output = Convert(i);
std::stringstream s;
assert(output.validate(s));
nlohmann::json j_elem;
to_json(j_elem, output);
j.push_back(j_elem);
}
response.send(Pistache::Http::Code::Ok, j.dump(), MIME(Application, Json));
PlotRequest req{.type = PlotType::RadIntPerFile};
auto plot = state_machine.GetPlots(req);
ProcessOutput(Convert(plot), response);
}
void JFJochBrokerHttp::plot_spot_count_post(const org::openapitools::server::model::Plot_request &plotRequest,
@@ -735,4 +755,58 @@ void JFJochBrokerHttp::config_internal_generator_image_put(const Pistache::Rest:
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::roi_box_get(Pistache::Http::ResponseWriter &response) {
ProcessOutput(Convert(state_machine.GetBoxROI()), response);
}
void JFJochBrokerHttp::roi_box_put(const org::openapitools::server::model::Roi_box_list &roiBoxList,
Pistache::Http::ResponseWriter &response) {
state_machine.SetBoxROI(Convert(roiBoxList));
response.send(Pistache::Http::Code::Ok);
}
void JFJochBrokerHttp::roi_circle_get(Pistache::Http::ResponseWriter &response) {
ProcessOutput(Convert(state_machine.GetCircleROI()), response);
}
void JFJochBrokerHttp::roi_circle_put(const org::openapitools::server::model::Roi_circle_list &roiCircleList,
Pistache::Http::ResponseWriter &response) {
state_machine.SetCircleROI(Convert(roiCircleList));
response.send(Pistache::Http::Code::Ok);
}
void JFJochBrokerHttp::xfel_event_code_get(Pistache::Http::ResponseWriter &response) {
auto array = state_machine.GetXFELEventCode();
if (array.empty())
response.send(Pistache::Http::Code::Not_Found);
nlohmann::json j = array;
response.send(Pistache::Http::Code::Ok, j.dump(), MIME(Application, Json));
}
void JFJochBrokerHttp::xfel_pulse_id_get(Pistache::Http::ResponseWriter &response) {
auto array = state_machine.GetXFELPulseID();
if (array.empty())
response.send(Pistache::Http::Code::Not_Found);
nlohmann::json j = array;
response.send(Pistache::Http::Code::Ok, j.dump(), MIME(Application, Json));
}
void JFJochBrokerHttp::plot_roi_max_count_post(const org::openapitools::server::model::Plot_request &plotRequest,
Pistache::Http::ResponseWriter &response) {
PlotRequest req{.type = PlotType::ROIMaxCount, .binning = 0};
if (plotRequest.binningIsSet())
req.binning = plotRequest.getBinning();
auto plot = state_machine.GetPlots(req);
ProcessOutput(Convert(plot), response);
}
void JFJochBrokerHttp::plot_roi_valid_pixels_post(const org::openapitools::server::model::Plot_request &plotRequest,
Pistache::Http::ResponseWriter &response) {
PlotRequest req{.type = PlotType::ROIPixels, .binning = 0};
if (plotRequest.binningIsSet())
req.binning = plotRequest.getBinning();
auto plot = state_machine.GetPlots(req);
ProcessOutput(Convert(plot), response);
}

View File

@@ -43,8 +43,6 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi {
void plot_roi_sum_post(const org::openapitools::server::model::Plot_request &plotRequest,
Pistache::Http::ResponseWriter &response) override;
void plot_saturated_pixel_post(const org::openapitools::server::model::Plot_request &plotRequest,
Pistache::Http::ResponseWriter &response) override;
void plot_error_pixel_post(const org::openapitools::server::model::Plot_request &plotRequest,
Pistache::Http::ResponseWriter &response) override;
void plot_strong_pixel_post(const org::openapitools::server::model::Plot_request &plotRequest,
@@ -71,6 +69,12 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi {
void plot_spot_count_post(const org::openapitools::server::model::Plot_request &plotRequest,
Pistache::Http::ResponseWriter &response) override;
void plot_roi_max_count_post(const org::openapitools::server::model::Plot_request &plotRequest,
Pistache::Http::ResponseWriter &response) override;
void plot_roi_valid_pixels_post(const org::openapitools::server::model::Plot_request &plotRequest,
Pistache::Http::ResponseWriter &response) override;
void plot_resolution_estimate_histogram_get(Pistache::Http::ResponseWriter &response) override;
void statistics_calibration_get(Pistache::Http::ResponseWriter &response) override;
@@ -104,9 +108,19 @@ class JFJochBrokerHttp : public org::openapitools::server::api::DefaultApi {
void preview_jpeg_settings_put(const org::openapitools::server::model::Preview_settings &previewSettings,
Pistache::Http::ResponseWriter &response) override;
void roi_box_get(Pistache::Http::ResponseWriter &response) override;
void roi_box_put(const org::openapitools::server::model::Roi_box_list &roiBoxList,
Pistache::Http::ResponseWriter &response) override;
void roi_circle_get(Pistache::Http::ResponseWriter &response) override;
void roi_circle_put(const org::openapitools::server::model::Roi_circle_list &roiCircleList,
Pistache::Http::ResponseWriter &response) override;
void config_internal_generator_image_put(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter &response) override;
void xfel_event_code_get(Pistache::Http::ResponseWriter &response) override;
void xfel_pulse_id_get(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;

View File

@@ -116,7 +116,7 @@ std::optional<JFJochReceiverStatus> JFJochServices::GetReceiverStatus() {
return receiver->GetStatus();
}
Plot JFJochServices::GetPlots(const PlotRequest &request) {
MultiLinePlot JFJochServices::GetPlots(const PlotRequest &request) {
if (receiver == nullptr)
return {};
@@ -127,17 +127,6 @@ Plot JFJochServices::GetPlots(const PlotRequest &request) {
}
}
RadialIntegrationProfiles JFJochServices::GetRadialIntegrationProfiles() {
if (receiver == nullptr)
return {};
try {
return receiver->GetRadialIntegrationProfiles();
} catch (...) {
return {};
}
}
void JFJochServices::SetSpotFindingSettings(const SpotFindingSettings &settings) {
if (receiver)
receiver->SetSpotFindingSettings(settings);
@@ -180,3 +169,13 @@ void JFJochServices::LoadInternalGeneratorImage(const DiffractionExperiment &exp
if (receiver)
receiver->LoadInternalGeneratorImage(experiment, image, image_number);
}
void JFJochServices::GetXFELPulseID(std::vector<uint64_t> &v) const {
if (receiver)
receiver->GetXFELPulseID(v);
}
void JFJochServices::GetXFELEventCode(std::vector<uint64_t> &v) const {
if (receiver)
receiver->GetXFELPulseID(v);
}

View File

@@ -32,8 +32,7 @@ public:
const std::vector<uint16_t> &image,
uint64_t image_number);
std::optional<JFJochReceiverStatus> GetReceiverStatus();
Plot GetPlots(const PlotRequest &request);
RadialIntegrationProfiles GetRadialIntegrationProfiles();
MultiLinePlot GetPlots(const PlotRequest &request);
void SetSpotFindingSettings(const SpotFindingSettings &settings);
JFJochServices& Receiver(JFJochReceiverService *input);
@@ -42,6 +41,9 @@ public:
std::string GetPreviewJPEG(const PreviewJPEGSettings &settings) const;
std::string GetPreviewTIFF(bool calibration) const;
void GetXFELPulseID(std::vector<uint64_t> &v) const;
void GetXFELEventCode(std::vector<uint64_t> &v) const;
};

View File

@@ -263,6 +263,7 @@ void JFJochStateMachine::Initialize() {
logger.Info("Initialize");
state = JFJochState::Busy;
ClearMeasurementStatistics();
measurement = std::async(std::launch::async, &JFJochStateMachine::InitializeThread, this, std::move(ul));
}
@@ -494,6 +495,7 @@ void JFJochStateMachine::LoadDetectorSettings(const DetectorSettings &settings)
ApplyDetectorSettings(experiment, settings);
break;
case JFJochState::Idle:
state = JFJochState::Busy;
ApplyDetectorSettings(experiment, settings);
measurement = std::async(std::launch::async, &JFJochStateMachine::PedestalThread, this, std::move(ul));
break;
@@ -523,14 +525,10 @@ BrokerStatus JFJochStateMachine::GetStatus() const {
return ret;
}
Plot JFJochStateMachine::GetPlots(const PlotRequest &request) const {
MultiLinePlot JFJochStateMachine::GetPlots(const PlotRequest &request) const {
return services.GetPlots(request);
}
RadialIntegrationProfiles JFJochStateMachine::GetRadialIntegrationProfiles() const {
return services.GetRadialIntegrationProfiles();
}
void JFJochStateMachine::SetSpotFindingSettings(const SpotFindingSettings &settings) {
std::unique_lock<std::mutex> ul(data_processing_settings_mutex);
DiffractionExperiment::CheckDataProcessingSettings(settings);
@@ -690,3 +688,43 @@ void JFJochStateMachine::LoadInternalGeneratorImage(const void *data, size_t siz
services.LoadInternalGeneratorImage(experiment, image, image_number);
}
void JFJochStateMachine::SetBoxROI(const std::vector<ROIBox> &input) {
std::unique_lock<std::mutex> ul(m);
if (IsRunning())
throw WrongDAQStateException ("ROI can be modified only when detector is not running");
experiment.ROI().SetROIBox(input);
}
void JFJochStateMachine::SetCircleROI(const std::vector<ROICircle> &input) {
std::unique_lock<std::mutex> ul(m);
if (IsRunning())
throw WrongDAQStateException ("ROI can be modified only when detector is not running");
experiment.ROI().SetROICircle(input);
}
std::vector<ROIBox> JFJochStateMachine::GetBoxROI() const {
std::unique_lock<std::mutex> ul(m);
return experiment.ROI().GetROIBox();
}
std::vector<ROICircle> JFJochStateMachine::GetCircleROI() const {
std::unique_lock<std::mutex> ul(m);
return experiment.ROI().GetROICircle();
}
std::vector<uint64_t> JFJochStateMachine::GetXFELPulseID() const {
std::vector<uint64_t> ret;
services.GetXFELPulseID(ret);
return ret;
}
std::vector<uint64_t> JFJochStateMachine::GetXFELEventCode() const {
std::vector<uint64_t> ret;
services.GetXFELEventCode(ret);
return ret;
}

View File

@@ -13,6 +13,7 @@
#include "../common/Logger.h"
#include "JFJochServices.h"
#include "../common/ROIMask.h"
enum class JFJochState {Inactive, Idle, Measuring, Error, Busy, Pedestal};
@@ -125,7 +126,6 @@ class JFJochStateMachine {
bool ImportPedestalG0(const JFJochReceiverOutput &receiver_output);
bool IsRunning() const; // Is state Busy/Pedestal/Measure
std::optional<std::string> CheckError();
void TakePedestalInternalAll(std::unique_lock<std::mutex> &ul);
void TakePedestalInternalG0(std::unique_lock<std::mutex> &ul);
void TakePedestalInternalG1(std::unique_lock<std::mutex> &ul, int32_t storage_cell = 0);
@@ -154,8 +154,7 @@ public:
std::vector<JFCalibrationModuleStatistics> GetCalibrationStatistics() const;
BrokerStatus GetStatus() const;
Plot GetPlots(const PlotRequest &request) const;
RadialIntegrationProfiles GetRadialIntegrationProfiles() const;
MultiLinePlot GetPlots(const PlotRequest &request) const;
void SetSpotFindingSettings(const SpotFindingSettings& settings);
SpotFindingSettings GetSpotFindingSettings() const;
@@ -182,6 +181,15 @@ public:
// Function for debug only - UNSAFE for real operation
void DebugOnly_SetState(JFJochState state);
void SetBoxROI(const std::vector<ROIBox>& input);
void SetCircleROI(const std::vector<ROICircle>& input);
std::vector<ROIBox> GetBoxROI() const;
std::vector<ROICircle> GetCircleROI() const;
std::vector<uint64_t> GetXFELPulseID() const;
std::vector<uint64_t> GetXFELEventCode() const;
};

View File

@@ -56,8 +56,9 @@ void DefaultApi::setupRoutes() {
Routes::Get(*router, base + "/plot/rad_int_per_file", Routes::bind(&DefaultApi::plot_rad_int_per_file_get_handler, this));
Routes::Post(*router, base + "/plot/receiver_delay", Routes::bind(&DefaultApi::plot_receiver_delay_post_handler, this));
Routes::Get(*router, base + "/plot/resolution_estimate_histogram", Routes::bind(&DefaultApi::plot_resolution_estimate_histogram_get_handler, this));
Routes::Post(*router, base + "/plot/roi_max_count", Routes::bind(&DefaultApi::plot_roi_max_count_post_handler, this));
Routes::Post(*router, base + "/plot/roi_sum", Routes::bind(&DefaultApi::plot_roi_sum_post_handler, this));
Routes::Post(*router, base + "/plot/saturated_pixel", Routes::bind(&DefaultApi::plot_saturated_pixel_post_handler, this));
Routes::Post(*router, base + "/plot/roi_valid_pixels", Routes::bind(&DefaultApi::plot_roi_valid_pixels_post_handler, this));
Routes::Post(*router, base + "/plot/spot_count", Routes::bind(&DefaultApi::plot_spot_count_post_handler, this));
Routes::Post(*router, base + "/plot/strong_pixel", Routes::bind(&DefaultApi::plot_strong_pixel_post_handler, this));
Routes::Get(*router, base + "/preview/calibration.tiff", Routes::bind(&DefaultApi::preview_calibration_tiff_get_handler, this));
@@ -65,12 +66,18 @@ void DefaultApi::setupRoutes() {
Routes::Get(*router, base + "/preview/image.tiff", Routes::bind(&DefaultApi::preview_image_tiff_get_handler, this));
Routes::Get(*router, base + "/preview/jpeg_settings", Routes::bind(&DefaultApi::preview_jpeg_settings_get_handler, this));
Routes::Put(*router, base + "/preview/jpeg_settings", Routes::bind(&DefaultApi::preview_jpeg_settings_put_handler, this));
Routes::Get(*router, base + "/roi/box", Routes::bind(&DefaultApi::roi_box_get_handler, this));
Routes::Put(*router, base + "/roi/box", Routes::bind(&DefaultApi::roi_box_put_handler, this));
Routes::Get(*router, base + "/roi/circle", Routes::bind(&DefaultApi::roi_circle_get_handler, this));
Routes::Put(*router, base + "/roi/circle", Routes::bind(&DefaultApi::roi_circle_put_handler, this));
Routes::Post(*router, base + "/start", Routes::bind(&DefaultApi::start_post_handler, this));
Routes::Get(*router, base + "/statistics/calibration", Routes::bind(&DefaultApi::statistics_calibration_get_handler, this));
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::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));
// Default handler, called when a route is not found
router->addCustomHandler(Routes::bind(&DefaultApi::default_api_default_handler, this));
@@ -669,6 +676,39 @@ void DefaultApi::plot_resolution_estimate_histogram_get_handler(const Pistache::
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::plot_roi_max_count_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the body param
Plot_request plotRequest;
try {
nlohmann::json::parse(request.body()).get_to(plotRequest);
plotRequest.validate();
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
this->plot_roi_max_count_post(plotRequest, 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::plot_roi_sum_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
@@ -703,7 +743,7 @@ void DefaultApi::plot_roi_sum_post_handler(const Pistache::Rest::Request &reques
}
}
void DefaultApi::plot_saturated_pixel_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
void DefaultApi::plot_roi_valid_pixels_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
@@ -721,7 +761,7 @@ void DefaultApi::plot_saturated_pixel_post_handler(const Pistache::Rest::Request
}
try {
this->plot_saturated_pixel_post(plotRequest, response);
this->plot_roi_valid_pixels_post(plotRequest, response);
} catch (Pistache::Http::HttpError &e) {
response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
return;
@@ -914,6 +954,112 @@ void DefaultApi::preview_jpeg_settings_put_handler(const Pistache::Rest::Request
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::roi_box_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->roi_box_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::roi_box_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the body param
Roi_box_list roiBoxList;
try {
nlohmann::json::parse(request.body()).get_to(roiBoxList);
roiBoxList.validate();
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
this->roi_box_put(roiBoxList, 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::roi_circle_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->roi_circle_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::roi_circle_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
// Getting the body param
Roi_circle_list roiCircleList;
try {
nlohmann::json::parse(request.body()).get_to(roiCircleList);
roiCircleList.validate();
} catch (std::exception &e) {
const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
response.send(errorInfo.first, errorInfo.second);
return;
}
try {
this->roi_circle_put(roiCircleList, 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::start_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response) {
try {
@@ -1047,6 +1193,46 @@ void DefaultApi::wait_till_done_post_handler(const Pistache::Rest::Request &, Pi
response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
}
}
void DefaultApi::xfel_event_code_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->xfel_event_code_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::xfel_pulse_id_get_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
try {
try {
this->xfel_pulse_id_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::default_api_default_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {

View File

@@ -35,11 +35,12 @@
#include "Detector_status.h"
#include "Error_message.h"
#include "Measurement_statistics.h"
#include "Plot.h"
#include "Plot_request.h"
#include "Plots.h"
#include "Preview_settings.h"
#include "Rad_int_settings.h"
#include "Radial_integration_plots_inner.h"
#include "Roi_box_list.h"
#include "Roi_circle_list.h"
#include "Spot_finding_settings.h"
#include <string>
@@ -80,8 +81,9 @@ private:
void plot_rad_int_per_file_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void plot_receiver_delay_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void plot_resolution_estimate_histogram_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void plot_roi_max_count_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void plot_roi_sum_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void plot_saturated_pixel_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void plot_roi_valid_pixels_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void plot_spot_count_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void plot_strong_pixel_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void preview_calibration_tiff_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
@@ -89,12 +91,18 @@ private:
void preview_image_tiff_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void preview_jpeg_settings_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void preview_jpeg_settings_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void roi_box_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void roi_box_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void roi_circle_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void roi_circle_put_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void start_post_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
void statistics_calibration_get_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
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 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);
void default_api_default_handler(const Pistache::Rest::Request &request, Pistache::Http::ResponseWriter response);
const std::shared_ptr<Pistache::Rest::Router> router;
@@ -227,7 +235,7 @@ private:
/// Generate error pixels plot
/// </summary>
/// <remarks>
/// Count of error pixels per image; binning is configurable
/// Count of error (mean) and saturated (mean/max) pixels per image; binning is configurable
/// </remarks>
/// <param name="plotRequest"> (optional)</param>
virtual void plot_error_pixel_post(const org::openapitools::server::model::Plot_request &plotRequest, Pistache::Http::ResponseWriter &response) = 0;
@@ -284,6 +292,14 @@ private:
/// </remarks>
virtual void plot_resolution_estimate_histogram_get(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Generate plot of ROI max count
/// </summary>
/// <remarks>
/// Max count of ROI per image; binning is configurable
/// </remarks>
/// <param name="plotRequest"> (optional)</param>
virtual void plot_roi_max_count_post(const org::openapitools::server::model::Plot_request &plotRequest, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Generate ROI sum plot
/// </summary>
/// <remarks>
@@ -292,13 +308,13 @@ private:
/// <param name="plotRequest"> (optional)</param>
virtual void plot_roi_sum_post(const org::openapitools::server::model::Plot_request &plotRequest, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Generate saturated pixels plot
/// Generate plot of ROI valid pixels
/// </summary>
/// <remarks>
/// Count of saturated pixels per image; binning is configurable
/// Number of pixels within a ROI area; pixels with special values (overload, bad pixel) are excluded; multipixels are counted just once; binning is configurable
/// </remarks>
/// <param name="plotRequest"> (optional)</param>
virtual void plot_saturated_pixel_post(const org::openapitools::server::model::Plot_request &plotRequest, Pistache::Http::ResponseWriter &response) = 0;
virtual void plot_roi_valid_pixels_post(const org::openapitools::server::model::Plot_request &plotRequest, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Generate spot count plot
/// </summary>
@@ -352,6 +368,36 @@ private:
/// <param name="previewSettings"> (optional)</param>
virtual void preview_jpeg_settings_put(const org::openapitools::server::model::Preview_settings &previewSettings, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Get box ROIs
/// </summary>
/// <remarks>
///
/// </remarks>
virtual void roi_box_get(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Upload box ROIs
/// </summary>
/// <remarks>
///
/// </remarks>
/// <param name="roiBoxList"> (optional)</param>
virtual void roi_box_put(const org::openapitools::server::model::Roi_box_list &roiBoxList, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Get circular ROI
/// </summary>
/// <remarks>
///
/// </remarks>
virtual void roi_circle_get(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Upload circular ROI
/// </summary>
/// <remarks>
///
/// </remarks>
/// <param name="roiCircleList"> (optional)</param>
virtual void roi_circle_put(const org::openapitools::server::model::Roi_circle_list &roiCircleList, Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Start detector
/// </summary>
/// <remarks>
@@ -394,6 +440,20 @@ private:
/// 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.
/// </remarks>
virtual void wait_till_done_post(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Return XFEL event codes for the current data acquisition
/// </summary>
/// <remarks>
/// Return array of XFEL event codes
/// </remarks>
virtual void xfel_event_code_get(Pistache::Http::ResponseWriter &response) = 0;
/// <summary>
/// Return XFEL pulse IDs for the current data acquisition
/// </summary>
/// <remarks>
/// Return array of XFEL pulse IDs - (-1) if image not recorded
/// </remarks>
virtual void xfel_pulse_id_get(Pistache::Http::ResponseWriter &response) = 0;
};

View File

@@ -55,7 +55,6 @@ Dataset_settings::Dataset_settings()
m_Image_appendixIsSet = false;
m_Photon_energy_multiplier = 1.0f;
m_Photon_energy_multiplierIsSet = false;
m_Roi_sum_areaIsSet = false;
m_Unit_cellIsSet = false;
}
@@ -225,7 +224,7 @@ bool Dataset_settings::validate(std::stringstream& msg, const std::string& pathP
}
}
return success;
}
@@ -295,9 +294,6 @@ bool Dataset_settings::operator==(const Dataset_settings& rhs) const
((!photonEnergyMultiplierIsSet() && !rhs.photonEnergyMultiplierIsSet()) || (photonEnergyMultiplierIsSet() && rhs.photonEnergyMultiplierIsSet() && getPhotonEnergyMultiplier() == rhs.getPhotonEnergyMultiplier())) &&
((!roiSumAreaIsSet() && !rhs.roiSumAreaIsSet()) || (roiSumAreaIsSet() && rhs.roiSumAreaIsSet() && getRoiSumArea() == rhs.getRoiSumArea())) &&
((!unitCellIsSet() && !rhs.unitCellIsSet()) || (unitCellIsSet() && rhs.unitCellIsSet() && getUnitCell() == rhs.getUnitCell()))
;
@@ -346,8 +342,6 @@ void to_json(nlohmann::json& j, const Dataset_settings& o)
j["image_appendix"] = o.m_Image_appendix;
if(o.photonEnergyMultiplierIsSet())
j["photon_energy_multiplier"] = o.m_Photon_energy_multiplier;
if(o.roiSumAreaIsSet())
j["roi_sum_area"] = o.m_Roi_sum_area;
if(o.unitCellIsSet())
j["unit_cell"] = o.m_Unit_cell;
@@ -435,11 +429,6 @@ void from_json(const nlohmann::json& j, Dataset_settings& o)
j.at("photon_energy_multiplier").get_to(o.m_Photon_energy_multiplier);
o.m_Photon_energy_multiplierIsSet = true;
}
if(j.find("roi_sum_area") != j.end())
{
j.at("roi_sum_area").get_to(o.m_Roi_sum_area);
o.m_Roi_sum_areaIsSet = true;
}
if(j.find("unit_cell") != j.end())
{
j.at("unit_cell").get_to(o.m_Unit_cell);
@@ -743,23 +732,6 @@ void Dataset_settings::unsetPhoton_energy_multiplier()
{
m_Photon_energy_multiplierIsSet = false;
}
org::openapitools::server::model::Dataset_settings_roi_sum_area Dataset_settings::getRoiSumArea() const
{
return m_Roi_sum_area;
}
void Dataset_settings::setRoiSumArea(org::openapitools::server::model::Dataset_settings_roi_sum_area const& value)
{
m_Roi_sum_area = value;
m_Roi_sum_areaIsSet = true;
}
bool Dataset_settings::roiSumAreaIsSet() const
{
return m_Roi_sum_areaIsSet;
}
void Dataset_settings::unsetRoi_sum_area()
{
m_Roi_sum_areaIsSet = false;
}
org::openapitools::server::model::Dataset_settings_unit_cell Dataset_settings::getUnitCell() const
{
return m_Unit_cell;

View File

@@ -21,7 +21,6 @@
#include "Rotation_axis.h"
#include <string>
#include "Dataset_settings_roi_sum_area.h"
#include "Dataset_settings_unit_cell.h"
#include <nlohmann/json.hpp>
@@ -194,13 +193,6 @@ public:
/// <summary>
///
/// </summary>
org::openapitools::server::model::Dataset_settings_roi_sum_area getRoiSumArea() const;
void setRoiSumArea(org::openapitools::server::model::Dataset_settings_roi_sum_area const& value);
bool roiSumAreaIsSet() const;
void unsetRoi_sum_area();
/// <summary>
///
/// </summary>
org::openapitools::server::model::Dataset_settings_unit_cell getUnitCell() const;
void setUnitCell(org::openapitools::server::model::Dataset_settings_unit_cell const& value);
bool unitCellIsSet() const;
@@ -249,8 +241,6 @@ protected:
bool m_Image_appendixIsSet;
float m_Photon_energy_multiplier;
bool m_Photon_energy_multiplierIsSet;
org::openapitools::server::model::Dataset_settings_roi_sum_area m_Roi_sum_area;
bool m_Roi_sum_areaIsSet;
org::openapitools::server::model::Dataset_settings_unit_cell m_Unit_cell;
bool m_Unit_cellIsSet;

View File

@@ -49,7 +49,106 @@ bool Dataset_settings_unit_cell::validate(std::stringstream& msg, const std::str
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Dataset_settings_unit_cell" : pathPrefix;
/* a */ {
const float& value = m_a;
const std::string currentValuePath = _pathPrefix + ".A";
if (value < static_cast<float>(0))
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
}
/* b */ {
const float& value = m_b;
const std::string currentValuePath = _pathPrefix + ".B";
if (value < static_cast<float>(0))
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
}
/* c */ {
const float& value = m_c;
const std::string currentValuePath = _pathPrefix + ".C";
if (value < static_cast<float>(0))
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
}
/* Alpha */ {
const float& value = m_Alpha;
const std::string currentValuePath = _pathPrefix + ".alpha";
if (value < static_cast<float>(0))
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
if (value > static_cast<float>(360))
{
success = false;
msg << currentValuePath << ": must be less than or equal to 360;";
}
}
/* Beta */ {
const float& value = m_Beta;
const std::string currentValuePath = _pathPrefix + ".beta";
if (value < static_cast<float>(0))
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
if (value > static_cast<float>(360))
{
success = false;
msg << currentValuePath << ": must be less than or equal to 360;";
}
}
/* Gamma */ {
const float& value = m_Gamma;
const std::string currentValuePath = _pathPrefix + ".gamma";
if (value < static_cast<float>(0))
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
if (value > static_cast<float>(360))
{
success = false;
msg << currentValuePath << ": must be less than or equal to 360;";
}
}
return success;
}

View File

@@ -21,6 +21,7 @@ namespace org::openapitools::server::model
Plot::Plot()
{
m_Title = "";
}
@@ -43,7 +44,7 @@ bool Plot::validate(std::stringstream& msg, const std::string& pathPrefix) const
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Plot" : pathPrefix;
/* x */ {
const std::vector<float>& value = m_x;
@@ -94,6 +95,9 @@ bool Plot::operator==(const Plot& rhs) const
return
(getTitle() == rhs.getTitle())
&&
(getX() == rhs.getX())
&&
@@ -111,6 +115,7 @@ bool Plot::operator!=(const Plot& rhs) const
void to_json(nlohmann::json& j, const Plot& o)
{
j = nlohmann::json();
j["title"] = o.m_Title;
j["x"] = o.m_x;
j["y"] = o.m_y;
@@ -118,11 +123,20 @@ void to_json(nlohmann::json& j, const Plot& o)
void from_json(const nlohmann::json& j, Plot& o)
{
j.at("title").get_to(o.m_Title);
j.at("x").get_to(o.m_x);
j.at("y").get_to(o.m_y);
}
std::string Plot::getTitle() const
{
return m_Title;
}
void Plot::setTitle(std::string const& value)
{
m_Title = value;
}
std::vector<float> Plot::getX() const
{
return m_x;

View File

@@ -19,6 +19,7 @@
#define Plot_H_
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
@@ -58,6 +59,11 @@ public:
/////////////////////////////////////////////
/// Plot members
/// <summary>
///
/// </summary>
std::string getTitle() const;
void setTitle(std::string const& value);
/// <summary>
///
/// </summary>
@@ -72,6 +78,8 @@ public:
friend void to_json(nlohmann::json& j, const Plot& o);
friend void from_json(const nlohmann::json& j, Plot& o);
protected:
std::string m_Title;
std::vector<float> m_x;
std::vector<float> m_y;

140
broker/gen/model/Plots.cpp Normal file
View File

@@ -0,0 +1,140 @@
/**
* 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 "Plots.h"
#include "Helpers.h"
#include <sstream>
namespace org::openapitools::server::model
{
Plots::Plots()
{
m_Title = "";
m_TitleIsSet = false;
}
void Plots::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
bool Plots::validate(std::stringstream& msg) const
{
return validate(msg, "");
}
bool Plots::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Plots" : pathPrefix;
/* Plot */ {
const std::vector<org::openapitools::server::model::Plot>& value = m_Plot;
const std::string currentValuePath = _pathPrefix + ".plot";
{ // Recursive validation of array elements
const std::string oldValuePath = currentValuePath;
int i = 0;
for (const org::openapitools::server::model::Plot& value : value)
{
const std::string currentValuePath = oldValuePath + "[" + std::to_string(i) + "]";
success = value.validate(msg, currentValuePath + ".plot") && success;
i++;
}
}
}
return success;
}
bool Plots::operator==(const Plots& rhs) const
{
return
((!titleIsSet() && !rhs.titleIsSet()) || (titleIsSet() && rhs.titleIsSet() && getTitle() == rhs.getTitle())) &&
(getPlot() == rhs.getPlot())
;
}
bool Plots::operator!=(const Plots& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Plots& o)
{
j = nlohmann::json();
if(o.titleIsSet())
j["title"] = o.m_Title;
j["plot"] = o.m_Plot;
}
void from_json(const nlohmann::json& j, Plots& o)
{
if(j.find("title") != j.end())
{
j.at("title").get_to(o.m_Title);
o.m_TitleIsSet = true;
}
j.at("plot").get_to(o.m_Plot);
}
std::string Plots::getTitle() const
{
return m_Title;
}
void Plots::setTitle(std::string const& value)
{
m_Title = value;
m_TitleIsSet = true;
}
bool Plots::titleIsSet() const
{
return m_TitleIsSet;
}
void Plots::unsetTitle()
{
m_TitleIsSet = false;
}
std::vector<org::openapitools::server::model::Plot> Plots::getPlot() const
{
return m_Plot;
}
void Plots::setPlot(std::vector<org::openapitools::server::model::Plot> const& value)
{
m_Plot = value;
}
} // namespace org::openapitools::server::model

View File

@@ -10,17 +10,18 @@
* Do not edit the class manually.
*/
/*
* Radial_integration_plots_inner.h
* Plots.h
*
*
*/
#ifndef Radial_integration_plots_inner_H_
#define Radial_integration_plots_inner_H_
#ifndef Plots_H_
#define Plots_H_
#include "Plot.h"
#include <string>
#include <vector>
#include <nlohmann/json.hpp>
namespace org::openapitools::server::model
@@ -29,11 +30,11 @@ namespace org::openapitools::server::model
/// <summary>
///
/// </summary>
class Radial_integration_plots_inner
class Plots
{
public:
Radial_integration_plots_inner();
virtual ~Radial_integration_plots_inner() = default;
Plots();
virtual ~Plots() = default;
/// <summary>
@@ -53,33 +54,35 @@ public:
/// </summary>
bool validate(std::stringstream& msg, const std::string& pathPrefix) const;
bool operator==(const Radial_integration_plots_inner& rhs) const;
bool operator!=(const Radial_integration_plots_inner& rhs) const;
bool operator==(const Plots& rhs) const;
bool operator!=(const Plots& rhs) const;
/////////////////////////////////////////////
/// Radial_integration_plots_inner members
/// Plots members
/// <summary>
///
/// </summary>
std::string getTitle() const;
void setTitle(std::string const& value);
bool titleIsSet() const;
void unsetTitle();
/// <summary>
///
/// </summary>
org::openapitools::server::model::Plot getPlot() const;
void setPlot(org::openapitools::server::model::Plot const& value);
std::vector<org::openapitools::server::model::Plot> getPlot() const;
void setPlot(std::vector<org::openapitools::server::model::Plot> const& value);
friend void to_json(nlohmann::json& j, const Radial_integration_plots_inner& o);
friend void from_json(const nlohmann::json& j, Radial_integration_plots_inner& o);
friend void to_json(nlohmann::json& j, const Plots& o);
friend void from_json(const nlohmann::json& j, Plots& o);
protected:
std::string m_Title;
org::openapitools::server::model::Plot m_Plot;
bool m_TitleIsSet;
std::vector<org::openapitools::server::model::Plot> m_Plot;
};
} // namespace org::openapitools::server::model
#endif /* Radial_integration_plots_inner_H_ */
#endif /* Plots_H_ */

View File

@@ -24,6 +24,8 @@ Preview_settings::Preview_settings()
m_Saturation = 0L;
m_Show_spots = true;
m_Show_spotsIsSet = false;
m_Show_roi = false;
m_Show_roiIsSet = false;
m_Jpeg_quality = 0L;
m_Jpeg_qualityIsSet = false;
@@ -67,7 +69,7 @@ bool Preview_settings::validate(std::stringstream& msg, const std::string& pathP
}
}
if (jpegQualityIsSet())
{
const int64_t& value = m_Jpeg_quality;
@@ -102,6 +104,9 @@ bool Preview_settings::operator==(const Preview_settings& rhs) const
((!showSpotsIsSet() && !rhs.showSpotsIsSet()) || (showSpotsIsSet() && rhs.showSpotsIsSet() && isShowSpots() == rhs.isShowSpots())) &&
((!showRoiIsSet() && !rhs.showRoiIsSet()) || (showRoiIsSet() && rhs.showRoiIsSet() && isShowRoi() == rhs.isShowRoi())) &&
((!jpegQualityIsSet() && !rhs.jpegQualityIsSet()) || (jpegQualityIsSet() && rhs.jpegQualityIsSet() && getJpegQuality() == rhs.getJpegQuality()))
;
@@ -118,6 +123,8 @@ void to_json(nlohmann::json& j, const Preview_settings& o)
j["saturation"] = o.m_Saturation;
if(o.showSpotsIsSet())
j["show_spots"] = o.m_Show_spots;
if(o.showRoiIsSet())
j["show_roi"] = o.m_Show_roi;
if(o.jpegQualityIsSet())
j["jpeg_quality"] = o.m_Jpeg_quality;
@@ -131,6 +138,11 @@ void from_json(const nlohmann::json& j, Preview_settings& o)
j.at("show_spots").get_to(o.m_Show_spots);
o.m_Show_spotsIsSet = true;
}
if(j.find("show_roi") != j.end())
{
j.at("show_roi").get_to(o.m_Show_roi);
o.m_Show_roiIsSet = true;
}
if(j.find("jpeg_quality") != j.end())
{
j.at("jpeg_quality").get_to(o.m_Jpeg_quality);
@@ -164,6 +176,23 @@ void Preview_settings::unsetShow_spots()
{
m_Show_spotsIsSet = false;
}
bool Preview_settings::isShowRoi() const
{
return m_Show_roi;
}
void Preview_settings::setShowRoi(bool const value)
{
m_Show_roi = value;
m_Show_roiIsSet = true;
}
bool Preview_settings::showRoiIsSet() const
{
return m_Show_roiIsSet;
}
void Preview_settings::unsetShow_roi()
{
m_Show_roiIsSet = false;
}
int64_t Preview_settings::getJpegQuality() const
{
return m_Jpeg_quality;

View File

@@ -70,6 +70,13 @@ public:
bool showSpotsIsSet() const;
void unsetShow_spots();
/// <summary>
/// Show ROI areas on the image
/// </summary>
bool isShowRoi() const;
void setShowRoi(bool const value);
bool showRoiIsSet() const;
void unsetShow_roi();
/// <summary>
/// Quality of JPEG image (100 - highest; 0 - lowest)
/// </summary>
int64_t getJpegQuality() const;
@@ -84,6 +91,8 @@ protected:
bool m_Show_spots;
bool m_Show_spotsIsSet;
bool m_Show_roi;
bool m_Show_roiIsSet;
int64_t m_Jpeg_quality;
bool m_Jpeg_qualityIsSet;

View File

@@ -1,104 +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 "Radial_integration_plots_inner.h"
#include "Helpers.h"
#include <sstream>
namespace org::openapitools::server::model
{
Radial_integration_plots_inner::Radial_integration_plots_inner()
{
m_Title = "";
}
void Radial_integration_plots_inner::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
bool Radial_integration_plots_inner::validate(std::stringstream& msg) const
{
return validate(msg, "");
}
bool Radial_integration_plots_inner::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Radial_integration_plots_inner" : pathPrefix;
return success;
}
bool Radial_integration_plots_inner::operator==(const Radial_integration_plots_inner& rhs) const
{
return
(getTitle() == rhs.getTitle())
&&
(getPlot() == rhs.getPlot())
;
}
bool Radial_integration_plots_inner::operator!=(const Radial_integration_plots_inner& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Radial_integration_plots_inner& o)
{
j = nlohmann::json();
j["title"] = o.m_Title;
j["plot"] = o.m_Plot;
}
void from_json(const nlohmann::json& j, Radial_integration_plots_inner& o)
{
j.at("title").get_to(o.m_Title);
j.at("plot").get_to(o.m_Plot);
}
std::string Radial_integration_plots_inner::getTitle() const
{
return m_Title;
}
void Radial_integration_plots_inner::setTitle(std::string const& value)
{
m_Title = value;
}
org::openapitools::server::model::Plot Radial_integration_plots_inner::getPlot() const
{
return m_Plot;
}
void Radial_integration_plots_inner::setPlot(org::openapitools::server::model::Plot const& value)
{
m_Plot = value;
}
} // namespace org::openapitools::server::model

View File

@@ -0,0 +1,217 @@
/**
* 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 "Roi_box.h"
#include "Helpers.h"
#include <sstream>
namespace org::openapitools::server::model
{
Roi_box::Roi_box()
{
m_Name = "";
m_Min_x_pxl = 0L;
m_Max_x_pxl = 0L;
m_Min_y_pxl = 0L;
m_Max_y_pxl = 0L;
}
void Roi_box::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
bool Roi_box::validate(std::stringstream& msg) const
{
return validate(msg, "");
}
bool Roi_box::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Roi_box" : pathPrefix;
/* Name */ {
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;";
}
}
/* Min_x_pxl */ {
const int64_t& value = m_Min_x_pxl;
const std::string currentValuePath = _pathPrefix + ".minXPxl";
if (value < 0ll)
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
}
/* Max_x_pxl */ {
const int64_t& value = m_Max_x_pxl;
const std::string currentValuePath = _pathPrefix + ".maxXPxl";
if (value < 0ll)
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
}
/* Min_y_pxl */ {
const int64_t& value = m_Min_y_pxl;
const std::string currentValuePath = _pathPrefix + ".minYPxl";
if (value < 0ll)
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
}
/* Max_y_pxl */ {
const int64_t& value = m_Max_y_pxl;
const std::string currentValuePath = _pathPrefix + ".maxYPxl";
if (value < 0ll)
{
success = false;
msg << currentValuePath << ": must be greater than or equal to 0;";
}
}
return success;
}
bool Roi_box::operator==(const Roi_box& rhs) const
{
return
(getName() == rhs.getName())
&&
(getMinXPxl() == rhs.getMinXPxl())
&&
(getMaxXPxl() == rhs.getMaxXPxl())
&&
(getMinYPxl() == rhs.getMinYPxl())
&&
(getMaxYPxl() == rhs.getMaxYPxl())
;
}
bool Roi_box::operator!=(const Roi_box& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Roi_box& o)
{
j = nlohmann::json();
j["name"] = o.m_Name;
j["min_x_pxl"] = o.m_Min_x_pxl;
j["max_x_pxl"] = o.m_Max_x_pxl;
j["min_y_pxl"] = o.m_Min_y_pxl;
j["max_y_pxl"] = o.m_Max_y_pxl;
}
void from_json(const nlohmann::json& j, Roi_box& o)
{
j.at("name").get_to(o.m_Name);
j.at("min_x_pxl").get_to(o.m_Min_x_pxl);
j.at("max_x_pxl").get_to(o.m_Max_x_pxl);
j.at("min_y_pxl").get_to(o.m_Min_y_pxl);
j.at("max_y_pxl").get_to(o.m_Max_y_pxl);
}
std::string Roi_box::getName() const
{
return m_Name;
}
void Roi_box::setName(std::string const& value)
{
m_Name = value;
}
int64_t Roi_box::getMinXPxl() const
{
return m_Min_x_pxl;
}
void Roi_box::setMinXPxl(int64_t const value)
{
m_Min_x_pxl = value;
}
int64_t Roi_box::getMaxXPxl() const
{
return m_Max_x_pxl;
}
void Roi_box::setMaxXPxl(int64_t const value)
{
m_Max_x_pxl = value;
}
int64_t Roi_box::getMinYPxl() const
{
return m_Min_y_pxl;
}
void Roi_box::setMinYPxl(int64_t const value)
{
m_Min_y_pxl = value;
}
int64_t Roi_box::getMaxYPxl() const
{
return m_Max_y_pxl;
}
void Roi_box::setMaxYPxl(int64_t const value)
{
m_Max_y_pxl = value;
}
} // namespace org::openapitools::server::model

105
broker/gen/model/Roi_box.h Normal file
View File

@@ -0,0 +1,105 @@
/**
* 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.
*/
/*
* Roi_box.h
*
* Box ROI
*/
#ifndef Roi_box_H_
#define Roi_box_H_
#include <string>
#include <nlohmann/json.hpp>
namespace org::openapitools::server::model
{
/// <summary>
/// Box ROI
/// </summary>
class Roi_box
{
public:
Roi_box();
virtual ~Roi_box() = 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 Roi_box& rhs) const;
bool operator!=(const Roi_box& rhs) const;
/////////////////////////////////////////////
/// Roi_box members
/// <summary>
/// Name for the ROI; used in the plots
/// </summary>
std::string getName() const;
void setName(std::string const& value);
/// <summary>
/// Lower bound (inclusive) in X coordinate for the box
/// </summary>
int64_t getMinXPxl() const;
void setMinXPxl(int64_t const value);
/// <summary>
/// Upper bound (inclusive) in X coordinate for the box
/// </summary>
int64_t getMaxXPxl() const;
void setMaxXPxl(int64_t const value);
/// <summary>
/// Lower bound (inclusive) in Y coordinate for the box
/// </summary>
int64_t getMinYPxl() const;
void setMinYPxl(int64_t const value);
/// <summary>
/// Upper bound (inclusive) in Y coordinate for the box
/// </summary>
int64_t getMaxYPxl() const;
void setMaxYPxl(int64_t const value);
friend void to_json(nlohmann::json& j, const Roi_box& o);
friend void from_json(const nlohmann::json& j, Roi_box& o);
protected:
std::string m_Name;
int64_t m_Min_x_pxl;
int64_t m_Max_x_pxl;
int64_t m_Min_y_pxl;
int64_t m_Max_y_pxl;
};
} // namespace org::openapitools::server::model
#endif /* Roi_box_H_ */

View File

@@ -0,0 +1,131 @@
/**
* 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 "Roi_box_list.h"
#include "Helpers.h"
#include <sstream>
namespace org::openapitools::server::model
{
Roi_box_list::Roi_box_list()
{
m_RoisIsSet = false;
}
void Roi_box_list::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
bool Roi_box_list::validate(std::stringstream& msg) const
{
return validate(msg, "");
}
bool Roi_box_list::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Roi_box_list" : pathPrefix;
if (roisIsSet())
{
const std::vector<org::openapitools::server::model::Roi_box>& value = m_Rois;
const std::string currentValuePath = _pathPrefix + ".rois";
if (value.size() > 32)
{
success = false;
msg << currentValuePath << ": must have at most 32 elements;";
}
{ // Recursive validation of array elements
const std::string oldValuePath = currentValuePath;
int i = 0;
for (const org::openapitools::server::model::Roi_box& value : value)
{
const std::string currentValuePath = oldValuePath + "[" + std::to_string(i) + "]";
success = value.validate(msg, currentValuePath + ".rois") && success;
i++;
}
}
}
return success;
}
bool Roi_box_list::operator==(const Roi_box_list& rhs) const
{
return
((!roisIsSet() && !rhs.roisIsSet()) || (roisIsSet() && rhs.roisIsSet() && getRois() == rhs.getRois()))
;
}
bool Roi_box_list::operator!=(const Roi_box_list& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Roi_box_list& o)
{
j = nlohmann::json();
if(o.roisIsSet() || !o.m_Rois.empty())
j["rois"] = o.m_Rois;
}
void from_json(const nlohmann::json& j, Roi_box_list& o)
{
if(j.find("rois") != j.end())
{
j.at("rois").get_to(o.m_Rois);
o.m_RoisIsSet = true;
}
}
std::vector<org::openapitools::server::model::Roi_box> Roi_box_list::getRois() const
{
return m_Rois;
}
void Roi_box_list::setRois(std::vector<org::openapitools::server::model::Roi_box> const& value)
{
m_Rois = value;
m_RoisIsSet = true;
}
bool Roi_box_list::roisIsSet() const
{
return m_RoisIsSet;
}
void Roi_box_list::unsetRois()
{
m_RoisIsSet = false;
}
} // namespace org::openapitools::server::model

View File

@@ -0,0 +1,80 @@
/**
* 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.
*/
/*
* Roi_box_list.h
*
* List of box ROIs
*/
#ifndef Roi_box_list_H_
#define Roi_box_list_H_
#include <vector>
#include "Roi_box.h"
#include <nlohmann/json.hpp>
namespace org::openapitools::server::model
{
/// <summary>
/// List of box ROIs
/// </summary>
class Roi_box_list
{
public:
Roi_box_list();
virtual ~Roi_box_list() = 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 Roi_box_list& rhs) const;
bool operator!=(const Roi_box_list& rhs) const;
/////////////////////////////////////////////
/// Roi_box_list members
/// <summary>
///
/// </summary>
std::vector<org::openapitools::server::model::Roi_box> getRois() const;
void setRois(std::vector<org::openapitools::server::model::Roi_box> const& value);
bool roisIsSet() const;
void unsetRois();
friend void to_json(nlohmann::json& j, const Roi_box_list& o);
friend void from_json(const nlohmann::json& j, Roi_box_list& o);
protected:
std::vector<org::openapitools::server::model::Roi_box> m_Rois;
bool m_RoisIsSet;
};
} // namespace org::openapitools::server::model
#endif /* Roi_box_list_H_ */

View File

@@ -0,0 +1,161 @@
/**
* 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 "Roi_circle.h"
#include "Helpers.h"
#include <sstream>
namespace org::openapitools::server::model
{
Roi_circle::Roi_circle()
{
m_Name = "";
m_Center_x_pxl = 0.0f;
m_Center_y_pxl = 0.0f;
m_Radius_pxl = 0.0f;
}
void Roi_circle::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
bool Roi_circle::validate(std::stringstream& msg) const
{
return validate(msg, "");
}
bool Roi_circle::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Roi_circle" : pathPrefix;
/* Name */ {
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;";
}
}
/* Radius_pxl */ {
const float& value = m_Radius_pxl;
const std::string currentValuePath = _pathPrefix + ".radiusPxl";
if (value <= static_cast<float>(0.0))
{
success = false;
msg << currentValuePath << ": must be greater than 0.0;";
}
}
return success;
}
bool Roi_circle::operator==(const Roi_circle& rhs) const
{
return
(getName() == rhs.getName())
&&
(getCenterXPxl() == rhs.getCenterXPxl())
&&
(getCenterYPxl() == rhs.getCenterYPxl())
&&
(getRadiusPxl() == rhs.getRadiusPxl())
;
}
bool Roi_circle::operator!=(const Roi_circle& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Roi_circle& o)
{
j = nlohmann::json();
j["name"] = o.m_Name;
j["center_x_pxl"] = o.m_Center_x_pxl;
j["center_y_pxl"] = o.m_Center_y_pxl;
j["radius_pxl"] = o.m_Radius_pxl;
}
void from_json(const nlohmann::json& j, Roi_circle& o)
{
j.at("name").get_to(o.m_Name);
j.at("center_x_pxl").get_to(o.m_Center_x_pxl);
j.at("center_y_pxl").get_to(o.m_Center_y_pxl);
j.at("radius_pxl").get_to(o.m_Radius_pxl);
}
std::string Roi_circle::getName() const
{
return m_Name;
}
void Roi_circle::setName(std::string const& value)
{
m_Name = value;
}
float Roi_circle::getCenterXPxl() const
{
return m_Center_x_pxl;
}
void Roi_circle::setCenterXPxl(float const value)
{
m_Center_x_pxl = value;
}
float Roi_circle::getCenterYPxl() const
{
return m_Center_y_pxl;
}
void Roi_circle::setCenterYPxl(float const value)
{
m_Center_y_pxl = value;
}
float Roi_circle::getRadiusPxl() const
{
return m_Radius_pxl;
}
void Roi_circle::setRadiusPxl(float const value)
{
m_Radius_pxl = value;
}
} // namespace org::openapitools::server::model

View File

@@ -0,0 +1,98 @@
/**
* 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.
*/
/*
* Roi_circle.h
*
* Circular ROI
*/
#ifndef Roi_circle_H_
#define Roi_circle_H_
#include <string>
#include <nlohmann/json.hpp>
namespace org::openapitools::server::model
{
/// <summary>
/// Circular ROI
/// </summary>
class Roi_circle
{
public:
Roi_circle();
virtual ~Roi_circle() = 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 Roi_circle& rhs) const;
bool operator!=(const Roi_circle& rhs) const;
/////////////////////////////////////////////
/// Roi_circle members
/// <summary>
/// Name for the ROI; used in the plots
/// </summary>
std::string getName() const;
void setName(std::string const& value);
/// <summary>
/// X coordinate of center of the circle [pixels]
/// </summary>
float getCenterXPxl() const;
void setCenterXPxl(float const value);
/// <summary>
/// Y coordinate of center of the circle [pixels]
/// </summary>
float getCenterYPxl() const;
void setCenterYPxl(float const value);
/// <summary>
/// Radius of the circle [pixels]
/// </summary>
float getRadiusPxl() const;
void setRadiusPxl(float const value);
friend void to_json(nlohmann::json& j, const Roi_circle& o);
friend void from_json(const nlohmann::json& j, Roi_circle& o);
protected:
std::string m_Name;
float m_Center_x_pxl;
float m_Center_y_pxl;
float m_Radius_pxl;
};
} // namespace org::openapitools::server::model
#endif /* Roi_circle_H_ */

View File

@@ -0,0 +1,116 @@
/**
* 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 "Roi_circle_list.h"
#include "Helpers.h"
#include <sstream>
namespace org::openapitools::server::model
{
Roi_circle_list::Roi_circle_list()
{
}
void Roi_circle_list::validate() const
{
std::stringstream msg;
if (!validate(msg))
{
throw org::openapitools::server::helpers::ValidationException(msg.str());
}
}
bool Roi_circle_list::validate(std::stringstream& msg) const
{
return validate(msg, "");
}
bool Roi_circle_list::validate(std::stringstream& msg, const std::string& pathPrefix) const
{
bool success = true;
const std::string _pathPrefix = pathPrefix.empty() ? "Roi_circle_list" : pathPrefix;
/* Rois */ {
const std::vector<org::openapitools::server::model::Roi_circle>& value = m_Rois;
const std::string currentValuePath = _pathPrefix + ".rois";
if (value.size() > 32)
{
success = false;
msg << currentValuePath << ": must have at most 32 elements;";
}
{ // Recursive validation of array elements
const std::string oldValuePath = currentValuePath;
int i = 0;
for (const org::openapitools::server::model::Roi_circle& value : value)
{
const std::string currentValuePath = oldValuePath + "[" + std::to_string(i) + "]";
success = value.validate(msg, currentValuePath + ".rois") && success;
i++;
}
}
}
return success;
}
bool Roi_circle_list::operator==(const Roi_circle_list& rhs) const
{
return
(getRois() == rhs.getRois())
;
}
bool Roi_circle_list::operator!=(const Roi_circle_list& rhs) const
{
return !(*this == rhs);
}
void to_json(nlohmann::json& j, const Roi_circle_list& o)
{
j = nlohmann::json();
j["rois"] = o.m_Rois;
}
void from_json(const nlohmann::json& j, Roi_circle_list& o)
{
j.at("rois").get_to(o.m_Rois);
}
std::vector<org::openapitools::server::model::Roi_circle> Roi_circle_list::getRois() const
{
return m_Rois;
}
void Roi_circle_list::setRois(std::vector<org::openapitools::server::model::Roi_circle> const& value)
{
m_Rois = value;
}
} // namespace org::openapitools::server::model

View File

@@ -0,0 +1,78 @@
/**
* 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.
*/
/*
* Roi_circle_list.h
*
* List of circular ROIs
*/
#ifndef Roi_circle_list_H_
#define Roi_circle_list_H_
#include "Roi_circle.h"
#include <vector>
#include <nlohmann/json.hpp>
namespace org::openapitools::server::model
{
/// <summary>
/// List of circular ROIs
/// </summary>
class Roi_circle_list
{
public:
Roi_circle_list();
virtual ~Roi_circle_list() = 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 Roi_circle_list& rhs) const;
bool operator!=(const Roi_circle_list& rhs) const;
/////////////////////////////////////////////
/// Roi_circle_list members
/// <summary>
///
/// </summary>
std::vector<org::openapitools::server::model::Roi_circle> getRois() const;
void setRois(std::vector<org::openapitools::server::model::Roi_circle> const& value);
friend void to_json(nlohmann::json& j, const Roi_circle_list& o);
friend void from_json(const nlohmann::json& j, Roi_circle_list& o);
protected:
std::vector<org::openapitools::server::model::Roi_circle> m_Rois;
};
} // namespace org::openapitools::server::model
#endif /* Roi_circle_list_H_ */

View File

@@ -164,31 +164,6 @@ components:
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
roi_sum_area:
type: object
description: Rectangle for ROI summation
required:
- x_min
- x_max
- y_min
- y_max
properties:
x_min:
type: integer
format: int64
example: 12
x_max:
type: integer
format: int64
example: 14
y_min:
type: integer
format: int64
example: 25
y_max:
type: integer
format: int64
example: 32
unit_cell:
type: object
description: Units of angstrom and degree
@@ -204,26 +179,35 @@ components:
type: number
format: float
example: 37
minimum: 0
b:
type: number
format: float
example: 37
minimum: 0
c:
type: number
format: float
example: 78
minimum: 0
alpha:
type: number
format: float
example: 90
minimum: 0
maximum: 360
beta:
type: number
format: float
example: 90
minimum: 0
maximum: 360
gamma:
type: number
format: float
example: 90
minimum: 0
maximum: 360
detector_status:
type: object
@@ -515,8 +499,12 @@ components:
required:
- x
- y
- title
description: x and y coordinates for plotting, it is OK to assume that both arrays have the same size; layout is optimized for Plotly
properties:
title:
type: string
default: ""
x:
type: array
items:
@@ -527,18 +515,17 @@ components:
items:
type: number
format: float
radial_integration_plots:
type: array
items:
type: object
required:
- title
- plot
properties:
title:
type: string
plot:
$ref: "#/components/schemas/plot"
plots:
type: object
required:
- plot
properties:
title:
type: string
plot:
type: array
items:
$ref: '#/components/schemas/plot'
calibration_statistics:
type: array
items:
@@ -597,6 +584,10 @@ components:
type: boolean
default: true
description: "Show spot finding results on the image"
show_roi:
type: boolean
default: false
description: "Show ROI areas on the image"
jpeg_quality:
type: integer
description: "Quality of JPEG image (100 - highest; 0 - lowest)"
@@ -618,7 +609,87 @@ components:
type: string
description: "Enumerate field for automated analysis"
enum: ["WrongDAQState", "Other"]
roi_circle:
type: object
description: "Circular ROI"
required:
- name
- center_x_pxl
- center_y_pxl
- radius_pxl
properties:
name:
type: string
minLength: 1
description: "Name for the ROI; used in the plots"
center_x_pxl:
type: number
format: float
description: "X coordinate of center of the circle [pixels]"
center_y_pxl:
type: number
format: float
description: "Y coordinate of center of the circle [pixels]"
radius_pxl:
type: number
format: float
minimum: 0.0
exclusiveMinimum: true
description: "Radius of the circle [pixels]"
roi_box:
type: object
description: "Box ROI"
required:
- name
- min_x_pxl
- max_x_pxl
- min_y_pxl
- max_y_pxl
properties:
name:
type: string
minLength: 1
description: "Name for the ROI; used in the plots"
min_x_pxl:
type: integer
format: int64
description: "Lower bound (inclusive) in X coordinate for the box"
minimum: 0
max_x_pxl:
type: integer
format: int64
description: "Upper bound (inclusive) in X coordinate for the box"
minimum: 0
min_y_pxl:
type: integer
format: int64
description: "Lower bound (inclusive) in Y coordinate for the box"
minimum: 0
max_y_pxl:
type: integer
format: int64
description: "Upper bound (inclusive) in Y coordinate for the box"
minimum: 0
roi_circle_list:
type: object
description: "List of circular ROIs"
required:
- rois
properties:
rois:
type: array
maxItems: 32
items:
$ref: "#/components/schemas/roi_circle"
roi_box_list:
type: object
description: "List of box ROIs"
properties:
rois:
type: array
maxItems: 32
items:
$ref: "#/components/schemas/roi_box"
paths:
/initialize:
post:
@@ -935,6 +1006,39 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/broker_status'
/xfel/pulse_id:
get:
summary: Return XFEL pulse IDs for the current data acquisition
description: Return array of XFEL pulse IDs - (-1) if image not recorded
responses:
"200":
description: "Pulse ID collected"
content:
application/json:
schema:
type: array
items:
type: integer
format: int64
"404":
description: "Not in XFEL mode or no acquisition recorded"
/xfel/event_code:
get:
summary: Return XFEL event codes for the current data acquisition
description: Return array of XFEL event codes
responses:
"200":
description: "Event codes collected"
content:
application/json:
schema:
type: array
items:
type: integer
format: int64
"404":
description: "Not in XFEL mode or no acquisition recorded"
/detector/status:
get:
summary: Get detector status
@@ -955,7 +1059,72 @@ paths:
schema:
type: string
description: Exception error
/roi/box:
get:
summary: Get box ROIs
responses:
"200":
description: "OK"
content:
application/json:
schema:
$ref: '#/components/schemas/roi_box_list'
put:
summary: Upload box ROIs
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/roi_box_list"
responses:
"200":
description: Everything OK
"400":
description: Input parsing or validation error
content:
text/plain:
schema:
type: string
description: Exception error
"500":
description: Error within Jungfraujoch code - see output message.
content:
application/json:
schema:
$ref: '#/components/schemas/error_message'
/roi/circle:
get:
summary: Get circular ROI
responses:
"200":
description: "OK"
content:
application/json:
schema:
$ref: '#/components/schemas/roi_circle_list'
put:
summary: Upload circular ROI
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/roi_circle_list"
responses:
"200":
description: Everything OK
"400":
description: Input parsing or validation error
content:
text/plain:
schema:
type: string
description: Exception error
"500":
description: Error within Jungfraujoch code - see output message.
content:
application/json:
schema:
$ref: '#/components/schemas/error_message'
/plot/bkg_estimate:
post:
summary: Generate background estimate plot
@@ -971,7 +1140,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
"400":
description: Input parsing or validation error
content:
@@ -994,7 +1163,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
"400":
description: Input parsing or validation error
content:
@@ -1017,30 +1186,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
"400":
description: Input parsing or validation error
content:
text/plain:
schema:
type: string
description: Exception error
/plot/saturated_pixel:
post:
summary: Generate saturated pixels plot
description: Count of saturated pixels per image; binning is configurable
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/plot_request'
responses:
"200":
description: Everything OK
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
"400":
description: Input parsing or validation error
content:
@@ -1051,7 +1197,7 @@ paths:
/plot/error_pixel:
post:
summary: Generate error pixels plot
description: Count of error pixels per image; binning is configurable
description: Count of error (mean) and saturated (mean/max) pixels per image; binning is configurable
requestBody:
content:
application/json:
@@ -1063,7 +1209,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
"400":
description: Input parsing or validation error
content:
@@ -1086,7 +1232,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
"400":
description: Input parsing or validation error
content:
@@ -1109,7 +1255,53 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
"400":
description: Input parsing or validation error
content:
text/plain:
schema:
type: string
description: Exception error
/plot/roi_max_count:
post:
summary: Generate plot of ROI max count
description: Max count of ROI per image; binning is configurable
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/plot_request'
responses:
"200":
description: Everything OK
content:
application/json:
schema:
$ref: '#/components/schemas/plots'
"400":
description: Input parsing or validation error
content:
text/plain:
schema:
type: string
description: Exception error
/plot/roi_valid_pixels:
post:
summary: Generate plot of ROI valid pixels
description: Number of pixels within a ROI area; pixels with special values (overload, bad pixel) are excluded; multipixels are counted just once; binning is configurable
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/plot_request'
responses:
"200":
description: Everything OK
content:
application/json:
schema:
$ref: '#/components/schemas/plots'
"400":
description: Input parsing or validation error
content:
@@ -1132,7 +1324,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
"400":
description: Input parsing or validation error
content:
@@ -1155,7 +1347,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
"400":
description: Input parsing or validation error
content:
@@ -1173,7 +1365,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
/plot/resolution_estimate_histogram:
get:
summary: Generate resolution estimate histogram
@@ -1184,7 +1376,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
/plot/rad_int:
get:
summary: Generate radial integration profile
@@ -1195,7 +1387,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/plot'
$ref: '#/components/schemas/plots'
/plot/rad_int_per_file:
get:
summary: Generate radial integration profiles per file
@@ -1206,7 +1398,7 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/radial_integration_plots'
$ref: '#/components/schemas/plots'
/statistics/data_collection:
get:
summary: Get data collection statistics
@@ -1306,4 +1498,4 @@ paths:
type: string
format: binary
"404":
description: No preview image recorded so far
description: No preview image recorded so far

File diff suppressed because one or more lines are too long

View File

@@ -24,14 +24,14 @@ const std::vector<uint64_t> &ADUHistogram::GetHistogram() const {
return histogram;
}
Plot ADUHistogram::GetPlot() const {
MultiLinePlot ADUHistogram::GetPlot() const {
std::unique_lock<std::mutex> ul(m);
Plot ret;
ret.x.resize(ADU_HISTO_BIN_COUNT);
ret.y.resize(ADU_HISTO_BIN_COUNT);
MultiLinePlot ret(1);
ret[0].x.resize(ADU_HISTO_BIN_COUNT);
ret[0].y.resize(ADU_HISTO_BIN_COUNT);
for (int i = 0; i < ADU_HISTO_BIN_COUNT; i++) {
ret.x[i] = ADU_HISTO_BIN_WIDTH * i + ADU_HISTO_BIN_WIDTH / 2;
ret.y[i] = histogram[i];
ret[0].x[i] = ADU_HISTO_BIN_WIDTH * i + ADU_HISTO_BIN_WIDTH / 2;
ret[0].y[i] = histogram[i];
}
return ret;
}

View File

@@ -15,7 +15,7 @@ public:
void Add(const std::vector<uint64_t>& input);
void Add(const DeviceOutput &output);
const std::vector<uint64_t>& GetHistogram() const;
Plot GetPlot() const;
MultiLinePlot GetPlot() const;
void Restart();
};

View File

@@ -46,6 +46,14 @@ ADD_LIBRARY( JFJochCommon STATIC
ZMQWrappers.cpp ZMQWrappers.h
DatasetSettings.cpp
DatasetSettings.h
ROIMask.cpp
ROIMask.h
ROIElement.cpp
ROIElement.h
ROICircle.cpp
ROICircle.h
ROIBox.cpp
ROIBox.h
)
TARGET_LINK_LIBRARIES(JFJochCommon Compression JFCalibration "$<BUILD_INTERFACE:libzmq-static>" -lrt)

View File

@@ -111,7 +111,18 @@ DatasetSettings &DatasetSettings::Compression(CompressionAlgorithm input) {
}
DatasetSettings &DatasetSettings::SetUnitCell(const std::optional<UnitCell> &cell) {
unit_cell = cell;
if (cell && (cell->a * cell->b * cell->c * cell->alpha * cell->beta * cell->gamma != 0.0)) {
check_min("Angle alpha", cell->alpha, 0);
check_min("Angle beta", cell->beta, 0);
check_min("Angle gamma", cell->gamma, 0);
check_max("Angle alpha", cell->alpha, 360);
check_max("Angle beta", cell->beta, 360);
check_max("Angle gamma", cell->gamma, 360);
unit_cell = cell;
} else
unit_cell.reset();
return *this;
}
@@ -185,11 +196,6 @@ DatasetSettings &DatasetSettings::ImageAppendix(const std::string &input) {
return *this;
}
DatasetSettings &DatasetSettings::ROISummation(const std::optional<ROIRectangle> &input) {
roi_sum = input;
return *this;
}
DatasetSettings &DatasetSettings::PhotonEnergyMultiplayer(float input) {
check_finite("Photon energy multiplier", input);
check_min("Photon energy multiplier", input, 1/64.f);
@@ -254,10 +260,6 @@ std::string DatasetSettings::GetImageAppendix() const {
return image_appendix;
}
std::optional<ROIRectangle> DatasetSettings::GetROISummation() const {
return roi_sum;
}
float DatasetSettings::GetPhotonEnergyMultiplier() const {
return photon_energy_multiplier;
}

View File

@@ -47,7 +47,6 @@ class DatasetSettings {
std::string header_appendix;
std::optional<Coord> omega_rotation_axis;
std::optional<ROIRectangle> roi_sum;
public:
DatasetSettings();
@@ -71,7 +70,6 @@ public:
DatasetSettings& OmegaAxis(const std::optional<Coord> &c);
DatasetSettings& HeaderAppendix(const std::string& input);
DatasetSettings& ImageAppendix(const std::string& input);
DatasetSettings& ROISummation(const std::optional<ROIRectangle>& input);
DatasetSettings& PhotonEnergyMultiplayer(float input);
DatasetSettings& SaveCalibration(bool input);
DatasetSettings& Summation(int64_t input);
@@ -84,7 +82,6 @@ public:
std::optional<Coord> GetOmegaAxis() const;
std::string GetHeaderAppendix() const;
std::string GetImageAppendix() const;
std::optional<ROIRectangle> GetROISummation() const;
float GetPhotonEnergyMultiplier() const;
std::optional<UnitCell> GetUnitCell() const;
int64_t GetSpaceGroupNumber() const;

View File

@@ -8,6 +8,9 @@
#include "GitInfo.h"
#include "DiffractionExperiment.h"
#include "JFJochException.h"
#include "RawToConvertedGeometry.h"
using namespace std::literals::chrono_literals;
#define check_max(param, val, max) if ((val) > (max)) throw JFJochException(JFJochExceptionCategory::InputParameterAboveMax, param)
#define check_min(param, val, min) if ((val) < (min)) throw JFJochException(JFJochExceptionCategory::InputParameterBelowMin, param)
@@ -15,7 +18,8 @@
DiffractionExperiment::DiffractionExperiment() : DiffractionExperiment(DetectorGeometry(8, 2)) {}
DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) : detector(det_setup) {
DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup)
: detector(det_setup), roi_mask(det_setup) {
default_omega_axis = {1, 0, 0};
rad_int_polarization_corr = false;
@@ -63,11 +67,14 @@ DiffractionExperiment::DiffractionExperiment(const DetectorSetup& det_setup) : d
pulsed_source = false;
mode = DetectorMode::Conversion;
max_spot_count = MAX_SPOT_COUNT;
}
// setter functions
DiffractionExperiment &DiffractionExperiment::Detector(const DetectorSetup &input) {
detector = input;
roi_mask = ROIMask(input);
return *this;
}
@@ -230,7 +237,7 @@ DiffractionExperiment& DiffractionExperiment::QSpacingForAzimInt_recipA(float in
}
DiffractionExperiment &DiffractionExperiment::SetUnitCell(const std::optional<UnitCell> &cell) {
dataset.SetUnitCell(cell);
dataset.SetUnitCell(cell);
return *this;
}
@@ -556,11 +563,12 @@ std::chrono::microseconds DiffractionExperiment::GetPreviewPeriod() const {
return std::chrono::microseconds(0);
}
int64_t DiffractionExperiment::GetSpotFindingBin() const {
if (GetImageTime().count() >= 200*1000)
return 1;
int64_t DiffractionExperiment::GetDefaultPlotBinning() const {
auto tmp = 500ms / GetImageTime();
if (GetImageNum() / tmp >= 10)
return tmp; // 1 bin == 500 ms
else
return 200*1000 / GetImageTime().count(); // 1 bin = 1 second
return 1; // no binning if less than 10 bins with 200 ms
}
bool DiffractionExperiment::IsUsingInternalPacketGen() const {
@@ -642,8 +650,15 @@ float DiffractionExperiment::GetQSpacingForAzimInt_recipA() const {
return q_spacing;
}
DiffractionExperiment &DiffractionExperiment::MaxSpotCount(int64_t input) {
check_min("Max spot count", input, 10);
check_max("Max spot count", input, 500);
max_spot_count = input;
return *this;
}
int64_t DiffractionExperiment::GetMaxSpotCount() const {
return MAX_SPOT_COUNT;
return max_spot_count;
}
std::string DiffractionExperiment::GetSampleName() const {
@@ -722,7 +737,6 @@ void DiffractionExperiment::FillMessage(StartMessage &message) const {
message.instrument_name_short = GetInstrumentNameShort();
message.summation = GetSummation();
message.user_data = GetHeaderAppendix();
message.roi_summation_area = GetROISummation();
message.countrate_correction_enabled = false;
message.flatfield_enabled = false;
@@ -737,6 +751,9 @@ void DiffractionExperiment::FillMessage(StartMessage &message) const {
message.series_unique_id = GetSeriesIDString();
message.gain_file_names = detector.GetGainFileNames();
for (const auto &[x, y]: roi_mask.GetROINameMap())
message.roi_names.emplace_back(x);
}
DiffractionExperiment &DiffractionExperiment::ApplyPixelMaskInFPGA(bool input) {
@@ -1052,15 +1069,6 @@ Coord DiffractionExperiment::GetModuleSlowDirection(uint16_t module_number) cons
return detector.GetGeometry().GetSlowDirection(module_number);
}
DiffractionExperiment &DiffractionExperiment::ROISummation(const std::optional<ROIRectangle> &input) {
dataset.ROISummation(input);
return *this;
}
std::optional<ROIRectangle> DiffractionExperiment::GetROISummation() const {
return dataset.GetROISummation();
}
DiffractionExperiment &DiffractionExperiment::ConversionOnFPGA(bool input) {
conversion_on_fpga = input;
return *this;
@@ -1151,3 +1159,20 @@ DiffractionExperiment &DiffractionExperiment::ImportDatasetSettings(const Datase
DatasetSettings DiffractionExperiment::GetDatasetSettings() const {
return dataset;
}
ROIMask &DiffractionExperiment::ROI() {
return roi_mask;
}
const ROIMask &DiffractionExperiment::ROI() const {
return roi_mask;
}
void DiffractionExperiment::ExportROIMask(uint16_t *dest, size_t module_number) const {
if (GetDetectorMode() == DetectorMode::Conversion)
ConvertedToRawGeometry(*this, module_number, dest, roi_mask.GetMask().data());
else {
for (int i = 0; i < RAW_MODULE_SIZE; i++)
dest[i] = UINT16_MAX;
}
}

View File

@@ -16,6 +16,7 @@
#include "DetectorSetup.h"
#include "../image_analysis/SpotFindingSettings.h"
#include "DatasetSettings.h"
#include "ROIMask.h"
enum class DetectorMode {
Conversion, Raw, PedestalG0, PedestalG1, PedestalG2
@@ -99,7 +100,9 @@ class DiffractionExperiment {
// Dataset settings
DatasetSettings dataset;
ROIMask roi_mask;
int64_t max_spot_count;
public:
// Public methods are atomic
DiffractionExperiment();
@@ -168,11 +171,11 @@ public:
DiffractionExperiment& OmegaAxis();
DiffractionExperiment& HeaderAppendix(const std::string& input);
DiffractionExperiment& ImageAppendix(const std::string& input);
DiffractionExperiment& ROISummation(const std::optional<ROIRectangle>& input);
DiffractionExperiment& PhotonEnergyMultiplayer(float input);
DiffractionExperiment& SaveCalibration(bool input);
DiffractionExperiment& Summation(int64_t input);
DiffractionExperiment& FPGAOutputMode(FPGAPixelOutput input);
DiffractionExperiment& MaxSpotCount(int64_t input);
DiffractionExperiment& ImportDatasetSettings(const DatasetSettings& input);
DatasetSettings GetDatasetSettings() const;
@@ -210,8 +213,6 @@ public:
DiffractionExperiment& DetectorDelay(std::chrono::nanoseconds input);
std::chrono::nanoseconds GetDetectorDelay() const;
int64_t GetMaxCompressedSize() const;
int64_t GetDataStreamsNum() const;
@@ -231,7 +232,7 @@ public:
std::chrono::microseconds GetPreviewPeriod() const;
int64_t GetSpotFindingBin() const;
int64_t GetDefaultPlotBinning() const;
bool IsUsingInternalPacketGen() const;
int64_t GetInternalPacketGeneratorImages() const;
@@ -302,7 +303,6 @@ public:
Coord GetOmegaAxis() const;
std::string GetHeaderAppendix() const;
std::string GetImageAppendix() const;
std::optional<ROIRectangle> GetROISummation() const;
float GetPhotonEnergyMultiplier() const;
std::optional<UnitCell> GetUnitCell() const;
int64_t GetSpaceGroupNumber() const;
@@ -324,6 +324,10 @@ public:
CompressionAlgorithm GetCompressionAlgorithm() const;
int64_t GetNumTriggers() const;
int64_t GetImageNumPerTrigger() const;
ROIMask& ROI();
const ROIMask& ROI() const;
void ExportROIMask(uint16_t *v, size_t module_number) const;
};
inline int64_t CalculateStride(const std::chrono::microseconds &frame_time, const std::chrono::microseconds &preview_time) {

View File

@@ -27,18 +27,18 @@ public:
}
}
Plot GetPlot() {
MultiLinePlot GetPlot() {
std::unique_lock<std::mutex> ul(m);
Plot ret;
ret.x.resize(sum.size());
ret.y.resize(sum.size());
MultiLinePlot ret(1);
ret[0].x.resize(sum.size());
ret[0].y.resize(sum.size());
for (int i = 0; i < sum.size(); i++) {
ret.x[i] = static_cast<float>(i);
ret[0].x[i] = static_cast<float>(i);
if (count[i] > 0)
ret.y[i] = static_cast<float>(sum[i]) / count[i];
ret[0].y[i] = static_cast<float>(sum[i]) / count[i];
else
ret.y[i] = 0;
ret[0].y[i] = 0;
}
return ret;
}
@@ -65,15 +65,15 @@ public:
count[bin] += 1;
}
Plot GetPlot() {
MultiLinePlot GetPlot() {
std::unique_lock<std::mutex> ul(m);
Plot ret;
ret.x.resize(count.size());
ret.y.resize(count.size());
MultiLinePlot ret(1);
ret[0].x.resize(count.size());
ret[0].y.resize(count.size());
for (int i = 0; i < count.size(); i++) {
ret.x[i] = min + (i + 0.5f) * spacing;
ret.y[i] = static_cast<float>(count[i]);
ret[0].x[i] = min + (i + 0.5f) * spacing;
ret[0].y[i] = static_cast<float>(count[i]);
}
return ret;
}

View File

@@ -7,8 +7,9 @@
#include <cstdint>
#include <string>
enum class PlotType {BkgEstimate, RadInt, SpotCount, IndexingRate, IndexingRatePerFile, SaturatedPixels,
ErrorPixels, ImageCollectionEfficiency, ReceiverDelay, StrongPixels, ROISum,
enum class PlotType {BkgEstimate, RadInt, RadIntPerFile, SpotCount, IndexingRate, IndexingRatePerFile,
ErrorPixels, ImageCollectionEfficiency, ReceiverDelay, StrongPixels,
ROISum, ROIMaxCount, ROIPixels,
ResEstimation};
struct PlotRequest {
@@ -16,18 +17,12 @@ struct PlotRequest {
uint64_t binning;
};
struct Plot {
struct MultiLinePlotStruct {
std::string title;
std::vector<float> x;
std::vector<float> y;
};
struct RadialIntegrationProfileStruct {
std::string title;
Plot plot;
};
struct RadialIntegrationProfiles {
std::vector<RadialIntegrationProfileStruct> profiles;
};
typedef std::vector<MultiLinePlotStruct> MultiLinePlot;
#endif //JUNGFRAUJOCH_PLOT_H

44
common/ROIBox.cpp Normal file
View File

@@ -0,0 +1,44 @@
// Copyright (2019-2024) Paul Scherrer Institute
#include "ROIBox.h"
#include "JFJochException.h"
ROIBox::ROIBox(const std::string &in_name, int64_t in_x_min, int64_t in_x_max, int64_t in_y_min, int64_t in_y_max)
: ROIElement(in_name), x_min(in_x_min), x_max(in_x_max), y_min(in_y_min), y_max(in_y_max) {
if (x_min < 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "ROI rectangle Xmin negative");
if (y_min < 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "ROI rectangle Ymin negative");
if (x_max < x_min)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "ROI rectangle Xmax must be in range Xmin - (Xdetector - 1)");
if (y_max < y_min)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "ROI rectangle Ymax must be in range Ymin - (Ydetector - 1)");
}
int64_t ROIBox::GetXMin() const {
return x_min;
}
int64_t ROIBox::GetXMax() const {
return x_max;
}
int64_t ROIBox::GetYMin() const {
return y_min;
}
int64_t ROIBox::GetYMax() const {
return y_max;
}
void ROIBox::MarkROI(std::vector<uint16_t> &v, uint16_t value_to_mark, int64_t xpixel, int64_t ypixel) const {
if (v.size() != xpixel * ypixel)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"ROIRectangle::MarkROI mismatch in input array size");
for (int64_t y = y_min; y <= y_max; y++) {
for (int64_t x = x_min; x <= x_max; x++) {
v[y * xpixel + x] = value_to_mark;
}
}
}

22
common/ROIBox.h Normal file
View File

@@ -0,0 +1,22 @@
// Copyright (2019-2024) Paul Scherrer Institute
#ifndef JUNGFRAUJOCH_ROIBOX_H
#define JUNGFRAUJOCH_ROIBOX_H
#include "ROIElement.h"
class ROIBox : public ROIElement {
int64_t x_min;
int64_t x_max;
int64_t y_min;
int64_t y_max;
public:
ROIBox(const std::string &name, int64_t x_min, int64_t x_max, int64_t y_min, int64_t y_max);
[[nodiscard]] int64_t GetXMin() const;
[[nodiscard]] int64_t GetXMax() const;
[[nodiscard]] int64_t GetYMin() const;
[[nodiscard]] int64_t GetYMax() const;
void MarkROI(std::vector<uint16_t> &v, uint16_t value_to_mark, int64_t xpixel, int64_t ypixel) const override;
};
#endif //JUNGFRAUJOCH_ROIBOX_H

42
common/ROICircle.cpp Normal file
View File

@@ -0,0 +1,42 @@
// Copyright (2019-2024) Paul Scherrer Institute
#include <cmath>
#include "ROICircle.h"
#include "JFJochException.h"
ROICircle::ROICircle(const std::string &name, float in_x, float in_y, float in_r_pxl)
: ROIElement(name), center_x(in_x), center_y(in_y), r_pxl(in_r_pxl) {
if (r_pxl <= 0.0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"ROIRectangle::MarkROI mismatch in input array size");
}
float ROICircle::GetX() const {
return center_x;
}
float ROICircle::GetY() const {
return center_y;
}
float ROICircle::GetRadius_pxl() const {
return r_pxl;
}
void ROICircle::MarkROI(std::vector<uint16_t> &v, uint16_t value_to_mark, int64_t xpixel, int64_t ypixel) const {
if (v.size() != xpixel * ypixel)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"ROICircle::MarkROI mismatch in input array size");
float r_pxl_sq = r_pxl * r_pxl;
for (int64_t y = 0; y < ypixel; y++) {
for (int64_t x = 0; x < xpixel; x++) {
float x_fl = static_cast<float>(x) - center_x;
float y_fl = static_cast<float>(y) - center_y;
float dist_from_center_sq = x_fl * x_fl + y_fl * y_fl;
if (dist_from_center_sq <= r_pxl_sq)
v[y * xpixel + x] = value_to_mark;
}
}
}

20
common/ROICircle.h Normal file
View File

@@ -0,0 +1,20 @@
// Copyright (2019-2024) Paul Scherrer Institute
#ifndef JUNGFRAUJOCH_ROICIRCLE_H
#define JUNGFRAUJOCH_ROICIRCLE_H
#include "ROIElement.h"
class ROICircle : public ROIElement {
float center_x;
float center_y;
float r_pxl;
public:
ROICircle(const std::string &name, float x, float y, float r_pxl);
[[nodiscard]] float GetX() const;
[[nodiscard]] float GetY() const;
[[nodiscard]] float GetRadius_pxl() const;
void MarkROI(std::vector<uint16_t> &v, uint16_t value_to_mark, int64_t xpixel, int64_t ypixel) const override;
};
#endif //JUNGFRAUJOCH_ROICIRCLE_H

10
common/ROIElement.cpp Normal file
View File

@@ -0,0 +1,10 @@
// Copyright (2019-2024) Paul Scherrer Institute
#include "ROIElement.h"
ROIElement::ROIElement(const std::string &in_name)
: name(in_name) {}
std::string ROIElement::GetName() const {
return name;
}

20
common/ROIElement.h Normal file
View File

@@ -0,0 +1,20 @@
// Copyright (2019-2024) Paul Scherrer Institute
#ifndef JUNGFRAUJOCH_ROIELEMENT_H
#define JUNGFRAUJOCH_ROIELEMENT_H
#include <string>
#include <vector>
#include <cstdint>
class ROIElement {
protected:
std::string name;
explicit ROIElement(const std::string &name);
public:
[[nodiscard]] std::string GetName() const;
virtual void MarkROI(std::vector<uint16_t> &v, uint16_t value_to_mark, int64_t xpixel, int64_t ypixel) const = 0;
};
#endif //JUNGFRAUJOCH_ROIELEMENT_H

67
common/ROIMask.cpp Normal file
View File

@@ -0,0 +1,67 @@
// Copyright (2019-2024) Paul Scherrer Institute
#include "ROIMask.h"
#include "JFJochException.h"
ROIMask::ROIMask(int64_t in_xpixel, int64_t in_ypixel)
: mask(in_xpixel * in_ypixel, 0),
xpixel(in_xpixel), ypixel(in_ypixel) {
}
ROIMask::ROIMask(const DetectorSetup &setup)
: ROIMask(setup.GetGeometry().GetWidth(), setup.GetGeometry().GetHeight()) {}
void ROIMask::UpdateMask() {
roi_name_map.clear();
for (auto &i: mask)
i = UINT16_MAX;
for (int i = 0; i < boxes.size(); i++) {
boxes[i].MarkROI(mask, i, xpixel, ypixel);
roi_name_map[boxes[i].GetName()] = i;
}
for (int i = 0; i < circles.size(); i++) {
size_t id = boxes.size() + i;
circles[i].MarkROI(mask, id, xpixel, ypixel);
roi_name_map[circles[i].GetName()] = id;
}
}
const std::vector<uint16_t>& ROIMask::GetMask() const {
return mask;
}
const std::map<std::string, uint16_t> &ROIMask::GetROINameMap() const {
return roi_name_map;
}
void ROIMask::SetROIBox(const std::vector<ROIBox> &input) {
if (boxes.size() > box_array_size)
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Limit of box ROIs exceeded");
for (const auto &i: input) {
if (i.GetXMax() >= xpixel)
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "ROI box X coordinate out of detector bounds");
if (i.GetYMax() >= ypixel)
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "ROI box Y coordinate out of detector bounds");
}
boxes = input;
UpdateMask();
}
void ROIMask::SetROICircle(const std::vector<ROICircle> &input) {
if (circles.size() > circle_array_size)
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds, "Limit of circular ROIs exceeded");
circles = input;
UpdateMask();
}
const std::vector<ROIBox> &ROIMask::GetROIBox() const {
return boxes;
}
const std::vector<ROICircle> &ROIMask::GetROICircle() const {
return circles;
}

38
common/ROIMask.h Normal file
View File

@@ -0,0 +1,38 @@
// Copyright (2019-2024) Paul Scherrer Institute
#ifndef JUNGFRAUJOCH_ROIMASK_H
#define JUNGFRAUJOCH_ROIMASK_H
#include <map>
#include <vector>
#include <cstdint>
#include <optional>
#include "DetectorSetup.h"
#include "ROIBox.h"
#include "ROICircle.h"
class ROIMask {
std::vector<ROIBox> boxes;
std::vector<ROICircle> circles;
std::vector<uint16_t> mask;
std::map<std::string, uint16_t> roi_name_map;
int64_t xpixel;
int64_t ypixel;
static constexpr const size_t box_array_size = 32;
static constexpr const size_t circle_array_size = 32;
void UpdateMask();
public:
explicit ROIMask(const DetectorSetup& setup);
ROIMask(int64_t xpixel, int64_t ypixel);
void SetROIBox(const std::vector<ROIBox> &input);
void SetROICircle(const std::vector<ROICircle> &input);
[[nodiscard]] const std::vector<ROIBox>& GetROIBox() const;
[[nodiscard]] const std::vector<ROICircle>& GetROICircle() const;
[[nodiscard]] const std::vector<uint16_t>& GetMask() const;
[[nodiscard]] const std::map<std::string, uint16_t>& GetROINameMap() const;
};
#endif //JUNGFRAUJOCH_ROIMASK_H

View File

@@ -49,19 +49,24 @@ inline Coord RawToConvertedCoordinate(const DiffractionExperiment& experiment, u
}
template<class T>
void ConvertedToRawGeometry(const DiffractionExperiment &experiment, T *destination, const T *source) {
for (size_t module_number = 0; module_number < experiment.GetModulesNum(); module_number++) {
for (size_t line = 0; line < RAW_MODULE_LINES; line++) {
LineConvtToRaw<T>(destination + module_number * RAW_MODULE_SIZE + RAW_MODULE_COLS * line,
source + experiment.GetPixel0OfModule(module_number) +
experiment.GetModuleSlowDirectionStep(module_number) *
(line + ((line > 255) ? 2 : 0)),
experiment.GetModuleFastDirectionStep(module_number)
);
}
void ConvertedToRawGeometry(const DiffractionExperiment &experiment, size_t module_number,
T *destination, const T *source) {
for (size_t line = 0; line < RAW_MODULE_LINES; line++) {
LineConvtToRaw<T>(destination + RAW_MODULE_COLS * line,
source + experiment.GetPixel0OfModule(module_number) +
experiment.GetModuleSlowDirectionStep(module_number) *
(line + ((line > 255) ? 2 : 0)),
experiment.GetModuleFastDirectionStep(module_number)
);
}
}
template<class T>
void ConvertedToRawGeometry(const DiffractionExperiment &experiment, T *destination, const T *source) {
for (size_t module_number = 0; module_number < experiment.GetModulesNum(); module_number++)
ConvertedToRawGeometry(experiment, module_number, destination + module_number * RAW_MODULE_SIZE, source);
}
// Input coord is column + 1024 * (line + 512 * module)
template<class Ts>
void RawToConvertedGeometryAdjustMultipixels(const DiffractionExperiment &experiment, Ts *destination, const Ts *source) {

View File

@@ -17,6 +17,25 @@ template <class T> class StatusVector {
mutable std::mutex m;
std::map<uint32_t, T > content;
uint32_t max_id = 0;
MultiLinePlot GeneratePlot(const std::vector<float> &status, int32_t bin_size) const {
MultiLinePlot ret(1);
if (status.size() == 1) {
ret[0].x = {max_id / 2.0f};
ret[0].y = {status[0]};
} else if (!status.empty()) {
ret[0].y = status;
ret[0].x.resize(status.size());
if (bin_size == 1) {
for (int i = 0; i < status.size(); i++)
ret[0].x[i] = i;
} else {
for (int i = 0; i < status.size(); i++)
ret[0].x[i] = bin_size * (i + 0.5f);
}
}
return ret;
}
public:
void AddElement(uint32_t id, T val) {
std::unique_lock<std::mutex> ul(m);
@@ -26,6 +45,14 @@ public:
}
[[nodiscard]] std::vector<T> ExportArray(T def_value) const {
std::unique_lock<std::mutex> ul(m);
std::vector<T> ret(max_id + 1, def_value);
for (auto &[x,y]: content)
ret[x] = y;
return ret;
}
[[nodiscard]] float Mean() const {
std::unique_lock<std::mutex> ul(m);
size_t count = content.size();
@@ -39,7 +66,7 @@ public:
return NAN;
}
[[nodiscard]] std::vector<float> GetStatus(int32_t bin_size) const {
[[nodiscard]] std::vector<float> GetMeanPerBin(int32_t bin_size) const {
std::unique_lock<std::mutex> ul(m);
if (bin_size <= 0)
@@ -73,22 +100,43 @@ public:
return ret;
}
Plot GetPlot(int64_t bin_size) const {
// GetStatus has mutex, no need to lock again
auto status = GetStatus(bin_size);
[[nodiscard]] std::vector<float> GetMaxPerBin(int32_t bin_size, float default_val = 0.0) const {
std::unique_lock<std::mutex> ul(m);
Plot ret;
if (status.size() == 1) {
ret.x = {max_id / 2.0f};
ret.y = {status[0]};
} else if (!status.empty()) {
ret.y = status;
ret.x.resize(status.size());
for (int i = 0; i < status.size(); i++)
ret.x[i] = bin_size * (i + 0.5f);
if (bin_size <= 0)
throw JFJochException(JFJochExceptionCategory::ArrayOutOfBounds,
"Bin number must be greater than zero");
std::vector<float> ret;
size_t elems = (max_id + 1) / bin_size + (((max_id + 1) % bin_size > 0) ? 1 : 0);
ret.resize(elems);
if (!content.empty()) {
for (int bin = 0; bin < elems; bin++) {
ret[bin] = default_val;
auto it_start = content.lower_bound(bin * bin_size);
auto it_end = content.upper_bound((bin + 1) * bin_size);
if ((it_start != content.end()) && (it_start->first < (bin + 1) * bin_size)) {
for (auto it = it_start; it != it_end; it++) {
if (ret[bin] < it->second)
ret[bin] = it->second;
}
}
}
}
return ret;
}
MultiLinePlot GetMeanPlot(int64_t bin_size) const {
// GetStatus has mutex, no need to lock again
return GeneratePlot(GetMeanPerBin(bin_size), bin_size);
}
MultiLinePlot GetMaxPlot(int64_t bin_size) const {
return GeneratePlot(GetMaxPerBin(bin_size), bin_size);
}
};

View File

@@ -15,8 +15,8 @@ PreviewImage::PreviewImage(const DiffractionExperiment &experiment) :
beam_y(experiment.GetBeamY_pxl()),
pixel_depth_bytes(experiment.GetPixelDepth()),
pixel_is_signed(experiment.IsPixelSigned()),
uncompressed_image(experiment.GetPixelsNum() * experiment.GetPixelDepth()) {
}
uncompressed_image(experiment.GetPixelsNum() * experiment.GetPixelDepth()),
roi_mask(experiment.ROI().GetMask()) {}
void PreviewImage::UpdateImage(const void *in_uncompressed_image,
const std::vector<SpotToSave> &in_spots) {
@@ -41,6 +41,12 @@ void colormap(std::vector<unsigned char>& ret, float v, size_t pixel) {
}
}
void roi(std::vector<unsigned char>& ret, size_t pixel) {
ret[pixel * 3] = 0x7B;
ret[pixel * 3+1] = 0x1F;
ret[pixel * 3+2] = 0xA2;
}
void feature(std::vector<unsigned char>& ret, size_t pixel) {
ret[pixel * 3] = 0xE9;
ret[pixel * 3+1] = 0x1E;
@@ -92,9 +98,13 @@ std::string PreviewImage::GenerateJPEG(const PreviewJPEGSettings &settings) cons
else
v = GenerateRGB<int32_t>((int32_t *) uncompressed_image.data(), xpixel * ypixel, settings.saturation_value,
INT32_MIN);
AddSpots(v);
if (settings.show_spots)
AddSpots(v);
}
if (settings.show_roi)
AddROI(v);
AddBeamCenter(v);
return WriteJPEGToMem(v, xpixel, ypixel, settings.jpeg_quality);
@@ -215,3 +225,13 @@ void PreviewImage::AddSpots(std::vector<uint8_t> &rgb_image) const {
}
}
}
void PreviewImage::AddROI(std::vector<uint8_t> &rgb_image) const {
if (rgb_image.size() != roi_mask.size() * 3)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in array size");
for (int i = 0; i < roi_mask.size(); i++) {
if (roi_mask[i] != UINT16_MAX)
roi(rgb_image, i);
}
}

View File

@@ -12,11 +12,13 @@ struct PreviewJPEGSettings {
int64_t saturation_value = 10;
int64_t jpeg_quality = 70;
bool show_spots = true;
bool show_roi = false;
};
class PreviewImage {
mutable std::mutex m;
std::vector<uint16_t> roi_mask;
std::vector<uint8_t> uncompressed_image;
std::vector<SpotToSave> spots;
size_t xpixel;
@@ -28,6 +30,7 @@ class PreviewImage {
void AddBeamCenter(std::vector<uint8_t> &rgb_image) const;
void AddSpots(std::vector<uint8_t> &rgb_image) const;
void AddROI(std::vector<uint8_t> &rgb_image) const;
public:
explicit PreviewImage(const DiffractionExperiment& experiment);
void UpdateImage(const void *uncompressed_image, const std::vector<SpotToSave> &spots);

View File

@@ -2,26 +2,7 @@
#include "hls_jfjoch.h"
ap_uint<768> extend_18_to_24(ap_int<576> input) {
#pragma HLS INLINE
ap_int<18> tmp16[32];
ap_int<24> tmp24[32];
unpack32(input, tmp16);
for (int i = 0; i < 32; i++) {
if (tmp16[i] == INT18_MAX)
tmp24[i] = INT24_MAX;
else if (tmp16[i] == INT18_MIN)
tmp24[i] = INT24_MIN;
else
tmp24[i] = tmp16[i];
}
return pack32(tmp24);
}
void frame_summation(STREAM_576 &data_in, STREAM_768 &data_out,
void frame_summation(STREAM_768 &data_in, STREAM_768 &data_out,
hls::stream<axis_completion > &s_axis_completion,
hls::stream<axis_completion > &m_axis_completion,
volatile ap_uint<1> &idle) {
@@ -36,14 +17,13 @@ void frame_summation(STREAM_576 &data_in, STREAM_768 &data_out,
ap_uint<24 * 32> memory_0[16384];
#pragma HLS BIND_STORAGE variable=memory_0 type=ram_t2p impl=uram latency=3
packet_576_t packet_in;
packet_768_t packet_out;
packet_768_t packet_in, packet_out;
{
#pragma HLS PROTOCOL fixed
data_in >> packet_in;
ap_wait();
data_out << packet_768_t{.data = packet_in.data, .user = 0, .last = 0};
data_out << packet_in;
ap_wait();
idle = 0;
ap_wait();
@@ -70,7 +50,7 @@ void frame_summation(STREAM_576 &data_in, STREAM_768 &data_out,
for (int i = 0; i < 16384; i++) {
#pragma HLS PIPELINE II=1
ap_int<18> val_0[32];
ap_int<24> val_0[32];
ap_int<24> val_1[32];
unpack32(packet_in.data, val_0);
if (s == 0)
@@ -79,9 +59,9 @@ void frame_summation(STREAM_576 &data_in, STREAM_768 &data_out,
unpack32(memory_0[i], val_1);
for (int j = 0; j < 32; j++) {
if ((val_0[j] == INT18_MIN) || (val_1[j] == INT24_MIN))
if ((val_0[j] == INT24_MIN) || (val_1[j] == INT24_MIN))
val_1[j] = INT24_MIN;
else if ((val_0[j] == INT18_MAX) || (val_1[j] == INT24_MAX))
else if ((val_0[j] == INT24_MAX) || (val_1[j] == INT24_MAX))
val_1[j] = INT24_MAX;
else {
ap_int<25> tmp = val_1[j] + val_0[j];
@@ -108,10 +88,7 @@ void frame_summation(STREAM_576 &data_in, STREAM_768 &data_out,
m_axis_completion << cmpl;
for (int i = 0; i < 16384; i++) {
#pragma HLS PIPELINE II=1
packet_out.data = extend_18_to_24(packet_in.data);
packet_out.user = 0;
packet_out.last = ((i == 16383) ? 1 : 0);
data_out << packet_out;
data_out << packet_in;
data_in >> packet_in;
}
s_axis_completion >> cmpl;

View File

@@ -14,7 +14,7 @@ int test(size_t nframes, int16_t min, int16_t max) {
std::vector<int16_t> input_frame(nframes * RAW_MODULE_SIZE);
STREAM_576 input;
STREAM_768 input;
STREAM_768 output;
hls::stream<axis_completion> compl_in;
hls::stream<axis_completion> compl_out;
@@ -38,20 +38,20 @@ int test(size_t nframes, int16_t min, int16_t max) {
auto input_frame_512 = (ap_uint<512>*) input_frame.data();
ap_uint<576> action_control = 0;
ap_uint<768> action_control = 0;
ACT_REG_NSUMMATION(action_control) = nframes - 1;
input << packet_576_t { .data = action_control, .user = 0 };
input << packet_768_t { .data = action_control, .user = 0 };
for (int i = 0; i < nframes * RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) {
ap_int<16> tmp1[32];
ap_int<18> tmp2[32];
ap_int<24> tmp2[32];
unpack32(input_frame_512[i], tmp1);
for (int j = 0; j < 32; j++)
tmp2[j] = tmp1[j];
input << packet_576_t{.data = pack32(tmp2), .user = 0};
input << packet_768_t{.data = pack32(tmp2), .user = 0};
}
input << packet_576_t { .user = 1 };
input << packet_768_t { .user = 1 };
ap_uint<128> packet_mask;
for (int i = 0; i < 128; i++)

View File

@@ -9,7 +9,7 @@ int test(size_t nframes, int16_t min, int16_t max) {
std::vector<int16_t> input_frame(nframes * RAW_MODULE_SIZE);
STREAM_576 input;
STREAM_768 input;
STREAM_768 output;
hls::stream<axis_completion> compl_in;
hls::stream<axis_completion> compl_out;
@@ -33,20 +33,20 @@ int test(size_t nframes, int16_t min, int16_t max) {
auto input_frame_512 = (ap_uint<512>*) input_frame.data();
ap_uint<576> action_control = 0;
ap_uint<768> action_control = 0;
ACT_REG_NSUMMATION(action_control) = 0;
input << packet_576_t { .data = action_control, .user = 0 };
input << packet_768_t { .data = action_control, .user = 0 };
for (int i = 0; i < nframes * RAW_MODULE_SIZE * sizeof(uint16_t) / 64; i++) {
ap_int<16> tmp1[32];
ap_int<18> tmp2[32];
ap_int<24> tmp2[32];
unpack32(input_frame_512[i], tmp1);
for (int j = 0; j < 32; j++)
tmp2[j] = tmp1[j];
input << packet_576_t{.data = pack32(tmp2), .user = 0};
input << packet_768_t{.data = pack32(tmp2), .user = 0};
}
input << packet_576_t { .user = 1 };
input << packet_768_t { .user = 1 };
ap_uint<128> packet_mask;
for (int i = 0; i < 128; i++)

View File

@@ -26,12 +26,6 @@ namespace hls {
#include "../include/jfjoch_fpga.h"
#define INT18_MAX (131071)
#define INT18_MIN (-131072)
#define INT24_MAX 8388607
#define INT24_MIN (-8388608)
typedef ap_ufixed<16,2, AP_RND_CONV> gainG0_t;
typedef ap_ufixed<16,4, AP_RND_CONV> gainG1_t;
typedef ap_ufixed<16,6, AP_RND_CONV> gainG2_t;
@@ -56,12 +50,10 @@ template<int D,int U,int TI,int TD>
#endif
typedef ap_axiu<512, 1, 1, 1> packet_512_t;
typedef ap_axiu<576, 1, 1, 1> packet_576_t;
typedef ap_axiu<768, 1, 1, 1> packet_768_t;
typedef hls::stream<packet_512_t> AXI_STREAM;
typedef hls::stream<packet_512_t> STREAM_512;
typedef hls::stream<packet_576_t> STREAM_576;
typedef hls::stream<packet_768_t> STREAM_768;
#define ACT_REG_MODE(x) ((x)(32 , 0)) // 32 bit
@@ -287,7 +279,7 @@ void pedestal(STREAM_512 &data_in, STREAM_512 &data_out,
ap_uint<256> *d_hbm_p5_w,
ap_uint<32> hbm_size_bytes);
void jf_conversion(STREAM_512 &data_in, STREAM_576 &data_out,
void jf_conversion(STREAM_512 &data_in, STREAM_768 &data_out,
hls::stream<axis_completion > &s_axis_completion,
hls::stream<axis_completion > &m_axis_completion,
hls::burst_maxi<hbm256_t> d_hbm_p0, hls::burst_maxi<hbm256_t> d_hbm_p1,
@@ -402,7 +394,7 @@ int load_calibration(ap_uint<256> *d_hbm_p0,
hls::stream<ap_axiu<512,1,1,1> > &host_memory_in,
const uint64_t *dma_address_table);
void frame_summation(STREAM_576 &data_in, STREAM_768 &data_out,
void frame_summation(STREAM_768 &data_in, STREAM_768 &data_out,
hls::stream<axis_completion > &s_axis_completion,
hls::stream<axis_completion > &m_axis_completion,
volatile ap_uint<1> &idle);

View File

@@ -18,7 +18,7 @@ namespace hls {
// (HBM) p8, p9 - pedestal G1
// (HBM) p10, p11 - pedestal G2
ap_uint<576> convert(ap_uint<512> data_in,
ap_uint<768> convert(ap_uint<512> data_in,
ap_uint<256> packed_gainG0_1, ap_uint<256> packed_gainG0_2,
ap_uint<256> packed_gainG1_1, ap_uint<256> packed_gainG1_2,
ap_uint<256> packed_gainG2_1, ap_uint<256> packed_gainG2_2,
@@ -32,10 +32,10 @@ ap_uint<576> convert(ap_uint<512> data_in,
#pragma HLS PIPELINE
#pragma HLS INLINE off
const ap_fixed<21, 18, AP_RND_CONV> half = 0.5f;
const ap_fixed<37, 34, AP_RND_CONV> half = 0.5f;
ap_uint<16> in_val[32];
ap_int<18> out_val[32];
ap_int<24> out_val[32];
Loop0: for (int i = 0; i < 512; i++) in_val[i/16][i%16] = data_in[i];
ap_uint<16> pedeG0[32];
@@ -57,17 +57,17 @@ ap_uint<576> convert(ap_uint<512> data_in,
for (int i = 0; i < 32; i++) {
ap_uint<2> gain = in_val[i](15,14);
if (save_raw) for (int j = 0; j < 16; j++) out_val[i][j] = in_val[i][j];
else if ((gain == 0) && (gainG0[i] == 0)) out_val[i] = INT18_MIN; // if G0 gain factor is zero - mask pixel
else if ((gain == 1) && (gainG1[i] == 0)) out_val[i] = INT18_MIN; // if G1 gain factor is zero - mask pixel
else if ((gain == 3) && (gainG2[i] == 0)) out_val[i] = INT18_MIN; // if G2 gain factor is zero - mask pixel
else if (in_val[i] == 0xc000) out_val[i] = fixed_g1 ? INT18_MIN : INT18_MAX; // can saturate G2 - overload (but not when fixed G1)
else if (in_val[i] == 0xffff) out_val[i] = INT18_MIN; //error
else if (in_val[i] == 0x4000) out_val[i] = fixed_g1 ? INT18_MAX : INT18_MIN; // Cannot saturate G1 - error (but it is possible in fixed G1 mode)
else if (gain == 2) out_val[i] = INT18_MIN; // invalid gain
else if ((pedeG0[i] > 16383) && (gain == 0)) out_val[i] = INT18_MIN;
else if ((pedeG1[i] > 16383) && (gain == 1)) out_val[i] = INT18_MIN;
else if ((pedeG2[i] > 16383) && (gain == 3)) out_val[i] = INT18_MIN;
else if ((gain != 1) && fixed_g1) out_val[i] = INT18_MIN; // With fixed gain G1, don't expected anything else!
else if ((gain == 0) && (gainG0[i] == 0)) out_val[i] = INT24_MIN; // if G0 gain factor is zero - mask pixel
else if ((gain == 1) && (gainG1[i] == 0)) out_val[i] = INT24_MIN; // if G1 gain factor is zero - mask pixel
else if ((gain == 3) && (gainG2[i] == 0)) out_val[i] = INT24_MIN; // if G2 gain factor is zero - mask pixel
else if (in_val[i] == 0xc000) out_val[i] = fixed_g1 ? INT24_MIN : INT24_MAX; // can saturate G2 - overload (but not when fixed G1)
else if (in_val[i] == 0xffff) out_val[i] = INT24_MIN; //error
else if (in_val[i] == 0x4000) out_val[i] = fixed_g1 ? INT24_MAX : INT24_MIN; // Cannot saturate G1 - error (but it is possible in fixed G1 mode)
else if (gain == 2) out_val[i] = INT24_MIN; // invalid gain
else if ((pedeG0[i] > 16383) && (gain == 0)) out_val[i] = INT24_MIN;
else if ((pedeG1[i] > 16383) && (gain == 1)) out_val[i] = INT24_MIN;
else if ((pedeG2[i] > 16383) && (gain == 3)) out_val[i] = INT24_MIN;
else if ((gain != 1) && fixed_g1) out_val[i] = INT24_MIN; // With fixed gain G1, don't expected anything else!
else {
ap_fixed<18,16, AP_RND_CONV> val_diff = 0;
ap_ufixed<25,6,AP_RND_CONV> val_gain = 0;
@@ -86,9 +86,9 @@ ap_uint<576> convert(ap_uint<512> data_in,
val_gain = gainG2[i];
}
ap_fixed<21, 18, AP_RND_CONV> val_result = (val_diff * val_gain) * one_over_energy_in_keV;
if (val_result > INT18_MAX)
out_val[i] = INT18_MAX;
ap_fixed<37, 34, AP_RND_CONV> val_result = (val_diff * val_gain) * one_over_energy_in_keV;
if (val_result > INT24_MAX)
out_val[i] = INT24_MAX;
else if (val_result >= 0)
out_val[i] = val_result + half;
else
@@ -99,7 +99,7 @@ ap_uint<576> convert(ap_uint<512> data_in,
return pack32(out_val);
}
void jf_conversion(STREAM_512 &data_in, STREAM_576 &data_out,
void jf_conversion(STREAM_512 &data_in, STREAM_768 &data_out,
hls::stream<axis_completion > &s_axis_completion,
hls::stream<axis_completion > &m_axis_completion,
hls::burst_maxi<hbm256_t> d_hbm_p0, hls::burst_maxi<hbm256_t> d_hbm_p1,
@@ -143,7 +143,7 @@ void jf_conversion(STREAM_512 &data_in, STREAM_576 &data_out,
max_read_burst_length=16 max_write_burst_length=2 latency=120 num_write_outstanding=2 num_read_outstanding=9
packet_512_t packet_in;
packet_576_t packet_out;
packet_768_t packet_out;
{
#pragma HLS PROTOCOL fixed
data_in >> packet_in;
@@ -249,7 +249,7 @@ void jf_conversion(STREAM_512 &data_in, STREAM_576 &data_out,
#pragma HLS PIPELINE II=1
data_in >> packet_in;
ap_uint<16> val_in[32];
ap_int<18> val_out[32];
ap_int<24> val_out[32];
unpack32(packet_in.data, val_in);
for (int i = 0; i < 32; i++)
val_out[i] = val_in[i];

View File

@@ -71,6 +71,9 @@ typedef __u64 uint64_t;
#define FPGA_ROI_COUNT 64
#define INT24_MAX (8388607)
#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))
@@ -241,8 +244,8 @@ struct ModuleStatistics {
};
struct ROICount {
uint64_t sum;
int64_t sum2;
int64_t sum;
uint64_t sum2;
float sum_x_weighted;
float sum_y_weighted;
uint32_t good_pixels;

View File

@@ -172,31 +172,6 @@ inline std::pair<const uint8_t *, size_t> GetCBORByteString(CborValue &value) {
return {ptr, len};
}
inline ROIRectangle GetROIRectangle(CborValue &value) {
ROIRectangle ret{};
CborValue map_value;
if (GetCBORMapLen(value) != 4)
throw JFJochException(JFJochExceptionCategory::CBORError, "ROI Rectangle must be 4 values");
cborErr(cbor_value_enter_container(&value, &map_value));
while (!cbor_value_at_end(&map_value)) {
auto key = GetCBORString(map_value);
if (key == "x_min")
ret.x_min = GetCBORUInt(map_value);
else if (key == "x_max")
ret.x_max = GetCBORUInt(map_value);
else if (key == "y_min")
ret.y_min = GetCBORUInt(map_value);
else if (key == "y_max")
ret.y_max = GetCBORUInt(map_value);
else
throw JFJochException(JFJochExceptionCategory::CBORError, "Unexpected entry in ROI");
}
cborErr(cbor_value_leave_container(&value, &map_value));
return ret;
}
inline void GetCBORFloatArray(CborValue &value, std::vector<float> &v) {
if (GetCBORTag(value) != TagFloatLE)
throw JFJochException(JFJochExceptionCategory::CBORError, "Incorrect array type tag");
@@ -493,8 +468,8 @@ bool CBORStream2Deserializer::ProcessImageMessageElement(CborValue &value) {
data_message.bkg_estimate = GetCBORFloat(value);
else if (key == "adu_histogram")
GetCBORUInt64Array(value, data_message.adu_histogram);
else if (key == "roi_sum")
data_message.roi_sum = GetCBORInt(value);
else if (key == "roi_integrals")
ProcessROIElementMap(value);
else {
if (cbor_value_is_tag(&value))
cbor_value_advance(&value);
@@ -603,6 +578,41 @@ void CBORStream2Deserializer::ProcessUnitCellElement(CborValue &value) {
start_message.unit_cell = unit_cell;
}
void CBORStream2Deserializer::ProcessROIElementMap(CborValue &value) {
CborValue map_value;
cborErr(cbor_value_enter_container(&value, &map_value));
while (! cbor_value_at_end(&map_value))
ProcessROIElement(map_value);
cborErr(cbor_value_leave_container(&value, &map_value));
}
void CBORStream2Deserializer::ProcessROIElement(CborValue &value) {
ROIMessage msg{};
// key
const std::string roi_name = GetCBORString(value);
// value
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 == "sum")
msg.sum = GetCBORInt(map_value);
else if (key == "sum_square")
msg.sum_square = GetCBORUInt(map_value);
else if (key == "max_count")
msg.max_count = GetCBORInt(map_value);
else if (key == "pixels")
msg.pixels = GetCBORUInt(map_value);
else
cbor_value_advance(&map_value);
}
cborErr(cbor_value_leave_container(&value, &map_value));
data_message.roi[roi_name] = msg;
}
void CBORStream2Deserializer::ProcessStartUserData(CborValue &value) {
try {
@@ -637,6 +647,10 @@ void CBORStream2Deserializer::ProcessStartUserData(CborValue &value) {
}
if (j.contains("space_group_number"))
start_message.space_group_number = j["space_group_number"];
if (j.contains("gain_file_names"))
start_message.gain_file_names = j["gain_file_names"];
if (j.contains("roi_names"))
start_message.roi_names = j["roi_names"];
} catch (const std::exception &e) {
throw JFJochException(JFJochExceptionCategory::CBORError, "Cannot parse user_data as valid JSON " + std::string(e.what()));
@@ -742,10 +756,6 @@ bool CBORStream2Deserializer::ProcessStartMessageElement(CborValue &value) {
start_message.storage_cell_number = GetCBORUInt(value);
else if (key == "storage_cell_delay")
start_message.storage_cell_delay_ns = GetRational(value).first;
else if (key == "roi_sum_area")
start_message.roi_summation_area = GetROIRectangle(value);
else if (key == "gain_file_names")
GetCBORStringArray(value, start_message.gain_file_names);
else if (key == "calibration")
ProcessCalibration(value);
else {

View File

@@ -39,6 +39,8 @@ private:
void ProcessPixelMaskElement(CborValue &value);
void ProcessRadIntResultElement(CborValue &value);
void ProcessADUHistogramElement(CborValue &value);
void ProcessROIElement(CborValue &value);
void ProcessROIElementMap(CborValue &value);
void ProcessUnitCellElement(CborValue &value);
void ProcessStartUserData(CborValue &value);
bool ProcessImageMessageElement(CborValue &value);

View File

@@ -196,17 +196,6 @@ inline void CBOR_ENC(CborEncoder &encoder, const char* key, const std::vector<Sp
cborErr(cbor_encoder_close_container(&encoder, &arrayEncoder));
}
inline void CBOR_ENC(CborEncoder &encoder, const char* key, const ROIRectangle& roi) {
CborEncoder mapEncoder;
cborErr(cbor_encode_text_stringz(&encoder, key));
cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, 4));
CBOR_ENC(mapEncoder, "x_min", roi.x_min);
CBOR_ENC(mapEncoder, "x_max", roi.x_max);
CBOR_ENC(mapEncoder, "y_min", roi.y_min);
CBOR_ENC(mapEncoder, "y_max", roi.y_max);
cborErr(cbor_encoder_close_container(&encoder, &mapEncoder));
}
inline void CBOR_ENC(CborEncoder &encoder, const char* key, const CompressedImage& message) {
CborEncoder mapEncoder;
@@ -256,6 +245,32 @@ inline void CBOR_ENC(CborEncoder &encoder, const char* key, const std::vector<st
cborErr(cbor_encoder_close_container(&encoder, &arrayEncoder));
}
inline void CBOR_ENC(CborEncoder &encoder, const char* key, const ROIMessage &val) {
CborEncoder mapEncoder;
cborErr(cbor_encode_text_stringz(&encoder, key));
cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, 4));
CBOR_ENC(mapEncoder, "sum", val.sum);
CBOR_ENC(mapEncoder, "sum_square", val.sum_square);
CBOR_ENC(mapEncoder, "max_count", val.max_count);
CBOR_ENC(mapEncoder, "pixels", val.pixels);
cborErr(cbor_encoder_close_container(&encoder, &mapEncoder));
}
inline void CBOR_ENC(CborEncoder &encoder, const char* key, const std::map<std::string, ROIMessage> &map) {
CborEncoder mapEncoder;
if (map.empty())
return;
cborErr(cbor_encode_text_stringz(&encoder, key));
cborErr(cbor_encoder_create_map(&encoder, &mapEncoder, map.size()));
for (const auto &[x, y]: map)
CBOR_ENC(mapEncoder, x.c_str(), y);
cborErr(cbor_encoder_close_container(&encoder, &mapEncoder));
}
inline void CBOR_ENC_UNIT_CELL(CborEncoder &encoder, const char* key, const UnitCell &val) {
CborEncoder mapEncoder;
@@ -297,6 +312,8 @@ inline void CBOR_ENC_START_USER_DATA(CborEncoder& encoder, const char* key,
j["total_flux"] = message.total_flux.value();
j["omega_rotation_axis"] = {message.omega.axis[0], message.omega.axis[1], message.omega.axis[2]};
j["space_group_number"] = message.space_group_number;
j["roi_names"] = message.roi_names;
j["gain_file_names"] = message.gain_file_names;
auto str = j.dump();
CBOR_ENC(encoder, key, str);
@@ -358,8 +375,6 @@ void CBORStream2Serializer::SerializeSequenceStart(const StartMessage& message)
CBOR_ENC(mapEncoder, "storage_cell_number", message.storage_cell_number);
CBOR_ENC_RATIONAL(mapEncoder, "storage_cell_delay", message.storage_cell_delay_ns, 1000*1000*1000UL);
CBOR_ENC(mapEncoder, "roi_sum_area", message.roi_summation_area);
switch (message.pixel_bit_depth) {
case 8:
CBOR_ENC(mapEncoder, "image_dtype", message.pixel_signed ? "int8" : "uint8");
@@ -378,7 +393,6 @@ void CBORStream2Serializer::SerializeSequenceStart(const StartMessage& message)
CBOR_ENC(mapEncoder, "az_int_bin_number", message.az_int_bin_number);
CBOR_ENC(mapEncoder, "az_int_bin_to_q", message.az_int_bin_to_q);
CBOR_ENC(mapEncoder, "summation", message.summation);
CBOR_ENC(mapEncoder, "gain_file_names", message.gain_file_names);
if (!message.calibration.empty())
CBOR_ENC(mapEncoder, "calibration", message.calibration);
@@ -447,10 +461,8 @@ void CBORStream2Serializer::SerializeImage(const DataMessage& message) {
CBOR_ENC(mapEncoder, "data_collection_efficiency", message.image_collection_efficiency);
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);
if (message.roi_sum)
CBOR_ENC(mapEncoder, "roi_sum", message.roi_sum.value());
CBOR_ENC(mapEncoder, "data", message.image);
cborErr(cbor_encoder_close_container(&encoder, &mapEncoder));

View File

@@ -17,13 +17,6 @@
constexpr const uint64_t user_data_release = 3;
constexpr const uint64_t user_data_magic_number = 0x52320000UL | user_data_release;
struct ROIRectangle {
size_t x_min;
size_t x_max;
size_t y_min;
size_t y_max;
};
struct CompressedImage {
const uint8_t *data;
size_t size; // Including compression
@@ -45,6 +38,13 @@ struct CompressedImage {
std::vector<uint8_t> tmp_storage; // This should be private but will brake initialization list - need to do that properly later
};
struct ROIMessage {
int64_t sum;
uint64_t sum_square;
int64_t max_count;
uint64_t pixels;
};
struct DataMessage {
int64_t number = INT64_MIN;
CompressedImage image;
@@ -82,9 +82,10 @@ struct DataMessage {
std::optional<float> resolution_estimation;
std::optional<int64_t> roi_sum;
std::optional<uint64_t> xfel_pulse_id;
std::optional<uint64_t> xfel_event_code;
std::map<std::string, ROIMessage> roi;
};
struct GoniometerAxis {
@@ -146,6 +147,8 @@ struct StartMessage {
uint64_t series_id;
std::vector<std::string> gain_file_names;
std::vector<std::string> roi_names;
GoniometerAxis omega;
float detector_translation[3];
@@ -164,7 +167,6 @@ struct StartMessage {
std::optional<float> total_flux;
std::optional<float> attenuator_transmission;
std::optional<ROIRectangle> roi_summation_area;
size_t approx_size = 1024*1024;
// Use function below to update approx_size

View File

@@ -23,6 +23,7 @@
"react-dom": "^18.2.0",
"react-plotly.js": "^2.6.0",
"react-scripts": "^5.0.1",
"react-zoom-pan-pinch": "^3.4.3",
"typescript": "^4.9.4"
},
"devDependencies": {
@@ -15890,6 +15891,19 @@
"react-dom": ">=16.6.0"
}
},
"node_modules/react-zoom-pan-pinch": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.4.3.tgz",
"integrity": "sha512-x5MFlfAx2D6NTpZu8OISqc2nYn4p+YEaM1p21w7S/VE1wbVzK8vRzTo9Bj1ydufa649MuP7JBRM3vvj1RftFZw==",
"engines": {
"node": ">=8",
"npm": ">=5"
},
"peerDependencies": {
"react": "*",
"react-dom": "*"
}
},
"node_modules/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -30534,6 +30548,12 @@
"prop-types": "^15.6.2"
}
},
"react-zoom-pan-pinch": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.4.3.tgz",
"integrity": "sha512-x5MFlfAx2D6NTpZu8OISqc2nYn4p+YEaM1p21w7S/VE1wbVzK8vRzTo9Bj1ydufa649MuP7JBRM3vvj1RftFZw==",
"requires": {}
},
"read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",

View File

@@ -19,6 +19,7 @@
"react-dom": "^18.2.0",
"react-plotly.js": "^2.6.0",
"react-scripts": "^5.0.1",
"react-zoom-pan-pinch": "^3.4.3",
"typescript": "^4.9.4"
},
"scripts": {

View File

@@ -15,6 +15,7 @@ import DetectorStatus from "./components/DetectorStatus";
import Paper from "@mui/material/Paper";
import PreviewImage from "./components/PreviewImage";
import PreviewImageSettings from "./components/PreviewImageSettings";
import ROI from "./components/ROI";
const jfjoch_theme = createTheme({
palette: {
@@ -26,7 +27,8 @@ const jfjoch_theme = createTheme({
type MyState = {
show_detector_setup: boolean,
show_module_calibration: boolean,
show_preview: boolean
show_preview: boolean,
show_roi_setup: boolean
}
type MyProps = {}
@@ -36,7 +38,8 @@ class App extends Component<MyProps, MyState> {
state : MyState = {
show_detector_setup: false,
show_module_calibration: false,
show_preview: true
show_preview: true,
show_roi_setup: false
}
showPreviewToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
@@ -51,6 +54,10 @@ class App extends Component<MyProps, MyState> {
this.setState({show_module_calibration: event.target.checked});
}
showROISetupToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
this.setState({show_roi_setup: event.target.checked});
}
renderTitleWithSwitch = (name: string, checked: boolean, func: ((event: React.ChangeEvent<HTMLInputElement>) => void)) => {
return <Grid item xs={12}>
<Paper style={{textAlign: 'center'}} sx={{height: 60, width: '100%'}} component={Stack}
@@ -100,10 +107,10 @@ class App extends Component<MyProps, MyState> {
this.renderTitleWithSwitch("Live image preview", this.state.show_preview, this.showPreviewToggle)
}
<Grid item xs={9}>
{this.state.show_preview ? <PreviewImage/> : "" }
{this.state.show_preview ? <PreviewImage/> : ""}
</Grid>
<Grid item xs={3}>
{this.state.show_preview ? <PreviewImageSettings/> : "" }
{this.state.show_preview ? <PreviewImageSettings/> : ""}
</Grid>
<br/><br/>
{
@@ -126,11 +133,22 @@ class App extends Component<MyProps, MyState> {
<Grid item xs={4}>
{this.state.show_detector_setup ? <DetectorStatus/> : ""}
</Grid>
<br/><br/>
{
this.renderTitleWithSwitch("Region of interest (ROI)",
this.state.show_roi_setup, this.showROISetupToggle)
}
<Grid item xs={12}>
{this.state.show_roi_setup ? <ROI/> : ""}
</Grid>
</Grid>
</div>
<br/>
<center>Developed at Paul Scherrer Institute (2019-2024). Main author: <a href="mailto:filip.leonarski@psi.ch">Filip Leonarski</a> <br/>
For more information see <a href="https://doi.org/10.1107/S1600577522010268"><i>J. Synchrotron Rad.</i> (2023). <b>30</b>, 227234</a> </center>
<center>Developed at Paul Scherrer Institute (2019-2024). Main author: <a
href="mailto:filip.leonarski@psi.ch">Filip Leonarski</a> <br/>
For more information see <a href="https://doi.org/10.1107/S1600577522010268"><i>J. Synchrotron
Rad.</i> (2023). <b>30</b>, 227234</a></center>
<br/>
</ThemeProvider>
}

View File

@@ -1,10 +1,9 @@
import React, {Component} from 'react';
import PlotWrapper from "./PlotWrapper";
import {DefaultService, plot} from "../openapi";
import {DefaultService, plots} from "../openapi";
import MultiLinePlotWrapper from "./MultiLinePlotWrapper";
export enum PlotType {
SATURATED_PIXELS,
COLLECTION_EFFICIENCY,
SPOT_COUNT,
RAD_INT,
@@ -16,6 +15,7 @@ export enum PlotType {
RECEIVER_DELAY,
STRONG_PIXELS,
ROI_SUM,
ROI_MAX_COUNT,
RES_ESTIMATION
}
@@ -27,107 +27,128 @@ type MyProps = {
};
type MyState = {
plot : plot,
plots : plots,
connection_error: boolean
}
type PlotlyPlot = {
x: number[],
y: number[],
type: string,
mode: string,
name: string
}
type PlotlyData = PlotlyPlot[]
class DataProcessingPlot extends Component<MyProps, MyState> {
interval: undefined | NodeJS.Timer;
state: MyState = {
plot: {
x: [0,100,200,300,400,500],
y: [0.1, 0.3,0.5, 0.2, 0.0, 0.1]
plots: {
plot : [
{
x: [0, 100, 200, 300, 400, 500],
y: [0.1, 0.3, 0.5, 0.2, 0.0, 0.1],
title: "Example"
}
]
},
connection_error: true
}
getValues() {
switch(this.props.type) {
case PlotType.SATURATED_PIXELS:
DefaultService.postPlotSaturatedPixel({binning: this.props.binning})
.then(data => this.setState({plot: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.ERROR_PIXELS:
DefaultService.postPlotErrorPixel({binning: this.props.binning})
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.STRONG_PIXELS:
DefaultService.postPlotStrongPixel({binning: this.props.binning})
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.COLLECTION_EFFICIENCY:
DefaultService.postPlotImageCollectionEfficiency({binning: this.props.binning})
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.SPOT_COUNT:
DefaultService.postPlotSpotCount({binning: this.props.binning})
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.BKG_ESTIMATE:
DefaultService.postPlotBkgEstimate({binning: this.props.binning})
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.RAD_INT:
DefaultService.getPlotRadInt()
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.INDEXING_RATE_PER_FILE:
DefaultService.getPlotIndexingRatePerFile()
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.INDEXING_RATE:
DefaultService.postPlotIndexingRate({binning: this.props.binning})
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.RECEIVER_DELAY:
DefaultService.postPlotReceiverDelay({binning: this.props.binning})
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.ROI_SUM:
DefaultService.postPlotRoiSum({binning: this.props.binning})
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.ROI_MAX_COUNT:
DefaultService.postPlotRoiMaxCount({binning: this.props.binning})
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.RES_ESTIMATION:
DefaultService.getPlotResolutionEstimateHistogram()
.then(data => this.setState({plot: data, connection_error: false}))
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
break;
case PlotType.RAD_INT_PER_FILE:
DefaultService.getPlotRadIntPerFile()
.then(data => this.setState({plots: data, connection_error: false}))
.catch(error => {
this.setState({connection_error: true});
});
}
}
componentDidMount() {
@@ -140,12 +161,23 @@ class DataProcessingPlot extends Component<MyProps, MyState> {
}
render() {
if (this.state.plot !== undefined)
return <PlotWrapper xaxis={this.props.xlabel} yaxis={this.props.ylabel} x={this.state.plot.x}
y={this.state.plot.y}/>
else
return <div/>;
if (this.state.connection_error
|| (this.state.plots === undefined)
|| (this.state.plots.plot === null)
|| (this.state.plots.plot.length === 0))
return <div>No plots available</div>;
let data: PlotlyData = [];
this.state.plots.plot.map(d =>
data.push({
x: d.x,
y: d.y,
type: "scatter",
mode: "line",
name: d.title
}));
return <MultiLinePlotWrapper xaxis={this.props.xlabel} yaxis={this.props.ylabel} data={data}/>
}
}

View File

@@ -6,7 +6,6 @@ import DataProcessingPlot, {PlotType} from "./DataProcessingPlot";
import Toolbar from "@mui/material/Toolbar";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import RadialIntegrationProfilePlots from "./RadialIntegrationProfilePlots";
import Select, {SelectChangeEvent} from "@mui/material/Select";
type MyProps = {
@@ -53,7 +52,7 @@ class DataProcessingPlots extends Component<MyProps, MyState> {
this.setState({type: PlotType.RAD_INT_PER_FILE, xlabel: "Q [&#8491;<sup>-1</sup>]", ylabel: "Photon count"});
break;
case "6":
this.setState({type: PlotType.SATURATED_PIXELS, xlabel: "Image number", ylabel: "Count"});
this.setState({type: PlotType.ROI_MAX_COUNT, xlabel: "Image number", ylabel: "Photon count"});
break;
case "7":
this.setState({type: PlotType.COLLECTION_EFFICIENCY, xlabel: "Image number", ylabel: "Efficiency"});
@@ -97,11 +96,11 @@ class DataProcessingPlots extends Component<MyProps, MyState> {
<MenuItem value={2}>Spot count</MenuItem>
<MenuItem value={3}>Azimuthal integration profile</MenuItem>
<MenuItem value={11}>ROI area sum</MenuItem>
<MenuItem value={6}>ROI area max count</MenuItem>
<MenuItem value={12}>Crystal resolution histogram</MenuItem>
<MenuItem value={4}>Indexing rate (per file)</MenuItem>
<MenuItem value={5}>Azimuthal integration profile (per file)</MenuItem>
<MenuItem value={6}>Saturated pixels</MenuItem>
<MenuItem value={8}>Error pixels</MenuItem>
<MenuItem value={8}>Error and saturated pixels</MenuItem>
<MenuItem value={10}>Strong pixels (for spot finding)</MenuItem>
<MenuItem value={7}>Image collection efficiency</MenuItem>
<MenuItem value={9}>Receiver delay (internal debugging)</MenuItem>
@@ -117,13 +116,13 @@ class DataProcessingPlots extends Component<MyProps, MyState> {
label="Binning"
>
<MenuItem value={0}>
<em>Auto binning (200 ms)</em>
<em>Auto binning</em>
</MenuItem>
<MenuItem value={1}>1 image</MenuItem>
<MenuItem value={10}>10 images</MenuItem>
<MenuItem value={100}>100 images</MenuItem>
<MenuItem value={200}>200 images</MenuItem>
<MenuItem value={500}>500 images</MenuItem>
<MenuItem value={1000}>1000 images</MenuItem>
<MenuItem value={2000}>2000 images</MenuItem>
<MenuItem value={5000}>5000 images</MenuItem>
<MenuItem value={10000}>10000 images</MenuItem>
</Select>
@@ -131,12 +130,8 @@ class DataProcessingPlots extends Component<MyProps, MyState> {
</Grid>
</Toolbar>
<Box sx={{width:"95%", height: 550}} >
{
(this.state.type === PlotType.RAD_INT_PER_FILE) ?
<RadialIntegrationProfilePlots /> :
<DataProcessingPlot type={this.state.type} xlabel={this.state.xlabel} ylabel={this.state.ylabel}
binning={Number(this.state.binning)}/>
}
<DataProcessingPlot type={this.state.type} xlabel={this.state.xlabel} ylabel={this.state.ylabel}
binning={Number(this.state.binning)}/>
</Box>
</Paper>
}

View File

@@ -37,7 +37,6 @@ class DetectorSelection extends Component<MyProps, MyState> {
connection_error: false
}))
.catch(error => {
console.log(error);
this.setState({connection_error: true});
});
}
@@ -48,7 +47,6 @@ class DetectorSelection extends Component<MyProps, MyState> {
connection_error: false
}))
.catch(error => {
console.log(error);
this.setState({connection_error: true});
});
}

View File

@@ -221,7 +221,6 @@ class DetectorSettings extends Component<MyProps, MyState> {
connection_error: false
}))
.catch(error => {
console.log(error);
this.setState({connection_error: true});
});
}

View File

@@ -1,30 +0,0 @@
import React, {Component} from 'react';
import Plot from "react-plotly.js";
// Not using TypeScript, as plotly is not TypeScript :(
class PlotWrapper extends Component {
render() {
return <Plot
style={{width: "100%", height: "100%"}}
data={[
{
x: this.props.x,
y: this.props.y,
type: 'scatter',
mode: 'lines',
marker: {color: "303f9f"},
},
]}
layout={ {
xaxis: {title: this.props.xaxis},
yaxis: {title: this.props.yaxis},
uirevision: true
} }
config = {{responsive: true}}
/>
}
}
export default PlotWrapper;

View File

@@ -2,6 +2,7 @@ import React, {Component} from 'react';
import Paper from "@mui/material/Paper";
import {handleErrors} from "./handleErrors";
import {Stack} from "@mui/material";
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
type MyProps = {}
@@ -47,7 +48,11 @@ class PreviewImage extends Component<MyProps, MyState> {
{(!this.state.connection_error && (this.state.s_url !== null)) ?
<div>
<br/>
<img src={this.state.s_url} alt="Live preview" style={{maxWidth: "90%", maxHeight: "90%"}}/>
<TransformWrapper>
<TransformComponent>
<img src={this.state.s_url} alt="Live preview" style={{maxWidth: "90%", maxHeight: "90%"}}/>
</TransformComponent>
</TransformWrapper>
<br/>
</div>
: "Preview not available"}

View File

@@ -15,8 +15,9 @@ class PreviewImageSettings extends Component<MyProps, MyState> {
state : MyState = {
s: {
saturation: 10,
jpeg_quality: 70,
show_spots: false
jpeg_quality: 95,
show_spots: false,
show_roi: false
},
connection_error: true
}
@@ -65,6 +66,13 @@ class PreviewImageSettings extends Component<MyProps, MyState> {
this.putValues2(x);
}
showROIToggle = (event: React.ChangeEvent<HTMLInputElement>) => {
let x = this.state;
x.s.show_roi = event.target.checked;
this.putValues2(x);
}
render() {
return <Paper style={{textAlign: 'center'}} sx={{ height: '60%', width: '100%' }}>
@@ -79,7 +87,9 @@ class PreviewImageSettings extends Component<MyProps, MyState> {
value={Number(this.state.s.saturation)} min={1} max={80}
onChange={this.setSaturation} valueLabelDisplay="auto"/><br/>
<Switch disabled={this.state.connection_error} checked={this.state.s.show_spots}
onChange={this.showSpotsToggle} name="Show spots"/> Show spots
onChange={this.showSpotsToggle} name="Show spots"/> Show spots<br/>
<Switch disabled={this.state.connection_error} checked={this.state.s.show_roi}
onChange={this.showROIToggle} name="Show ROI"/> Show ROI<br/>
</Grid>
<Grid item xs={1}/>
</Grid>

View File

@@ -0,0 +1,260 @@
import React from 'react';
import Paper from '@mui/material/Paper';
import {DefaultService, roi_box, roi_box_list, roi_circle, roi_circle_list} from "../openapi";
import {Grid} from "@mui/material";
import Button from "@mui/material/Button";
import {DataGrid, GridActionsCellItem, GridRowModel} from "@mui/x-data-grid";
import DeleteIcon from '@mui/icons-material/DeleteOutlined';
type MyProps = {
};
type MyState = {
box: roi_box_list;
circle: roi_circle_list;
};
function getRandomInt(max : number) {
return Math.floor(Math.random() * max);
}
class ROI extends React.Component<MyProps, MyState> {
state : MyState = {
box: { rois: [] },
circle: { rois: []},
}
componentDidMount() {
this.getValues();
}
checkDuplicatesBox = (input : roi_box[]) => {
let roi_names : string[] = [];
input.map(element => roi_names.push(element.name));
this.state.circle.rois?.map(element => roi_names.push(element.name));
const duplicates = roi_names.filter((item, index) => roi_names.indexOf(item) !== index);
return (duplicates.length !== 0);
}
checkDuplicatesCircle = (input : roi_circle[]) => {
let roi_names : string[] = [];
input.map(element => roi_names.push(element.name));
this.state.box.rois?.map(element => roi_names.push(element.name));
const duplicates = roi_names.filter((item, index) => roi_names.indexOf(item) !== index);
return (duplicates.length !== 0);
}
validateBoxRow = (input: roi_box) => {
return !((input.min_x_pxl < 0)
|| (input.max_x_pxl < input.min_x_pxl)
|| (input.min_y_pxl < 0)
|| (input.max_y_pxl < input.min_y_pxl));
}
validateCircleRow = (input: roi_circle) => {
return (input.radius_pxl > 0);
}
uploadButton = () => { this.putValues(); }
downloadButton = () => { this.getValues(); }
addBoxButton = () => {
if (this.state.box.rois === undefined) {
} else {
this.setState({
box: {
rois: [
...this.state.box.rois,
{
name: "new_roi" + getRandomInt(99999),
min_x_pxl: 0,
max_x_pxl: 0,
min_y_pxl: 0,
max_y_pxl: 0
}
]
}
});
}
}
addCircleButton = () => {
if (this.state.circle.rois === undefined) {
} else {
this.setState({
circle: {
rois: [
...this.state.circle.rois,
{
name: "new_roi" + getRandomInt(65536),
center_x_pxl: 0,
center_y_pxl: 0,
radius_pxl: 10
}
]
}
});
}
}
putValues = () => {
DefaultService.putRoiBox(this.state.box).catch(error => {} );
DefaultService.putRoiCircle(this.state.circle).catch(error => {} );
}
getValues = () => {
DefaultService
.getRoiBox()
.then(data => this.setState({box: data}))
.catch(error => {});
DefaultService
.getRoiCircle()
.then(data => this.setState({circle: data}))
.catch(error => {});
}
handleDeleteBoxROIClick = (id: GridRowModel) => () => {
if (this.state.box.rois !== undefined) {
this.setState({
box: {
rois: [
...this.state.box.rois.filter((row) => row.name !== id.id),
]
}
});
}
};
handleDeleteCircleROIClick = (id: GridRowModel) => () => {
if (this.state.circle.rois !== undefined) {
this.setState({
circle: {
rois: this.state.circle.rois.filter((row) => row.name !== id.id),
}
});
}
};
processRowBoxUpdate = (newRow: roi_box, oldRow: roi_box) => {
if (this.state.box.rois !== undefined) {
let new_state = this.state.box.rois.map(item => item === oldRow ? newRow : item);
if (this.checkDuplicatesBox(new_state))
throw new Error("Duplicate ROI name");
if (!this.validateBoxRow(newRow))
throw new Error("Wrong numeric parameters");
this.setState({ box: {rois: new_state } });
}
return newRow;
};
processRowCircleUpdate = (newRow: roi_circle, oldRow: roi_circle) => {
if (this.state.circle.rois !== undefined) {
let new_state = this.state.circle.rois.map(item => item === oldRow ? newRow : item);
if (this.checkDuplicatesCircle(new_state))
throw new Error("Duplicate ROI name");
if (!this.validateCircleRow(newRow))
throw new Error("Wrong numeric parameters");
this.setState({ circle: {rois: new_state } });
}
return newRow;
};
columns_box = [
{ field: 'name', type: 'string', headerName: 'Name' , editable: true, width: 200},
{ field: 'min_x_pxl', type: 'number', headerName: 'Min X', editable: true},
{ field: 'max_x_pxl', type: 'number', headerName: 'Max X', editable: true},
{ field: 'min_y_pxl', type: 'number', headerName: 'Min Y', editable: true},
{ field: 'max_y_pxl', type: 'number', headerName: 'Max Y', editable: true},
{ field: 'actions', type: 'actions', width: 50, cellClassName: 'actions',
getActions: (id : GridRowModel) => {
return [
<GridActionsCellItem
icon={<DeleteIcon />}
label="Delete"
onClick={this.handleDeleteBoxROIClick(id)}
color="inherit"
/>,
];
}}
];
columns_circle = [
{ field: 'name', type: 'string', headerName: 'Name' , editable: true, width: 200},
{ field: 'center_x_pxl', type: 'number', headerName: 'X [pxl]', editable: true},
{ field: 'center_y_pxl', type: 'number', headerName: 'Y [pxl]', editable: true},
{ field: 'radius_pxl', type: 'number', headerName: 'Radius [pxl]', editable: true},
{ field: 'actions', type: 'actions', width: 50, cellClassName: 'actions',
getActions: (id : GridRowModel) => {
return [
<GridActionsCellItem
icon={<DeleteIcon />}
label="Delete"
onClick={this.handleDeleteCircleROIClick(id)}
color="inherit"
/>,
];
}}
];
render() {
return <Paper style={{textAlign: 'center'}} sx={{ height: 500, width: '100%' }}>
<Grid container spacing={0}>
<Grid item xs={0.25}/>
<Grid item xs={5.5} >
<strong>Box ROI</strong>
<br/><br/><br/>
<Paper sx={{height: 300, width: '100%'}} elevation={0}>
{(this.state.box.rois !== undefined) ?
<DataGrid
getRowId={row => row.name}
rows={this.state.box.rois}
columns={this.columns_box}
editMode={"row"}
experimentalFeatures={{newEditingApi: true}}
processRowUpdate={this.processRowBoxUpdate}
pageSize={100}
/> : <div/>}
</Paper>
</Grid>
<Grid item xs={0.5}/>
<Grid item xs={5.5}>
<strong>Radial ROI</strong>
<br/><br/><br/>
<Paper sx={{height: 300, width: '100%'}} elevation={0}>
{(this.state.circle.rois !== undefined) ?
<DataGrid
getRowId={row => row.name}
rows={this.state.circle.rois}
columns={this.columns_circle}
editMode={"row"}
experimentalFeatures={{newEditingApi: true}}
processRowUpdate={this.processRowCircleUpdate}
pageSize={100}
/> : <div/>}
</Paper>
</Grid>
<Grid item xs={0.25}/>
<Grid item xs={1}/>
<Grid item xs={10}><br/><br/>
<Button color="secondary" onClick={this.addBoxButton} variant="contained"
disableElevation>Add Box ROI</Button>&nbsp;&nbsp;
<Button color="secondary" onClick={this.addCircleButton} variant="contained"
disableElevation>Add Circle ROI</Button>&nbsp;&nbsp;
<Button color="secondary" onClick={this.downloadButton} variant="contained"
disableElevation>Download</Button>&nbsp;&nbsp;
<Button color="secondary" onClick={this.uploadButton} variant="contained"
disableElevation>Upload</Button>
<br/><br/>
</Grid>
<Grid item xs={1}/>
</Grid>
</Paper>
}
}
export default ROI;

View File

@@ -1,75 +0,0 @@
import React, {Component} from 'react';
import MultiLinePlotWrapper from "./MultiLinePlotWrapper";
import {DefaultService, radial_integration_plots} from "../openapi";
type MyProps = {}
type PlotlyPlot = {
x: number[],
y: number[],
type: string,
mode: string,
name: string
}
type PlotlyData = PlotlyPlot[]
type MyState = {
profiles : radial_integration_plots | null,
connection_error: boolean
}
class RadialIntegrationProfilePlots extends Component<MyProps, MyState> {
interval: undefined | NodeJS.Timer;
state: MyState = {
profiles: [
{
plot: {
x: [0, 100, 200, 300, 400, 500],
y: [0.1, 0.3, 0.5, 0.2, 0.0, 0.1]
},
title: "dataset"
}
],
connection_error: true
}
getValues() {
DefaultService.getPlotRadIntPerFile()
.then(data => this.setState({profiles: data, connection_error: false}))
.catch(error => {
console.log(error);
this.setState({connection_error: true});
});
}
componentDidMount() {
this.getValues();
this.interval = setInterval(() => this.getValues(), 500);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
if (!this.state.connection_error && (this.state.profiles !== null) && (this.state.profiles.length > 0)) {
let data: PlotlyData = [];
this.state.profiles.map(d =>
data.push({
x: d.plot.x,
y: d.plot.y,
type: "scatter",
mode: "line",
name: d.title
}));
console.log(data);
return <MultiLinePlotWrapper xaxis="Q [A<sup>-1</sup>]" yaxis="Photon count" data={data}/>
} else
return <div/>;
}
}
export default RadialIntegrationProfilePlots;

View File

@@ -1,5 +1,4 @@
export function handleErrors(response: Response): Response {
console.log(response.ok);
if (!response.ok) {
throw Error(response.statusText);
}

View File

@@ -18,9 +18,13 @@ export { error_message } from './models/error_message';
export { measurement_statistics } from './models/measurement_statistics';
export type { plot } from './models/plot';
export type { plot_request } from './models/plot_request';
export type { plots } from './models/plots';
export type { preview_settings } from './models/preview_settings';
export type { rad_int_settings } from './models/rad_int_settings';
export type { radial_integration_plots } from './models/radial_integration_plots';
export type { roi_box } from './models/roi_box';
export type { roi_box_list } from './models/roi_box_list';
export type { roi_circle } from './models/roi_circle';
export type { roi_circle_list } from './models/roi_circle_list';
export type { rotation_axis } from './models/rotation_axis';
export type { spot_finding_settings } from './models/spot_finding_settings';

View File

@@ -93,15 +93,6 @@ export type dataset_settings = {
* For JUNGFRAU conversion it is possible to multiply energy by a given factor to get fractional/multiplied photon counts
*/
photon_energy_multiplier?: number;
/**
* Rectangle for ROI summation
*/
roi_sum_area?: {
x_min: number;
x_max: number;
y_min: number;
y_max: number;
};
/**
* Units of angstrom and degree
*/

View File

@@ -7,6 +7,7 @@
* x and y coordinates for plotting, it is OK to assume that both arrays have the same size; layout is optimized for Plotly
*/
export type plot = {
title: string;
'x': Array<number>;
'y': Array<number>;
};

View File

@@ -5,7 +5,8 @@
import type { plot } from './plot';
export type radial_integration_plots = Array<{
title: string;
plot: plot;
}>;
export type plots = {
title?: string;
plot: Array<plot>;
};

View File

@@ -15,6 +15,10 @@ export type preview_settings = {
* Show spot finding results on the image
*/
show_spots?: boolean;
/**
* Show ROI areas on the image
*/
show_roi?: boolean;
/**
* Quality of JPEG image (100 - highest; 0 - lowest)
*/

View File

@@ -0,0 +1,31 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
/**
* Box ROI
*/
export type roi_box = {
/**
* Name for the ROI; used in the plots
*/
name: string;
/**
* Lower bound (inclusive) in X coordinate for the box
*/
min_x_pxl: number;
/**
* Upper bound (inclusive) in X coordinate for the box
*/
max_x_pxl: number;
/**
* Lower bound (inclusive) in Y coordinate for the box
*/
min_y_pxl: number;
/**
* Upper bound (inclusive) in Y coordinate for the box
*/
max_y_pxl: number;
};

View File

@@ -0,0 +1,14 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { roi_box } from './roi_box';
/**
* List of box ROIs
*/
export type roi_box_list = {
rois?: Array<roi_box>;
};

View File

@@ -0,0 +1,27 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
/**
* Circular ROI
*/
export type roi_circle = {
/**
* Name for the ROI; used in the plots
*/
name: string;
/**
* X coordinate of center of the circle [pixels]
*/
center_x_pxl: number;
/**
* Y coordinate of center of the circle [pixels]
*/
center_y_pxl: number;
/**
* Radius of the circle [pixels]
*/
radius_pxl: number;
};

View File

@@ -0,0 +1,14 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { roi_circle } from './roi_circle';
/**
* List of circular ROIs
*/
export type roi_circle_list = {
rois: Array<roi_circle>;
};

View File

@@ -10,11 +10,12 @@ import type { detector_selection } from '../models/detector_selection';
import type { detector_settings } from '../models/detector_settings';
import type { detector_status } from '../models/detector_status';
import type { measurement_statistics } from '../models/measurement_statistics';
import type { plot } from '../models/plot';
import type { plot_request } from '../models/plot_request';
import type { plots } from '../models/plots';
import type { preview_settings } from '../models/preview_settings';
import type { rad_int_settings } from '../models/rad_int_settings';
import type { radial_integration_plots } from '../models/radial_integration_plots';
import type { roi_box_list } from '../models/roi_box_list';
import type { roi_circle_list } from '../models/roi_circle_list';
import type { spot_finding_settings } from '../models/spot_finding_settings';
import type { CancelablePromise } from '../core/CancelablePromise';
@@ -354,6 +355,38 @@ export class DefaultService {
});
}
/**
* Return XFEL pulse IDs for the current data acquisition
* Return array of XFEL pulse IDs - (-1) if image not recorded
* @returns number Pulse ID collected
* @throws ApiError
*/
public static getXfelPulseId(): CancelablePromise<Array<number>> {
return __request(OpenAPI, {
method: 'GET',
url: '/xfel/pulse_id',
errors: {
404: `Not in XFEL mode or no acquisition recorded`,
},
});
}
/**
* Return XFEL event codes for the current data acquisition
* Return array of XFEL event codes
* @returns number Event codes collected
* @throws ApiError
*/
public static getXfelEventCode(): CancelablePromise<Array<number>> {
return __request(OpenAPI, {
method: 'GET',
url: '/xfel/event_code',
errors: {
404: `Not in XFEL mode or no acquisition recorded`,
},
});
}
/**
* Get detector status
* Status of the JUNGFRAU detector
@@ -371,16 +404,82 @@ export class DefaultService {
});
}
/**
* Get box ROIs
* @returns roi_box_list OK
* @throws ApiError
*/
public static getRoiBox(): CancelablePromise<roi_box_list> {
return __request(OpenAPI, {
method: 'GET',
url: '/roi/box',
});
}
/**
* Upload box ROIs
* @param requestBody
* @returns any Everything OK
* @throws ApiError
*/
public static putRoiBox(
requestBody?: roi_box_list,
): CancelablePromise<any> {
return __request(OpenAPI, {
method: 'PUT',
url: '/roi/box',
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Input parsing or validation error`,
500: `Error within Jungfraujoch code - see output message.`,
},
});
}
/**
* Get circular ROI
* @returns roi_circle_list OK
* @throws ApiError
*/
public static getRoiCircle(): CancelablePromise<roi_circle_list> {
return __request(OpenAPI, {
method: 'GET',
url: '/roi/circle',
});
}
/**
* Upload circular ROI
* @param requestBody
* @returns any Everything OK
* @throws ApiError
*/
public static putRoiCircle(
requestBody?: roi_circle_list,
): CancelablePromise<any> {
return __request(OpenAPI, {
method: 'PUT',
url: '/roi/circle',
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Input parsing or validation error`,
500: `Error within Jungfraujoch code - see output message.`,
},
});
}
/**
* Generate background estimate plot
* Mean intensity for d = 3 - 5 A per image; binning is configurable
* @param requestBody
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static postPlotBkgEstimate(
requestBody?: plot_request,
): CancelablePromise<plot> {
): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/bkg_estimate',
@@ -396,12 +495,12 @@ export class DefaultService {
* Generate spot count plot
* Number of spots per image; binning is configurable
* @param requestBody
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static postPlotSpotCount(
requestBody?: plot_request,
): CancelablePromise<plot> {
): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/spot_count',
@@ -417,12 +516,12 @@ export class DefaultService {
* Generate indexing rate plot
* Image indexing rate; binning is configurable
* @param requestBody
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static postPlotIndexingRate(
requestBody?: plot_request,
): CancelablePromise<plot> {
): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/indexing_rate',
@@ -434,37 +533,16 @@ export class DefaultService {
});
}
/**
* Generate saturated pixels plot
* Count of saturated pixels per image; binning is configurable
* @param requestBody
* @returns plot Everything OK
* @throws ApiError
*/
public static postPlotSaturatedPixel(
requestBody?: plot_request,
): CancelablePromise<plot> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/saturated_pixel',
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Input parsing or validation error`,
},
});
}
/**
* Generate error pixels plot
* Count of error pixels per image; binning is configurable
* Count of error (mean) and saturated (mean/max) pixels per image; binning is configurable
* @param requestBody
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static postPlotErrorPixel(
requestBody?: plot_request,
): CancelablePromise<plot> {
): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/error_pixel',
@@ -480,12 +558,12 @@ export class DefaultService {
* Generate strong pixels plot
* Count of strong pixels per image (from spot finding); binning is configurable
* @param requestBody
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static postPlotStrongPixel(
requestBody?: plot_request,
): CancelablePromise<plot> {
): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/strong_pixel',
@@ -501,12 +579,12 @@ export class DefaultService {
* Generate ROI sum plot
* Sum of ROI rectangle per image; binning is configurable
* @param requestBody
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static postPlotRoiSum(
requestBody?: plot_request,
): CancelablePromise<plot> {
): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/roi_sum',
@@ -518,16 +596,58 @@ export class DefaultService {
});
}
/**
* Generate plot of ROI max count
* Max count of ROI per image; binning is configurable
* @param requestBody
* @returns plots Everything OK
* @throws ApiError
*/
public static postPlotRoiMaxCount(
requestBody?: plot_request,
): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/roi_max_count',
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Input parsing or validation error`,
},
});
}
/**
* Generate plot of ROI valid pixels
* Number of pixels within a ROI area; pixels with special values (overload, bad pixel) are excluded; multipixels are counted just once; binning is configurable
* @param requestBody
* @returns plots Everything OK
* @throws ApiError
*/
public static postPlotRoiValidPixels(
requestBody?: plot_request,
): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/roi_valid_pixels',
body: requestBody,
mediaType: 'application/json',
errors: {
400: `Input parsing or validation error`,
},
});
}
/**
* Generate receiver delay plot
* Amount of frames the receiver is behind the FPGA for each image - used for internal debugging; binning is configurable
* @param requestBody
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static postPlotReceiverDelay(
requestBody?: plot_request,
): CancelablePromise<plot> {
): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/receiver_delay',
@@ -543,12 +663,12 @@ export class DefaultService {
* Generate image collection efficiency plot
* Ratio of collected and expected packets per image; binning is configurable
* @param requestBody
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static postPlotImageCollectionEfficiency(
requestBody?: plot_request,
): CancelablePromise<plot> {
): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'POST',
url: '/plot/image_collection_efficiency',
@@ -563,10 +683,10 @@ export class DefaultService {
/**
* Generate indexing rate per file
* Indexing rate per each of data files; useful for example for time resolved data
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static getPlotIndexingRatePerFile(): CancelablePromise<plot> {
public static getPlotIndexingRatePerFile(): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'GET',
url: '/plot/indexing_rate_per_file',
@@ -576,10 +696,10 @@ export class DefaultService {
/**
* Generate resolution estimate histogram
* Generate histogram of crystal resolutions from 1.0 to 5.0 A based on ML model
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static getPlotResolutionEstimateHistogram(): CancelablePromise<plot> {
public static getPlotResolutionEstimateHistogram(): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'GET',
url: '/plot/resolution_estimate_histogram',
@@ -589,10 +709,10 @@ export class DefaultService {
/**
* Generate radial integration profile
* Generate average radial integration profile
* @returns plot Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static getPlotRadInt(): CancelablePromise<plot> {
public static getPlotRadInt(): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'GET',
url: '/plot/rad_int',
@@ -602,10 +722,10 @@ export class DefaultService {
/**
* Generate radial integration profiles per file
* Radial integration plots for both the whole dataset and per file; useful for time-resolved measurements
* @returns radial_integration_plots Everything OK
* @returns plots Everything OK
* @throws ApiError
*/
public static getPlotRadIntPerFile(): CancelablePromise<radial_integration_plots> {
public static getPlotRadIntPerFile(): CancelablePromise<plots> {
return __request(OpenAPI, {
method: 'GET',
url: '/plot/rad_int_per_file',

View File

@@ -52,12 +52,17 @@ std::vector<float> AzimuthalIntegrationProfile::GetResult() const {
return rad_int_profile;
}
Plot AzimuthalIntegrationProfile::GetPlot() const {
void AzimuthalIntegrationProfile::SetTitle(const std::string &input) {
title = input;
}
MultiLinePlot AzimuthalIntegrationProfile::GetPlot() const {
std::unique_lock<std::mutex> ul(m);
Plot ret;
ret.x = bin_to_q;
ret.y = GetResult();
MultiLinePlot ret(1);
ret[0].x = bin_to_q;
ret[0].y = GetResult();
ret[0].title = title;
return ret;
}

View File

@@ -15,16 +15,18 @@ class AzimuthalIntegrationProfile {
std::vector<float> sum;
std::vector<uint64_t> count;
std::vector<float> bin_to_q;
std::string title;
public:
explicit AzimuthalIntegrationProfile(const AzimuthalIntegrationMapping &mapping);
AzimuthalIntegrationProfile(const AzimuthalIntegrationProfile& other); // Not thread safe
AzimuthalIntegrationProfile(AzimuthalIntegrationProfile&& other) noexcept; // Not thread safe
AzimuthalIntegrationProfile& operator=(const AzimuthalIntegrationProfile& other); //Not thread safe
void SetTitle(const std::string& input);
void Add(const DeviceOutput &result);
void Add(const std::vector<float> &sum, const std::vector<uint32_t> &count);
std::vector<float> GetResult() const;
float GetMeanValueOfBins(uint16_t min_bin, uint16_t max_bin) const;
Plot GetPlot() const;
MultiLinePlot GetPlot() const;
AzimuthalIntegrationProfile& operator+=(const AzimuthalIntegrationProfile& profile);
};

View File

@@ -5,7 +5,11 @@ ADD_LIBRARY(JFJochImageAnalysis STATIC
StrongPixelSet.cpp StrongPixelSet.h AzimuthalIntegrationProfile.cpp AzimuthalIntegrationProfile.h
SpotFindingSettings.h
AzimuthalIntegration.cpp
AzimuthalIntegration.h)
AzimuthalIntegration.h
CPUSpotFinder.cpp
CPUSpotFinder.h
MXAnalyzer.cpp
MXAnalyzer.h)
TARGET_LINK_LIBRARIES(JFJochImageAnalysis JFJochCommon)

View File

@@ -0,0 +1,64 @@
// Copyright (2019-2024) Paul Scherrer Institute
#include "CPUSpotFinder.h"
template <int N>
void FindSpots(StrongPixelSet& set,
int big_column, int big_row,
const SpotFindingSettings& settings,
const int16_t* image) {
uint64_t sum = 0;
uint64_t sum2 = 0;
uint64_t valid_count = 0;
for (int y = 0; y < N; y++) {
for (int x = 0; x < N; x++) {
size_t coord = (big_row * N + y) * RAW_MODULE_COLS + big_column * N + x;
if ((image[coord] != INT16_MIN) || (image[coord] != INT16_MAX)) {
sum += image[coord];
sum2 += image[coord] * image[coord];
valid_count++;
}
}
}
int64_t variance = valid_count * sum2 - sum * sum;
float threshold = variance * settings.signal_to_noise_threshold * settings.signal_to_noise_threshold;
for (int y = 0; y < N; y++) {
for (int x = 0; x < N; x++) {
size_t coord = (big_row * N + y) * RAW_MODULE_COLS + big_column * N + x;
bool strong_pixel = true;
if ((settings.photon_count_threshold < 0)
&& (settings.signal_to_noise_threshold <= 0))
strong_pixel = false;
if ((settings.photon_count_threshold >= 0)
&& (image[coord] < settings.photon_count_threshold)) {
strong_pixel = false;
}
if (settings.signal_to_noise_threshold > 0) {
int64_t in_minus_mean = image[coord] * valid_count - sum;
if ((in_minus_mean * in_minus_mean <= threshold)
|| (in_minus_mean <= 0)
|| (valid_count < N * N / 2))
strong_pixel = false;
}
if (strong_pixel)
set.AddStrongPixel(big_column * N + x, big_row * N + y, image[coord]);
}
}
}
void FindSpots(StrongPixelSet& set,
const SpotFindingSettings& settings,
const int16_t* image) {
for (int i = 0; i < RAW_MODULE_LINES / 32; i++) {
for (int j = 0; j < RAW_MODULE_COLS / 32; j++)
FindSpots<32>(set, j, i, settings, image);
}
}

View File

@@ -0,0 +1,14 @@
// Copyright (2019-2024) Paul Scherrer Institute
#ifndef JUNGFRAUJOCH_CPUSPOTFINDER_H
#define JUNGFRAUJOCH_CPUSPOTFINDER_H
#include "../common/DiffractionExperiment.h"
#include "SpotFindingSettings.h"
#include "StrongPixelSet.h"
void FindSpots(StrongPixelSet& set,
const SpotFindingSettings& settings,
const int16_t* image);
#endif //JUNGFRAUJOCH_CPUSPOTFINDER_H

View File

@@ -0,0 +1,65 @@
// Copyright (2019-2024) Paul Scherrer Institute
#include "MXAnalyzer.h"
#include "CPUSpotFinder.h"
MXAnalyzer::MXAnalyzer(const DiffractionExperiment &in_experiment)
: experiment(in_experiment) {
auto uc = experiment.GetUnitCell();
if (uc) {
do_indexing = true;
indexer.Setup(uc.value());
}
if (experiment.IsSpotFindingEnabled())
find_spots = true;
}
void MXAnalyzer::ReadFromFPGA(const DeviceOutput *output, const SpotFindingSettings &settings, size_t module_number) {
if (!find_spots)
return;
StrongPixelSet strong_pixel_set;
strong_pixel_set.ReadFPGAOutput(*output);
strong_pixel_set.FindSpots(experiment, settings, spots, module_number);
}
void MXAnalyzer::ReadFromCPU(const int16_t *image, const SpotFindingSettings &settings, size_t module_number) {
if (!find_spots)
return;
StrongPixelSet strong_pixel_set;
FindSpots(strong_pixel_set, settings, image);
strong_pixel_set.FindSpots(experiment, settings, spots, module_number);
}
bool MXAnalyzer::Process(DataMessage &message) {
message.indexing_result = 0;
if (!find_spots)
return false;
bool indexed = false;
std::vector<DiffractionSpot> spots_out;
FilterSpotsByCount(experiment, spots, spots_out);
for (const auto &spot: spots_out)
message.spots.push_back(spot);
if (do_indexing) {
std::vector<Coord> recip;
for (const auto &i: spots_out)
recip.push_back(i.ReciprocalCoord(experiment));
auto indexer_result = indexer.Run(recip);
if (!indexer_result.empty()) {
message.indexing_result = 1;
for (int i = 0; i < recip.size(); i++)
message.spots[i].indexed = indexer_result[0].indexed_spots[i];
indexer_result[0].l.Save(message.indexing_lattice);
message.indexing_unit_cell = indexer_result[0].l.GetUnitCell();
indexed = true;
}
}
spots.clear();
return indexed;
}

View File

@@ -0,0 +1,30 @@
// Copyright (2019-2024) Paul Scherrer Institute
#ifndef JUNGFRAUJOCH_MXANALYZER_H
#define JUNGFRAUJOCH_MXANALYZER_H
#include "../common/DiffractionExperiment.h"
#include "IndexerWrapper.h"
#include "StrongPixelSet.h"
class MXAnalyzer {
const DiffractionExperiment &experiment;
IndexerWrapper indexer;
bool do_indexing = false;
bool find_spots = false;
std::vector<DiffractionSpot> spots;
public:
explicit MXAnalyzer(const DiffractionExperiment& experiment);
void ReadFromFPGA(const DeviceOutput* output,
const SpotFindingSettings& settings,
size_t module_number);
void ReadFromCPU(const int16_t *image,
const SpotFindingSettings& settings,
size_t module_number);
bool Process(DataMessage &message);
};
#endif //JUNGFRAUJOCH_MXANALYZER_H

View File

@@ -17,17 +17,21 @@ JFConversionFloatingPoint::JFConversionFloatingPoint(const DiffractionExperiment
if (pixel_signed) {
err_pixel = INT16_MIN;
overload_pixel = INT16_MAX;
overload_value = overload_pixel;
} else {
err_pixel = UINT16_MAX;
overload_pixel = UINT16_MAX;
overload_value = overload_pixel;
}
} else if (experiment.GetPixelDepth() == 4) {
if (pixel_signed) {
err_pixel = INT32_MIN;
overload_pixel = INT32_MAX;
overload_value = INT24_MAX;
} else {
err_pixel = UINT32_MAX;
overload_pixel = UINT32_MAX;
overload_value = INT24_MAX;
}
}
}
@@ -103,7 +107,7 @@ void JFConversionFloatingPoint::ConvertFP(double *dest, const uint16_t *source)
if ((summation > 1) && !special_val)
expected *= summation;
if ((expected > overload_pixel) && !special_val)
if ((expected >= overload_value) && !special_val)
expected = overload_pixel;
if ((!pixel_signed) && (expected < 0))

View File

@@ -16,6 +16,7 @@ class JFConversionFloatingPoint {
double err_pixel = INT16_MIN;
double overload_pixel = INT16_MAX;
double overload_value;
bool fixed_g1 = false;
int64_t summation = 1;
bool pixel_signed = true;

View File

@@ -9,7 +9,9 @@ ADD_LIBRARY(JFJochReceiver STATIC
ImageMetadata.cpp
ImageMetadata.h
PreviewCounter.cpp
PreviewCounter.h)
PreviewCounter.h
LossyFilter.cpp
LossyFilter.h)
TARGET_LINK_LIBRARIES(JFJochReceiver ImagePusher JFJochImageAnalysis JFJochAcquisitionDevice JFJochCommon JFJochHLSSimulation JFJochImageExport JFJochResonet)

View File

@@ -14,25 +14,6 @@ template <class T> void FillVector(std::vector<char> &v, T fill_value) {
ptr[i] = fill_value;
}
template <class T>
int64_t calc_roi(const void* array, size_t width,
const ROIRectangle &input,
int64_t min_val, int64_t max_val) {
int64_t ret = 0;
for (size_t y = input.y_min; y <= input.y_max; y++) {
for (size_t x = input.x_min; x <= input.x_max; x++) {
int64_t val = ((T *)array)[y * width + x];
if ((ret == INT64_MIN) || (val < min_val))
ret = INT64_MIN;
else if ((ret == INT64_MAX) || (val > max_val))
ret = INT64_MAX;
else
ret += val;
}
}
return ret;
}
FrameTransformation::FrameTransformation(const DiffractionExperiment &in_experiment) :
experiment(in_experiment),
pixel_depth(experiment.GetPixelDepth()), pixel_signed(experiment.IsPixelSigned()),
@@ -138,23 +119,3 @@ const void *FrameTransformation::GetImage() const {
void FrameTransformation::FillNotCollectedModule(uint16_t module_number, int data_stream) {
ProcessModule(err_value.data(), module_number, data_stream);
}
int64_t FrameTransformation::CalculateROISum(const ROIRectangle &input) {
if ((input.x_min > input.x_max) || (input.y_min > input.y_max))
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Mismatch in min/max ROI size");
if ((input.x_max >= experiment.GetXPixelsNum()) || (input.y_max >= experiment.GetYPixelsNum()))
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Max pixel value for ROI sum outside of the detector range");
if (pixel_depth == 2) {
if (pixel_signed)
return calc_roi<int16_t>(precompression_buffer.data(), experiment.GetXPixelsNum(), input, INT16_MIN + 1, INT16_MAX - 1);
else
return calc_roi<uint16_t>(precompression_buffer.data(), experiment.GetXPixelsNum(), input, 0, UINT16_MAX - 2);
} else if (pixel_depth == 4) {
if (pixel_signed)
return calc_roi<int32_t>(precompression_buffer.data(), experiment.GetXPixelsNum(), input, INT32_MIN + 1, INT32_MAX - 1);
else
return calc_roi<uint32_t>(precompression_buffer.data(), experiment.GetXPixelsNum(), input, 0, UINT32_MAX - 2);
} else
return 0;
}

View File

@@ -26,7 +26,6 @@ public:
CompressedImage GetCompressedImage();
size_t CompressImage(void *output);
const void *GetImage() const;
int64_t CalculateROISum(const ROIRectangle &input);
};
#endif //JUNGFRAUJOCH_FRAMETRANSFORMATION_H

View File

@@ -1,13 +1,29 @@
// Copyright (2019-2023) Paul Scherrer Institute
#include "ImageMetadata.h"
#include <cmath>
inline uint64_t convert_pulse_id(double pulse_id) {
if (!std::isfinite(pulse_id))
return UINT64_MAX;
double integer_part;
double fractional_part = std::modf(pulse_id, &integer_part);
if (fractional_part != 0.0)
return UINT64_MAX;
return static_cast<uint64_t>(integer_part);
}
ImageMetadata::ImageMetadata(const DiffractionExperiment &experiment)
: pulsed_source(experiment.IsPulsedSource()) {}
: pulsed_source(experiment.IsPulsedSource()) {
roi_map_name = experiment.ROI().GetROINameMap();
for (const auto &[x,y]: roi_map_name)
rois[x] = ROIMessage{.max_count = INT64_MIN};
}
void ImageMetadata::Process(const DeviceOutput *output) {
uint64_t module_pulse_id = convert_pulse_id(output->module_statistics.pulse_id);
if (!first_module_loaded) {
xfel_pulse_id = output->module_statistics.pulse_id;
xfel_pulse_id = module_pulse_id;
jf_info = output->module_statistics.debug;
storage_cell = (jf_info >> 8) & 0xF;
xfel_event_code = (jf_info >> 16) & UINT8_MAX;
@@ -15,13 +31,23 @@ void ImageMetadata::Process(const DeviceOutput *output) {
exptime = output->module_statistics.exptime;
first_module_loaded = true;
} else {
if (pulsed_source && (output->module_statistics.pulse_id != xfel_pulse_id))
if (pulsed_source && (module_pulse_id != xfel_pulse_id)) {
metadata_consistent = false;
xfel_pulse_id = UINT64_MAX; // mark clearly inconsistent frames
}
}
saturated_pixels += output->module_statistics.saturated_pixels;
error_pixels += output->module_statistics.err_pixels;
strong_pixels += output->spot_finding_result.strong_pixel_count;
packets_collected += output->module_statistics.packet_count;
for (const auto &[key, val]: roi_map_name) {
rois[key].sum += output->roi_counts[val].sum;
rois[key].sum_square += output->roi_counts[val].sum2;
rois[key].pixels += output->roi_counts[val].good_pixels;
if (output->roi_counts[val].max_value > rois[key].max_count)
rois[key].max_count = output->roi_counts[val].max_value;
}
}
bool ImageMetadata::IsBunchIDConsistent() const {
@@ -30,7 +56,7 @@ bool ImageMetadata::IsBunchIDConsistent() const {
void ImageMetadata::Export(DataMessage &message, uint64_t packets_expected_per_image) const {
if (pulsed_source) {
message.xfel_pulse_id = static_cast<uint64_t>(xfel_pulse_id);
message.xfel_pulse_id = xfel_pulse_id;
message.xfel_event_code = xfel_event_code;
}
message.jf_info = jf_info;
@@ -47,4 +73,6 @@ void ImageMetadata::Export(DataMessage &message, uint64_t packets_expected_per_i
/ static_cast<double>(packets_expected_per_image);
else
message.image_collection_efficiency = 0.0f;
message.roi = rois;
}

View File

@@ -14,7 +14,7 @@ class ImageMetadata {
bool first_module_loaded = false;
bool metadata_consistent = true;
uint64_t xfel_pulse_id = 0;
uint64_t xfel_pulse_id = UINT64_MAX;
uint64_t xfel_event_code = 0;
uint64_t jf_info = 0;
@@ -26,8 +26,10 @@ class ImageMetadata {
uint64_t strong_pixels = 0;
uint64_t packets_collected = 0;
std::map<std::string, ROIMessage> rois;
std::map<std::string, uint16_t> roi_map_name;
public:
ImageMetadata(const DiffractionExperiment &experiment);
explicit ImageMetadata(const DiffractionExperiment &experiment);
void Process(const DeviceOutput *output);
void Export(DataMessage &message, uint64_t packets_expected_per_image) const;
bool IsBunchIDConsistent() const;

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