The broker logs for the dropped runs show the connection torn down ~2s into
a collection (not 3s), via "TCP send failed -> Removed dead connection ->
Accepted (new socket)". That is too early for the SendAll send deadline:
the real gate was the fixed 2-second enqueue deadline in the zerocopy
SendImage path. At the start of a large dataset the writer briefly stalls
draining the socket while it creates the master file and writes the large
START metadata + calibration frames to GPFS; the per-connection queue fills,
and after 2s SendImage marked the connection broken. The writer then
reconnected outside the active session, so the rest of the run was dropped
and the half-written file was finalized at the next START.
Replace the fixed 2s enqueue deadline with the same peer-liveness condition
used on the send path: keep applying backpressure while the writer proves it
is alive (BUSY heartbeats / ACKs refresh last_peer_activity_ns from a thread
independent of the stalled write path), and only declare it dead after the
liveness window of complete silence. A transient startup stall is now ridden
out instead of dropping the run.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A slow filesystem could stall the writer's consume pipeline, propagating
TCP backpressure to the pusher. The pusher then treated that backpressure
as a dead peer and force-closed the connection mid-run; the writer
reconnected as a brand-new connection outside the active session, so the
rest of the run was silently dropped and the half-written HDF5 file was
later finalized with holes.
Replace the throughput/progress-based send timeout with a peer-liveness
timeout:
- Add TCPFrameType::BUSY (wire version 2 -> 3).
- TCPImagePuller runs a heartbeat thread that sends BUSY every 250ms on a
thread independent of the (possibly stalled) write path, so liveness
keeps flowing during deep stalls. A send_mutex serializes
ACK/pong/heartbeat writes.
- TCPStreamPusher refreshes last_peer_activity_ns on every inbound frame
and only declares a connection dead after peer_liveness_timeout (15s) of
complete silence, tolerating arbitrarily long backpressure while still
catching a genuinely dead peer (and immediate EPIPE/ECONNRESET).
- Re-key both backpressure waits (the SendAll data path and the post-END
WaitForEndAck) onto this liveness signal instead of byte-progress /
DATA-ACK-progress, so a slow final flush at END is tolerated too.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The settings content stopped resizing past ~360 px, leaving dead space when the
dock was widened. Cause: QFormLayout's default field growth policy keeps fields
at their size hint. Set AllNonFixedFieldsGrow on all five forms (geometry, unit
cell, spot finding, indexing, azint) so the fields grow to fill the dock width.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- The chart top margin was too tight (2 px), so the highest Y-axis label
overlapped the top edge; give it 10 px of room (both chart views).
- The settings dock had no width constraints (unlike the inspector), so it
stretched ugly when widened and would not fold back narrowly. Cap it to
330–480 px like the inspector.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In per-image mode the embedded chart brought its own combo box, so the plot
panel showed two. Drop the per-image chart's combo and drive it from the one
dataset-info combo:
- JFJochViewerSidePanelChart loses its combo; it exposes PlotTypes() (the
available profiles) and a setPlotType(code) slot, driven externally.
- JFJochViewerDatasetInfo fills its single combo with the per-image plot types
while in per-image mode (per-dataset metrics otherwise) and routes the
selection to the chart; dataset/runs/live updates leave the per-image combo
and plot untouched.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Plots:
- A "+ Plot" button on the dataset-info panel spawns another plot dock, placed
beside the previous one (horizontal split) so several metrics can be watched
side by side. Same path as the Charts menu, now one click away.
Image strip:
- The image number is painted into the thumbnail bitmap (coral badge, top-left)
instead of a text label under the icon, so no height is lost to it.
- Thumbnails are icon-only and scale to the available dock height (resizeEvent),
so the strip never needs more room than it has; lowered its minimum.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When the plot dock was short, Qt Charts dropped the axis labels first, making
the plot hard to read.
- Reclaim Qt Charts' outer graphics-layout padding and trim the inner margins
(both chart views) so the plot and its labels get the available space.
- Raise the chart minimum height (dataset-info 80 -> 140, per-image 120 -> 140)
so the dock can't be squeezed below the point where the axis labels fit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The image-strip thumbnail renderer could take the whole viewer down:
- Only the image load was wrapped in try/catch; the rest of RenderThumbnail_i
(pixel access, LUT mapping, QPainter) ran unguarded on the worker thread, so
any exception there called std::terminate. Wrap the entire function.
- std::clamp(idx, 0, lutSize - 1) is undefined behaviour when the colour LUT is
empty (lo > hi). Bail out early if the LUT has no entries.
A click landing while a later thumbnail is still rendering surfaced this.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address the review on the image strip / hit feed:
- Height constraints: JFJochSimpleChartView used a hard setFixedHeight(300) and,
being a page in the dataset-info stack, forced the whole plot dock (and thus
the window) taller than the screen once the strip was stacked below. Make it a
soft minimum (120). Wrap the settings dock in a QScrollArea so its content can
scroll instead of forcing window height. Smaller strip thumbnails (96) and
lower default bottom-dock heights. The window no longer grows past its
requested size.
- Stochastic selection: representatives are now picked at random within N equal
bins (over image index, or a metric's sorted order), and a Refresh button
re-rolls a fresh set — avoiding deterministic-spacing artefacts. "Most spots"
stays deterministic; "Indexed" becomes spaced-random.
- Live stability: the strip stores dataset updates but only rebuilds on file
open (worker fileOpened) / mode / Spots / Refresh, so HTTP sync image updates
no longer trigger constant thumbnail refetching.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up to the image strip, addressing the review:
- Composition: stack the plots and the thumbnail strip vertically (plots on top
with more height, strip below) instead of sharing horizontal space — both
benefit from width, and the strip needs less height.
- Processing dock is hidden by default and narrower; it reveals itself only when
a reprocessing job starts (new jobStarted signal), and the Processing
perspective no longer force-shows it.
- Thumbnail spot overlays now use the same feature (indexed) / spot colours as
the main viewer, and follow the side-panel colour pickers.
- New strip selection modes "Resolution" and "Background": pick images that span
that metric's distribution (a quick histogram-representative selection).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A dockable strip of thumbnails for a handful of representative images, with
spots overlaid so a real pattern reads like a constellation; click opens that
image.
- JFJochViewerImageStrip: mode selector (evenly spaced / most spots / indexed,
computed from the dataset's per-image metrics) + a Spots toggle; a scrollable
row of thumbnail buttons; click emits imageSelected.
- The reading worker renders thumbnails off-thread and non-disruptively: load
each image via its reader, downsample by block-maximum (keeps Bragg spots),
map through the colour-scale LUT, optionally paint spots (coral indexed /
teal not), and emit thumbnailReady(image_number, QImage). File mode only.
- Docked in the bottom area, shown in the Processing perspective; the colour map
follows the display toolbar.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Complete pass over both toolbars (review items g–k), closing the toolbar topic.
New ToolbarIcons: crisp QPainter vector glyphs (Qt SVG is not a build dep), with
white "on" variants for toggles and a shared flat button style (coral hover,
navy checked).
Navigation toolbar, laid out source-first:
- Open (3.5" diskette) · HTTP sync · Movie (reel-on-top camera, distinct from
the next/play triangle) ║ the scrub slider, which expands to fill the bar
(coral track, navy handle) so it is the obvious way to move across the data ║
precise navigation: first/prev/[number]/next/last, Jump, Sum.
- Open and HTTP-sync reach the file / connect dialogs (JFJochViewerMenu
openSelected and openHttpSelected, now public).
- HTTP-sync has three states via a status dot (grey disconnected / green live /
amber frozen); clicking with no live source attached opens the connect dialog.
Removed the separate "Reanalyze" toggle.
Display toolbar:
- Styled foreground slider (matching), Auto/HDR as styled text toggles.
Hero buttons:
- "Reanalyze image" is now a toggle (worker ReanalyzeImages: run now + keep
re-analysing on image/settings/processing changes; coral = active).
Processing dock:
- Drop the "New job…" toolbar action (the hero button drives it) and parent the
job dialog to the main window instead of the dock.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Declutter the side and settings panels (review items a–f):
- New CollapsibleSection widget (slim navy header + coral rule + chevron).
- Inspector: Image features / Resolution rings / ROI are now collapsible and
start folded (ROI auto-expands when ROIs change); drop the Data-analysis and
Powder-calibration sections (they live in the hero buttons and settings dock).
- Settings dock: move Geometry to a shared section above the MX/AzInt toggle
(both communities need it); add Detector tilt (PONI rot1/rot2, deg) and
rename "Beam center" -> "Beam origin" with PONI/XDS tooltips; show the
space-group number and resolved Hermann–Mauguin symbol on one line; wrap
sections in accordions, anchored top with a bottom stretch so expanding one
does not shift the others.
- Toolbar: drop the redundant "Image number" label.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remove the duplicated per-image plot from the side panel and host it in the
dataset-info dock instead:
- JFJochViewerDatasetInfo gains a "Per-image" toggle (next to Grid) that swaps
the stacked view to the existing JFJochViewerSidePanelChart (azimuthal 1D,
Wilson, I/sigma, spot and fluorescence profiles of the current image). The
per-dataset metric combo is disabled while in per-image mode.
- The per-image profile follows the displayed image (imageLoaded forwarded).
- Drop the "Image statistics plot" section from JFJochViewerSidePanel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The two capabilities that set Jungfraujoch apart get prominent, paired navy
buttons at the right of the display toolbar, with purpose-drawn icons (a single
diffraction frame vs a stack of frames):
- "Reanalyze image" re-runs the analysis pipeline on the current image
(worker Analyze).
- "Reanalyze dataset" opens a new whole-dataset processing job
(JFJochProcessingJobsWindow::newJob, now public).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Show the PSI logo in the menu-bar corner, picking one of four interchangeable
dot designs at random each launch. Embedded as PNGs (rasterised from the SVG
sources, kept alongside) so no Qt SVG module dependency is needed.
- Settings dock: put beam center X and Y on a single "Beam center" row to save
vertical space on laptop screens.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Surface a surgical subset of processing settings in an always-visible dock
instead of hidden windows:
- New JFJochViewerSettingsDock with an MX / AzInt segmented toggle.
MX page: geometry (energy, distance, beam X/Y), a new unit-cell +
space-group editor (no such input existed before; enables known-cell
ffbidx), spot finding (S/N, photon count, min pixels/spot), indexing
algorithm and geometry refinement. AzInt page: q range / spacing /
azimuthal bins plus the existing powder-calibration widget.
- Edits feed straight into the worker (UpdateSpotFindingSettings,
UpdateAzintSettings, UpdateDataset, FindCenter); fields populate from the
loaded dataset.
- Add CeO2 and Silicon calibrant presets.
- Dock it left, objectName "settingsDock", show it in the Processing
perspective (hidden in Image).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the layout reconfigurable, the foundation for the redesign:
- The diffraction image becomes the central widget; the right-hand side panel
is now a dockable "Inspector" (QDockWidget, right area).
- Every dock and toolbar gets a stable objectName so QMainWindow saveState /
restoreState round-trips. Dataset-info docks are numbered uniquely.
- Persist geometry + dock state to QSettings on close and restore on launch,
so the user's arrangement resumes.
- New "View" menu with Image / Processing perspectives (show/hide the bottom
plots + jobs panel) and "Reset layout" (back to the as-built arrangement,
captured at startup).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First pass of the viewer redesign (see docs/review/VIEWER_REDESIGN.md), no
structural change:
- TitleLabel: replace the 50px solid #FA7268 section bars with a slim 26px
navy-bold header + coral accent rule, removing the "venetian blind" stack
while keeping the salmon identity.
- Palette: switch the accent (QPalette::Highlight) from teal to navy #1F3A5F.
- Image toolbar: replace the unicode arrow glyphs (|<= <= => =>|) with flat
media icons (first/prev/next/last) + tooltips, and a play icon on Movie.
- Bottom dock: give the per-dataset plot more default height (340 -> 420).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Eigen is an external find_package(Eigen3 3.4) dependency. Eigen's
same-major-version rule means a bare 3.4 request only accepts 3.x, so 5.x
cannot be used without changing every requester (jfjoch, Ceres, and the
upstream ffbidx). Standardise on Eigen 3.4.x:
- docs: correct the Windows Eigen install recipe to 3.4.0 and note the
same-major constraint; SOFTWARE.md now says 3.4.x (not "3.4 or newer").
- docker/{rocky8,rocky9,ubuntu2204,ubuntu2404}: actually install Eigen 3.4.0
from source to /opt/eigen-3.4 (header-only) and add it to CMAKE_PREFIX_PATH.
The images previously installed no Eigen at all, relying on the obsolete
"CMake fetches it" assumption; a rebuild would have failed at configure.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Locate nvcc via find_program (HINTS CUDA_PATH / /usr/local/cuda) before
CHECK_LANGUAGE(CUDA), so CMAKE_CUDA_COMPILER no longer has to be passed by
hand. CHECK_LANGUAGE only searches PATH, which is missed routinely on Windows
and intermittently on Linux; the CUDA installer always sets CUDA_PATH. An
explicit -DCMAKE_CUDA_COMPILER / $CUDACXX still wins.
Docs: zlib and Eigen are external find_package deps (not auto-fetched);
simplify the Windows configure to just CMAKE_PREFIX_PATH (no CMAKE_CUDA_COMPILER,
no ZLIB_ROOT); fix the Eigen 5.0.1 install recipe to disable BLAS/LAPACK
(they fail MSVC with C1128 /bigobj) and use cmake --install.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Fusion fills QGroupBox interiors with a flat light colour, so the settings window
lost its salmon look. A tiny app stylesheet (QGroupBox { background: transparent })
makes them show the salmon window background again; entry widgets stay white via
the palette.
- The dataset-info chart now fixes the x-axis to the whole dataset [0, n) (the
largest run = the original file), so a subset run is drawn at its real image
positions instead of being stretched to fill the plot. Subsets with binning bin
by ordinal and place each point at its mapped image number (correct for the
common contiguous sub-range).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build jfjoch_hdf5_test once in a new build-hdf5-test job and hand the binary
to dials-test as an artifact, instead of recompiling it from scratch in every
rocky9 processing job. Uses the christopherhx gitea-{upload,download}-artifact
fork (mirrored under gitea.psi.ch/actions) to avoid the stock v4 action's
GHESNotSupportedError. Probe scope: dials-test only; xds-* still self-build
until the round-trip is confirmed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Running rotation indexing on a sub-range (e.g. images 60-120) segfaulted: the
first pass passed the *global* image number to RotationIndexer::ProcessImage,
which indexes v_ (sized to the run's image count) -> out-of-bounds write.
- ProcessImage now takes an explicit mid-exposure angle (optional; falls back to
the goniometer at the image index), so the indexer no longer assumes its slot
index equals the goniometer image index. IndexAndRefine supplies it via
RotationAngle(), matching the angle used for prediction. Added a bounds guard in
ProcessImage so a bad index can never corrupt memory.
- JFJochProcess feeds the rotation indexer the local ordinal (not the global
index), and shifts the goniometer (start += start_image*incr, incr *= stride,
per-image wedge preserved) so local index i maps to the angle of original image
start+i*stride - fixing rotation angles for the whole sub-range pipeline
(prediction, refinement, output), not just the indexer.
- Expose "Rotation images" (number used for the first pass) in the job dialog,
enabled when rotation indexing is on. (Count > available is already clamped by
select_equally_spaced_image_ordinals.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Styling (now via the application palette in main(), not a stylesheet, so it
applies to every widget incl. dialogs):
- Entry fields and item views (line edits, spin boxes, combos, tables) are white
when enabled and salmon (the GUI default) when disabled - so it's clear where
you can type. Panels stay salmon (Window role).
- Teal (#2a9d8f) accent via the Highlight role: selections and progress-bar chunks.
Runs list / plots:
- The original file is listed as a first "Original" run (Mode "HDF5"); double-click
any run row to show it (replaces the "Show original" button). The currently shown
run is bold (driven by snapshotsChanged).
- Fix the colour "swap" when switching runs: the primary line is matched by the
active-dataset pointer (not active_id_), so a run keeps its colour even while a
datasetLoaded/runsChanged pair is mid-flight.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Styling:
- Entry widgets (line edits, spin boxes, combos, item views) are salmon (the GUI
default) when inactive and turn white while focused/active.
- A teal accent (#2a9d8f) for selections and the QProgressBar chunk, against the
salmon background.
- Move the jobs-table Status column (the progress bar) to column 2 so it stays
visible in the narrow dock instead of scrolling off the right edge.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the ambiguous "Images" count with explicit "Start image" and "End image"
spinboxes (end 0 = to the last image). buildConfig sets config.start_image /
end_image; the table shows the range ("start-end" / "all") and the progress bar
expects end-start images.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Foundation for a dataset (snapshot or, later, the main file) being a subset of the
truly collected images:
- JFJochReaderDataset gains source_image_number (image index -> original image
number; empty = identity).
- HDF5MetadataSource reads /entry/detector/number into that map and an inverse
(original -> local) map; FillPerImage / ReadSpots translate the requested global
image to this source's local index via ToLocalIndex (return nothing if the image
is not covered), so partial snapshots are correct and never read out of bounds.
- RegisterSnapshot now accepts a snapshot with fewer images than the dataset
(only rejects more), so sub-range / strided reprocessing runs register.
- The dataset-info plot draws each run at its original image numbers (x map from
source_image_number), so a subset run lands at the right place on the shared
axis. The live run's map is filled from msg.original_number.
This makes the foundation ready for strided / filtered selections (e.g. reprocess
only images with >N spots) without restricting to a min-max sub-range.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Lower the dataset-info chart and jobs-table minimum heights (200 -> 80, table 60)
so the bottom dock area can be dragged smaller; the comfortable default size is
still set via resizeDocks.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The current-image marker (a scatter series) was picking an arbitrary theme colour
(green), which read as a stray series. Pin it to black so it's an unambiguous
"current image" dot, distinct from the run line colours. Its legend entry is
already hidden.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- "Remove result" toolbar action drops a reprocessing run: reader RemoveSnapshot
(Original is protected; if the removed run was active the view falls back to
Original), worker RemoveRun, and the table row is removed.
- Opening a new file clears the jobs table (worker fileOpened -> clearJobs) to
match the reader, which already resets snapshots on ReadFile.
- Plot fixes: each run keeps a stable colour by its position (Original = blue),
so colours no longer swap when the active run changes; the current-image marker
is hidden from the legend (was the stray "[Image #N]" entry).
- The status bar shows processing rate (Hz) and estimated remaining time while a
job runs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The dataset-info plot now overlays every run as a separate named line instead of
replacing the plot when a snapshot is activated:
- Reader gains AllSnapshotDatasets() (every snapshot's dataset, Original first).
- The worker owns the run collection: a stable snapshot id plus an editable
display label (RunData), emitted as runsChanged(runs, active_id) on file open,
snapshot register, activate and rename. RenameRun(id, label) updates the legend
label without touching the reader key (decoupled id vs label).
- The chart view draws the active run as the primary series (markers, hover,
binning, axes) and the other runs as overlay lines sharing its axes, with a
legend shown when overlaying (appendSeries factored out for both).
- The dataset-info widget holds the run list + the live run, extracts the selected
metric from each (ExtractMetric), and unions the available metrics across runs.
- The live run is its own "Live" overlay (lightweight per-tick refresh, no combo
rebuild); it is cleared on finish so the persisted snapshot takes over.
- The processing jobs table gets a "Started" column and an editable Name column;
editing a name renames that run's legend label.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- The Indexing tab now shows what the selected algorithm resolves to on this
machine/dataset ("Effective on this system: ..."), mirroring
DiffractionExperiment::GetIndexingAlgorithm() so Auto is no longer ambiguous
(GPU present? unit cell known?). Cell-known state is forwarded from the loaded
dataset via JFJochSettingsWindow::datasetLoaded.
- FFBIDX and FFT (GPU) radio options are disabled on builds without CUDA, where
only the FFTW CPU indexer exists.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Regressions from docking the processing panel + live plots:
- Default window size is now screen-aware (fits a laptop) instead of a fixed
1200x1200.
- Give the bottom dock area a guaranteed height (resizeDocks vertical) and a
minimum height on the dataset-info chart, so the plot and its axis labels stay
visible next to the processing panel.
- Activating a metadata snapshot (Show original / View results) no longer re-runs
full analysis: it re-reads the image against the snapshot's stored results with
reanalysis suppressed, instead of re-indexing on every switch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Convert JFJochProcessingJobsWindow from a standalone helper window into a
dockable QWidget panel (toolbar + stacked table/message), placed in the bottom
dock area and split horizontally to sit in the bottom-right corner next to the
dataset-info plots. Its show/hide toggle moves to the Window menu via the new
JFJochViewerMenu::AddDockEntry.
- When connected to a live HTTP stream the panel shows "Dataset re-processing is
currently available only in File mode" and disables the toolbar, driven by the
worker's httpConnectionChanged signal.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Processing settings:
- Split the spot/index settings widget into two tabs (Spot finding | Indexing)
via TakeSpotFindingPage()/TakeIndexingPage().
- Indexing tab now exposes the indexing algorithm (Auto/FFBIDX/FFT/FFTW/None) and
geometry refinement (None/Orientation/Beam center/Pixel refine) as radio groups
with short explanations.
- Fix: UpdateSpotFindingSettings dropped algorithm + geometry-refinement when
copying into indexing_settings (the geom checkbox was a no-op); both now flow
into jobs via curr_experiment.
Processing jobs window:
- Rotation indexing from the job dialog now also sets RotationIndexing(true) on
the experiment's IndexingSettings; otherwise IndexAndRefine builds no rotation
indexer and the two-pass pre-pass throws.
- Status cell shows a QProgressBar with "<done> / <expected>".
- Live results: JFJochProcessController::OnImageProcessed accumulates per-image
results into a JFJochReaderDataset and emits it throttled (~4 Hz) as liveDataset,
forwarded to the dataset-info plots so they update while a job runs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
One "Processing settings" window with tabs: Spot finding & indexing | Azimuthal | Bragg
integration | Scaling, replacing the two separate settings windows. The spot/index and azimuthal
tabs reuse the existing windows' widgets unchanged (their content is lifted into tabs via
takeCentralWidget), so all their logic/signals keep working; Bragg integration and scaling are new
editable panels (previously not adjustable in the GUI).
JFJochImageReadingWorker gains UpdateBraggIntegrationSettings / UpdateScalingSettings; both persist
as worker state and are re-imported into curr_experiment on file load / dataset update (like the
indexing/azint settings), so they apply to interactive analysis (Bragg) and flow into processing
jobs via GetReprocessingInputs (Bragg + scaling). Scaling only affects the job post-pass, so it is
just stored, not reanalyzed.
Verified: jfjoch_viewer builds and runs (offscreen) with the converged window.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Only the ~1800-image rotation dataset is kept in LFS; a separate ~5000-image serial set is too
large to ship, and the serial path can be exercised by running the rotation series in serial
mode if needed. Removes JFJochProcess_LysoSerial and the serial entry from the start-up listener
and README. The rotation [large] test now runs against the committed data and passes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Real reference dataset for the [large] JFJochProcess_LysoRotation test, stored with git-LFS
(tests/data/*.h5). lyso_rotation_master.h5 is the 1800-image lysozyme rotation series
(its data files keep the names the master links to). The test indexes it at 100% with cell
~78.2/78.2/37.8; it SKIPs when the data is not pulled.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Makes the viewer a processing frontend, not just an image viewer:
- JFJochProcessingJobsWindow (menu "Processing"): a table of processing jobs on the open
dataset. "New job" configures mode (full/azint), image count, threads, output, and (full)
rotation indexing + scale/merge, using the viewer's current processing settings. A job can
be Run locally (off the GUI thread via JFJochProcessController, with live status/progress and
Cancel) or its jfjoch_process command line copied for a cluster.
- A finished local run is registered as a reader metadata snapshot and becomes the active
dataset (bottom plots + per-image overlays follow it); "View results" / "Show original" switch
between runs - so several settings attempts on one dataset can be compared.
- JFJochImageReadingWorker gains GetReprocessingInputs() (one locked read of file + experiment +
mask + spot-finding settings, so jobs share the interactive settings) and
RegisterProcessingSnapshot/SetActiveSnapshot slots + snapshotsChanged signal over the reader's
snapshot API. Files only (not live HTTP).
First-cut / open ends: one job at a time; output lands in the working dir (FileWriter rejects
absolute prefixes); Bragg/scaling settings still use defaults until the converged settings
window lands. Viewer builds and runs (offscreen) cleanly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Foundation for making processing a first-class GUI activity:
- process/JFJochProcessCommandLine: reconstruct the equivalent jfjoch_process / jfjoch_azint
command line from a ProcessConfig + DiffractionExperiment + input path, for handing a job
off to a cluster. Unit-tested (full + azint).
- viewer/JFJochProcessController: runs one JFJochProcess job off the GUI thread (its own private
reader; HDF5 access is globally serialized so it is safe next to the interactive reader) and
reports back via queued Qt signals (started/phaseChanged/progress/finished/failed). Cancel()
forwards to JFJochProcess::Cancel(). Progress is throttled to ~200 updates per run.
The visible processing UI (jobs window + snapshot switcher + converged settings) builds on this.
Verified: tests/jfjoch_test [process]; jfjoch_viewer links and builds against JFJochProcess.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- .gitattributes tracks tests/data/*.h5 via git-LFS for big reference datasets.
- tests/TestData.h resolves tests/data files and reports absent / unfetched-LFS-pointer
so tests can SKIP() instead of failing; tests/data/README.md documents fetching + the
expected lyso_rotation/lyso_serial datasets.
- JFJochProcessLargeTest: a Catch start-up listener that prints dataset availability, plus
[large] full-analysis runs (rotation indexing + serial) that SKIP when data is absent.
Verified against the real 1800-image lyso rotation set (100% indexing, cell 78.2/78.2/37.8)
and skips cleanly without it.
- jfjoch_process.cpp: drop the ~15 now-unused workflow includes left after the JFJochProcess
extraction.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>