Commit Graph

1246 Commits

Author SHA1 Message Date
leonarski_f c9803ccbfd Separate JFJochWriter and JFJochStreamWriter 2026-06-19 22:56:11 +02:00
leonarski_f 5a6485da3a cmake: use upstream libtiff (gitlab) at v4.7.1
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 11m1s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 11m2s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 10m29s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 10m34s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 12m0s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 11m35s
Build Packages / build:rpm (rocky8) (push) Successful in 12m19s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 11m10s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 10m35s
Build Packages / Generate python client (push) Successful in 18s
Build Packages / build:rpm (rocky9) (push) Successful in 12m46s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 45s
Build Packages / XDS test (durin plugin) (push) Successful in 9m28s
Build Packages / DIALS test (push) Successful in 14m43s
Build Packages / XDS test (neggia plugin) (push) Successful in 6m54s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m36s
Build Packages / Unit tests (push) Successful in 1h0m51s
Switch the libtiff FetchContent from the personal GitHub mirror to the
upstream gitlab repo and bump v4.6.0 -> v4.7.1 -- cleaner provenance; the
mirror was only ever a network-reachability workaround.

Verified on Linux: fetches, builds static (libtiff.a/libtiffxx.a), and
jfjoch_viewer links cleanly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 22:47:36 +02:00
leonarski_f 53645434be cmake: enable FFTW SSE2/AVX/AVX2 codelets (x86, runtime-dispatched)
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 14m9s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m53s
Build Packages / build:rpm (rocky8) (push) Successful in 14m56s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 15m3s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 15m10s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 15m12s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m38s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 8m15s
Build Packages / Generate python client (push) Successful in 30s
Build Packages / XDS test (durin plugin) (push) Successful in 9m16s
Build Packages / Create release (push) Skipped
Build Packages / XDS test (neggia plugin) (push) Successful in 8m48s
Build Packages / Build documentation (push) Successful in 1m10s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m15s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m29s
Build Packages / build:rpm (rocky9) (push) Successful in 13m11s
Build Packages / DIALS test (push) Successful in 13m21s
Build Packages / Unit tests (push) Successful in 1h16m18s
FFTW selects SIMD codelets at runtime via cpuid, so enabling AVX2 does not
require an AVX2 CPU -- it just speeds up the CPU FFT fallback indexer on
capable hardware and falls back to SSE2/scalar otherwise. Arch-guarded to
x86_64/AMD64 (ARM would need ENABLE_NEON). AVX-512 left off on purpose:
it's x86-64-v4 (not our v3 target), the FFT gain over AVX2 is marginal,
older Intel downclocks on it, and it's the riskiest to build under MSVC.

Verified on Linux: SSE2/AVX/AVX2 codelets compile, libfftw3f.a stays a
single static archive, jfjoch_viewer relinks cleanly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 22:37:09 +02:00
leonarski_f 0220c6376d cmake: fetch libtiff and FFTW instead of relying on system libs
Both are leaf deps (JFJochPreview / JFJochIndexing) that only our own code
looks for, so building them ourselves removes the system-package lottery and
gives a reproducible, statically-linked build on every platform.

- libtiff: FetchContent, library only (jbig/zstd/lzma/jpeg/old-jpeg/tools/
  tests off). The C++ binding (TIFF::CXX / libtiffxx) is packaged
  inconsistently across distros -- missing on Rocky 9 -- and absent on
  Windows, so find_package(TIFF COMPONENTS CXX) was unreliable; that call is
  removed and JFJochPreview links the tiff/tiffxx targets directly. GitHub
  mirror because upstream (gitlab) is unreachable from some restricted hosts.
- FFTW: FetchContent single precision (ENABLE_FLOAT) from the release tarball
  -- the git repo ships no pre-generated codelets (needs OCaml genfft). It's
  now always available, so the CPU FFT indexer is always built and
  JFJOCH_USE_FFTW always defined; the "FFTW disabled" path is gone. Static
  (libfftw3f.a) via the global BUILD_SHARED_LIBS OFF.

