Skip to content

Fix/config driven pairs mng data - #42

Merged
johnaoga merged 14 commits into
mainfrom
fix/config-driven-pairs-mng-data
Sep 29, 2026
Merged

johnaoga merged 14 commits into
mainfrom
fix/config-driven-pairs-mng-data

Conversation

@johnaoga

Copy link
Copy Markdown
Collaborator

No description provided.

johnaoga and others added 13 commits September 10, 2026 03:16
…ocol; forced frame window

Bugs surfaced by an 8-camera / 4-pair dataset (subject 'Artem', MNG rig) run
through the camerapairs pipeline:

- camera_pairs was parsed but never consulted: every Utils::getCamerasForPair
  call site used the hard-coded {1,2 ; 4,3} table, so pairs >= 3 silently
  mapped to cameras (1,2) (REF mask of pair 3 applied to cam 1 -> 'could not
  seed any current image'). Utils now keeps a process-wide table registered
  from Config::camera_pairs (main.cpp + DicAnalysis ctor); pairs beyond the
  table fall back to (2N-1, 2N).
- new im_saturation_mode (default true): skip satur.m clipping for videos that
  were already filtered upstream (clipping flattened the speckle and ncorr
  diverged with hessian failures).
- limit_grayscale=0 now means 'auto' (legacy subject-number rule); a positive
  value is used as-is (subjects without a number, e.g. 'Artem', got S<8=70).
- new force_frame_window (default false): idx_frame_start/end/jump are
  authoritative, the protocol-derived per-phase window is skipped.
- protocol .mat is optional when ref_trial_id is set (MNG .tsv protocols);
  pair order falls back to 1..num_pair and Step D now appends pairs > 2 to the
  stitch order.
- video lookup: strict '<subject>_<material>_speckles_<trial>_' pattern first,
  then a relaxed '*_<trial>_*_cam_<id>.mp4' fallback (warned) for other rigs.
- video_quality accepts high/medium/low (the shipped default 'high' crashed
  with an uncaught stoi).
- startup log prints the resolved camera pairs, saturation/filter/engine/threads.
- deploy: submit_job.sh gains TRIAL / TRIALS / APP_ARGS for cppxdic; the
  cluster ncorr_params template pins dic_engine=ncorr (compiled default is
  cuncorr, which is a single-threaded CPU fallback in the CPU-only image).
- Tools/CppNCorr re-pinned to feat/fixed-step-ref (01b6e81): main uses
  fixed_step_ref, which CppNCorr main (861b5ce) does not have.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ing gate

cutoff_max_corrcoef / cutoff_max_diffnorm / seeds_are_optimized were parsed
from ncorr_params.txt but never copied into DIC_analysis_parallel_input, so
CppNCorr's built-in 0.5 / 0.1 always applied. Inter-view MATCHING seeds
(cam1->cam2 at the reference frame) correlate worse than tracking seeds by
nature (MNG mirrored rig pair 1 converges at corrcoef 0.51 and was rejected by
the 0.5 gate -> 'could not seed any current image'), so matching calls now use
a dedicated matching_cutoff_max_corrcoef (default 1.0). Config defaults
aligned with the engine (seeds_are_optimized=false, diffnorm 0.1, corrcoef 0.5).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…, mirrored worktree

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A user-drawn seed near the ROI boundary can be seen under a very oblique angle
by the other camera and the matching seed then never converges (Artem pair 3,
cams 5->6: seed (145,469) fails at radius 30-80 while the ROI centroid
(532,311) converges at 30 and 60). matchingInitialFrame now catches the
'could not seed any current image' error once and retries from the ROI centre
of mass; the second camera's seed is mapped from that point, the first camera
keeps the user seed for tracking.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…the matching field

performMatching re-derives the second camera's seed from the user seed after
reloading the matching checkpoint. When that seed sits where the inter-camera
field never converged (edge of the ROI), u=v=0 there and the seed was 'mapped'
onto itself, outside the matched ROI, so tracking of the second camera failed
with 'could not seed any current image' (Artem trial 2, pair 3). The transport
now checks the field validity at the seed's grid point and otherwise uses the
valid grid point nearest the centroid of the valid field.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Now that cutoff_max_corrcoef really reaches the engine, the template's 1.0 let
fixed-reference tracking run too long before re-referencing and the delayed
segment could not be seeded (Artem pair 3, frames 518/868). 0.5 is what every
run used de facto before; matching keeps its own 1.0 gate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Geometric overlap removal is O(iterations x boundary x faces) with one vertex
removed per iteration and no spatial acceleration; on the 8-view / 4-pair MNG
rig (Artem) it ran for >9 h per trial while the 2-pair S09 rig takes minutes.
'simple' appends the pairs without overlap removal (seconds), which is enough
for per-pair kinematics and for a quick full-pipeline pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…, CPU/GPU runs

Records the three reported symptoms and their real causes (camera_pairs parsed
but ignored, unconditional saturation with a subject-number level, protocol .mat
silently overriding the frame window), the seven fixes, and the full-pipeline
results: trials 001-003 complete on both engines with identical reconstructions
(11.8k points, 22.9k faces). cuNCorr/A100 is only ~1.14x faster than ncorr on 32
threads for tracking (94% of Step D), against 3.7-4x in the S09 study — dispatch
and reference-update hypotheses ruled out, still unexplained. Also records the
unusable geometric stitcher on a 4-pair rig and the Lemaitre queue situation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…p_e_ray_bvh)

