ced0ac4bdd640151518a6d18e5ac58df43cfb331
14
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9c9b987928 |
Merge host-mem-2 into rc176: a host-memory budget from the machine's total RAM decides what runs side by side, the CPU ingest reads the reflections in place (24 B per partial), merge scratch is really freed, and CPU MR/validation workers are bounded by their bytes; output unchanged
Peak live heap, CPU path -N10, before -> after: 4nwv scaling 14.8 -> 11.9 GiB, analyses 13.5 -> 7.3; 8qaw scaling 34.0 -> 27.1; 9v16 17.2 -> 13.5; 9zlo/9gjx/9s02 7.7/7.4/8.9 -> 6.3/6.3/7.5. With the budget of a 16 GB machine, 4nwv validation 18.4 -> 10.8-12.3 and MR ~17 -> 12.5. GPU 4nwv 16.2 -> 14.8. Byte-identical to its base on GPU and --no-gpu (timing standard + inhouse, 4nwv/8qaw/9v16/ lyso_x06da_ref/cytc_x10sa), at the machine's budget and with a 16 GB one. Conflict in RugnuxScaleMerge.cpp: perf-8gb-cpu's card-byte declaration of the merge and this branch's host-budget decisions on the post-refinement and the all-observation arm, kept both, in that order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
af1bad8f47 |
MR on the CPU: placement refinements reserve their grids against the host worker pool
The first copies' placements are refined side by side, one thread each, and without a GPU each makes its structure factors and rigid body on the CPU - about a gigabyte of grids on a large cell, five at once at the 4nwv molecular-replacement peak (14.9 GiB live with a 16 GB machine's budget). Each now reserves 32 B per point of its grid before it starts, as a null replicate does. What each computes, and where its score goes, does not change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
2f3885259f |
Merge mr-gpu-r2 into rc176: MR and model validation spread their rigid-body engines over the cards, and MR packs the transform where its cost model expects it faster; output unchanged
Validated on the 4x T4 server (round 2): p.hkl, p_model.pdb, MR_* and the candidate table identical on 9zlo/9s02/9gjx/4nwv against round 1 on 1 and 4 cards; 4nwv on 4 cards 140.8 -> 127.9 s wall (MR 34.0 -> 21.2 s; rotation 18.4 -> 4.8 s), 9zlo/9s02/9gjx 1-3% faster. Conflicts were the crash fix both branches carry: the branch's side taken (the per-card Reserve of the device test). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
bc5577d32c |
Merge mr-multigpu-crash-fix into rc176: rigid-body engine calls restore the caller's card and the MR GPU functions run on their own card, fixing an illegal memory access in MR with engines on other cards; output unchanged on one card
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 23m23s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 27m42s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m56s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 27m8s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 5m35s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 17m8s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 30m6s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 20m19s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 13m19s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 16m43s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 35m34s
Build Packages / Create release (push) Successful in 7s
Build Packages / Generate python client (push) Successful in 11s
Build Packages / Build documentation (push) Successful in 45s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 24m56s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 28m38s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 29m12s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 29m13s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 30m13s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 30m37s
Build Packages / Unit tests (push) Successful in 1h12m25s
Build Packages / Validation Battery (push) Successful in 33m41s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
210664f454 |
Model scale fit: no log ratio at |Fcalc| = 0, and no LM step once the model has underflowed
Two ways the scale fit's normal matrix went singular and gemmi's jordan_solve threw "Trying to reverse singular matrix. Column 0 is zeroed.", ending the run: 1. The isotropic start (fit_isotropic_b_approximately) takes log(Fobs/|Fcalc|) over the strong reflections. At a phase-restricted reflection whose Fcalc and Fmask share a phase, some solvent pair of the k_sol/b_sol grid can cancel the model exactly in float, |Fcalc + k_sol exp(-b_sol s^2) Fmask| = 0. log(Fobs/0) = inf made that grid point's k_overall and B NaN, every sum of the Levenberg-Marquardt NaN, and the solve failed. This is what stopped three open-arm sets in the output pass after MR on the GPU (the scale fit after model validation's rigid body): one strong reflection, one grid point. The CPU path has the same exposure; which grid point hits an exact zero depends on the last bits of Fcalc, so the --no-gpu run of the same set went through. Such a reflection has no log ratio and is now left out of the start - in the GPU kernel, in FixedSolventFit::Start and, as a marked local change, in gemmi's own fit_isotropic_b_approximately, so the three stay equal and the held-solvent fits are covered too. 2. In FitModelScale's CPU Levenberg-Marquardt (ModelValidation_CCModelUnrelatedModelConfirmsNothing in a CUDA=OFF build): on 66 reflections of an unrelated model the fit walked to k_overall -424 and a B where k exp(-B s^2) |F| underflows at every reflection; the squares in J^T J were all 0 while J^T r kept a residue near 1e-210, which jordan_solve rejects. The fit now ends there, at its best so far, as it would at the lambda limit; that grid point then loses on R. The GPU fit takes the derivatives in float and their squares in double, so it cannot reach this state. Both changes only touch fits that threw before. Byte identity checked against an rc176 build on the standard and inhouse timing benchmarks and on 4nwv, 8tyy, 6oel (p.hkl, p_model.pdb, MTZ data, MR_* report keys). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
80f634b641 |
MR GPU: engines spread over the cards; the transform packed where it is expected faster
Build Packages / Create release (push) Successful in 8s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 5m31s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 12m45s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 37m25s
Build Packages / build:portable:linux-x86_64:cuda (push) Canceled after 0s
Build Packages / build:portable:linux-x86_64:nocuda (push) Canceled after 0s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Canceled after 0s
Build Packages / Validation Battery (push) Canceled after 0s
Build Packages / Unit tests (push) Canceled after 48m13s
Build Packages / build:jfjoch:rocky8:cuda (push) Canceled after 0s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Canceled after 0s
Build Packages / build:jfjoch:rocky8:nocuda (push) Canceled after 0s
Build Packages / build:jfjoch:rocky9:cuda (push) Canceled after 0s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Canceled after 0s
Build Packages / build:jfjoch:rocky9:nocuda (push) Canceled after 0s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Canceled after 0s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Canceled after 0s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Canceled after 0s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Canceled after 0s
Build Packages / Generate python client (push) Canceled after 0s
Build Packages / Build documentation (push) Canceled after 0s
Build Packages / build:portable:windows-x86_64:cuda (push) Canceled after 21m47s
Engine placement: the rigid-body engines past this card's first go one card after the other in turn, from
the next card and this one last, each within half of its budget. A small cell on four cards (24 engines of
0.09 GB) had put all of them on this card, which has room for them, where rc176 spread them; now 6/6/6/6.
A large cell on four 15.6 GB cards keeps T+1/T+2/T+2/T+2.
Layout: packing was refused wherever it cost any card an engine, which kept 4nwv plain on four T4s although
the packed rotation function on ONE card (15.1 s) already beat plain over four (18.5 s). Now the two layouts'
plans are compared on a small cost model, decided once before the search from sizes and counts alone:
seconds = rotation interpolations (orientations x reflections x operators) x s/interpolation / cards with a copy
+ rigid-body fits at once x engine GB x s/(fit GB) / engines
Constants measured on 4nwv on Tesla T4 (17255 x 244183 x 4 interpolations): 75.8 s plain and 15.1 s packed on
one card; rescoring + null 28.5 s with one engine and 11.6 s with seven, 9 fits of 2.10 GB, so 19.7 s shared
among the engines. Packing must still keep the search, the scores and (where plain has it) the rigid body on
the GPU, and the budget must hold both grids while the packed one is made. Expected on four T4s: packed
T+1/T+1/T+1/T+1, 8.7 s against 21.8 s plain. One card is unchanged (the engines are the same either way, so
packed). The layout line now logs both expected times and the search's size.
Layout and engine count change where the work runs, never a number.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
|
||
|
|
3fa17b9385 |
Model validation: the rigid-body engines on every card in turn, even where this card has room for all
The engines past this card's first now go one card after the other, from the next card and this one last, each within half of its own budget, as MR's do. Before, this card took every extra engine it had room for and the other cards only the rest, so a small cell on four cards ran all its fits on one. Where this card has no room for a second engine (a large cell on 15.6 GB cards) the plan is unchanged: 1/3/3/3. This card's scale fits take the room its engines leave. Engines are interchangeable and deterministic, so only where fits run changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
43e836573d |
MR and model validation on the CPU: workers bounded by their bytes, not the thread count
- The CPU translation function runs as many rotations at once as the host worker pool holds (8 B per grid point each, 550 MiB on a 400 A cell; 33 at once at 32 threads was 18 GiB), at most nthreads. Counted, not reserved: the rotations run on ParallelFor's pool, whose workers must not wait on memory. - Null replicates (model validation's and MR's) whose structure factors are made on the CPU reserve 32 B per point of their grid (ModelGridPoints) against the pool before they start, so the nine replicates, and nulls run side by side, hold at most the pool between them. Every replicate and rotation computes what it did and is stored by index: no result depends on how many run at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
fbdf036e6f |
Rigid-body engines leave the calling thread on its own card; the MR search runs on its transform's card
Every RigidBodyGPUEngine call did cudaSetDevice(engine's card) and never set the caller back. Molecular replacement's group threads refine copies on the pool's engines - on any card where every engine on this one is taken - and then run the next translation function on the same thread. MolecularReplacementGPU ran its calls on whatever card the thread was on, so that function's buffers and cuFFT plan were made on the engine's card, beside the transform and the stream on the search's card: an illegal memory access, 9s02 with four cards visible, every run (the further-copies loop: refine a trial on another card's engine, then translation_function on the group thread). - Each engine call (and the constructor) now holds a DeviceGuard: on the engine's card for the call, back on the caller's after it. - MolecularReplacementGPU remembers the card its transform was uploaded to and runs every call (and its destructor) there, whichever card the calling thread is on. - RigidBodyGPU_CallsLeaveTheCallerOnItsCard: one engine per card, all taken from one thread; the thread's card is unchanged after each call (meaningful with two or more cards). No number changes: where every call runs is the same card as before for each object. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
a3f30d03c1 |
Rigid-body engines leave the calling thread on its own card; the MR search runs on its transform's card
Every RigidBodyGPUEngine call did cudaSetDevice(engine's card) and never set the caller back. Molecular replacement's group threads refine copies on the pool's engines - on any card where every engine on this one is taken - and then run the next translation function on the same thread. MolecularReplacementGPU ran its calls on whatever card the thread was on, so that function's buffers and cuFFT plan were made on the engine's card, beside the transform and the stream on the search's card: an illegal memory access, 9s02 with four cards visible, every run (the further-copies loop: refine a trial on another card's engine, then translation_function on the group thread). - Each engine call (and the constructor) now holds a DeviceGuard: on the engine's card for the call, back on the caller's after it. - MolecularReplacementGPU remembers the card its transform was uploaded to and runs every call (and its destructor) there, whichever card the calling thread is on. - RigidBodyGPU_CallsLeaveTheCallerOnItsCard: one engine per card, all taken from one thread; the thread's card is unchanged after each call (meaningful with two or more cards). No number changes: where every call runs is the same card as before for each object. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
0f461a65a2 |
Merge mr-transform-layout: the corner-packed molecular transform beside MR on every card
Build Packages / Create release (push) Successful in 7s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 4m38s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 8m58s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 14m20s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 18m0s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 21m31s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m55s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 21m49s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 13m41s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 25m30s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 26m7s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 15m22s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 21m54s
Build Packages / Generate python client (push) Successful in 31s
Build Packages / Build documentation (push) Successful in 1m13s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 18m45s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 23m54s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 25m56s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 25m47s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 20m33s
Build Packages / Unit tests (push) Failing after 1h28m5s
Build Packages / Validation Battery (push) Successful in 34m34s
Combines mr-multigpu (per-card engine budgets, a transform copy on each other card, the rotation/translation functions split over the cards) with mr-transform-layout (the GPU transform optionally held corner-packed, same bits, 2.2x faster rotation function). Conflict (MolecularReplacement.cpp): the two new functions side by side (PackMolecularTransformGPU next to SplitRotationFunction/SplitTranslationFunction). On top of the textual resolution: - One layout decision for all cards, not one per card: the functions are split into equal slices, so a mix of packed and plain cards would run at the speed of the plain ones; either layout gives the same bits. - PackMolecularTransformGPU now plans with the other cards' budgets too and packs only where every card keeps what the plain plan gives it: this card's transform, engines and score engine, and on every other card its copy and its engine count. A packed copy is made after the card's engines are reserved; copy and engines within half of that card's budget leave room for the plain grid it is made from. - The copies on the other cards are made in the chosen layout, and the per-card plan (copies, engines, room) is made with the bytes actually placed. - Test: four 15.6 GB cards stay plain (packed, each other card would fall from T+2 to T+1); with 24 GB cards beside, packed. So on a 4x T4 4nwv runs split and plain, on one card packed; whether giving up 3 of 7 engines for the packed rotation function would pay there is left to a server measurement. Workstation (1x RTX 5080, --gpulock), against rc176: battery timing --benchmark standard (9zlo, 9s02, 9gjx, 4nwv) and --benchmark inhouse (myob, cytc, 4nwv) on GPU, inhouse also --no-gpu: p.hkl, p_model.pdb and the MR_ report block byte-identical on every set. 4nwv GPU: rotation 5.53 -> 2.50 s, MR step 20.1 -> 16.5 s (packed, 2.28 GB in place of 0.84 GB). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
3aa67a6059 |
MR GPU: corner-packed molecular transform for the rotation function
Each sample of the molecular transform interpolates over 8 grid corners that lie in four u-rows of the half-l grid, 4-5 32-byte sectors per sample. On the GPU the transform can now be held packed: every point (i, j, l) stores its four (v, w) corners, so the two neighbouring records hold all eight, read from two places. The packed grid is cut to |u| <= reach as the plain one already is in v, and has the conjugate plane l = -1 in front; below l = -1 the eight corners are read mirrored about -i0 - 1 and conjugated. Same floats, same accumulation order: rotation and translation functions give the same bits (checked in MolecularReplacement_GPUMatchesCPU). The layout is chosen up front from the budget (PackMolecularTransformGPU): packed where the answer merge's plan holds every part beside it that it holds beside the plain transform, and the budget holds both grids while the packed one is made from the plain one on the device; logged either way. The upload no longer stages a host copy of the grid. The CPU At() is unchanged: a microbenchmark gained 1.3x single-threaded and ~1.0-1.1x at 16-32 threads, not worth 2.7x the host memory. 4nwv (moved model, timing benchmark), RTX 5080: rotation 5.56 -> 2.48 s, MR step 20.9 -> 16.7 s; transform on the card 0.84 -> 2.28 GB. p.hkl, p_model.pdb and the MR_ report block byte-identical on the timing sets (GPU and --no-gpu) and on 4nwv, 8tyy, 6oel, 3inp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
bfc6ca8487 |
MR and model validation: use every card's memory, split MR's functions over the cards
On a multi-GPU host the structure stage ran essentially on one card: the rotation function's launches all went to the search's card, and the rigid-body engines of model validation and MR were admitted only within half of that one card's budget, although RigidBodyGPUPool already placed engines on other cards. On a 4x T4 server 4nwv's MR rotation function took 75.8 s on one card, validation queued its 10 fits on one engine and MR's rescoring and null got one engine. - PlanModelValidationGPU / PlanMolecularReplacementGPU: this card is planned exactly as on a machine with it alone (GPU-vs-CPU placement unchanged: 80% of the total, less what is resident). The rigid-body engines it has no room for go on the other cards in turn, each against its own budget (80% of its total, less the resident bytes, counted on every card) within half of it. MR also puts a copy of the molecular transform on each other card within half of its budget. - RigidBodyGPUPool::Reserve takes per-card engine counts. - Validation forwards the most it holds on any card as gpu_bytes to a validation beside, and may run one beside only where twice that fits every card's budget. - MR splits every rotation and translation function into contiguous slices of the orientation list over the cards holding a transform copy (and room for the call's buffers), one thread per card, gathered back in order. Each orientation is scored by itself (one block / one map), nothing is summed across orientations, so N cards give the bytes of one. - ScoreEngines keeps a room per card; score engines always go on the search's own card; function buffers are held on the card they run on. Byte-identical at N=1 (workstation, one RTX 5080): timing benchmark (myob, cytc, 4nwv) and 4nwv, 8tyy, 6oel, 3inp with --model give the same p.hkl, MTZ data, p_model.pdb, maps and report against rc176. New tests: per-card plans on four 15.6 GB cards (validation 1/3/3/3 engines, MR T+1/T+2/T+2/T+2), and the split driven over 1-4 virtual cards on one device, bitwise equal to one card. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 |
||
|
|
19b135186d |
v1.0.0-rc.175 (#85)
Build Packages / Create release (push) Successful in 7s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 4m56s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 9m10s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 13m51s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 16m56s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 20m59s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m25s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 21m17s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 14m14s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 25m59s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 25m48s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 15m52s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 19m33s
Build Packages / Generate python client (push) Successful in 29s
Build Packages / Build documentation (push) Successful in 1m19s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 20m49s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 25m31s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 25m24s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 26m5s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 22m19s
Build Packages / Unit tests (push) Failing after 2h28m24s
Build Packages / Validation Battery (push) Successful in 40m33s
* Rugnux: Processes a collection live while jfjoch_broker writes it (`rugnux <master.h5> <broker URL>`). * Rugnux: Processing starts on the first images and confirms its choices once all are in, so analysis can begin during collection. * Rugnux: Faster processing, especially on servers with several GPUs and CPU sockets and on computers without a GPU (`--no-gpu`, macOS). * Rugnux: Uses much less GPU memory, so large data sets stay on the GPU of smaller cards, and a data set too large for the card is processed on the CPU instead. * Rugnux: On macOS, Bragg integration runs on the Apple GPU. * Rugnux: Better handling of twinning and pseudo-symmetry, with the twin hypothesis written as `<prefix>_twin_<SG>.mtz`, and a wrong `--model` no longer confirms the data or decides the hand. * Rugnux: `--model` accepts predicted (AlphaFold) models and falls back to molecular replacement when the model is not placed as a rigid body (experimental `--mr` forces it), settling space group, hand and twinning and writing a different answer as `<prefix>_mr.mtz`. * Rugnux: Molecular replacement is faster and settles the space group in more cases with several copies in the asymmetric unit. * Rugnux: Deposition-ready mmCIF, a richer report, and numbered steps on the terminal with the full log in `<prefix>_log.txt`; `_P1.mtz`, `--estimate-beam-center` and `--beam-center-search` are removed. * Rugnux: The beam-stop shadow is found correctly on tilted detectors. * Rugnux: Stills files that record a stationary goniometer axis get the default stills geometry refinement. * jfjoch_viewer: "Analyze dataset" uses the same defaults as a bare `rugnux <file>`, and shows the results of processed CBF, marCCD and SMV sweeps. * jfjoch_viewer: The Files panel refreshes on F5 and every few seconds, and the plot type and other selections stay put during live collection. * jfjoch_writer: Memory stays bounded and old data files are closed efficiently on long runs, any failure ends the run in an error state the broker is told about, and the master file appears only after its data files; the ZeroMQ pusher logs when a stalled writer makes it drop images. * Fixes: The TCP image pusher no longer blocks the broker's receiver, GPU out-of-memory failures stop with a clear message, and the XDS plugin masks module and chip edges. --------- Co-authored-by: Filip Leonarski <jungfrau@filips-mac-mini.home> Reviewed-on: #85 Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch> |