Verified on Linux: jfjoch_viewer builds and links libfftw3f.a + libtiff*.a,
all static.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 22:16:05 +02:00
leonarski_f fcbe19103d Update to most recent bitshuffle version 2026-06-19 22:10:06 +02:00
leonarski_f 0585fab9bf cmake: don't fetch sls/catch2 in a viewer-only build
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 8m20s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 8m43s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 10m34s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 11m3s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 9m57s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 10m27s
Build Packages / build:rpm (rocky8) (push) Successful in 10m17s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 9m17s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 10m22s
Build Packages / build:rpm (rocky9) (push) Successful in 11m10s
Build Packages / Generate python client (push) Successful in 19s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 51s
Build Packages / XDS test (durin plugin) (push) Successful in 7m16s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 6m38s
Build Packages / DIALS test (push) Successful in 12m31s
Build Packages / XDS test (neggia plugin) (push) Successful in 5m5s
Build Packages / Unit tests (push) Successful in 54m23s
Under JFJOCH_VIEWER_ONLY, only the viewer's transitive deps are built, so
sls_detector_package (detector_control/receiver) and catch2 (tests) are
never used -- and sls does not configure under MSVC, which is the whole
point of the viewer-only mode. Skip fetching just those two; zstd, hdf5,
spdlog, libzmq and httplib are still required (JFJochReader links httplib).

Verified: cmake -DJFJOCH_VIEWER_ONLY=ON configures with sls/catch2 absent
and `make jfjoch_viewer` still links.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 21:02:28 +02:00
leonarski_f 3c6439530d cmake: raise policy floor to 3.5 for FetchContent deps (CMake 4.x)
CMake >= 4.0 (4.3.1 ships bundled with Visual Studio 2026) makes any
cmake_minimum_required(VERSION < 3.5) a fatal error. The fetched libzmq
still declares VERSION 3.0.2, which aborts configuration before our own
CMakeLists gets a say. Set CMAKE_POLICY_VERSION_MINIMUM=3.5 before the
FetchContent_MakeAvailable calls so those subprojects configure; the
variable is simply unused (harmless) on CMake < 3.30.

Verified against CMake 4.3.1: the real libzmq source fails without it and
configures with it, and an in-file SET() propagates into the
add_subdirectory child exactly as a -D cache entry does.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 21:02:28 +02:00
leonarski_f f21c22d453 cmake: add JFJOCH_VIEWER_ONLY to build the viewer standalone
New option (default OFF) that compiles only jfjoch_viewer and the
libraries it transitively links -- common, image_analysis, writer,
reader, preview, image_puller, frame_serialize, gemmi_gph, compression,
jungfrau, and the OpenAPI model (JFJochAPI) -- skipping the Linux-only
online stack (broker service, receiver, fpga, acquisition_device,
detector_control, image_pusher, xds-plugin, tests, tools) and the
frontend. This is the standalone build path for the cross-platform
viewer.

JFJochAPI is the only piece the viewer needs from broker/, so the broker
service library and executable are gated behind NOT JFJOCH_VIEWER_ONLY.
The full build and JFJOCH_VIEWER_BUILD (viewer on top of the full build)
are unchanged -- that path is the verbatim ELSE() branch.

Verified on Linux: cmake -DJFJOCH_VIEWER_ONLY=ON configures and
`make jfjoch_viewer` links cleanly with the online stack absent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 21:02:28 +02:00
leonarski_f 74c2c808de cmake: drop GCC-only hardcoded flags, bump CUDA to C++20
Make the build less hostile to MSVC (needed for the viewer port) and
align the CUDA standard with C++.

- Remove the CMAKE_C/CXX_FLAGS_RELEASE overrides: -O3/-DNDEBUG only
  duplicate CMake's own GCC/Clang Release defaults, and the SET()
  clobbered the MSVC defaults. The lone meaningful flag,
  -Wno-deprecated-enum-enum-conversion, merely silenced warnings from
  the vendored Xilinx ap_private.h in the FPGA path; with no -Werror
  it is just log noise, so drop it.
- CMAKE_CUDA_STANDARD 17 -> 20 (+ STANDARD_REQUIRED); CUDA >= 12.8
  already supports C++20.
- Drop the file-scoped -Ofast on JFPedestalCalc.cpp /
  JFConversionFloatingPoint.cpp: it is GCC-only and reaches the MSVC
  viewer via JFJochCommon -> JFCalibration. Those files now build at
  plain -O3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 21:02:28 +02:00