The overlap-removal erosion casts a ray from every boundary vertex of one
surface against every face of the other, once per removed vertex: O(rays x
faces) per iteration with no spatial structure. Minutes on the 2-pair S09 rig,
>9 h without finishing on a 4-pair 8-view rig.

Adds a median-split AABB hierarchy over the faces, built once per ray-set call,
traversed with a slab test and an early-out on the best hit so far. Exact, not
approximate: a ray that hits a triangle also hits its padded box, so no
candidate that could be hit is pruned, and survivors go through the same
rayTriangleHit test and the same min-t rule.

Opt-in via step_e_ray_bvh (default false) so the brute-force path stays
available for comparison until the option is validated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Retracts 'geometric stitching is pathologically slow / unusable on a 4-pair
rig'. Measured: the same 2D results from the Lemaitre job killed after 5 h in
stitching complete Step E in 9 min 13 s on Manneback with the identical code
path (prefilter off). The hours-long stitching could not be reproduced and its
cause is unknown; do not treat the claim as established.

Also records: the AABB prefilter is exact (three input sets, identical meshes,
h5diff 0 differences) but only 1.1-1.3x end to end, so it stays off by default;
and a separate pre-existing bug where geometric stitching on the 2-pair S09
inputs silently discards every face and still reports success (the July 7a0e3ce
image behaves identically).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
23 of 24 runs complete the full pipeline with all 4 pairs. Step D speedup
1.07-1.25x (mean 1.15x), GPU peak memory 63-93 GB vs 89-117 GB on CPU, and the
two engines agree exactly on 9 of 11 comparable trials. The single failure is
CPU trial 011 (ncorr could not seed the segment at frame 683/711) where the GPU
run of the same trial succeeded.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Same code/config/data on Lemaitre4: 11 of 12 trials pass and trial 011 fails at
the identical frame 683, so that failure is deterministic and cluster-
independent. Timing pattern is consistent: Lemaitre is FASTER than Manneback on
Step D (0.63-0.88x the time) and 5-15x SLOWER on Step F.

That penalty on the single-threaded memory-bound phases is the right order to
turn a 9-minute geometric stitch into the 5-hour one observed there, so the
earlier 'cause unknown' is resolved: it was the machine, not the algorithm.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… open questions

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@johnaoga
johnaoga added this pull request to stack #44 September 17, 2026 09:50
…ef is merged

CppNCorr merged the fixed-step-ref work upstream as PR #20, so the divergent pin
to feat/fixed-step-ref (01b6e81) is no longer needed. Moving to main also brings
the leveled logging facility (#18) and the CI workflows the old pin lacked.

Verified before re-pinning: step_d_workflow.cpp, dic_analysis.cpp and
surface_stitching.cpp all compile against ae8262f's headers.

NOTE: main rewrote ~343 lines of src/ncorr.cpp for the logging facility, so
images rebuilt after this commit are not binary-comparable with earlier ones.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@johnaoga
johnaoga merged commit b83e402 into main Sep 29, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant