SWATGenXSWATGenX
Watershed ExplorerExample modelsCloud calibrationDocsAccess
SWATGenXDocs

Compile the SWAT+ fork

Applies to SWATGenX engine extensions · Updated August 2026

Clone rafiei-vahid/swatplus, build with Intel ifx and ifx-built NetCDF-Fortran, set the CMake NetCDF and OpenMP switches, install into TxtInOut.

SWATGenX packages are ordinary SWAT+ TxtInOut trees plus documented extensions. The engine that reads NetCDF cdfout, OpenMP run modes, PFAS inputs, and research mf6.con coupling is the public fork of upstream SWAT+ at github.com/rafiei-vahid/swatplus. This chapter is the operator build recipe for that fork. Stock SWAT+ build docs remain upstream; do not treat this page as a substitute for swat-model/swatplus.

PFAS and MODFLOW 6 coupling modules are compiled into the fork’s main / ship-tag line; they are not separate CMake products. They stay dormant unless the model supplies PFAS inputs (pfas.dat / related files) or mf6.con (plus libmf6 on the library path). NetCDF and OpenMP are the two build-time toggles.

Prerequisites

ComponentRequirementNotes
Fortran compilerIntel ifx (oneAPI HPC Toolkit) for production-scale buildsgfortran can configure the same CMake options but is not the production toolchain; large models have failed under gfortran while building cleanly under ifx.
CMake≥ 3.16Unix Makefiles generator is the documented path.
NetCDF-C + HDF5System packages OKDebian/Ubuntu: libnetcdf-dev (and runtime libs). Only the Fortran bindings must match the Fortran compiler.
netcdf-fortranBuilt with the same ifx as the engineDistro libnetcdff-dev is gfortran-built; ifx cannot read those .mod files.
OpenMPProvided by ifx when SWATPLUS_OPENMP=ONCMake uses find_package(OpenMP) → OpenMP::OpenMP_Fortran (−fiopenmp / equivalent).
gitRequiredCMake names the executable from git describe --tags.
# Load Intel oneAPI (do this before set -u — setvars.sh dereferences unset vars)
source /opt/intel/oneapi/setvars.sh
command -v ifx   # must resolve (e.g. …/compiler/2026.0/bin/ifx)

# gfortran-only path (simpler, not production toolchain)
# sudo apt-get install -y gfortran cmake libnetcdff-dev libnetcdf-dev
If your shell enables set -u, source setvars.sh first (or temporarily disable -u). A failed setvars leaves ifx off PATH; CMake then silently picks /usr/bin/f95 and fails on ifx-only flags such as -recursive / -init=zero.

Clone the fork