leonarski_f 1e53db8f64 Docker: Update 2606 to support python3.12/3.13
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 12m15s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 12m45s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 12m18s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 13m12s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 12m56s
Build Packages / XDS test (durin plugin) (push) Successful in 7m24s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 11m52s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 13m7s
Build Packages / build:rpm (rocky8) (push) Successful in 12m55s
Build Packages / Generate python client (push) Successful in 17s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (ubuntu2204) (push) Successful in 12m29s
Build Packages / build:rpm (rocky9) (push) Successful in 13m40s
Build Packages / Build documentation (push) Successful in 1m7s
Build Packages / DIALS test (push) Successful in 14m7s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m23s
Build Packages / XDS test (neggia plugin) (push) Successful in 6m25s
Build Packages / Unit tests (push) Failing after 1h8m4s
2026-06-19 20:56:13 +02:00
leonarski_f 3ce7666738 make_doc.sh: prefer the newest available python3.x
Build Packages / Unit tests (push) Successful in 51m32s
Build Packages / DIALS test (push) Successful in 9m31s
Build Packages / XDS test (durin plugin) (push) Successful in 5m48s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 6m3s
Build Packages / XDS test (neggia plugin) (push) Successful in 5m31s
Build Packages / Generate python client (push) Successful in 26s
Build Packages / Build documentation (push) Successful in 54s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 13m15s
Build Packages / build:rpm (rocky8) (push) Successful in 14m9s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 14m22s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 14m41s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 14m48s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 14m47s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 15m3s
Build Packages / build:rpm (rocky9) (push) Successful in 15m4s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 13m8s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 12m36s
The bare python3 is often too old for the Sphinx build. Auto-select the
newest python3.13/3.12/3.11/3 found on PATH, still allowing $PYTHON to
override.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 16:37:32 +02:00
leonarski_f 4e9505e6bb make_doc.sh: Use python3
Build Packages / build:rpm (rocky8_nocuda) (push) Failing after 2m58s
Build Packages / build:rpm (rocky9_nocuda) (push) Failing after 2m56s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Failing after 2m31s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Failing after 3m0s
Build Packages / build:rpm (rocky8) (push) Failing after 3m6s
Build Packages / build:rpm (rocky9_sls9) (push) Failing after 3m23s
Build Packages / build:rpm (rocky8_sls9) (push) Failing after 3m31s
Build Packages / build:rpm (ubuntu2204) (push) Failing after 2m46s
Build Packages / build:rpm (rocky9) (push) Failing after 2m54s
Build Packages / Generate python client (push) Successful in 11s
Build Packages / Build documentation (push) Failing after 9s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (ubuntu2404) (push) Failing after 3m18s
Build Packages / XDS test (neggia plugin) (push) Successful in 5m47s
Build Packages / XDS test (durin plugin) (push) Successful in 6m54s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 6m58s
Build Packages / DIALS test (push) Successful in 9m47s
Build Packages / Unit tests (push) Successful in 53m21s
2026-06-19 16:06:49 +02:00
leonarski_f a34a033c99 frontend: auto-fill the missing phi bound for a sector
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Failing after 3m39s
Build Packages / build:rpm (rocky8_nocuda) (push) Failing after 3m47s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Failing after 3m41s
Build Packages / build:rpm (rocky8_sls9) (push) Failing after 3m45s
Build Packages / build:rpm (rocky9_nocuda) (push) Failing after 4m0s
Build Packages / build:rpm (rocky8) (push) Failing after 3m53s
Build Packages / build:rpm (rocky9_sls9) (push) Failing after 3m55s
Build Packages / build:rpm (ubuntu2204) (push) Failing after 2m41s
Build Packages / Generate python client (push) Successful in 32s
Build Packages / Build documentation (push) Failing after 27s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (rocky9) (push) Failing after 4m37s
Build Packages / build:rpm (ubuntu2404) (push) Failing after 4m49s
Build Packages / XDS test (neggia plugin) (push) Successful in 5m42s
Build Packages / XDS test (durin plugin) (push) Successful in 6m17s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 7m4s
Build Packages / DIALS test (push) Successful in 10m37s
Build Packages / Unit tests (push) Successful in 56m38s
When only one azimuthal phi bound is entered, fill the other so the
sector is well-defined and the server accepts it: a missing phi_min
becomes 0 and a missing phi_max becomes 360. Leaving both empty still
means a full ring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 16:05:15 +02:00
leonarski_f e9e5ec79cd frontend: phi_min/phi_max columns in the azimuthal ROI table
Surface the optional azimuthal phi-sector bounds (phi_min_deg/phi_max_deg)
as editable columns, so a sector can be set from the web UI, not only the
viewer. Also fix the Q_max row's d header, which read d_max but is d_min.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 16:01:13 +02:00
leonarski_f e60b42ea83 viewer: white, compact, right-aligned ROI numeric fields
The ROI bound editors now have a white background, a capped width and
right-aligned text, which reads better for numeric entry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 16:01:13 +02:00
leonarski_f abc1d1c079 viewer: add/subtract the selected ROI to/from the user mask
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Failing after 3m45s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Failing after 3m44s
Build Packages / build:rpm (rocky8_nocuda) (push) Failing after 3m50s
Build Packages / build:rpm (rocky8_sls9) (push) Failing after 3m45s
Build Packages / build:rpm (rocky8) (push) Failing after 3m46s
Build Packages / build:rpm (rocky9_nocuda) (push) Failing after 4m0s
Build Packages / build:rpm (rocky9_sls9) (push) Failing after 3m56s
Build Packages / build:rpm (ubuntu2204) (push) Failing after 3m5s
Build Packages / build:rpm (ubuntu2404) (push) Failing after 3m7s
Build Packages / build:rpm (rocky9) (push) Failing after 3m12s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Failing after 21s
Build Packages / Generate python client (push) Successful in 31s
Build Packages / XDS test (durin plugin) (push) Successful in 5m53s
Build Packages / XDS test (neggia plugin) (push) Successful in 6m12s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 6m54s
Build Packages / DIALS test (push) Successful in 8m46s
Build Packages / Unit tests (push) Successful in 48m22s
Restore the ROI-to-mask action on the new list: "Add to mask" and
"Subtract from mask" buttons rasterise the selected ROI into the user
mask (set or clear), through the same UpdateUserMask_i path. The ROI is
evaluated with per-pixel resolution and phi from the geometry, so box,
circle and azimuthal (sector) ROIs all map correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 15:08:59 +02:00
leonarski_f 81b48febcf viewer: remove the dead scratch-ROI widgets and worker methods
With the scratch ROI panel gone, delete the now-orphaned
JFJochViewerImageROIStatistics(_Box/_Circle) widgets and the worker's
unused scratch-ROI plumbing (SetROIBox/SetROICircle, the ROIElement
member, AddROIToUserMask/SubtractROIFromUserMask). ROI-to-mask, if wanted
later, should act on the selected list ROI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:58:33 +02:00
leonarski_f 52aca9a4a9 docs: ROIs/azimuthal apply to both FPGA and DECTRIS workflows
Clarify in FPGA_DATA_ANALYSIS.md that the ROI and azimuthal definitions
are also evaluated on CPU via the shared image_analysis library, so they
apply to the DECTRIS SIMPLON (EIGER) path that has no FPGA, not only the
FPGA-accelerated JUNGFRAU/PSI path. Document the three NXmx writer formats
(Legacy/VDS/Integrated) and the two acquisition workflows in CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:55:01 +02:00
leonarski_f d4c96d48fc make_doc.sh: Use default python 2026-06-19 14:52:40 +02:00
leonarski_f fef9c2f4c3 viewer: load user mask from TIFF (replace or add)
Two Mask-menu entries read a 16-bit TIFF (via ReadTIFFFromString16) and
apply it as the user mask: "replace" overwrites the current mask, "add"
unions the TIFF into it. The TIFF must match the detector dimensions; any
non-zero pixel masks. Both go through UpdateUserMask_i like the other
mask edits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:52:21 +02:00
leonarski_f b2c60dfbd0 viewer: download/upload ROIs to the broker
Add Download and "Upload to server" buttons to the ROI panel. The HTTP
reader gains GetROIDefinitions (GET /config/roi) and UploadROIDefinitions
(PUT /config/roi), converting between ROIDefinition and the generated
Roi_definitions model (including the optional azimuthal phi sector), the
same shapes OpenAPIConvert uses on the server. Download applies the
fetched ROIs through SetROIDefinition; upload pushes the current ones.
Both are no-ops unless the viewer is connected to a broker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:47:10 +02:00
leonarski_f 142cb88aa8 viewer: shift/ctrl-drag creates list ROIs; remove the old scratch panel
The interactive shift-drag (box) / shift+ctrl-drag (circle) now creates a
new persistent ROI in the list instead of feeding the old single-ROI
scratch panel. The base emits a roiScratchDrawn hook on release; the
diffraction image turns the drawn shape into a named ROI committed via
SetROIDefinition.

