From 266d070f2cd8779ba4c244cfd6a072ce146d2f6a Mon Sep 17 00:00:00 2001 From: ClePol Date: Wed, 13 May 2026 15:45:36 +0200 Subject: [PATCH 1/2] Make surface reconstruction deterministic --- recon_surf/recon-surf.sh | 2 +- recon_surf/spherically_project.py | 2 +- recon_surf/spherically_project_wrapper.py | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/recon_surf/recon-surf.sh b/recon_surf/recon-surf.sh index e0e480493..eac769aef 100755 --- a/recon_surf/recon-surf.sh +++ b/recon_surf/recon-surf.sh @@ -794,7 +794,7 @@ for hemi in lh rh ; do echo "echo \"\"" } | tee -a "$CMDF" - cmd="recon-all -subject $subject -hemi $hemi -fix -no-isrunning -umask $(umask) $hiresflag $fsthreads" + cmd="env OMP_NUM_THREADS=1 ITK_GLOBAL_DEFAULT_NUMBER_OF_THREADS=1 recon-all -subject $subject -hemi $hemi -fix -no-isrunning -umask $(umask) $hiresflag -threads 1 -itkthreads 1" RunIt "$cmd" "$LF" "$CMDF" # fix the surfaces if they are corrupt diff --git a/recon_surf/spherically_project.py b/recon_surf/spherically_project.py index c0706d47a..0de5c4649 100644 --- a/recon_surf/spherically_project.py +++ b/recon_surf/spherically_project.py @@ -145,7 +145,7 @@ def get_flipped_area(tria): return area fem = Solver(tria, lump=False, use_cholmod=use_cholmod) - evals, evecs = fem.eigs(k=4) + evals, evecs = fem.eigs(k=4, rng=0) if debug: data = dict() diff --git a/recon_surf/spherically_project_wrapper.py b/recon_surf/spherically_project_wrapper.py index 09b3eb9bd..957c2a06e 100644 --- a/recon_surf/spherically_project_wrapper.py +++ b/recon_surf/spherically_project_wrapper.py @@ -48,8 +48,20 @@ def setup_options(): if __name__ == "__main__": import sys + from os import environ opts = setup_options() + # The spectral projection is sensitive to tiny threaded BLAS/eigensolver + # differences, and those can be amplified by later topology correction. + for var in ( + "OMP_NUM_THREADS", + "OPENBLAS_NUM_THREADS", + "MKL_NUM_THREADS", + "NUMEXPR_NUM_THREADS", + "VECLIB_MAXIMUM_THREADS", + ): + environ[var] = "1" + # identify whether sksparse is installed (in which case we can use_cholmod in LaPy try: # ignore ruff F401 (unused import) @@ -59,8 +71,6 @@ def setup_options(): has_sksparse = False # First try to run standard spherical project try: - from os import environ - from recon_surf.spherically_project import spherically_project_surface source_surface = opts.sd / opts.subject / "surf" / f"{opts.hemi}.smoothwm.nofix" From 3ba6895e7289b7763d05a991ea84b159a4b3b45f Mon Sep 17 00:00:00 2001 From: ClePol Date: Thu, 21 May 2026 12:05:57 +0200 Subject: [PATCH 2/2] Fix surfaceRAS header check --- recon_surf/recon-surf.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recon_surf/recon-surf.sh b/recon_surf/recon-surf.sh index eac769aef..4d1d648d7 100755 --- a/recon_surf/recon-surf.sh +++ b/recon_surf/recon-surf.sh @@ -714,7 +714,7 @@ for hemi in lh rh ; do # Check if the surfaceRAS was correctly set and exit otherwise (sanity check in case nibabel changes their default header behaviour) { - cmd="mris_info $outmesh | tr -s ' ' | grep -q 'vertex locs : surfaceRAS'" + cmd="mris_info $outmesh | awk '\$1 == \"vertex\" && \$2 == \"locs\" && \$3 == \":\" && \$4 == \"surfaceRAS\" { found = 1 } END { exit !found }'" echo "echo \"$cmd\"" echo "$timecmd $cmd" } | tee -a "$CMDF"