Pin a release tag for reproducible builds. A stable public tag on the fork is ship/v1.0-49. Branch main is the consolidated line (OpenMP + NetCDF + PFAS + MF6) and moves; prefer a ship/* tag for a known binary.

git clone https://github.com/rafiei-vahid/swatplus.git
cd swatplus
git fetch --tags
git checkout ship/v1.0-49
# optional: confirm tip
git describe --tags   # expect ship/v1.0-49 (or equivalent)

rafiei-vahid/swatplus (fork) · swat-model/swatplus (upstream)

What to compile

  • One executableCMake target name swatplus-<git-describe>-ifx-lin_<arch>-Rel (slashes in tags become hyphens). There is no separate “PFAS binary” vs “base binary” on this fork line.
  • SWATPLUS_NETCDF=ONcompiles the NetCDF-4 output backend (still gated at run time by cdfout in print.prt).
  • SWATPLUS_OPENMP=ONlinks OpenMP; parallelism is selected at run time via OMP_NUM_THREADS and SWATPLUS_ROUTING_SERIAL (see Engine I/O).
  • PFAS + MF6 coupler sourcesalways present on main / ship tags; inert without model inputs / libmf6.
CMake optionDefault in fork CMakeListsRecommended
SWATPLUS_NETCDFONON
SWATPLUS_OPENMPOFFON
CMAKE_BUILD_TYPE(unset)Release
CMAKE_Fortran_COMPILER(auto)ifx (pass explicitly)

Build netcdf-fortran with ifx (required trap)

Fortran .mod files are compiler-specific. If you build the engine with ifx, rebuild netcdf-fortran with ifx against the system NetCDF-C. Point PKG_CONFIG_PATH at that prefix before cmake so pkg_check_modules does not pick the gfortran system package.

# Example prefix; any writable path is fine
PREFIX="$HOME/deps/netcdf-ifx"
# Source tarball: netcdf-fortran 4.5.4 (Unidata release)

export FC=ifx F77=ifx CC=gcc CXX=g++
./configure --prefix="$PREFIX" \
            --enable-shared --disable-fortran-type-check \
            CPPFLAGS="$(pkg-config --cflags netcdf)" \
            LDFLAGS="$(pkg-config --libs netcdf)"
make -j"$(nproc)" && make install

export PKG_CONFIG_PATH="$PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH"
# Runtime later: LD_LIBRARY_PATH="$PREFIX/lib:<oneAPI ifx lib dir>:$LD_LIBRARY_PATH"
Symptom of the wrong NetCDF: the compiler rejects the NetCDF Fortran module (“module file was not generated by any release of this compiler”), or you see a cascade of undefined NF90_* symbols. Fix PKG_CONFIG_PATH and reconfigure in a fresh build directory.

Configure and build

These are the CMake switches for a NetCDF + OpenMP ifx build matching the fork’s documented recipe. Always pass CMAKE_Fortran_COMPILER=ifx on a clean build directory.

cmake -S . -B build/ifx \
      -DCMAKE_BUILD_TYPE=Release \
      -DCMAKE_Fortran_COMPILER=ifx \
      -DCMAKE_Fortran_FLAGS="-O3 -ipo -recursive -init=zero -init=arrays -free -fpe0" \
      -DSWATPLUS_NETCDF=ON \
      -DSWATPLUS_OPENMP=ON

cmake --build build/ifx -j"$(nproc)"

# Locate the executable (name embeds git describe)
ls -1 build/ifx/swatplus-*-ifx-*-Rel
  • −init=zero −init=arrayszeroes uninitialized locals; used so thread-count comparisons are meaningful.
  • −ipointerprocedural optimization (ifx).
  • Do not pass −static together with a dynamic NetCDF build (CMakeLists refuses that combination when SWATPLUS_NETCDF=ON).
  • CMAKE_Fortran_FLAGS_RELEASE in the fork CMakeLists is overwritten to a short −O; put production flags in CMAKE_Fortran_FLAGS (as above), not only in FLAGS_RELEASE.

Install the binary into a model

SWAT+ must be launched from inside the scenario TxtInOut directory (where object.cnt lives). Copy or symlink the built executable as ./swatplus in that directory, or invoke it by absolute path from that cwd.

TXTINOUT=/path/to/Scenarios/Default/TxtInOut
BIN=$(ls -1 build/ifx/swatplus-*-ifx-*-Rel | head -1)
cp -f "$BIN" "$TXTINOUT/swatplus"
chmod +x "$TXTINOUT/swatplus"

# Runtime libs (ifx OpenMP + ifx netcdf-fortran)
export LD_LIBRARY_PATH="$PREFIX/lib:${ONEAPI_ROOT:-/opt/intel/oneapi}/compiler/latest/lib:${LD_LIBRARY_PATH:-}"

cd "$TXTINOUT"
OMP_NUM_THREADS=1 ./swatplus
  • NetCDF output: set cdfout = y on the value line under csvout dbout cdfout in print.prt (shipped SWATGenX packages already do). Optional: SWATPLUS_NC_DEFLATE=0|4.
  • Parallel modes: see Engine I/OOMP_NUM_THREADS and SWATPLUS_ROUTING_SERIAL. The engine binary ignores unknown CLI flags and will start a simulation anyway; do not use --version as a no-op.
  • Research MF6 coupling: place mf6.con per the MODFLOW coupling chapter and ensure libmf6 is discoverable.

Optional checks

  • Smoke: serial run (OMP_NUM_THREADS=1) of a small TxtInOut completes and writes expected channel_sd / NetCDF streams.
  • Same-binary thread check: re-run at N threads and compare the streams you care about. Prefer NetCDF (cdfout=y). When management text output is enabled, mgt_out.txt line order can differ across parallel runs even when sorted content matches — exclude or sort before comparing.
  • Do not treat a fresh rebuild as byte-identical to an older binary of the same source: compiler floating-point noise between builds is expected. Same-binary mode comparisons are the meaningful check.
  • Carbon (cswat = 2): not supported in parallel on this forkuse OMP_NUM_THREADS=1 if carbon is on.

Common failure modes

SymptomLikely causeFix
f95: unrecognized option -recursive / -init=zeroCMake picked gfortran because ifx was not on PATHSource setvars.sh without set -u; pass -DCMAKE_Fortran_COMPILER=ifx; delete the build dir and reconfigure
error #7013 … module file … [NETCDF]pkg-config found gfortran netcdf-fortranRebuild netcdf-fortran with ifx; export PKG_CONFIG_PATH before cmake; fresh build dir
Cannot find object.cntBinary launched outside TxtInOutcd into TxtInOut first
Missing libiomp5 / libnetcdff at runtimeLD_LIBRARY_PATH incompleteAdd ifx lib dir and the ifx netcdf-fortran lib dir
Large-model crash under gfortran buildKnown gfortran limitation at regional HRU countsRebuild with ifx before treating as an engine bug

rafiei-vahid/swatplus