The old JFJochViewerImageROIStatistics scratch panel and all its wiring
(box/circle configuration, single-ROI result, add/subtract user mask) are
removed from the side panel and window; the ROI list is now the single
source.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:31:23 +02:00
leonarski_f 1d015145a4 viewer: numeric editing of the selected ROI's bounds
The ROI panel now shows editable numeric fields for the selected ROI,
labelled by type: box min/max X/Y, circle centre/radius, or azimuthal
Q-range and phi sector. Editing a field rebuilds that ROI and commits it
through the same SetROIDefinition path, so all three types can be created
(via +) and dialled in by typing, not only by dragging.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:24:57 +02:00
leonarski_f d413af0e92 viewer: azimuthal ROI handles, and keep panning inside the ROI
Azimuthal ROIs now show discrete grab handles on the selected ROI: the
inner/outer arc (resize Q/d) and, for a sector, the two phi edges
(rotate). Editing is by clicking a handle, with a generous tolerance,
which fixes the previously near-impossible phi-edge grab. Clicking the
(large) interior of an azimuthal ROI now only selects it and lets the
view pan, instead of capturing the gesture.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:21:23 +02:00
leonarski_f 00b58cd426 viewer: resize box/circle/azimuthal ROIs and delete with the Delete key
Extend canvas ROI editing beyond move:
- Box: drag corners/edges to resize (handles shown on the selected ROI).
- Circle: drag the perimeter to resize, interior to move.
- Azimuthal: drag the inner/outer arc to change the Q/d range, or a radial
  edge to rotate a phi bound; sampled through the geometry so it tracks
  the conic.
