Skip to content

Support Single Precision mode across the model#940

Draft
suvarchal wants to merge 8 commits into
mainfrom
support_sp
Draft

Support Single Precision mode across the model#940
suvarchal wants to merge 8 commits into
mainfrom
support_sp

Conversation

@suvarchal

@suvarchal suvarchal commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Single precision capability,

Adds opt-in single-precision (-DUSE_SINGLE_PRECISION=ON) for standalone fesom.x. Default build stays double precision and unchanged. Mesh/restart/forcing files remain double on disk; WP arrays convert on I/O so existing features. CVMIX in SP is wip.

CORE2

Benchmark: core2 mesh, core2 forcing, 1 year, on levante 64-tasks-1-compute node, used KPP as CVMIX needs bit more work to be used in SP mode. Compiled with intel compiler.
SP: SYPD : 22.0574 years/day
DP: SYPD : 13.3427 years/day
speedup : ~ 1.69x

spatial plots are just last month (december)
a_ice_north_SP_DP
a_ice_south_SP_DP
a_ice_timeseries_SP_DP
sst_SP_DP
ssh_SP_DP
salt_timeseries_SP_DP
sst_timeseries_SP_DP
ssh_timeseries_SP_DP

PI January 1948, 1 month)

Benchmark: bundled pi mesh (~3.1k nodes), CORE2 forcing, 2 976 steps (Δt = 900 s), lean monthly I/O (sst, sss, ssh, a_ice). Two builds: build-sp (SP) and build-dp (DP). Local ubuntu, GNU + OpenMPI.

Global metric — SYPD (Simulated Years Per Day, from fesom.stats): higher = more simulated time per wall-clock day.

SP vs DP: ~1.21× faster wall time at both rank counts (+17% at mpi2, +19% at mpi8). SYPD: +21% (mpi2) and +23% (mpi8).

MPI scaling (same precision): mpi2→mpi8 ≈ 2.7× wall-time speedup and 2.7× SYPD (sub-linear vs 4× cores on this small mesh).

Largest mpi2 component gains (SP/DP): oce_mix_pres ~1.6×, oce_ssh_solve ~1.55×, oce_timestep_ale ~1.27×. ice_timestep ~neutral (~1.01×).

Field sanity (month 1, mpi2): SST max|Δ| ≈ 0.24 °C, SSS ≈ 0.05 psu, SSH ≈ 2.3 mm — SP and DP stay close.
mpi2_a_ice_north_sp_dp_diff
mpi2_a_ice_south_sp_dp_diff
mpi2_ssh_sp_dp_diff
mpi2_sst_sp_dp_diff

@JanStreffing JanStreffing added this to the FESOM 2.8 milestone Jun 25, 2026
suvarchal and others added 4 commits July 4, 2026 05:07
Make working precision configurable via -DUSE_SINGLE_PRECISION=ON. Default
build stays double precision and unchanged.

- WP is now preprocessor-selected (4/8) in o_PARAM; central MPI_WP parameter
  in MOD_PARTIT mirrors it (MPI_REAL vs MPI_DOUBLE_PRECISION).
- CMake gains USE_SINGLE_PRECISION option with per-compiler default-real flag
  flip (Intel -r4, GNU drops -fdefault-real-8, Cray -s real32, NVHPC -Mr4);
  CVMix forced OFF in SP (double-only, out of scope).
- Replace MPI_DOUBLE_PRECISION/MPI_DOUBLE with MPI_WP at WP-data sites; convert
  WP comm/gather buffers from real(real64) to real(kind=WP).
- NetCDF stays double on disk; WP reads routed through generic nf_*_vara_x so
  existing meshes/restarts/forcing keep working (convert-on-I/O).
- mod_transit and reference-density locals converted to WP; io_meandata vector
  rotation round-trips through WP temps; iceberg subsystem made WP-consistent.
- Startup banner prints WP byte size and SINGLE/DOUBLE mode.

Co-authored-by: Cursor <cursoragent@cursor.com>
The KPP divide-by-zero guard epsln=1.0e-40 is a denormal in real32 and is
flushed to zero under Intel -O3 (FTZ/DAZ) in single-precision builds, defeating
the /(wm+epsln), /(hbl+epsln), /(dVsq+Vtsq+epsln) guards and producing 0/0 NaN
at the cold start (Wvel NaN at step 1 on core2). Make epsln precision-dependent:
1.0e-20 (normal, FTZ-safe) in single precision, 1.0e-40 (unchanged) in double
precision. The double-precision build is bit-identical.
Intel-compiled fesom.x stack-allocates large per-column automatic arrays and
SIGSEGVs on global meshes (e.g. core2) under the default 8 MB stack limit. Wrap
the test launch in /bin/sh -c "ulimit -s unlimited || ulimit -s 1048576; exec
..." so mpiexec and the ranks it spawns inherit a larger stack. Degrades
gracefully where unlimited is disallowed; harmless for GNU/CI.
CVMix is a fixed double-precision library (kind cvmix_r8 = real64); it was
forced OFF under USE_SINGLE_PRECISION. Link it in both precisions and convert
WP<->cvmix_r8 at the CVMix call boundary in the wrappers (scalar args cast,
array args via cvmix_r8 temp buffers; FESOM-side arrays stay WP). CVMix always
runs in double precision, so the mixing-scheme menu is identical in single and
double precision (enabling like-for-like comparison) and the default
double-precision build is numerically unchanged. Verified on core2: KPP, PP,
cvmix_PP, cvmix_KPP and cvmix_TKE all run in GNU and Intel single precision.
suvarchal added 4 commits July 4, 2026 05:48
In a single-precision build (WP=4) a namelist.io field may request 8-byte
output (e.g. the stock 'salt',1,'m',8). The mean-I/O layer already honours
this -- the field is written as NF_DOUBLE with its mean accumulated in real64
-- but the samples are single-precision-sourced. Make the user aware: tally
such fields as streams are defined and print one summary line at the end of
ini_mean_io (rank 0 only), listing the affected variables. No per-stream or
per-step output; silent in double-precision builds where accuracy > WP can
never trigger.

Add an SP-only ctest (integration_pi_sp_mpi2, label single_precision) that
runs the pi mesh and asserts the SINGLE PRECISION MODE startup banner. To
support it, add_fesom_test[_with_options] gains optional EXTRA_SUCCESS_MARKERS
and LABEL arguments; default behaviour is unchanged.
No integration test exercised the CVMix vertical-mixing path. The stock
namelist.oce ships mix_scheme='KPP' -- FESOM's native (non-CVMix) KPP -- so a
CVMix-enabled build (CVMIX=ON, the default) never runs CVMix code by default;
CI only ever covered native KPP. CVMix schemes such as cvmix_TKE (used at high
resolution) went untested.

Add integration_pi_cvmix_tke_mpi2 and integration_pi_cvmix_kpp_mpi2 (label
cvmix): pi-mesh runs with mix_scheme set to 'cvmix_TKE' / 'cvmix_KPP'. CVMix is
a fixed double-precision library (kind cvmix_r8 = real64) built into FESOM's
tree via FetchContent; only the FESOM-side WP<->cvmix_r8 conversion differs by
build. So each test covers the previously-untested FESOM-DP+CVMix path in a DP
build and the FESOM-SP+CVMix path (the conversion shims from the CVMix-in-DP
change) in an SP build -- run `ctest -L cvmix` in each build dir. Gated on
CVMIX (default ON); no precision guard. Pass/fail is the clean run + artifacts,
so a wrong scheme string or a CVMix-less build fails at setup.

To support it, add_fesom_test[_with_options] gains an optional MIX_SCHEME
argument that rewrites mix_scheme in the test's namelist.oce (whitespace-
tolerant, comment-preserving, matching the harness's other rewrites).
Verified: both schemes pass in GNU DP and GNU SP builds on pi, with CVMIX_TKE /
CVMIX_KPP genuinely initialised (real64 vs real32 params in the logs).
…kflow

Precision is a property of the build, not the test: in a USE_SINGLE_PRECISION
build every integration test runs single precision; in a DP build every test
runs double. The previous per-test SP modelling (integration_pi_sp_mpi2 + a
single_precision label) was redundant and left the base pi tests unlabelled.

Harness (cmake/FesomTesting.cmake):
- Every fesom.x integration test now auto-asserts the build's startup banner
  ('SINGLE'/'DOUBLE PRECISION MODE', chosen by USE_SINGLE_PRECISION) as a
  required success marker, so each test self-certifies it ran at the intended
  precision -- a mis-configured build fails loudly on every test.
- Every integration test gets a base 'integration' label; the optional LABEL
  arg (e.g. cvmix) is now appended, so cvmix tests carry 'integration;cvmix'.
  `ctest -L integration` runs the suite, `ctest -L cvmix` isolates CVMix.

tests/integration/CMakeLists.txt:
- Remove the now-redundant integration_pi_sp_mpi2 (its guarantee holds for
  every test in an SP build) and the single_precision label.

CI (.github/workflows/fesom2_sp_ctest.yml, new):
- SP-only, non-blocking (continue-on-error) workflow: builds full-config in
  single precision (mirrors DP: MESHPARTITIONER + MESHDIAG ON) so the whole
  local suite registers in SP, and runs it via `ctest -E '^(remote_|ecbundle_)'`.
  DP is already covered by fesom2_ctest_runner.yml and the default preset (which
  already runs the cvmix tests in DP), so no dp/sp matrix -- that would be a
  third DP run. Promote SP to blocking later by removing continue-on-error;
  widening to SP meshpart/meshdiag/remote needs no build change, only run
  selection.

Verified: build-dp/build-sp reconfigure; integration_pi_sp_mpi2 gone;
'integration'/'cvmix' labels present, 'single_precision' gone; generated test
scripts carry the correct DOUBLE/SINGLE marker; a DP integration test passes
with the new required marker.
Line 51 began with a literal '-' (a diff fragment committed by mistake in #938),
which terminated the `run: |` block scalar and made the whole workflow invalid
YAML -- GitHub rejects it ("Invalid workflow file") and act cannot parse it.
Restore the intended 8-space indentation so the line stays a comment inside the
run block; the commented-out ctest invocation is preserved, not deleted.
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.

2 participants