cuFFT is the only CUDA component linked dynamically (cudart and the
fast-feedback indexer are static), so the prior Windows installer would
fail to launch the GPU path on a host without a CUDA toolkit. Ship
cufft64_*.dll next to the viewer (CUDA 13 keeps it in bin/x64, earlier
toolkits in bin); the DLL is self-contained, so the installed app needs
only an NVIDIA driver.
Tag the variant where it matters and nowhere else: the installer
filename (-cuda<major> / -cpu) and the Add/Remove Programs entry
("Jungfraujoch (CUDA)" / "(CPU)") advertise it, while the install folder
and Start Menu group stay plain "Jungfraujoch" -- the CUDA build is a
strict superset, so the two variants share a location and replace each
other.
Docs: SOFTWARE.md + JFJOCH_VIEWER.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
MSVC/Windows build fixes:
- Force JFJOCH_VIEWER_ONLY ON for Windows and macOS; the broker/receiver/FPGA/
writer server stack is Linux-only, so those platforms build the viewer subset.
- Vendor an OpenBSD/NetBSD getopt/getopt_long shim (tools/wingetopt/, BSD/ISC)
as a WIN32-only static lib -- the MSVC CRT has no <getopt.h> -- and link it
into the four portable CLI tools on Windows.
- jfjoch_extract_hkl.cpp: include <getopt.h> explicitly (it relied on glibc's
transitive <unistd.h>).
- jfjoch_process.cpp: guard <unistd.h> with #ifndef _WIN32.
- Guard JFJochStreamWriter and jfjoch_writer with IF(NOT JFJOCH_VIEWER_ONLY):
the former pulls in JFJochImagePuller, the latter uses a fork()/waitpid()
multi-process design; neither belongs to the portable viewer subset.
- Record wingetopt in THIRD_PARTY_NOTICES.md and licenses/.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Acknowledge all bundled third-party software and satisfy attribution/notice
requirements, while keeping it maintainable:
- THIRD_PARTY_NOTICES.md: human-readable manifest (component, copyright, SPDX
license, link) for fetched, vendored, and runtime/SDK dependencies.
- licenses/: verbatim license texts; COLLECT.sh regenerates them from the
build trees and system SDK locations.
- Bundle the verbatim Qt LGPL-3.0 text and the CUDA Toolkit 12.8 EULA.
- frontend: self-contained npm attribution generator (`npm run licenses` ->
dist/THIRD_PARTY_LICENSES.txt), wired into the frontend build target.
- Install LICENSE + notices + licenses/ into share/doc/jfjoch for every
packaged component.
- viewer: Help > "Third-party Licenses" window (QTextBrowser) showing a
generated, self-contained HTML built from licenses/.
- docs/SOFTWARE.md: drop the stale hand-kept dependency lists; point at the
manifest.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The viewer's only .qrc is compiled explicitly via QT_ADD_RESOURCES into
APP_RESOURCES; no .qrc is added directly as a target source, so AUTORCC never
acted on anything. Remove the dead flag.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
NSIS installer was missing several things on Windows:
- License: show the repo GPLv3 LICENSE as the click-through license page
(CPACK_RESOURCE_FILE_LICENSE).
- Start Menu: no shortcut was created -- add CPACK_PACKAGE_EXECUTABLES for
jfjoch_viewer, and embed an app icon so the shortcut is not generic. The
icon is a new multi-size jfjoch.ico (256 PNG + 48/32/16) compiled into the
.exe via resources/jfjoch.rc; macOS gets the matching jfjoch.icns copied
into the .app bundle (MACOSX_BUNDLE_ICON_FILE). Both derived from
resources/jfjoch.png, padded square with transparent bands.
- Naming: install folder, Start Menu group and Add/Remove Programs entry are
now "Jungfraujoch" instead of "jfjoch <version>".
Also ship the offline analysis CLIs (jfjoch_process/scale/azint/extract_hkl)
in viewer-only / Windows packages: JFJochReceiverPlots now lives in
JFJochCommon, so their stale JFJochReceiver link is dropped, leaving only the
portable libs (reader/image_analysis/writer/common). tools/CMakeLists.txt is
split so those four build everywhere while the hardware tools stay gated
behind NOT JFJOCH_VIEWER_ONLY, and the viewer-only branch now adds tools/.
They install into the "viewer" CPack component.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the platform packaging the viewer was missing so it can ship as a .dmg
(macOS) or installer (Windows):
- viewer: set MACOSX_BUNDLE (a .app bundle on macOS) and WIN32_EXECUTABLE
(GUI subsystem, no console window) -- both ignored where they don't apply;
install with BUNDLE/RUNTIME destinations.
- viewer: qt_generate_deploy_app_script + install(SCRIPT) to bundle the Qt
runtime at install time (windeployqt on Windows, macdeployqt on macOS).
Gated on Qt >= 6.5, which is where the OUTPUT_SCRIPT signature and the Linux
deploy path landed; with a static Qt (our Linux builds) it is a no-op.
- CPack: select DragNDrop (.dmg) on macOS and NSIS on Windows, ahead of the
Linux-only /etc/* probes; DEB/RPM path unchanged.
Verified: configures + generates cleanly on Linux with the viewer enabled
(Qt 6.4.2 -> deploy step correctly skipped).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>
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>
M_PI is a POSIX <math.h> extension that MSVC does not define without
_USE_MATH_DEFINES. std::numbers::pi (introduced in the viewer guard commit) is
C++20, but CUDA here is compiled as C++17 (CMAKE_CUDA_STANDARD 17) and several
common/ headers are pulled into .cu device translation units, so std::numbers is
not available there.
Add common/JFJochMath.h with a dependency-free `constexpr double PI` that works
in host code (including MSVC), in CUDA device code, and under C++17/20, and use
it everywhere:
- common/ and image_analysis/ (incl. CUDA .cu): 78 M_PI occurrences, 22 files
- broker/OpenAPIConvert.cpp
- viewer/: the 5 files that used std::numbers::pi now use PI, for one consistent
convention across the codebase
Verified to build: JFJochImageAnalysis (incl. CUDA), jfjoch_viewer, JFJochBroker.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Step toward building jfjoch_viewer on Windows/MSVC. No change to the Linux
build: D-Bus stays on by default and the XCB plugin is still used.
- CMake: make Qt6::DBus optional via JFJOCH_VIEWER_DBUS (ON on Linux, OFF on
Windows/macOS where Qt6::DBus does not exist); compile/link/install the dbus/
adaptor + service file only when enabled. Select the platform integration
plugin per-OS (QXcb on Linux, QWindows on Windows, QCocoa on macOS) instead
of hard-coding QXcbIntegrationPlugin.
- JFJochViewerWindow: wrap the adaptor include and D-Bus registration in
#ifdef JFJOCH_VIEWER_DBUS.
- JFJochImageReadingWorker: the POSIX open()/fstat()/NFS-errno preflight is now
#ifndef _WIN32, with a portable QFileInfo fallback elsewhere; POSIX-only
headers are guarded too.
- Replace the POSIX M_PI/M_PI_2 extension with C++20 std::numbers::pi across the
viewer (not defined by MSVC without _USE_MATH_DEFINES).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a status-bar cluster, shown when connected over HTTP, that surfaces
the broker state and live acquisition info:
- broker state box (QProgressBar) with progress drawn as the bar fill,
polled ~1 Hz on its own timer independent of image sync
- Live/Disconnected connection badge (host:port in tooltip)
- "+N new" badge and effective live-rate (Hz) readout
All widgets are fixed-width and only blanked in place, so the bar never
reflows when things appear/disappear.
Add a third autoload mode (HTTPSyncDataset): manually selecting an image
while following live now freezes the displayed image but keeps the dataset,
plots and image count updating. Surfaced via a tri-state HTTP Sync button
(off / live / data-only).
Also fix GetBrokerStatus() dropping the message field and a couple of
copy-pasted exception strings in JFJochHttpReader.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PixelRefine is now an intensity-only operation: geometry is fixed (refined
upstream by XtalOptimizer) and the only objective is the factored per-reflection
likelihood (FACTORED_MODEL.md Terms 1+2) - measured per-resolution profile width
R1 plus one Fisher-weighted intensity/scaling residual per reflection, fitting
the per-image scale G and B. Validated on crystal 2 (fixed_master.h5 as stills,
1.7 A): CC1/2 84-92%, CCref 77-92%, flat - reproduces the env-flag prototype and
matches the rotation path from the stills path.
Removed:
- the per-pixel ShoeboxResidual loss and PixelResidual cost functor;
- all in-PixelRefine geometry refinement (orientation/cell/beam/distance/R),
the regularised-orientation LSQ, signal-weighting, and the global sweep;
- Term 3 (per-spot recentring) - a confirmed no-op on both crystals;
- the diagnostic scaffolding (covariance, centroid, adaptive_R1) and the
PR_* env knobs + stderr dumps in IndexAndRefine;
- the PredictImage/ChiSquaredImage renderers and the entire viewer
PixelRefine window/table/params + worker bindings + shoebox overlay.
The sweep box-integrator background median became mean (consistency) by virtue
of removing the sweep. METHODS.md rewritten for the current model; findings
recorded in FINDINGS-2026-06.md. Net -2200 lines.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This is an UNSTABLE release. The release has significant modifications for data processing - in case of troubles go back to 1.0.0-rc.144.
* jfjoch_broker: Improve azimuthal integration (add <I^2> calculation)
* jfjoch_broker: Fixes around indexing, aiming to handle multi-lattice crystals (work in progress, it is not fully integrated)
* jfjoch_writer: Save mean(I), stddev(I), and count(I) for each azimuthal bin
Reviewed-on: #58
This is an UNSTABLE release. The release has significant modifications for data processing - in case of troubles go back to 1.0.0-rc.144.
* jfjoch_viewer: Add reciprocal space viewer
* jfjoch_process: Two pass algorithm that does spot finding/indexing + integration of full dataset
* jfjoch_process: Improve logic for rotation indexer, to make execution more deterministic (still work in progress)
Reviewed-on: #57
Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
Co-committed-by: Filip Leonarski <filip.leonarski@psi.ch>
This is an UNSTABLE release. The release has significant modifications for data processing - in case of troubles go back to 1.0.0-rc.144.
jfjoch_process: Generate a dedicated file (_process.h5), which can be used as a replacement for the _master.h5 file for a reanalyzed dataset.
jfjoch_process: Improve the performance of scaling and merging, implement on the fly scaling.
jfjoch_writer: All final data analysis results are repopulated in the _master.h5 file.
jfjoch_scale: Dedicated tool for rescaling/merging existing data.
jfjoch_viewer: Fix bugs where pixel labels where displayed on a wrong pixel.
WARNING! Scaling and merging are experimental at the moment, and may not provide reasonable results for the time being.
Reviewed-on: #56