- Delete removes the selected ROI (the view now takes keyboard focus).

All edits go through the same live, throttled SetROIDefinition path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:07:16 +02:00
leonarski_f d9dfd36413 viewer: click to select an ROI, with live move and a hand cursor
Clicking a box/circle on the image now selects it (syncing the side-panel
combobox) and grabs it for moving, with a closed-hand cursor during the
drag. The move recomputes ROI statistics live rather than only on release,
throttled to at most one in-flight recompute so the worker is not flooded.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:56:09 +02:00
leonarski_f 308265c7b1 viewer: move the selected box/circle ROI on the canvas
Add base-class mouse hooks (roiEditPress/Move/Release) so the diffraction
image can edit the persistent ROI selected in the side-panel combobox.
The selected ROI is highlighted (dashed, thicker), and dragging its
interior moves a box or circle; on release the new geometry is committed
through SetROIDefinition, which recomputes only the ROIs. Resize,
azimuthal handles and delete-key follow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:56:09 +02:00
leonarski_f 0c780a5cbb Harmonize licsense files 2026-06-19 13:56:09 +02:00
leonarski_f e49a908862 viewer: ROI panel refinements — persist edits, combobox, compact toggles
- Edited ROIs now override the file's for every subsequently loaded image
  and survive settings changes, until a new file is opened (previously a
  delete/add was lost on the next image). Tracked via an roi_override_ that
  is re-applied to curr_experiment and to each loaded image's dataset.
- The ROI selector is a compact combobox instead of a list widget.
- "Show labels" and "Translucent fill" share one row to save space.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:56:09 +02:00
leonarski_f 2f8d486b51 viewer: ROI list panel — select, add, rename, delete, per-ROI results
Add JFJochViewerROIList to the side panel: a list of the dataset's ROIs
with selection, add (box/circle/azimuthal), rename and delete, plus a
statistics readout (sum/mean/std/max/valid/masked/centre-of-mass) for the
selected ROI, taken from the analysis output for the current image. Edits
emit a full ROIDefinition, routed to the worker's SetROIDefinition.

Per-ROI statistics now live in this panel rather than the canvas labels;
the diffraction image's labels show only the ROI name, and the ad-hoc
ROIIntegrationCPU computation there is removed in favour of the analysis
pipeline. The result widget now reports std dev instead of variance.

The single-ROI scratch panel remains for now and will be retired once the
interactive canvas editing replaces it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:56:09 +02:00
leonarski_f 4e45680e96 viewer: worker can update ROIs and recompute them without full re-analysis
The reading worker's experiment is the source of truth for ROIs. Add a
SetROIDefinition slot that updates curr_experiment.ROI(), rebuilds the
analysis ROI engine, mutates the dataset (so the canvas reflects the new
ROIs) and recomputes only the ROIs for the current image via RunROIOnly.
On image load when full re-analysis is off, ROIs are still computed via
AnalyzeROIOnly so the statistics stay current.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:56:09 +02:00
leonarski_f a433399106 image_analysis: surgical ROI-only entry points in MXAnalysisWithoutFPGA
Add three entry points so ROI statistics can be (re)computed without a
full re-analysis, in support of interactive ROI editing in the viewer:

- RebuildROI(): recreate the ROI engine after the ROI set changes (the
  CudaStream is now kept as a member so the GPU engine can be rebuilt).
- AnalyzeROIOnly(): decompress + preprocess + ROI, skipping azimuthal
  integration, spot finding and indexing (a new image when re-analysis
  is off).
- RunROIOnly(): rerun only the ROI integration on the already-preprocessed
  image (an interactive ROI move). A full Analyze() still computes ROIs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:56:09 +02:00
