From 75e401f0e57169cab49e54d165475249da1aa69c Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Tue, 23 Jun 2026 20:29:49 +0200 Subject: [PATCH] v1.0.0-rc.153 (#63) This is an UNSTABLE release. It includes many experimental features, as well as many AI generated fixes. We recommend using rc.152 for production use. * jfjoch_broker: Add EXPERIMENTAL pixelrefine mode for image processing * jfjoch_broker: Allow to load user mask from 8-bit and 16-bit TIFF files * jfjoch_broker: Add ROI calculation in non-FPGA workflow * jfjoch_broker: Fixes to TCP image pusher * jfjoch_broker: Remove NUMA bindings * jfjoch_broker: Improvements to indexing * jfjoch_broker: For PSI EIGER, trimming energies are taken from the detector configuration (now compulsory) instead of hardcoded values * jfjoch_writer: Save ROI definitions and the per-pixel ROI bitmap in the master file; azimuthal ROIs support phi (angular) sectors * jfjoch_viewer: Major redesign with dockable panels and saved layouts, plus on-canvas creation/move/resize of box, circle and azimuthal ROIs * jfjoch_viewer: Run jfjoch_process reprocessing jobs from inside the GUI and overlay per-run results Reviewed-on: https://gitea.psi.ch/mx/Jungfraujoch/pulls/63 --- .gitattributes | 3 + .gitea/workflows/build_and_test.yml | 18 +- CLAUDE.md | 192 + CMakeLists.txt | 301 +- LICENSE | 5 +- THIRD_PARTY_NOTICES.md | 86 + VERSION | 2 +- acquisition_device/AcquisitionDevice.cpp | 38 - acquisition_device/AcquisitionDevice.h | 7 +- acquisition_device/HLSSimulatedDevice.cpp | 8 +- acquisition_device/HLSSimulatedDevice.h | 9 +- acquisition_device/PCIExpressDevice.cpp | 9 + acquisition_device/PCIExpressDevice.h | 2 + broker/CMakeLists.txt | 26 +- broker/JFJochBrokerHttp.cpp | 7 +- broker/JFJochBrokerParser.cpp | 9 +- broker/JFJochServices.cpp | 8 + broker/JFJochStateMachine.cpp | 17 +- broker/JFJochStateMachine.h | 1 + broker/OpenAPIConvert.cpp | 20 +- broker/gen/.gitignore | 14 + broker/gen/model/Azim_int_settings.cpp | 2 +- broker/gen/model/Azim_int_settings.h | 2 +- broker/gen/model/Broker_status.cpp | 2 +- broker/gen/model/Broker_status.h | 2 +- .../model/Calibration_statistics_inner.cpp | 2 +- .../gen/model/Calibration_statistics_inner.h | 2 +- broker/gen/model/Dark_mask_settings.cpp | 2 +- broker/gen/model/Dark_mask_settings.h | 2 +- broker/gen/model/Dataset_settings.cpp | 2 +- broker/gen/model/Dataset_settings.h | 4 +- ...et_settings_xray_fluorescence_spectrum.cpp | 2 +- ...aset_settings_xray_fluorescence_spectrum.h | 2 +- broker/gen/model/Detector.cpp | 56 +- broker/gen/model/Detector.h | 11 +- broker/gen/model/Detector_list.cpp | 2 +- broker/gen/model/Detector_list.h | 2 +- broker/gen/model/Detector_list_element.cpp | 2 +- broker/gen/model/Detector_list_element.h | 2 +- broker/gen/model/Detector_module.cpp | 2 +- broker/gen/model/Detector_module.h | 2 +- .../gen/model/Detector_module_direction.cpp | 2 +- broker/gen/model/Detector_module_direction.h | 2 +- broker/gen/model/Detector_power_state.cpp | 2 +- broker/gen/model/Detector_power_state.h | 2 +- broker/gen/model/Detector_selection.cpp | 2 +- broker/gen/model/Detector_selection.h | 2 +- broker/gen/model/Detector_settings.cpp | 2 +- broker/gen/model/Detector_settings.h | 2 +- broker/gen/model/Detector_state.cpp | 2 +- broker/gen/model/Detector_state.h | 2 +- broker/gen/model/Detector_status.cpp | 2 +- broker/gen/model/Detector_status.h | 2 +- broker/gen/model/Detector_timing.cpp | 2 +- broker/gen/model/Detector_timing.h | 2 +- broker/gen/model/Detector_type.cpp | 2 +- broker/gen/model/Detector_type.h | 2 +- broker/gen/model/Error_message.cpp | 2 +- broker/gen/model/Error_message.h | 2 +- broker/gen/model/File_writer_format.cpp | 2 +- broker/gen/model/File_writer_format.h | 2 +- broker/gen/model/File_writer_settings.cpp | 2 +- broker/gen/model/File_writer_settings.h | 2 +- broker/gen/model/Fpga_status_inner.cpp | 2 +- broker/gen/model/Fpga_status_inner.h | 2 +- .../gen/model/Geom_refinement_algorithm.cpp | 2 +- broker/gen/model/Geom_refinement_algorithm.h | 2 +- broker/gen/model/Grid_scan.cpp | 2 +- broker/gen/model/Grid_scan.h | 2 +- broker/gen/model/Helpers.cpp | 2 +- broker/gen/model/Helpers.h | 2 +- broker/gen/model/Image_buffer_status.cpp | 2 +- broker/gen/model/Image_buffer_status.h | 2 +- broker/gen/model/Image_format_settings.cpp | 2 +- broker/gen/model/Image_format_settings.h | 2 +- broker/gen/model/Image_pusher_status.cpp | 2 +- broker/gen/model/Image_pusher_status.h | 2 +- broker/gen/model/Image_pusher_type.cpp | 2 +- broker/gen/model/Image_pusher_type.h | 2 +- broker/gen/model/Indexing_algorithm.cpp | 2 +- broker/gen/model/Indexing_algorithm.h | 2 +- broker/gen/model/Indexing_settings.cpp | 2 +- broker/gen/model/Indexing_settings.h | 2 +- broker/gen/model/Instrument_metadata.cpp | 2 +- broker/gen/model/Instrument_metadata.h | 2 +- broker/gen/model/Jfjoch_settings.cpp | 2 +- broker/gen/model/Jfjoch_settings.h | 4 +- broker/gen/model/Jfjoch_statistics.cpp | 2 +- broker/gen/model/Jfjoch_statistics.h | 2 +- broker/gen/model/Measurement_statistics.cpp | 2 +- broker/gen/model/Measurement_statistics.h | 2 +- broker/gen/model/Pcie_devices_inner.cpp | 2 +- broker/gen/model/Pcie_devices_inner.h | 2 +- broker/gen/model/Pixel_mask_statistics.cpp | 2 +- broker/gen/model/Pixel_mask_statistics.h | 2 +- broker/gen/model/Plot.cpp | 2 +- broker/gen/model/Plot.h | 2 +- broker/gen/model/Plot_unit_x.cpp | 2 +- broker/gen/model/Plot_unit_x.h | 2 +- broker/gen/model/Plots.cpp | 2 +- broker/gen/model/Plots.h | 2 +- broker/gen/model/Roi_azim_list.cpp | 2 +- broker/gen/model/Roi_azim_list.h | 2 +- broker/gen/model/Roi_azimuthal.cpp | 62 +- broker/gen/model/Roi_azimuthal.h | 24 +- broker/gen/model/Roi_box.cpp | 2 +- broker/gen/model/Roi_box.h | 2 +- broker/gen/model/Roi_box_list.cpp | 2 +- broker/gen/model/Roi_box_list.h | 2 +- broker/gen/model/Roi_circle.cpp | 2 +- broker/gen/model/Roi_circle.h | 2 +- broker/gen/model/Roi_circle_list.cpp | 2 +- broker/gen/model/Roi_circle_list.h | 2 +- broker/gen/model/Roi_definitions.cpp | 2 +- broker/gen/model/Roi_definitions.h | 2 +- broker/gen/model/Rotation_axis.cpp | 2 +- broker/gen/model/Rotation_axis.h | 2 +- broker/gen/model/Scan_result.cpp | 2 +- broker/gen/model/Scan_result.h | 2 +- broker/gen/model/Scan_result_images_inner.cpp | 2 +- broker/gen/model/Scan_result_images_inner.h | 2 +- broker/gen/model/Spot_finding_settings.cpp | 2 +- broker/gen/model/Spot_finding_settings.h | 2 +- .../gen/model/Standard_detector_geometry.cpp | 2 +- broker/gen/model/Standard_detector_geometry.h | 2 +- broker/gen/model/Tcp_settings.cpp | 2 +- broker/gen/model/Tcp_settings.h | 2 +- broker/gen/model/Unit_cell.cpp | 2 +- broker/gen/model/Unit_cell.h | 2 +- broker/gen/model/Zeromq_metadata_settings.cpp | 2 +- broker/gen/model/Zeromq_metadata_settings.h | 2 +- broker/gen/model/Zeromq_preview_settings.cpp | 2 +- broker/gen/model/Zeromq_preview_settings.h | 2 +- broker/gen/model/Zeromq_settings.cpp | 2 +- broker/gen/model/Zeromq_settings.h | 2 +- broker/jfjoch_api.yaml | 37 +- broker/jfjoch_broker.cpp | 2 + broker/redoc-static.html | 21 +- common/ADUHistogram.cpp | 1 + common/ADUHistogram.h | 4 +- common/AzimuthalIntegrationMapping.cpp | 11 +- common/AzimuthalIntegrationProfile.cpp | 2 +- common/AzimuthalIntegrationProfile.h | 2 +- common/AzimuthalIntegrationSettings.h | 5 +- common/BraggIntegrationSettings.cpp | 11 + common/BraggIntegrationSettings.h | 10 +- common/CMakeLists.txt | 18 +- common/CUDAWrapper.cpp | 4 +- common/CUDAWrapper.cu | 56 +- common/CUDAWrapper.h | 6 +- common/Coord.cpp | 3 +- common/CrystalLattice.cpp | 3 +- common/DatasetSettings.cpp | 9 + common/DatasetSettings.h | 3 + common/DetectorSetup.cpp | 10 + common/DetectorSetup.h | 3 + common/DiffractionExperiment.cpp | 14 + common/DiffractionExperiment.h | 5 + common/DiffractionGeometry.cpp | 7 +- common/GoniometerAxis.cpp | 3 +- common/ImageBuffer.cpp | 48 +- common/IndexingSettings.h | 2 +- common/JFJochMath.h | 10 + common/JFJochMessages.h | 6 + {receiver => common}/JFJochReceiverPlots.cpp | 2 +- {receiver => common}/JFJochReceiverPlots.h | 18 +- common/JfjochTCP.h | 7 +- common/NUMAHWPolicy.cpp | 125 - common/NUMAHWPolicy.h | 33 - common/NetworkAddressConvert.cpp | 5 + common/PixelMask.cpp | 49 + common/PixelMask.h | 2 + common/Plot.h | 2 +- common/ROIAzimuthal.cpp | 45 +- common/ROIAzimuthal.h | 15 +- common/ROIBox.cpp | 2 +- common/ROIBox.h | 2 +- common/ROICircle.cpp | 2 +- common/ROICircle.h | 2 +- common/ROIElement.cpp | 10 +- common/ROIElement.h | 4 +- common/ROIMap.cpp | 12 +- common/Reflection.h | 3 +- common/ScalingSettings.cpp | 9 + common/ScalingSettings.h | 5 +- common/time_utc.h | 24 +- compression/bitshuffle/bitshuffle.c | 19 +- compression/bitshuffle/bitshuffle.h | 12 +- compression/bitshuffle/bitshuffle_core.c | 123 +- compression/bitshuffle/bitshuffle_core.h | 2 +- compression/bitshuffle/bitshuffle_internals.h | 10 +- compression/bitshuffle/bshuf_h5filter.c | 34 +- compression/bitshuffle/bshuf_h5filter.h | 6 +- compression/bitshuffle/iochain.c | 5 +- compression/bitshuffle/iochain.h | 7 +- detector_control/SLSDetectorWrapper.cpp | 5 +- docker/rocky8/Dockerfile | 91 +- docker/rocky9/Dockerfile | 87 +- docker/ubuntu2204/Dockerfile | 93 +- docker/ubuntu2404/Dockerfile | 95 +- docs/CBOR.md | 24 +- docs/CHANGELOG.md | 14 + docs/CPU_DATA_ANALYSIS.md | 22 +- docs/DEPLOYMENT.md | 8 +- docs/FPGA_DATA_ANALYSIS.md | 8 + docs/HDF5.md | 465 ++ docs/JFJOCH_BROKER.md | 1 - docs/JFJOCH_PROCESS.md | 159 + docs/JFJOCH_VIEWER.md | 142 +- docs/JFJOCH_WRITER.md | 88 +- docs/LICENSE.md | 2 +- docs/SOFTWARE.md | 56 +- docs/TOOLS.md | 74 +- docs/conf.py | 12 +- docs/index.rst | 15 +- docs/python_client/README.md | 4 +- docs/python_client/docs/DatasetSettings.md | 2 +- docs/python_client/docs/DefaultApi.md | 5 +- docs/python_client/docs/Detector.md | 1 + docs/python_client/docs/JfjochSettings.md | 2 +- docs/python_client/docs/RoiAzimuthal.md | 4 +- fpga/hdl/action_config.v | 2 +- fpga/pcie_driver/dkms.conf | 2 +- fpga/pcie_driver/install_dkms.sh | 2 +- fpga/pcie_driver/jfjoch_drv.c | 2 +- fpga/pcie_driver/postinstall.sh | 2 +- fpga/pcie_driver/preuninstall.sh | 2 +- frame_serialize/CBORStream2Deserializer.cpp | 23 +- frame_serialize/CBORStream2Serializer.cpp | 37 +- frontend/openapi-ts.config.ts | 19 + frontend/package-lock.json | 2863 +++++++- frontend/package.json | 25 +- .../scripts/generate-third-party-licenses.mjs | 121 + frontend/src/App.tsx | 474 +- .../src/client/@tanstack/react-query.gen.ts | 1317 ++++ frontend/src/client/client.gen.ts | 16 + frontend/src/client/client/client.gen.ts | 277 + frontend/src/client/client/index.ts | 27 + frontend/src/client/client/types.gen.ts | 218 + frontend/src/client/client/utils.gen.ts | 316 + frontend/src/client/core/auth.gen.ts | 48 + .../src/client/core/bodySerializer.gen.ts | 82 + frontend/src/client/core/params.gen.ts | 171 + .../src/client/core/pathSerializer.gen.ts | 171 + .../src/client/core/queryKeySerializer.gen.ts | 117 + .../src/client/core/serverSentEvents.gen.ts | 242 + frontend/src/client/core/types.gen.ts | 110 + frontend/src/client/core/utils.gen.ts | 140 + frontend/src/client/index.ts | 4 + frontend/src/client/sdk.gen.ts | 640 ++ frontend/src/client/types.gen.ts | 3235 +++++++++ frontend/src/client/zod.gen.ts | 1217 ++++ frontend/src/components/AzIntSettings.tsx | 283 +- .../src/components/ButtonWithSnackbar.tsx | 111 +- frontend/src/components/Calibration.tsx | 62 +- frontend/src/components/DarkMaskSettings.tsx | 336 +- frontend/src/components/DataCollection.tsx | 572 +- .../src/components/DataProcessingPlot.tsx | 119 +- .../src/components/DataProcessingPlots.tsx | 225 +- .../src/components/DataProcessingSettings.tsx | 366 +- frontend/src/components/DetectorSelection.tsx | 123 +- frontend/src/components/DetectorSettings.tsx | 811 +-- frontend/src/components/DetectorStatus.tsx | 119 +- frontend/src/components/ErrorMessage.tsx | 61 +- .../src/components/FileWriterSettings.tsx | 161 +- frontend/src/components/FpgaStatus.tsx | 80 +- .../src/components/ImageFormatSettings.tsx | 508 +- frontend/src/components/ImagePusherStatus.tsx | 71 +- frontend/src/components/IndexingSettings.tsx | 569 +- .../src/components/InstrumentMetadata.tsx | 178 +- .../src/components/MeasurementStatistics.tsx | 147 +- .../src/components/MultiLinePlotWrapper.jsx | 3 +- frontend/src/components/NumberTextField.tsx | 139 +- frontend/src/components/PixelMask.tsx | 63 +- frontend/src/components/Plot.jsx | 12 + frontend/src/components/PreviewImage.tsx | 700 +- frontend/src/components/ROI.tsx | 511 +- frontend/src/components/SettingsPanel.tsx | 81 + frontend/src/components/StatusBar.tsx | 91 +- frontend/src/components/ZeroMQPreview.tsx | 201 +- frontend/src/components/useUpload.ts | 41 + frontend/src/index.tsx | 15 +- frontend/src/openapi/core/ApiError.ts | 25 - .../src/openapi/core/ApiRequestOptions.ts | 17 - frontend/src/openapi/core/ApiResult.ts | 11 - .../src/openapi/core/CancelablePromise.ts | 131 - frontend/src/openapi/core/OpenAPI.ts | 32 - frontend/src/openapi/core/request.ts | 320 - frontend/src/openapi/index.ts | 83 - .../src/openapi/models/azim_int_settings.ts | 30 - frontend/src/openapi/models/azint_unit.ts | 14 - frontend/src/openapi/models/background.ts | 9 - frontend/src/openapi/models/binning.ts | 9 - frontend/src/openapi/models/broker_status.ts | 56 - .../openapi/models/calibration_statistics.ts | 16 - frontend/src/openapi/models/color_scale.ts | 18 - .../src/openapi/models/crystal_lattice.ts | 11 - .../src/openapi/models/dark_mask_settings.ts | 31 - .../src/openapi/models/dataset_settings.ts | 231 - frontend/src/openapi/models/detector.ts | 68 - frontend/src/openapi/models/detector_list.ts | 12 - .../openapi/models/detector_list_element.ts | 26 - .../src/openapi/models/detector_module.ts | 14 - .../models/detector_module_direction.ts | 11 - .../openapi/models/detector_power_state.ts | 13 - .../src/openapi/models/detector_selection.ts | 9 - .../src/openapi/models/detector_settings.ts | 92 - frontend/src/openapi/models/detector_state.ts | 15 - .../src/openapi/models/detector_status.ts | 29 - .../src/openapi/models/detector_timing.ts | 11 - frontend/src/openapi/models/detector_type.ts | 10 - frontend/src/openapi/models/error_message.ts | 29 - .../src/openapi/models/experimental_coord.ts | 12 - .../src/openapi/models/file_writer_format.ts | 24 - .../openapi/models/file_writer_settings.ts | 16 - frontend/src/openapi/models/fill_value.ts | 10 - frontend/src/openapi/models/fpga_status.ts | 27 - .../models/geom_refinement_algorithm.ts | 16 - frontend/src/openapi/models/grid_scan.ts | 40 - .../src/openapi/models/image_buffer_status.ts | 47 - .../openapi/models/image_format_settings.ts | 84 - frontend/src/openapi/models/image_id.ts | 9 - .../src/openapi/models/image_pusher_status.ts | 51 - .../src/openapi/models/image_pusher_type.ts | 12 - .../src/openapi/models/indexing_algorithm.ts | 16 - .../src/openapi/models/indexing_settings.ts | 66 - .../src/openapi/models/instrument_metadata.ts | 44 - .../src/openapi/models/jfjoch_settings.ts | 64 - .../src/openapi/models/jfjoch_statistics.ts | 52 - frontend/src/openapi/models/jpeg_quality.ts | 9 - .../openapi/models/measurement_statistics.ts | 82 - frontend/src/openapi/models/pcie_devices.ts | 15 - .../openapi/models/pixel_mask_statistics.ts | 20 - frontend/src/openapi/models/plot.ts | 15 - frontend/src/openapi/models/plot_type.ts | 47 - frontend/src/openapi/models/plot_unit_x.ts | 13 - frontend/src/openapi/models/plots.ts | 22 - .../src/openapi/models/resolution_estimate.ts | 9 - .../src/openapi/models/resolution_ring.ts | 9 - frontend/src/openapi/models/roi.ts | 9 - frontend/src/openapi/models/roi_azim_list.ts | 14 - frontend/src/openapi/models/roi_azimuthal.ts | 23 - frontend/src/openapi/models/roi_box.ts | 31 - frontend/src/openapi/models/roi_box_list.ts | 14 - frontend/src/openapi/models/roi_circle.ts | 27 - .../src/openapi/models/roi_circle_list.ts | 14 - .../src/openapi/models/roi_definitions.ts | 18 - frontend/src/openapi/models/rotation_axis.ts | 35 - frontend/src/openapi/models/saturation.ts | 9 - frontend/src/openapi/models/scan_result.ts | 97 - .../src/openapi/models/show_beam_center.ts | 9 - frontend/src/openapi/models/show_roi.ts | 9 - frontend/src/openapi/models/show_spots.ts | 9 - frontend/src/openapi/models/show_user_mask.ts | 9 - .../openapi/models/spot_finding_settings.ts | 53 - .../models/standard_detector_geometry.ts | 27 - frontend/src/openapi/models/tcp_settings.ts | 27 - frontend/src/openapi/models/unit_cell.ts | 17 - .../models/zeromq_metadata_settings.ts | 25 - .../openapi/models/zeromq_preview_settings.ts | 27 - .../src/openapi/models/zeromq_settings.ts | 38 - .../src/openapi/services/DefaultService.ts | 1257 ---- frontend/src/react-app-env.d.ts | 1 - frontend/src/serviceWorker.js | 141 - frontend/src/setupTests.js | 5 - frontend/src/version.ts | 2 +- gemmi_gph/gemmi/utf.hpp | 78 + image_analysis/CMakeLists.txt | 11 +- image_analysis/IndexAndRefine.cpp | 155 +- image_analysis/IndexAndRefine.h | 17 + image_analysis/LoadFCalcFromMtz.cpp | 30 +- image_analysis/MXAnalysisWithoutFPGA.cpp | 42 +- image_analysis/MXAnalysisWithoutFPGA.h | 15 + image_analysis/UpdateReflectionResolution.h | 6 +- .../bragg_integration/BraggIntegrate2D.cpp | 26 +- .../bragg_prediction/BraggPrediction.cpp | 23 +- .../bragg_prediction/BraggPrediction.h | 6 + .../bragg_prediction/BraggPredictionGPU.cu | 23 +- .../bragg_prediction/BraggPredictionGPU.h | 1 + .../bragg_prediction/BraggPredictionRot.cpp | 7 +- .../bragg_prediction/BraggPredictionRotGPU.cu | 7 +- .../geom_refinement/AssignSpotsToRings.cpp | 9 +- image_analysis/geom_refinement/CMakeLists.txt | 2 + .../geom_refinement/LatticeReduction.cpp | 258 + .../geom_refinement/LatticeReduction.h | 19 + .../geom_refinement/RingOptimizer.cpp | 3 +- .../geom_refinement/XtalOptimizer.cpp | 289 +- .../geom_refinement/XtalOptimizer.h | 13 - image_analysis/indexing/AnalyzeIndexing.cpp | 11 +- image_analysis/indexing/CMakeLists.txt | 16 +- image_analysis/indexing/FFTIndexer.cpp | 20 +- image_analysis/indexing/FFTIndexerCPU.cpp | 38 +- image_analysis/indexing/FFTIndexerGPU.cu | 50 +- image_analysis/indexing/FitProfileRadius.cpp | 3 - image_analysis/indexing/IndexerThreadPool.cpp | 29 +- image_analysis/indexing/IndexerThreadPool.h | 1 - .../indexing/PostIndexingRefinement.cpp | 7 +- .../lattice_search/LatticeSearch.cpp | 7 +- .../pixel_refinement/CMakeLists.txt | 2 + .../pixel_refinement/FACTORED_MODEL.md | 142 + .../pixel_refinement/FINDINGS-2026-06.md | 122 + image_analysis/pixel_refinement/METHODS.md | 214 + .../pixel_refinement/PixelRefine.cpp | 708 ++ image_analysis/pixel_refinement/PixelRefine.h | 135 + image_analysis/roi/CMakeLists.txt | 5 + image_analysis/roi/ROIIntegration.cpp | 34 + image_analysis/roi/ROIIntegration.h | 46 + image_analysis/roi/ROIIntegrationCPU.cpp | 11 + image_analysis/roi/ROIIntegrationCPU.h | 71 + image_analysis/roi/ROIIntegrationGPU.cu | 152 + image_analysis/roi/ROIIntegrationGPU.h | 37 + .../rotation_indexer/RotationIndexer.cpp | 15 +- .../rotation_indexer/RotationIndexer.h | 8 +- image_analysis/scale_merge/Merge.cpp | 291 +- image_analysis/scale_merge/Merge.h | 41 + image_analysis/scale_merge/ScaleOnTheFly.cpp | 170 +- image_analysis/scale_merge/ScalingResult.cpp | 4 +- .../spot_finding/SpotFindingSettings.h | 2 +- image_analysis/spot_finding/SpotUtils.cpp | 9 +- image_analysis/spot_finding/StrongPixelSet.h | 2 +- image_puller/CMakeLists.txt | 2 +- image_puller/TCPImagePuller.cpp | 43 +- image_puller/TCPImagePuller.h | 7 + image_pusher/HDF5FilePusher.cpp | 3 +- image_pusher/HDF5FilePusher.h | 2 +- image_pusher/ImagePusher.cpp | 5 +- image_pusher/ImagePusher.h | 7 +- image_pusher/TCPStreamPusher.cpp | 107 +- image_pusher/TCPStreamPusher.h | 14 +- image_pusher/ZMQStream2Pusher.cpp | 7 +- image_pusher/ZMQStream2Pusher.h | 2 +- jungfrau/CMakeLists.txt | 2 - licenses/COLLECT.sh | 81 + licenses/NVIDIA-CUDA-EULA.txt | 1632 +++++ licenses/NVIDIA-CUDA-NOTICE.txt | 19 + licenses/Qt6-LGPL-3.0.txt | 165 + licenses/Qt6-NOTICE.txt | 24 + licenses/base64-macaron.txt | 24 + licenses/bitshuffle-hperf.txt | 202 + licenses/bitshuffle.txt | 21 + licenses/catch2.txt | 23 + licenses/ceres-solver.txt | 257 + licenses/cpp-httplib.txt | 22 + licenses/eigen-README.txt | 6 + licenses/eigen.txt | 373 ++ licenses/fast-feedback-indexer.txt | 22 + licenses/fftw.txt | 340 + licenses/gemmi.txt | 373 ++ licenses/hdf5.txt | 111 + licenses/libjpeg-turbo.txt | 135 + licenses/libtiff.txt | 49 + licenses/libzmq.txt | 373 ++ licenses/lz4.txt | 24 + licenses/nlohmann-json.txt | 21 + licenses/slsDetectorPackage-GPL-3.0.txt | 688 ++ licenses/slsDetectorPackage-LGPL-3.0.txt | 179 + licenses/spdlog.txt | 25 + licenses/tinycbor.txt | 21 + licenses/wingetopt.txt | 54 + licenses/xbflash-qspi.txt | 517 ++ licenses/xilinx-hls-headers.txt | 18 + licenses/zlib.txt | 19 + licenses/zstd.txt | 30 + make_doc.sh | 37 +- preview/CMakeLists.txt | 50 +- preview/JFJochTIFF.cpp | 75 +- preview/JFJochTIFF.h | 1 - preview/PreviewImage.cpp | 44 + process/CMakeLists.txt | 11 + process/JFJochProcess.cpp | 433 ++ process/JFJochProcess.h | 100 + process/JFJochProcessCommandLine.cpp | 138 + process/JFJochProcessCommandLine.h | 18 + reader/CMakeLists.txt | 6 + reader/HDF5ImageLocator.cpp | 160 + reader/HDF5ImageLocator.h | 60 + reader/HDF5ImageSource.cpp | 66 + reader/HDF5ImageSource.h | 36 + reader/HDF5MetadataSource.cpp | 1162 ++++ reader/HDF5MetadataSource.h | 77 + reader/JFJochHDF5Reader.cpp | 1393 +--- reader/JFJochHDF5Reader.h | 59 +- reader/JFJochHttpReader.cpp | 121 +- reader/JFJochHttpReader.h | 8 + reader/JFJochReaderDataset.h | 14 + receiver/CMakeLists.txt | 3 - receiver/JFJochReceiver.cpp | 4 +- receiver/JFJochReceiver.h | 6 +- receiver/JFJochReceiverFPGA.cpp | 30 +- receiver/JFJochReceiverFPGA.h | 4 +- receiver/JFJochReceiverLite.cpp | 17 +- receiver/JFJochReceiverLite.h | 4 +- receiver/JFJochReceiverOutput.h | 2 +- receiver/JFJochReceiverService.cpp | 12 - receiver/JFJochReceiverService.h | 4 - receiver/JFJochReceiverTest.cpp | 8 +- receiver/JFJochReceiverTest.h | 2 - tests/CBORTest.cpp | 46 +- tests/CMakeLists.txt | 10 +- tests/JFJochProcessLargeTest.cpp | 82 + tests/JFJochProcessTest.cpp | 181 + tests/JFJochReaderTest.cpp | 196 + tests/JFJochReceiverPlotsTest.cpp | 2 +- tests/LatticeReductionTest.cpp | 225 + tests/PixelMaskTest.cpp | 38 + tests/ROIIntegrationCPUTest.cpp | 95 + tests/ROIIntegrationGPUTest.cpp | 114 + tests/ROIMapTest.cpp | 64 + tests/TIFFTest.cpp | 55 +- tests/TestData.h | 28 + tests/XtalOptimizerTest.cpp | 213 - tests/data/README.md | 30 + tests/data/fixed_data_000001.h5 | 3 + tests/data/fixed_data_000002.h5 | 3 + tests/data/lyso_rotation_master.h5 | 3 + tools/CMakeLists.txt | 94 +- tools/jfjoch_azint.cpp | 207 +- tools/jfjoch_azint_test.cpp | 45 - tools/jfjoch_extract_hkl.cpp | 1 + tools/jfjoch_fpga_test.cpp | 6 +- tools/jfjoch_lite_perf_test.cpp | 4 +- tools/jfjoch_pcie_read_register.cpp | 32 - tools/jfjoch_process.cpp | 547 +- tools/jfjoch_scale.cpp | 15 +- tools/wingetopt/LICENSE | 54 + tools/wingetopt/getopt.c | 562 ++ tools/wingetopt/getopt.h | 105 + viewer/CMakeLists.txt | 133 +- viewer/JFJochImageReadingWorker.cpp | 622 +- viewer/JFJochImageReadingWorker.h | 101 +- viewer/JFJochProcessController.cpp | 132 + viewer/JFJochProcessController.h | 70 + viewer/JFJochViewerDatasetInfo.cpp | 279 +- viewer/JFJochViewerDatasetInfo.h | 18 +- viewer/JFJochViewerMenu.cpp | 63 +- viewer/JFJochViewerMenu.h | 21 +- viewer/JFJochViewerSidePanel.cpp | 98 +- viewer/JFJochViewerSidePanel.h | 24 +- viewer/JFJochViewerStatusBar.cpp | 86 +- viewer/JFJochViewerStatusBar.h | 29 +- viewer/JFJochViewerWindow.cpp | 402 +- viewer/JFJochViewerWindow.h | 33 +- viewer/RunData.h | 22 + viewer/charts/JFJochDatasetInfoChartView.cpp | 147 +- viewer/charts/JFJochDatasetInfoChartView.h | 52 +- viewer/charts/JFJochSimpleChartView.cpp | 5 +- viewer/image_viewer/JFJochAzIntImage.cpp | 3 +- .../image_viewer/JFJochDiffractionImage.cpp | 504 +- viewer/image_viewer/JFJochDiffractionImage.h | 45 + viewer/image_viewer/JFJochImage.cpp | 60 +- viewer/image_viewer/JFJochImage.h | 28 +- viewer/image_viewer/JFJochSimpleImage.cpp | 4 + viewer/image_viewer/JFJochSimpleImage.h | 2 + viewer/jfjoch_viewer.cpp | 17 + viewer/resources/generate_licenses_html.mjs | 71 + viewer/resources/jfjoch.icns | Bin 0 -> 95472 bytes viewer/resources/jfjoch.ico | Bin 0 -> 86899 bytes viewer/resources/jfjoch.rc | 3 + viewer/resources/psi_01.png | Bin 0 -> 5818 bytes viewer/resources/psi_01_sp.svg | 635 ++ viewer/resources/psi_02.png | Bin 0 -> 7457 bytes viewer/resources/psi_02_sp.svg | 851 +++ viewer/resources/psi_03.png | Bin 0 -> 7142 bytes viewer/resources/psi_03_sp.svg | 870 +++ viewer/resources/psi_04.png | Bin 0 -> 6204 bytes viewer/resources/psi_04_sp.svg | 738 +++ viewer/resources/resources.qrc | 5 + viewer/resources/third_party_licenses.html | 5869 +++++++++++++++++ viewer/toolbar/JFJochViewerToolbarDisplay.cpp | 37 +- viewer/toolbar/JFJochViewerToolbarDisplay.h | 9 +- viewer/toolbar/JFJochViewerToolbarImage.cpp | 207 +- viewer/toolbar/JFJochViewerToolbarImage.h | 26 +- viewer/widgets/CollapsibleSection.cpp | 44 + viewer/widgets/CollapsibleSection.h | 23 + .../JFJochViewerImageROIStatistics.cpp | 91 - .../widgets/JFJochViewerImageROIStatistics.h | 46 - .../JFJochViewerImageROIStatistics_Box.cpp | 71 - .../JFJochViewerImageROIStatistics_Box.h | 30 - .../JFJochViewerImageROIStatistics_Circle.cpp | 55 - .../JFJochViewerImageROIStatistics_Circle.h | 31 - viewer/widgets/JFJochViewerImageStrip.cpp | 192 + viewer/widgets/JFJochViewerImageStrip.h | 50 + viewer/widgets/JFJochViewerROIList.cpp | 281 + viewer/widgets/JFJochViewerROIList.h | 56 + viewer/widgets/JFJochViewerROIResult.cpp | 4 +- viewer/widgets/JFJochViewerSettingsDock.cpp | 341 + viewer/widgets/JFJochViewerSettingsDock.h | 75 + viewer/widgets/JFJochViewerSidePanelChart.cpp | 113 +- viewer/widgets/JFJochViewerSidePanelChart.h | 23 +- viewer/widgets/PowderCalibrationWidget.cpp | 13 +- viewer/widgets/TitleLabel.cpp | 18 +- viewer/widgets/ToolbarIcons.cpp | 173 + viewer/widgets/ToolbarIcons.h | 26 + .../windows/JFJochBraggIntegrationPanel.cpp | 51 + viewer/windows/JFJochBraggIntegrationPanel.h | 29 + viewer/windows/JFJochLicenseWindow.cpp | 23 + viewer/windows/JFJochLicenseWindow.h | 13 + viewer/windows/JFJochMagnifierWindow.cpp | 45 + viewer/windows/JFJochMagnifierWindow.h | 28 + viewer/windows/JFJochProcessingJobsWindow.cpp | 457 ++ viewer/windows/JFJochProcessingJobsWindow.h | 89 + viewer/windows/JFJochScalingPanel.cpp | 77 + viewer/windows/JFJochScalingPanel.h | 33 + viewer/windows/JFJochSettingsWindow.cpp | 45 + viewer/windows/JFJochSettingsWindow.h | 36 + .../windows/JFJochViewerImageListWindow.cpp | 6 + viewer/windows/JFJochViewerMetadataWindow.cpp | 9 +- .../windows/JFJochViewerProcessingWindow.cpp | 167 +- viewer/windows/JFJochViewerProcessingWindow.h | 24 +- writer/CMakeLists.txt | 20 +- writer/HDF5DataFile.cpp | 1 - writer/HDF5NXmx.cpp | 73 + writer/HDF5NXmx.h | 1 + writer/HDF5Objects.cpp | 2 +- writer/HDF5Objects.h | 2 +- 615 files changed, 44962 insertions(+), 13455 deletions(-) create mode 100644 CLAUDE.md create mode 100644 THIRD_PARTY_NOTICES.md create mode 100644 broker/gen/.gitignore create mode 100644 common/JFJochMath.h rename {receiver => common}/JFJochReceiverPlots.cpp (99%) rename {receiver => common}/JFJochReceiverPlots.h (92%) delete mode 100644 common/NUMAHWPolicy.cpp delete mode 100644 common/NUMAHWPolicy.h create mode 100644 docs/HDF5.md create mode 100644 docs/JFJOCH_PROCESS.md create mode 100644 frontend/openapi-ts.config.ts create mode 100644 frontend/scripts/generate-third-party-licenses.mjs create mode 100644 frontend/src/client/@tanstack/react-query.gen.ts create mode 100644 frontend/src/client/client.gen.ts create mode 100644 frontend/src/client/client/client.gen.ts create mode 100644 frontend/src/client/client/index.ts create mode 100644 frontend/src/client/client/types.gen.ts create mode 100644 frontend/src/client/client/utils.gen.ts create mode 100644 frontend/src/client/core/auth.gen.ts create mode 100644 frontend/src/client/core/bodySerializer.gen.ts create mode 100644 frontend/src/client/core/params.gen.ts create mode 100644 frontend/src/client/core/pathSerializer.gen.ts create mode 100644 frontend/src/client/core/queryKeySerializer.gen.ts create mode 100644 frontend/src/client/core/serverSentEvents.gen.ts create mode 100644 frontend/src/client/core/types.gen.ts create mode 100644 frontend/src/client/core/utils.gen.ts create mode 100644 frontend/src/client/index.ts create mode 100644 frontend/src/client/sdk.gen.ts create mode 100644 frontend/src/client/types.gen.ts create mode 100644 frontend/src/client/zod.gen.ts create mode 100644 frontend/src/components/Plot.jsx create mode 100644 frontend/src/components/SettingsPanel.tsx create mode 100644 frontend/src/components/useUpload.ts delete mode 100644 frontend/src/openapi/core/ApiError.ts delete mode 100644 frontend/src/openapi/core/ApiRequestOptions.ts delete mode 100644 frontend/src/openapi/core/ApiResult.ts delete mode 100644 frontend/src/openapi/core/CancelablePromise.ts delete mode 100644 frontend/src/openapi/core/OpenAPI.ts delete mode 100644 frontend/src/openapi/core/request.ts delete mode 100644 frontend/src/openapi/index.ts delete mode 100644 frontend/src/openapi/models/azim_int_settings.ts delete mode 100644 frontend/src/openapi/models/azint_unit.ts delete mode 100644 frontend/src/openapi/models/background.ts delete mode 100644 frontend/src/openapi/models/binning.ts delete mode 100644 frontend/src/openapi/models/broker_status.ts delete mode 100644 frontend/src/openapi/models/calibration_statistics.ts delete mode 100644 frontend/src/openapi/models/color_scale.ts delete mode 100644 frontend/src/openapi/models/crystal_lattice.ts delete mode 100644 frontend/src/openapi/models/dark_mask_settings.ts delete mode 100644 frontend/src/openapi/models/dataset_settings.ts delete mode 100644 frontend/src/openapi/models/detector.ts delete mode 100644 frontend/src/openapi/models/detector_list.ts delete mode 100644 frontend/src/openapi/models/detector_list_element.ts delete mode 100644 frontend/src/openapi/models/detector_module.ts delete mode 100644 frontend/src/openapi/models/detector_module_direction.ts delete mode 100644 frontend/src/openapi/models/detector_power_state.ts delete mode 100644 frontend/src/openapi/models/detector_selection.ts delete mode 100644 frontend/src/openapi/models/detector_settings.ts delete mode 100644 frontend/src/openapi/models/detector_state.ts delete mode 100644 frontend/src/openapi/models/detector_status.ts delete mode 100644 frontend/src/openapi/models/detector_timing.ts delete mode 100644 frontend/src/openapi/models/detector_type.ts delete mode 100644 frontend/src/openapi/models/error_message.ts delete mode 100644 frontend/src/openapi/models/experimental_coord.ts delete mode 100644 frontend/src/openapi/models/file_writer_format.ts delete mode 100644 frontend/src/openapi/models/file_writer_settings.ts delete mode 100644 frontend/src/openapi/models/fill_value.ts delete mode 100644 frontend/src/openapi/models/fpga_status.ts delete mode 100644 frontend/src/openapi/models/geom_refinement_algorithm.ts delete mode 100644 frontend/src/openapi/models/grid_scan.ts delete mode 100644 frontend/src/openapi/models/image_buffer_status.ts delete mode 100644 frontend/src/openapi/models/image_format_settings.ts delete mode 100644 frontend/src/openapi/models/image_id.ts delete mode 100644 frontend/src/openapi/models/image_pusher_status.ts delete mode 100644 frontend/src/openapi/models/image_pusher_type.ts delete mode 100644 frontend/src/openapi/models/indexing_algorithm.ts delete mode 100644 frontend/src/openapi/models/indexing_settings.ts delete mode 100644 frontend/src/openapi/models/instrument_metadata.ts delete mode 100644 frontend/src/openapi/models/jfjoch_settings.ts delete mode 100644 frontend/src/openapi/models/jfjoch_statistics.ts delete mode 100644 frontend/src/openapi/models/jpeg_quality.ts delete mode 100644 frontend/src/openapi/models/measurement_statistics.ts delete mode 100644 frontend/src/openapi/models/pcie_devices.ts delete mode 100644 frontend/src/openapi/models/pixel_mask_statistics.ts delete mode 100644 frontend/src/openapi/models/plot.ts delete mode 100644 frontend/src/openapi/models/plot_type.ts delete mode 100644 frontend/src/openapi/models/plot_unit_x.ts delete mode 100644 frontend/src/openapi/models/plots.ts delete mode 100644 frontend/src/openapi/models/resolution_estimate.ts delete mode 100644 frontend/src/openapi/models/resolution_ring.ts delete mode 100644 frontend/src/openapi/models/roi.ts delete mode 100644 frontend/src/openapi/models/roi_azim_list.ts delete mode 100644 frontend/src/openapi/models/roi_azimuthal.ts delete mode 100644 frontend/src/openapi/models/roi_box.ts delete mode 100644 frontend/src/openapi/models/roi_box_list.ts delete mode 100644 frontend/src/openapi/models/roi_circle.ts delete mode 100644 frontend/src/openapi/models/roi_circle_list.ts delete mode 100644 frontend/src/openapi/models/roi_definitions.ts delete mode 100644 frontend/src/openapi/models/rotation_axis.ts delete mode 100644 frontend/src/openapi/models/saturation.ts delete mode 100644 frontend/src/openapi/models/scan_result.ts delete mode 100644 frontend/src/openapi/models/show_beam_center.ts delete mode 100644 frontend/src/openapi/models/show_roi.ts delete mode 100644 frontend/src/openapi/models/show_spots.ts delete mode 100644 frontend/src/openapi/models/show_user_mask.ts delete mode 100644 frontend/src/openapi/models/spot_finding_settings.ts delete mode 100644 frontend/src/openapi/models/standard_detector_geometry.ts delete mode 100644 frontend/src/openapi/models/tcp_settings.ts delete mode 100644 frontend/src/openapi/models/unit_cell.ts delete mode 100644 frontend/src/openapi/models/zeromq_metadata_settings.ts delete mode 100644 frontend/src/openapi/models/zeromq_preview_settings.ts delete mode 100644 frontend/src/openapi/models/zeromq_settings.ts delete mode 100644 frontend/src/openapi/services/DefaultService.ts delete mode 100644 frontend/src/react-app-env.d.ts delete mode 100644 frontend/src/serviceWorker.js delete mode 100644 frontend/src/setupTests.js create mode 100644 gemmi_gph/gemmi/utf.hpp create mode 100644 image_analysis/geom_refinement/LatticeReduction.cpp create mode 100644 image_analysis/geom_refinement/LatticeReduction.h create mode 100644 image_analysis/pixel_refinement/CMakeLists.txt create mode 100644 image_analysis/pixel_refinement/FACTORED_MODEL.md create mode 100644 image_analysis/pixel_refinement/FINDINGS-2026-06.md create mode 100644 image_analysis/pixel_refinement/METHODS.md create mode 100644 image_analysis/pixel_refinement/PixelRefine.cpp create mode 100644 image_analysis/pixel_refinement/PixelRefine.h create mode 100644 image_analysis/roi/CMakeLists.txt create mode 100644 image_analysis/roi/ROIIntegration.cpp create mode 100644 image_analysis/roi/ROIIntegration.h create mode 100644 image_analysis/roi/ROIIntegrationCPU.cpp create mode 100644 image_analysis/roi/ROIIntegrationCPU.h create mode 100644 image_analysis/roi/ROIIntegrationGPU.cu create mode 100644 image_analysis/roi/ROIIntegrationGPU.h create mode 100644 licenses/COLLECT.sh create mode 100644 licenses/NVIDIA-CUDA-EULA.txt create mode 100644 licenses/NVIDIA-CUDA-NOTICE.txt create mode 100644 licenses/Qt6-LGPL-3.0.txt create mode 100644 licenses/Qt6-NOTICE.txt create mode 100644 licenses/base64-macaron.txt create mode 100644 licenses/bitshuffle-hperf.txt create mode 100644 licenses/bitshuffle.txt create mode 100644 licenses/catch2.txt create mode 100644 licenses/ceres-solver.txt create mode 100644 licenses/cpp-httplib.txt create mode 100644 licenses/eigen-README.txt create mode 100644 licenses/eigen.txt create mode 100644 licenses/fast-feedback-indexer.txt create mode 100644 licenses/fftw.txt create mode 100644 licenses/gemmi.txt create mode 100644 licenses/hdf5.txt create mode 100644 licenses/libjpeg-turbo.txt create mode 100644 licenses/libtiff.txt create mode 100644 licenses/libzmq.txt create mode 100644 licenses/lz4.txt create mode 100644 licenses/nlohmann-json.txt create mode 100644 licenses/slsDetectorPackage-GPL-3.0.txt create mode 100644 licenses/slsDetectorPackage-LGPL-3.0.txt create mode 100644 licenses/spdlog.txt create mode 100644 licenses/tinycbor.txt create mode 100644 licenses/wingetopt.txt create mode 100644 licenses/xbflash-qspi.txt create mode 100644 licenses/xilinx-hls-headers.txt create mode 100644 licenses/zlib.txt create mode 100644 licenses/zstd.txt create mode 100644 process/CMakeLists.txt create mode 100644 process/JFJochProcess.cpp create mode 100644 process/JFJochProcess.h create mode 100644 process/JFJochProcessCommandLine.cpp create mode 100644 process/JFJochProcessCommandLine.h create mode 100644 reader/HDF5ImageLocator.cpp create mode 100644 reader/HDF5ImageLocator.h create mode 100644 reader/HDF5ImageSource.cpp create mode 100644 reader/HDF5ImageSource.h create mode 100644 reader/HDF5MetadataSource.cpp create mode 100644 reader/HDF5MetadataSource.h create mode 100644 tests/JFJochProcessLargeTest.cpp create mode 100644 tests/JFJochProcessTest.cpp create mode 100644 tests/LatticeReductionTest.cpp create mode 100644 tests/ROIIntegrationCPUTest.cpp create mode 100644 tests/ROIIntegrationGPUTest.cpp create mode 100644 tests/TestData.h create mode 100644 tests/data/README.md create mode 100644 tests/data/fixed_data_000001.h5 create mode 100644 tests/data/fixed_data_000002.h5 create mode 100644 tests/data/lyso_rotation_master.h5 delete mode 100644 tools/jfjoch_azint_test.cpp delete mode 100644 tools/jfjoch_pcie_read_register.cpp create mode 100644 tools/wingetopt/LICENSE create mode 100644 tools/wingetopt/getopt.c create mode 100644 tools/wingetopt/getopt.h create mode 100644 viewer/JFJochProcessController.cpp create mode 100644 viewer/JFJochProcessController.h create mode 100644 viewer/RunData.h create mode 100644 viewer/resources/generate_licenses_html.mjs create mode 100644 viewer/resources/jfjoch.icns create mode 100644 viewer/resources/jfjoch.ico create mode 100644 viewer/resources/jfjoch.rc create mode 100644 viewer/resources/psi_01.png create mode 100644 viewer/resources/psi_01_sp.svg create mode 100644 viewer/resources/psi_02.png create mode 100644 viewer/resources/psi_02_sp.svg create mode 100644 viewer/resources/psi_03.png create mode 100644 viewer/resources/psi_03_sp.svg create mode 100644 viewer/resources/psi_04.png create mode 100644 viewer/resources/psi_04_sp.svg create mode 100644 viewer/resources/third_party_licenses.html create mode 100644 viewer/widgets/CollapsibleSection.cpp create mode 100644 viewer/widgets/CollapsibleSection.h delete mode 100644 viewer/widgets/JFJochViewerImageROIStatistics.cpp delete mode 100644 viewer/widgets/JFJochViewerImageROIStatistics.h delete mode 100644 viewer/widgets/JFJochViewerImageROIStatistics_Box.cpp delete mode 100644 viewer/widgets/JFJochViewerImageROIStatistics_Box.h delete mode 100644 viewer/widgets/JFJochViewerImageROIStatistics_Circle.cpp delete mode 100644 viewer/widgets/JFJochViewerImageROIStatistics_Circle.h create mode 100644 viewer/widgets/JFJochViewerImageStrip.cpp create mode 100644 viewer/widgets/JFJochViewerImageStrip.h create mode 100644 viewer/widgets/JFJochViewerROIList.cpp create mode 100644 viewer/widgets/JFJochViewerROIList.h create mode 100644 viewer/widgets/JFJochViewerSettingsDock.cpp create mode 100644 viewer/widgets/JFJochViewerSettingsDock.h create mode 100644 viewer/widgets/ToolbarIcons.cpp create mode 100644 viewer/widgets/ToolbarIcons.h create mode 100644 viewer/windows/JFJochBraggIntegrationPanel.cpp create mode 100644 viewer/windows/JFJochBraggIntegrationPanel.h create mode 100644 viewer/windows/JFJochLicenseWindow.cpp create mode 100644 viewer/windows/JFJochLicenseWindow.h create mode 100644 viewer/windows/JFJochMagnifierWindow.cpp create mode 100644 viewer/windows/JFJochMagnifierWindow.h create mode 100644 viewer/windows/JFJochProcessingJobsWindow.cpp create mode 100644 viewer/windows/JFJochProcessingJobsWindow.h create mode 100644 viewer/windows/JFJochScalingPanel.cpp create mode 100644 viewer/windows/JFJochScalingPanel.h create mode 100644 viewer/windows/JFJochSettingsWindow.cpp create mode 100644 viewer/windows/JFJochSettingsWindow.h diff --git a/.gitattributes b/.gitattributes index 717b707e..b81e799d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,5 @@ *.mcs filter=lfs diff=lfs merge=lfs -text *.mcs.gz filter=lfs diff=lfs merge=lfs -text + +# Large reference datasets for the [large] Catch tests (git-LFS; may not be pulled in CI). +tests/data/*.h5 filter=lfs diff=lfs merge=lfs -text diff --git a/.gitea/workflows/build_and_test.yml b/.gitea/workflows/build_and_test.yml index ac19d87e..fa13a3ce 100644 --- a/.gitea/workflows/build_and_test.yml +++ b/.gitea/workflows/build_and_test.yml @@ -31,6 +31,16 @@ jobs: CTEST_OUTPUT_ON_FAILURE: '1' steps: - uses: actions/checkout@v4 + - name: Configure auth and fetch LFS + shell: bash + env: + GITEA_TOKEN: ${{ secrets.PIP_REPOSITORY_API_TOKEN }} + run: | + git lfs install --local + AUTH=$(git config --local http.${{ github.server_url }}/.extraheader) + git config --local --unset http.${{ github.server_url }}/.extraheader + git config --local http.${{ github.server_url }}/${{ github.repository }}.git/info/lfs/objects/batch.extraheader "$AUTH" + git lfs pull - name: Build tests shell: bash run: | @@ -140,9 +150,13 @@ jobs: echo "No package files found for pattern: ${{ matrix.pkg_glob }}" exit 1 fi + url="${{ matrix.upload_url }}" + if [[ "$url" == *"/rpm/"* ]]; then + url="${url}?sign=true" + fi for file in "${files[@]}"; do - echo "Uploading $file -> ${{ matrix.upload_url }}" - curl --fail --user __token__:"$TOKEN" --upload-file "$file" "${{ matrix.upload_url }}" + echo "Uploading $file -> $url" + curl --fail --user __token__:"$TOKEN" --upload-file "$file" "$url" done cd .. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..f57bc197 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,192 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +Jungfraujoch is the data-acquisition and analysis system for the PSI JUNGFRAU and EIGER +X-ray detectors. It receives detector data, runs it through an FPGA-accelerated pipeline +(spot finding, azimuthal/ROI integration, compression), streams images out over ZeroMQ for +writing to HDF5, and runs crystallographic analysis (indexing, integration, scaling/merging). +Most authoritative documentation lives in `docs/` and on Read The Docs +(https://jungfraujoch.readthedocs.io). When changing CLI behaviour, the program's own +usage message is the source of truth, not the docs. + +## Build + +Out-of-source CMake build, C++20, heavy use of `FetchContent` (spdlog, zstd, HDF5, +slsDetectorPackage, Catch2, cpp-httplib, libzmq, Ceres, fast-feedback-indexer are downloaded +and statically linked — the **first configure needs network access** and is slow). + +``` +mkdir build && cd build +cmake -DCMAKE_BUILD_TYPE=Release .. +make -j$(nproc) jfjoch_broker # the main service; build other targets by name +``` + +Key CMake options: +- `JFJOCH_USE_CUDA` (default ON) — GPU path. Needs CUDA ≥ 12.8. Provides the `ffbidx` and `fft` + GPU indexers; without it only the CPU `fftw` indexer is available (requires FFTW at configure + time, auto-detected). CUDA absence is not a build error. +- `JFJOCH_WRITER_ONLY` (default OFF) — builds only the HDF5 writer; skips broker, FPGA, + receiver, analysis, tests, frontend. +- `JFJOCH_VIEWER_BUILD` (default OFF) — builds the Qt6 `jfjoch_viewer` desktop app. +- `SLS9` (default OFF) — build against slsDetectorPackage 9.2.0 instead of 8.0.2. + +The frontend is a separate custom target: `make frontend` (runs `npm ci && npm run build` in +`frontend/`). It is not built by default unless installing. + +## Test + +Tests use **Catch2** and are collected into a single binary `tests/jfjoch_test`. + +``` +make -j$(nproc) jfjoch_test +cd tests +./jfjoch_test # all tests +./jfjoch_test "" # one test case (exact name in TEST_CASE) +./jfjoch_test "[tag]" # by tag +./jfjoch_test -r junit -o report.xml +``` + +`make jfjoch_hdf5_test` builds the HDF5 write-speed benchmark, also used by CI to produce files +that are validated against XDS (Durin/Neggia) and CrystFEL. + +Lint config is `.clang-tidy` (broad `*` check set with many exceptions; namespaces lower_case, +classes CamelCase, global constants UPPER_CASE). + +## Code style + +The overriding principle is **simple, readable code** — favour the smallest, most direct +implementation that a reader can verify at a glance. Extra abstraction, speculative guards, and +clever-but-dense constructs are treated as actively harmful, not as polish. When torn between a +tidy abstraction and a flat, obvious version, pick the obvious one. + +This matters most in `image_analysis/pixel_refinement/` (e.g. `PixelRefine.cpp`), which is an +experimental prototype where readability is how the physics gets verified — keep it especially +plain. **Do not add defensive/unrequested code** (extra validation, rejection heuristics, "just in +case" branches) without asking first; if a guard isn't clearly needed, leave it out. + +Match the surrounding code's idiom, naming, and comment density rather than importing a different +style. + +## Local end-to-end run (no detector / no FPGA) + +The FPGA HLS logic can be simulated on the CPU (`HLSSimulatedDevice`), so the full software +stack runs without hardware (slowly — fixed-point math on CPU). See +`docs/JFJOCH_BROKER.md` for the canonical walkthrough. + +``` +cd build/broker +./jfjoch_broker ../../etc/broker_local.json 5232 # config JSON + HTTP port +# then, separately: +cd tests/test_data && python jfjoch_broker_test.py # feeds a test image, starts collection +# observe at http://localhost:5232 ; HDF5 is written under build/broker +``` + +`etc/broker_local.json`, `broker_eiger.json`, `broker_crmx.json` are example broker configs +(schema = `jfjoch_settings` in `broker/jfjoch_api.yaml`). + +## Architecture + +**Data flow (online):** detector → FPGA acquisition (`fpga/`, `acquisition_device/`) → +`receiver/` builds full images from per-module FPGA output → `image_pusher/` streams CBOR-encoded +images over ZeroMQ → `jfjoch_writer` (`writer/`) consumes the stream and writes NXmx HDF5. The +broker also emits a low-rate preview stream and a metadata stream (`preview/`). + +**Writer file split:** one acquisition produces one `_master.h5` plus many `_data_NNNNNN.h5` +files. Dataset-wide metadata (geometry, detector config, ROI/azimuthal definitions — anything +fixed for the whole run) is written to the **master** file in `writer/HDF5NXmx.cpp` (the `NXmx` +class). Per-image arrays (one entry per frame) are written to the **data** files by the +`HDF5DataFilePlugin` subclasses in `writer/`. Put shared metadata in `NXmx`, not in a data-file +plugin. + +The HDF5 master/data layout is one of three `FileWriterFormat`s (`common/JFJochMessages.h`), +all NXmx: **`NXmxLegacy`** (master + `_data_NNNNNN.h5` joined by external links), +**`NXmxVDS`** (master + data joined by HDF5 virtual datasets — the default), and +**`NXmxIntegrated`** (a single self-contained file, no separate data files). Per-image plugins +must work for all three; with `NXmxIntegrated` "master" and "data" are the same file. + +**Two acquisition workflows:** the FPGA-accelerated path (JUNGFRAU at PSI; FPGA does masking, +summation, spot finding, ROI/azimuthal integration, compression) and the DECTRIS SIMPLON path +(EIGER), which has no FPGA — masking/ROI/azimuthal analysis then runs on CPU through the shared +`image_analysis/` library. Treat ROI and azimuthal features as available in **both** workflows, +not FPGA-only. + +**`jfjoch_broker`** (`broker/`) is the central online service: HTTP/REST + OpenAPI control plane, +FPGA configuration, image building, ZeroMQ output. `JFJochStateMachine` drives acquisition state; +`JFJochServices` wires the pieces; `OpenAPIConvert`/`JFJochBrokerParser` translate between the +generated API model and internal types. + +**Three analysis frontends share one analysis library** (`image_analysis/`, built as +`JFJochImageAnalysis`): +- `jfjoch_broker` — online, real-time (FPGA + GPU). +- `jfjoch_viewer` — interactive Qt desktop (`viewer/`), results not persisted. +- `jfjoch_process` (`tools/jfjoch_process.cpp`) — offline batch over a stored HDF5; writes + `_process.h5` and `.mtz`/`.cif`/`.hkl`. `jfjoch_scale` re-scales/merges already-integrated data. + +**`image_analysis/` pipeline** (subdirs): `spot_finding`, `indexing` (`ffbidx`/`fft` GPU, +`fftw` CPU), `lattice_search`, `geom_refinement`, `pixel_refinement`, `bragg_prediction`, +`bragg_integration`, `rotation_indexer`, `azint`, `roi`, `scale_merge`. Least-squares refinement +uses **Ceres** (fetched, built with miniglog, no MKL, CXX_THREADS). `ffbidx` needs a known cell +(`-C`) and suits sparse serial stills; `fft`/`fftw` index de novo and suit strong rotation data. + +**FPGA** (`fpga/`): `hls/` is the Vitis HLS source (image-analysis kernels), `hls_simulation/` +runs that same HLS on CPU for hardware-free testing, `host_library/` is the host-side driver, +`pcie_driver/` is the kernel module. The HLS algorithms are documented in +`docs/FPGA_DATA_ANALYSIS.md`. + +**Detector control** (`detector_control/`): wrappers for SLS (JUNGFRAU) and DECTRIS SIMPLON +(EIGER). **`jungfrau/`**: JUNGFRAU ADU→energy gain/pedestal calibration. + +**Other libs:** `common/` (geometry, diffraction experiment, image buffer, CUDA wrappers — the +shared core, linked nearly everywhere), `compression/` (zstd + bitshuffle + sqrt lossy), +`frame_serialize/` (CBOR stream codec), `gemmi_gph/` (vendored GEMMI for MTZ/XDS_ASCII I/O), +`xds-plugin/` (XDS HDF5 read plugin). + +## Portability (jfjoch_viewer) + +Cross-platform support is a goal **only for `jfjoch_viewer` and its dependency tree** — keep that +code, and any shared library it transitively links (`common/`, `image_analysis/`, `reader/`, +`gemmi_gph/`, etc.), **MSVC-compatible** so the viewer can build on Windows. The rest of the +project (broker, receiver, FPGA host, detector control, …) is Linux-only and does not need to be +portable; don't constrain it for portability's sake. + +- **Windows/MSVC** is the primary portability target. The end goal is a Windows viewer built + with **MSVC *and* CUDA** (`JFJOCH_USE_CUDA=ON`): GPU processing is a wanted feature, not + optional, so the intended Windows config is the full GPU path (`ffbidx`, GPU `fft`), not a + CPU-only fallback. MSVC is required regardless, because CUDA on Windows requires it. Avoid + GCC/Clang-only extensions, POSIX-only APIs, and other non-MSVC constructs in viewer-reachable + code, and keep CUDA-reachable viewer code (`ffbidx`, GPU indexers) MSVC-buildable too. +- **macOS** is a nice-to-have for the viewer. It rules out CUDA, so anything the viewer depends on + must also have a working CPU-only / non-CUDA path (the `JFJOCH_USE_CUDA=OFF`, `fftw`-indexer + configuration). This non-CUDA path must keep working, but it is the macOS fallback — *not* the + intended Windows configuration. + +A self-contained Windows build still needs a few dependencies that the Linux build picks up from +the system and that are **not** auto-provided via `FetchContent` (besides Qt, supplied +externally): **ZLIB** (pulled by hdf5/libtiff/gemmi/libzmq — a bundled zlib-ng in `ZLIB_COMPAT` +mode is the intended fix, presented as the `ZLIB::ZLIB` target so the scattered +`find_package(ZLIB)` calls resolve), **libjpeg-turbo** (used by `preview/`; upstream discourages +`add_subdirectory`, so bring it in via `ExternalProject`), and **Eigen** (header-only; needed by +Ceres, by the analysis libs directly, and by `ffbidx` under CUDA — fetch it and point Ceres' +internal `find_package(Eigen3)` at it). Wire each guarded so the Linux build, which finds these on +the system, stays unchanged. + +## OpenAPI is the single source of truth + +`broker/jfjoch_api.yaml` defines the entire REST API **and the shared data schemas**. From it, +`update_version.sh` regenerates three clients — **do not hand-edit generated code**: +- C++ server model → `broker/gen/` (cpp-pistache-server generator; compiled as `JFJochAPI`). +- Python client → `python-client/` (and `gen_python_client.sh`, published as PyPI `jfjoch-client`). +- TypeScript frontend client → `frontend/src/client/` (hey-api `openapi-ts`, `npm run openapi`). + +When you change `jfjoch_api.yaml`, regenerate the relevant client(s); for a version bump run +`update_version.sh` (also rewrites `VERSION`, `frontend/src/version.ts`, and the Redoc html). + +## Frontend + +React 19 + TypeScript + MUI + Vite (`frontend/`). Data layer is generated from the OpenAPI spec +(`@hey-api/openapi-ts` → fetch client + TanStack Query hooks + zod schemas). Scripts: +`npm start` (dev server), `npm run build` (tsc + vite), `npm run openapi` (regen client), +`npm run redocly4broker` (regen `broker/redoc-static.html`). diff --git a/CMakeLists.txt b/CMakeLists.txt index 02668e08..7a5c6fcc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,18 +8,24 @@ SET(CMAKE_POLICY_DEFAULT_CMP0077 NEW) SET(CMAKE_CXX_STANDARD 20) SET(CMAKE_CXX_STANDARD_REQUIRED True) -SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -Wno-deprecated-enum-enum-conversion -DNDEBUG") -SET(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG") - SET(JFJOCH_WRITER_ONLY OFF CACHE BOOL "Compile HDF5 writer only") SET(JFJOCH_INSTALL_DRIVER_SOURCE OFF CACHE BOOL "Install kernel driver source (ignored if building writer only; necessary for RPM building)") SET(JFJOCH_USE_CUDA ON CACHE BOOL "Compile Jungfraujoch with CUDA") SET(JFJOCH_VIEWER_BUILD OFF CACHE BOOL "Compile Jungfraujoch viewer") -FIND_PACKAGE(ZLIB REQUIRED) +# Only the viewer (and its portable dependency tree) is supported on Windows and macOS -- the +# broker/receiver/FPGA/writer server stack is Linux-only. Force viewer-only on those platforms so a +# plain configure builds the right subset; on Linux it remains a user-togglable option. +IF (WIN32 OR APPLE) + SET(JFJOCH_VIEWER_ONLY ON CACHE BOOL "Compile only jfjoch_viewer and its dependencies" FORCE) +ELSE() + SET(JFJOCH_VIEWER_ONLY OFF CACHE BOOL "Compile only jfjoch_viewer and its dependencies") +ENDIF() SET (ZLIB_USE_STATIC_LIBS TRUE) +FIND_PACKAGE(ZLIB REQUIRED) + OPTION(SLS9 "Build with sls_detector_package v9.2.0" OFF) SET(BUILD_SHARED_LIBS OFF) @@ -39,10 +45,26 @@ SET(BUILD_FAST_INDEXER_STATIC ON) INCLUDE(CheckLanguage) INCLUDE(CheckIncludeFile) + +# Locate nvcc ourselves when it isn't already pinned (-DCMAKE_CUDA_COMPILER / $CUDACXX). CHECK_LANGUAGE +# below only searches PATH, which is missed routinely on Windows and intermittently on Linux; the +# standard CUDA install locations (CUDA_PATH on Windows, /usr/local/cuda on Linux) cover both, so the +# compiler need not be passed by hand. Only set it when actually found, leaving CHECK_LANGUAGE to run +# its normal detection otherwise. +IF (JFJOCH_USE_CUDA AND NOT CMAKE_CUDA_COMPILER AND NOT DEFINED ENV{CUDACXX}) + FIND_PROGRAM(_jfjoch_nvcc nvcc + HINTS ENV CUDA_PATH ENV CUDA_HOME ENV CUDA_ROOT /usr/local/cuda /opt/cuda + PATH_SUFFIXES bin) + IF (_jfjoch_nvcc) + SET(CMAKE_CUDA_COMPILER "${_jfjoch_nvcc}") + ENDIF() +ENDIF() + CHECK_LANGUAGE(CUDA) SET(CMAKE_CUDA_ARCHITECTURES 75 80 86 89 90 100 120) # T4, A100, RTX A4000, L4 -SET(CMAKE_CUDA_STANDARD 17) +SET(CMAKE_CUDA_STANDARD 20) +SET(CMAKE_CUDA_STANDARD_REQUIRED True) SET(CMAKE_CUDA_FLAGS_RELEASE "-O3 -lineinfo") SET(CMAKE_CUDA_RUNTIME_LIBRARY Static) @@ -56,6 +78,11 @@ IF (CMAKE_CUDA_COMPILER) FIND_PACKAGE(CUDAToolkit REQUIRED) ADD_COMPILE_DEFINITIONS(JFJOCH_USE_CUDA) SET(JFJOCH_CUDA_AVAILABLE ON) + # Blackwell GB10 (DGX Spark) is sm_121, only known to nvcc >= 12.9; add it there so the + # binary launches natively on Spark (the list above tops out at sm_120 and embeds no PTX). + IF (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "12.9") + LIST(APPEND CMAKE_CUDA_ARCHITECTURES 121) + ENDIF() ELSE() MESSAGE(WARNING "CUDA older than 12.8 not supported") ENDIF() @@ -64,20 +91,7 @@ IF (CMAKE_CUDA_COMPILER) ENDIF() ENDIF() -FIND_LIBRARY(FFTWF_LIBRARY NAMES libfftw3f.a libfftw3f.so fftw3f DOC "FFTW single-precision library" - PATHS /usr/lib /usr/lib64 /usr/lib/x86_64-linux-gnu/) -CHECK_INCLUDE_FILE(fftw3.h HAS_FFTW3_H) - -IF(HAS_FFTW3_H AND FFTWF_LIBRARY) - ADD_COMPILE_DEFINITIONS(JFJOCH_USE_FFTW) -ENDIF() - INCLUDE_DIRECTORIES(include) -INCLUDE(CheckIncludeFile) - -FIND_LIBRARY(NUMA_LIBRARY NAMES numa DOC "NUMA Library") -CHECK_INCLUDE_FILE(numaif.h HAS_NUMAIF) -CHECK_INCLUDE_FILE(numa.h HAS_NUMA_H) include(FetchContent) @@ -143,43 +157,168 @@ FetchContent_Declare( GIT_TAG v0.39.0 EXCLUDE_FROM_ALL ) +# httplib enables Brotli content-encoding whenever it finds system Brotli; we don't use it +# (gzip/zlib is enough for the broker), so disable it to avoid linking libbrotli. +SET(HTTPLIB_USE_BROTLI_IF_AVAILABLE OFF CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(zstd sls_detector_package catch2 hdf5 spdlog httplib) +# ZeroMQ (libzmq): fetch it here, at the top level, so that THIS project - not +# slsDetectorPackage - controls the version. slsDetectorPackage bundles its own libzmq +# archive, but only populates it behind `if(NOT libzmq_POPULATED)`; by making libzmq +# available before sls below, sls reuses this copy and a single libzmq-static target is +# built (no duplicate target / double-symbol clash). A future viewer-only / Windows build +# (which does not build sls) fetches the same libzmq standalone. +SET(BUILD_SHARED OFF CACHE BOOL "" FORCE) # libzmq: static only (matches sls) +SET(BUILD_TESTS OFF CACHE BOOL "" FORCE) # libzmq: no test build +SET(WITH_PERF_TOOL OFF CACHE BOOL "" FORCE) # libzmq: no perf tools +SET(WITH_DOCS OFF CACHE BOOL "" FORCE) # libzmq: no docs +SET(ENABLE_CPACK OFF CACHE BOOL "" FORCE) # libzmq: no CPack injection +FetchContent_Declare( + libzmq + GIT_REPOSITORY https://github.com/zeromq/libzmq.git + GIT_TAG v4.3.5 + EXCLUDE_FROM_ALL +) -ADD_SUBDIRECTORY(jungfrau) -ADD_SUBDIRECTORY(compression) -ADD_SUBDIRECTORY(common) -ADD_SUBDIRECTORY(writer) -ADD_SUBDIRECTORY(frame_serialize) -ADD_SUBDIRECTORY(reader) -ADD_SUBDIRECTORY(detector_control) -ADD_SUBDIRECTORY(image_puller) -ADD_SUBDIRECTORY(preview) -ADD_SUBDIRECTORY(gemmi_gph) -ADD_SUBDIRECTORY(xds-plugin) +# CMake >= 4.0 (e.g. the 4.x bundled with Visual Studio 2026) makes any +# cmake_minimum_required(VERSION < 3.5) a fatal error. Some fetched dependencies still +# declare such old floors (libzmq: 3.0.2), so raise the policy-version floor for the +# FetchContent subprojects. Ignored (harmless) on CMake < 3.30, which lacks this variable. +SET(CMAKE_POLICY_VERSION_MINIMUM 3.5) -IF (JFJOCH_WRITER_ONLY) - MESSAGE(STATUS "Compiling HDF5 writer only") +# libzmq must be made available BEFORE sls_detector_package for the override above to take effect. +FetchContent_MakeAvailable(libzmq) +IF (JFJOCH_VIEWER_ONLY) + # A viewer-only build still needs zstd/hdf5/spdlog/httplib (JFJochReader uses httplib). + # Only sls_detector_package (detector) and catch2 (tests) are not built here -- and sls + # in particular does not configure under MSVC -- so skip just those two. + FetchContent_MakeAvailable(zstd hdf5 spdlog httplib) ELSE() - ADD_SUBDIRECTORY(image_pusher) - ADD_SUBDIRECTORY(broker) - ADD_SUBDIRECTORY(fpga) - ADD_SUBDIRECTORY(acquisition_device) - ADD_SUBDIRECTORY(receiver) + FetchContent_MakeAvailable(zstd sls_detector_package catch2 hdf5 spdlog httplib) +ENDIF() + +# libtiff (used by JFJochPreview in every build mode): build it ourselves. Its C++ binding +# (tiffxx) is packaged inconsistently across distros (missing on Rocky 9) and absent on +# Windows. Library only; the SET()s below are libtiff's own codec/tool switches. +# We only need DEFLATE (zlib) + the internal LZW codec, matching what Python tifffile writes +# by default. The remaining codecs default to ON whenever their library is found on the build +# host, so each must be explicitly turned OFF to keep the dependency set minimal -- otherwise +# webp pulls in libwebp + libsharpyuv and lerc pulls in libLerc. +SET(jbig OFF) +SET(zstd OFF) +SET(lzma OFF) +SET(jpeg OFF) +SET(old-jpeg OFF) +SET(webp OFF) +SET(lerc OFF) +SET(tiff-tools OFF) +SET(tiff-tests OFF) +FetchContent_Declare(tiff + GIT_REPOSITORY https://gitlab.com/libtiff/libtiff.git + GIT_TAG v4.7.1 + EXCLUDE_FROM_ALL) +FetchContent_MakeAvailable(tiff) + +# FFTW single precision (target fftw3f): the CPU fallback indexer, enables JFJOCH_USE_FFTW. +# Built from the release tarball -- the git repo ships no pre-generated codelets (needs the +# OCaml genfft). +SET(ENABLE_FLOAT ON CACHE BOOL "" FORCE) +SET(BUILD_TESTS OFF CACHE BOOL "" FORCE) +# SIMD codelets are runtime-dispatched (cpuid), so enabling AVX2 does NOT require an AVX2 CPU +# -- FFTW falls back at runtime. The codelet sets are arch-specific, so guard by processor: +# x86 gets SSE2/AVX/AVX2, aarch64 (e.g. Grace on DGX Spark) gets NEON; other arches build scalar. +IF (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|AMD64|amd64") + SET(ENABLE_SSE2 ON CACHE BOOL "" FORCE) + SET(ENABLE_AVX ON CACHE BOOL "" FORCE) + SET(ENABLE_AVX2 ON CACHE BOOL "" FORCE) +ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|arm64|ARM64") + SET(ENABLE_NEON ON CACHE BOOL "" FORCE) +ENDIF() +FetchContent_Declare(fftw + URL https://www.fftw.org/fftw-3.3.10.tar.gz + URL_HASH SHA256=56c932549852cddcfafdab3820b0200c7742675be92179e59e6215b340e26467 + EXCLUDE_FROM_ALL) +FetchContent_MakeAvailable(fftw) +# FFTW exposes fftw3.h only via $, so consuming fftw3f straight from +# the build tree (FetchContent) leaves the header unreachable. On Linux a system-installed +# fftw3.h masks this; on Windows it does not. Add the source-tree api/ dir for build-tree use. +TARGET_INCLUDE_DIRECTORIES(fftw3f INTERFACE $) +ADD_COMPILE_DEFINITIONS(JFJOCH_USE_FFTW) + +# Eigen is an EXTERNAL dependency (like ZLIB), resolved by find_package(Eigen3) in the subdirectories +# that need it (image_analysis, and transitively Ceres and ffbidx). It is deliberately NOT vendored +# via FetchContent: declaring Eigen with OVERRIDE_FIND_PACKAGE makes the CMake bundled with Visual +# Studio (cmake 4.x "-msvc") intermittently SEGFAULT during configure. The fault is in CMake's own +# FetchContent variable-stack cleanup, reached when Ceres' find_package(Eigen3) resolves the override +# through a nested FetchContent_MakeAvailable -- ~1 in 3 fresh configures, and 100% with Ceres CUDA on. +# Stock Kitware CMake runs the identical scripts fine, so it is a bug in the VS-bundled cmake binary; +# providing Eigen externally avoids that code path entirely and is stable (verified, both Ceres CUDA +# on and off). Provide it via the system package on Linux (eigen3-devel / libeigen3-dev) or a build +# prefix on Windows (point CMAKE_PREFIX_PATH / Eigen3_DIR at it), exactly as for ZLIB. + +# getopt/getopt_long shim for Windows: the MSVC CRT has no . Vendored OpenBSD/NetBSD +# implementation (BSD-licensed). Built only on Windows and defined here, before the subdirectories, +# so the portable CLI tools in tools/ can link it. A no-op on Linux/macOS, where getopt lives in +# libc (macOS uses the system getopt even though it is also a forced viewer-only platform). +IF (WIN32) + ADD_LIBRARY(wingetopt STATIC tools/wingetopt/getopt.c tools/wingetopt/getopt.h) + TARGET_INCLUDE_DIRECTORIES(wingetopt PUBLIC tools/wingetopt) +ENDIF() + +IF (JFJOCH_VIEWER_ONLY) + # Minimal subtree: jfjoch_viewer and only the libraries it transitively links. + # (broker here provides JFJochAPI only; its service targets are gated out.) + ADD_SUBDIRECTORY(jungfrau) + ADD_SUBDIRECTORY(compression) + ADD_SUBDIRECTORY(common) + ADD_SUBDIRECTORY(gemmi_gph) + ADD_SUBDIRECTORY(frame_serialize) + ADD_SUBDIRECTORY(preview) + ADD_SUBDIRECTORY(writer) ADD_SUBDIRECTORY(image_analysis) - ADD_SUBDIRECTORY(tests) - ADD_SUBDIRECTORY(tools) -ENDIF() - -IF (JFJOCH_VIEWER_BUILD) + ADD_SUBDIRECTORY(broker) + ADD_SUBDIRECTORY(reader) + ADD_SUBDIRECTORY(process) ADD_SUBDIRECTORY(viewer) + ADD_SUBDIRECTORY(tools) # builds only the portable analysis tools (process/scale/azint/extract_hkl) +ELSE() + ADD_SUBDIRECTORY(jungfrau) + ADD_SUBDIRECTORY(compression) + ADD_SUBDIRECTORY(common) + ADD_SUBDIRECTORY(writer) + ADD_SUBDIRECTORY(frame_serialize) + ADD_SUBDIRECTORY(reader) + ADD_SUBDIRECTORY(detector_control) + ADD_SUBDIRECTORY(image_puller) + ADD_SUBDIRECTORY(preview) + ADD_SUBDIRECTORY(gemmi_gph) + ADD_SUBDIRECTORY(xds-plugin) + + IF (JFJOCH_WRITER_ONLY) + MESSAGE(STATUS "Compiling HDF5 writer only") + ELSE() + ADD_SUBDIRECTORY(image_pusher) + ADD_SUBDIRECTORY(broker) + ADD_SUBDIRECTORY(fpga) + ADD_SUBDIRECTORY(acquisition_device) + ADD_SUBDIRECTORY(receiver) + ADD_SUBDIRECTORY(image_analysis) + ADD_SUBDIRECTORY(process) + ADD_SUBDIRECTORY(tests) + ADD_SUBDIRECTORY(tools) + ENDIF() + + IF (JFJOCH_VIEWER_BUILD) + ADD_SUBDIRECTORY(viewer) + ENDIF() ENDIF() -IF (NOT JFJOCH_WRITER_ONLY) +IF (NOT JFJOCH_WRITER_ONLY AND NOT JFJOCH_VIEWER_ONLY) ADD_CUSTOM_COMMAND(OUTPUT frontend/dist/index.html COMMAND npm ci COMMAND npm run build + COMMAND npm run licenses # write dist/THIRD_PARTY_LICENSES.txt (npm deps attribution) COMMAND npm run redocly + COMMAND npm run docs # bundle Sphinx docs into dist/docs (served at /frontend/docs) WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/frontend) ADD_CUSTOM_TARGET(frontend DEPENDS frontend/dist/index.html) @@ -207,20 +346,19 @@ IF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) ENDIF(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) # Set Package Name -# Initialize CPACK_COMPONENTS_ALL with common components -set(CPACK_COMPONENTS_ALL jfjoch writer) - SET(CPACK_PACKAGE_NAME "jfjoch") -# Add optional components -if (JFJOCH_INSTALL_DRIVER_SOURCE) - list(APPEND CPACK_COMPONENTS_ALL driver-dkms) +# Select the components to package based on build mode +if (JFJOCH_VIEWER_ONLY) + set(CPACK_COMPONENTS_ALL viewer) else() set(CPACK_COMPONENTS_ALL jfjoch writer) -endif() - -if (JFJOCH_VIEWER_BUILD) - list(APPEND CPACK_COMPONENTS_ALL viewer) + if (JFJOCH_INSTALL_DRIVER_SOURCE) + list(APPEND CPACK_COMPONENTS_ALL driver-dkms) + endif() + if (JFJOCH_VIEWER_BUILD) + list(APPEND CPACK_COMPONENTS_ALL viewer) + endif() endif() # Common metadata @@ -228,8 +366,47 @@ set(CPACK_PACKAGE_CONTACT "Filip Leonarski ") set(CPACK_PACKAGE_VENDOR "Paul Scherrer Institut") set(CPACK_PACKAGE_VERSION ${JFJOCH_VERSION}) -# OS-aware packaging: DEB on Debian/Ubuntu, RPM on RHEL/Rocky -if (EXISTS "/etc/debian_version") +# OS-aware packaging: DragNDrop (.dmg) on macOS, NSIS installer on Windows, DEB on Debian/Ubuntu, +# RPM on RHEL/Rocky. macOS/Windows are checked first because the /etc/* probes below are Linux-only. +if (APPLE) + # .dmg containing jfjoch_viewer.app (Qt runtime already deployed into the bundle). + set(CPACK_GENERATOR "DragNDrop") +elseif (WIN32) + # NSIS installer .exe (Qt runtime deployed next to the binary by windeployqt). + set(CPACK_GENERATOR "NSIS") + + # GPLv3 text shown as the click-through license page of the installer. + set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") + + # Branding is split across three CPack knobs so the CUDA/CPU variant surfaces exactly where we + # want it and nowhere else: + # - Install folder + Start Menu group come from CPACK_PACKAGE_INSTALL_DIRECTORY and + # CPACK_NSIS_PACKAGE_NAME (the latter feeds $(^Name), the Start Menu group's default folder). + # Both stay plain "Jungfraujoch", so the Start Menu group carries no variant tag and the two + # builds install to the same place (CUDA is a strict superset -- they replace, not coexist). + # - CPACK_NSIS_DISPLAY_NAME is the Add/Remove Programs entry -- tagged "(CUDA)"/"(CPU)". + # - CPACK_PACKAGE_FILE_NAME is the installer .exe filename -- tagged "-cuda"/"-cpu", so + # the (much larger) CUDA download is self-identifying, with the CUDA major version baked in. + # The tag follows JFJOCH_CUDA_AVAILABLE automatically; CUDAToolkit_VERSION_MAJOR is set whenever + # it is ON (find_package(CUDAToolkit) ran in the same guard above). + set(CPACK_PACKAGE_INSTALL_DIRECTORY "Jungfraujoch") + set(CPACK_NSIS_PACKAGE_NAME "Jungfraujoch") + if (JFJOCH_CUDA_AVAILABLE) + set(CPACK_NSIS_DISPLAY_NAME "Jungfraujoch (CUDA)") + set(CPACK_PACKAGE_FILE_NAME "jfjoch-${JFJOCH_VERSION}-win64-cuda${CUDAToolkit_VERSION_MAJOR}") + else() + set(CPACK_NSIS_DISPLAY_NAME "Jungfraujoch (CPU)") + set(CPACK_PACKAGE_FILE_NAME "jfjoch-${JFJOCH_VERSION}-win64-cpu") + endif() + + # Start Menu shortcut for the viewer (";