leonarski_f 3996595606 viewer: per-ROI statistics on the diffraction image via the CPU ROI engine
When ROI labels are shown, each ROI's label now also reports its sum,
max and pixel count for the current image. Rather than reimplementing the
accumulation, this reuses the existing ROIIntegrationCPU engine (the
software counterpart of the FPGA roi_calc), built from the experiment and
cached per dataset. A small adapter folds the viewer's gap sentinel
(INT32_MIN+1) onto the engine's masked sentinel (INT32_MIN) so masked and
saturated pixels are handled correctly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:56:09 +02:00
leonarski_f 33118ebe8b viewer: fix stray line from origin on full-ring azimuthal ROI
The full-ring annulus built the inner ring as a separate QPainterPath and
merged it with addPath, which stitched a spurious segment from (0,0) to
the ring. Build both concentric rings as subpaths of one path, each begun
with an explicit moveTo, so there is no connecting segment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:56:09 +02:00
leonarski_f 7d6f79a1da viewer: draw azimuthal ROI wedges, with optional fill and labels
Azimuthal ROIs now render on the diffraction image as annular sectors
(or full-ring annuli), sampled through DiffractionGeometry::ResPhiToPxl
so the outline follows the ROI footprint, including wrap-around sectors.

Add two side-panel toggles (both default off): a translucent fill for
every ROI (helpful when outline colours clash with the image colour map,
and with many ROIs) and ROI name labels (constant on-screen size). Wired
side panel -> window -> diffraction image like the existing feature
toggles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:56:09 +02:00
leonarski_f 35f6ffdde9 viewer: draw loaded ROIs on the diffraction image
When a file with ROI definitions is opened (read into experiment.ROI()
by the HDF5 reader), the diffraction image now overlays the configured
box and circle ROIs as distinct colour-coded outlines, alongside the
existing resolution rings and spots. This is the first step of the
ROI-map-based multi-ROI canvas: showing the ROIs loaded from a file.

Azimuthal ROIs (wedge rendering) and per-ROI statistics from the bitmap
follow in subsequent steps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:56:09 +02:00
leonarski_f 332fd32224 frontend: link PSI in footer, add Source code and License to References
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Failing after 3m26s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Failing after 3m29s
Build Packages / build:rpm (rocky9_nocuda) (push) Failing after 3m37s
Build Packages / build:rpm (rocky9_sls9) (push) Failing after 3m45s
Build Packages / build:rpm (ubuntu2204) (push) Failing after 3m32s
Build Packages / build:rpm (rocky9) (push) Failing after 3m37s
Build Packages / build:rpm (ubuntu2404) (push) Failing after 3m46s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 8m31s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 8m52s
Build Packages / Generate python client (push) Successful in 20s
Build Packages / Build documentation (push) Successful in 59s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (rocky8) (push) Successful in 8m44s
Build Packages / XDS test (durin plugin) (push) Successful in 6m26s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 6m32s
Build Packages / XDS test (neggia plugin) (push) Successful in 5m56s
Build Packages / DIALS test (push) Successful in 9m21s
Build Packages / Unit tests (push) Successful in 49m53s
- Footer "Paul Scherrer Institute" now links to https://www.psi.ch
- Reference drawer gains a "Source code" entry linking out to the Gitea
  repository (new nav-item href that opens in a new tab)
- Reference drawer gains a "License" entry rendering the nicely formatted
  docs/LICENSE.md inline (generalises the changelog renderer into MarkdownDoc)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 13:23:51 +02:00
leonarski_f 6962a61489 frontend: render Changelog inline instead of in a Sphinx iframe
The framed Sphinx changelog reused MUI with the same colours, so it read as
a picture-in-picture. Bundle docs/CHANGELOG.md at build time (?raw) and render
it with react-markdown, themed to match the app, for a quick frame-less view.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 13:21:19 +02:00
leonarski_f cee4739221 frontend: bundle Sphinx docs locally instead of linking readthedocs
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Failing after 3m32s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Failing after 3m35s
Build Packages / build:rpm (rocky9_nocuda) (push) Failing after 3m51s
Build Packages / build:rpm (rocky9_sls9) (push) Failing after 3m56s
Build Packages / build:rpm (rocky9) (push) Failing after 4m3s
Build Packages / build:rpm (ubuntu2204) (push) Failing after 4m13s
Build Packages / build:rpm (ubuntu2404) (push) Failing after 4m13s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 9m7s
Build Packages / Generate python client (push) Successful in 22s
Build Packages / build:rpm (rocky8) (push) Successful in 9m34s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 9m48s
Build Packages / Build documentation (push) Successful in 49s
Build Packages / XDS test (neggia plugin) (push) Successful in 5m56s
Build Packages / XDS test (durin plugin) (push) Successful in 6m26s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 6m36s
Build Packages / DIALS test (push) Successful in 11m8s
Build Packages / Unit tests (push) Successful in 55m19s
The Documentation tab pointed at jungfraujoch.readthedocs.io, which lags
behind the installed version. Build the Sphinx docs into frontend/dist/docs
and serve them at /frontend/docs so they always match the package.

- make_doc.sh: accept an output dir (default public), absolutize it, run
  from the script dir, and allow $PYTHON override
- package.json: add "docs" script building into dist/docs
- CMakeLists: run "npm run docs" in the frontend target so CPack packs the
  docs via the existing dist/ install
- App.tsx: point the Documentation DocFrame at /frontend/docs/index.html

Also clean up the Sphinx build (911 -> 0 warnings):
- fix typo myst_heading_anchor -> myst_heading_anchors so cross-doc
  #anchor links actually resolve
- suppress myst.header/myst.xref_missing (auto-generated OpenAPI client
  docs only) and the harmless sphinx_material config.cache note
- drop a dangling "---" transition at the end of CPU_DATA_ANALYSIS.md
- add REPOSITORIES and the generated python_client model pages to toctrees

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 12:44:00 +02:00
leonarski_f eadbce51bd common: take ROIAzimuthal phi as plain floats, not optionals
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 10m48s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 11m35s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 12m2s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 12m58s
Build Packages / build:rpm (rocky8) (push) Successful in 13m0s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 13m58s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 14m29s
Build Packages / XDS test (durin plugin) (push) Successful in 7m30s
Build Packages / Generate python client (push) Successful in 39s
Build Packages / Build documentation (push) Successful in 51s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (ubuntu2404) (push) Successful in 10m11s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 10m55s
Build Packages / build:rpm (rocky9) (push) Successful in 12m15s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m11s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m33s
Build Packages / DIALS test (push) Successful in 12m0s
Build Packages / Unit tests (push) Successful in 57m36s
The phi bounds were stored as plain floats internally but passed through
std::optional in the constructor, which obscured the intent. Take them
as float arguments defaulting to 0 instead. The convention is explicit:
phi_min == phi_max means the full ring (all angles), a sector wraps
across 0 when phi_min > phi_max, and otherwise phi_min <= phi_max. The
"both bounds or none" rule belongs at the API/file boundary
(OpenAPIConvert, reader), not in the core class, so it lives there now.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:03:40 +02:00
leonarski_f 6b95600260 writer: link ROI results into the VDS master file
In VDS mode the per-image ROI results (max/sum/sum_sq/npixel/x/y) are
written into the data files but were not exposed in the master, so a VDS
master surfaced no ROI statistics. Add virtual datasets under
/entry/roi/<name> in LinkToData_VDS, one group per ROI, mirroring how the
spot-finding and azimuthal-integration arrays are linked. Integrated and
legacy formats are unaffected (the results are already reachable there).

Extended the reader round-trip test to write real ROI results and check
they read back from the master for both VDS and integrated formats.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 10:38:24 +02:00
leonarski_f c6e7f8aa15 writer/reader: move ROI definitions to /entry/roi_defs and read them back
Relocate the ROI definitions and the roi_map bitmap from /entry/roi to a
separate /entry/roi_defs group in the master file. /entry/roi keeps its
original meaning (per-image ROI results only), so an older reader that
iterates /entry/roi is not disturbed by the bitmap/definition entries
(which would otherwise make it try to read /entry/roi/roi_map/max and
fail to open the file at all). Back-compatibility for already-deployed
viewers is the reason for the split.

JFJochHDF5Reader now reads the logical definitions into experiment.ROI()
and the roi_map bitmask (+ a name->bit index) into the dataset, for all
file formats (the master always carries them). Reading both lets a later
viewer either re-derive ROIs with the current geometry (logical) or show
the exact written footprint (bitmap).

Added a write/read round-trip test over VDS and integrated formats.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 10:35:18 +02:00
leonarski_f 2bd276ae1b preview: draw azimuthal ROIs
AddROI now renders azimuthal ROIs in addition to box and circle ROIs:
inner/outer arcs at the Q (d) bounds and, for a sector, the two radial
edges at the phi bounds. The per-pixel phi comes from the same
DiffractionGeometry::Phi_rad used to assign ROIs, so the overlay matches
the ROI footprint exactly (including wrap-around sectors). Full-ring
azimuthal ROIs draw as two concentric arcs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 09:44:57 +02:00
leonarski_f 03814b1425 writer: save ROI bitmap and definitions in the master file
Persist regions of interest so an acquisition's ROI layout can be
recovered from the master (_master.h5 / _process.h5):

- /entry/roi/roi_map: uint16 per-pixel bitmask (bit i == ROI i).
- /entry/roi/<name>: logical definition (type + geometry params, incl.
  azimuthal phi sector) plus bit_index tying it to the bitmap plane.

The bitmap rides along in the StartMessage (CBOR, mirroring az_int_map)
and is filled both online (JFJochReceiver::SendStartMessage) and offline
(jfjoch_process). Definitions come from the already-transmitted rois.
Both are dataset-wide metadata, so they are written by the NXmx master
writer (new NXmx::ROI), not the per-image data-file plugin.

Documented the /entry/roi layout in docs/HDF5.md and the master-vs-data
writer convention in CLAUDE.md; added a CBOR roi_map round-trip test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 09:41:26 +02:00
leonarski_f 1d04656dc8 api: serialize azimuthal ROI phi sector over OpenAPI and CBOR
Expose the optional phi_min_deg / phi_max_deg azimuthal-sector bounds
added to ROIAzimuthal through the wire formats. Both are optional, so
older clients and streams (Q-only ROIs) remain valid.

- jfjoch_api.yaml: optional phi_min_deg / phi_max_deg on roi_azimuthal;
  regenerated the cpp-pistache server model and the TS frontend client.
- OpenAPIConvert: map phi both directions (set only when present).
- CBOR start message: emit phi_min/phi_max only for a sector; on decode,
  absent phi means a full ring.
- Documented the new optional CBOR fields; extended the CBOR round-trip
  test with a sector and a full-ring azimuthal ROI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 09:28:25 +02:00
leonarski_f 9e57219b31 common: add azimuthal-angle (phi) sectors to ROIAzimuthal
ROIAzimuthal can now be restricted to an azimuthal-angle sector in
addition to its Q/d range, enabling STXM-style directional ROIs. phi
bounds are optional (both-or-neither); absent means a full 360 ring, so
existing Q-only azimuthal ROIs are unchanged.

- ROIElement::CheckROI gains a phi_deg argument; box/circle ignore it.
- MarkROI gains an optional phi_map; ROIMap builds it from Phi_rad
  alongside the resolution map only when azimuthal ROIs are present.
- phi bounds are normalized to [0,360) and wrap-around sectors are
  supported (phi_min > phi_max).
- ROIConfigAzim carries phi_min/phi_max (kept trivially copyable for the
  union; phi_min == phi_max means full ring).

No phi crosses the wire yet (CBOR/API wiring follows separately).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 09:21:39 +02:00
leonarski_f 88f97fc197 docs: add CLAUDE.md with build/test/architecture, code-style and portability guidance
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 08:11:07 +02:00
leonarski_f a76aac65b7 frontend: add missing React keys in DetectorSelection and ROI
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 11m16s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 11m41s
Build Packages / build:rpm (rocky8) (push) Successful in 12m47s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 13m17s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 13m27s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 13m32s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 13m52s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 10m35s
Build Packages / XDS test (neggia plugin) (push) Successful in 8m15s
Build Packages / XDS test (durin plugin) (push) Successful in 8m58s
Build Packages / Generate python client (push) Successful in 14s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (ubuntu2404) (push) Successful in 9m58s
Build Packages / Build documentation (push) Successful in 40s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m30s
Build Packages / build:rpm (rocky9) (push) Successful in 12m11s
Build Packages / DIALS test (push) Successful in 12m4s
Build Packages / Unit tests (push) Successful in 56m3s
DetectorSelection rendered the info-table rows and the detector-select
menu items without keys; ROI's grid action cells likewise. Add stable
keys to silence the warnings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 08:01:03 +02:00
leonarski_f 4f9452736a frontend: drawer-based navigation shell
Replace the stack of toggle-revealed sections with a left navigation
drawer (collapsible, expanded by default) clipped under a persistent
status bar. Dashboard (plots + measurement statistics + spot-finding)
is the default view; every other panel is its own drawer entry, so one
thing shows at a time.

- Group entries under Acquisition / Expert / Reference subheaders;
  ROI folded into On-the-fly processing.
- Pale-indigo drawer with a lime accent on the selected entry.
- Gray out JUNGFRAU calibration / FPGA status when their data is empty.
- API reference and documentation open in-app via iframe.
- Fixed footer pinned to the page bottom.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 07:57:57 +02:00
leonarski_f 9fc971c1d2 frontend: add zod plugin to hey-api openapi-ts
Generate Zod schemas alongside the typed client (src/client/zod.gen.ts),
picking up the OpenAPI field defaults. Enables runtime validation and
default-filling for form payloads.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 07:24:52 +02:00