SIESTA Compilation: Fujitsu Compilers (frt/fcc/FCC) with Fujitsu MPI
This page describes how to compile SIESTA on Fugaku using the native Fujitsu
compilers (frt, fcc, FCC) together with Fujitsu’s MPI implementation.
Before proceeding, make sure you have configured your Spack environment as described
in Spack 1.0.1 Configuration Guide for Fugaku.
Note
The scripts on this page rely on the environment variables MY_USER,
MY_PROJECT, and MY_VOLUME to construct all file paths. These variables
are defined during the Spack account setup described in
Spack 1.0.1 Configuration Guide for Fugaku. Make sure they are exported in your session
before running any script:
export MY_USER=your_username
export MY_PROJECT=your_project
export MY_VOLUME=your_volume
If you added these variables to your ~/.bashrc as described in Step 12 of
the Spack setup guide, they will be available automatically in every new
session. Alternatively, the variables can be defined directly inside each
script at the top of the file.
Warning
Source code patches are required for Fujitsu compilers.
The Fujitsu Fortran compiler (frt) enforces the Fortran standard more
strictly than GNU Fortran (gfortran) or Intel Fortran (ifort). Several
constructs in the SIESTA source tree that are silently accepted by other
compilers are treated as hard errors by frt.
The main classes of issues are:
jwd1740i — A module name and a locally imported entity share the same identifier within the same scope (e.g.,
use parallelinside a subroutine that already importsparallelfrom the host scope).gfortranresolves this silently;frtrejects it.jwd2391i — Assignment between derived types that do not have a defined assignment operator.
gfortranallows this implicitly;frtrequires an explicit operator or a compatible intrinsic assignment.jwd2043i — An
intent(out)variable may not be assigned on all execution paths.gfortranonly warns;frtraises an error.jwd1130i —
USEstatements insideBLOCK … END BLOCKconstructs are not supported byfrt 4.12.1. The block must be dissolved and its declarations moved to the enclosing scope.
The get_siesta_fj.sh script applies a series of patches (PATCH 1–6)
that resolve all of these issues before CMake configuration begins. The
patches are verified automatically; the script exits with an error if any
patch fails to apply cleanly.
Prerequisites
Interactive Session
All compilation steps must be run inside a compute node session on Fugaku. Do not run the scripts on a login node.
Request an interactive session before proceeding, then work entirely within that session.
Spack Environment
Once inside the interactive session, load the local Spack environment:
. /path/to/your/spack/share/spack/setup-env.sh
This is the same source call that appears at the top of each compilation
script. Replace the path with the actual location of your Spack installation.
py-ruamel-yaml
The SIESTA test suite requires the ruamel.yaml Python package. Install it
via Spack inside the interactive session. First load the Python module that
will own the package:
spack load /qhm66vh # python@3.13.5 built with fj@4.12.0
Then install py-ruamel-yaml pinned to that Python:
spack install py-ruamel-yaml ^/qhm66vh
After the installation finishes, verify the package is importable:
python3.13 -c "import ruamel.yaml; print('Ok')"
If the command prints Ok, the installation is correct and the test suite
will be able to locate the package. If it raises an ImportError, check
that the correct Python module is active in your session.
Note
The hash /qhm66vh refers to python@3.13.5 built with the Fujitsu
compiler fj@4.12.0. This same hash is hard-coded in get_siesta_fj.sh
via the spack load /qhm66vh call so that the build environment is
consistent with the one used to install py-ruamel-yaml.
NetCDF Installation
Before compiling SIESTA, you need to install NetCDF using the install_netcdf_fj.sh
script. NetCDF is not available as a pre-installed module on Fugaku and must be
compiled from source.
Note
The install_netcdf_fj.sh script builds NetCDF from source using the
native Fujitsu toolchain:
frt/fcc— Fujitsu Fortran and C compilersmpifrt/mpifcc— Fujitsu MPI wrappers
The following libraries are built in order:
zlib 1.3.1
HDF5 1.14.3 (with parallel I/O and Fortran bindings)
NetCDF-C 4.9.2
NetCDF-Fortran 4.6.1
Run the script before proceeding with the SIESTA compilation:
./install_netcdf_fj.sh
You can download install_netcdf_fj.sh directly.
Show full script: install_netcdf_fj.sh
#!/bin/bash
#
# install_netcdf_fj.sh – build NetCDF from source using Fujitsu compilers
#
# Requires the following environment variables (set in ~/.bashrc or exported
# before calling this script):
# MY_USER – your Fugaku username
# MY_PROJECT – your project code
# MY_VOLUME – your storage volume
#
# The script builds zlib, HDF5, NetCDF-C, and NetCDF-Fortran in sequence,
# installs everything under ${WORK_DIR}/install, and writes a small
# environment file (netcdf_env.sh) that get_siesta_fj.sh sources later.
#
set -e
# Disable HugePages (avoids warnings on Fugaku compute nodes)
export XOSOPTION="off"
export XOS_MMM_L_HPAGE_TYPE="none"
###############################################################################
# Check required environment variables
###############################################################################
for var in MY_USER MY_PROJECT MY_VOLUME; do
if [[ -z "${!var:-}" ]]; then
echo "Error: environment variable ${var} is not set." >&2
echo "Export it or add it to your ~/.bashrc before running this script." >&2
exit 1
fi
done
echo "=========================================="
echo "NetCDF installation – Fujitsu toolchain"
echo "=========================================="
###############################################################################
# Paths
###############################################################################
BASE_DIR="/${MY_VOLUME}/mdt1/data/${MY_PROJECT}/${MY_USER}"
WORK_DIR="${BASE_DIR}/netcdf_fujitsu"
SRC_DIR="${WORK_DIR}/src"
INSTALL_DIR="${WORK_DIR}/install"
FUJITSU_DIR="/opt/FJSVxtclanga/tcsds-1.2.42"
###############################################################################
# Library versions
###############################################################################
ZLIB_VERSION="1.3.1"
HDF5_VERSION="1.14.3"
NETCDF_C_VERSION="4.9.2"
NETCDF_FORTRAN_VERSION="4.6.1"
###############################################################################
# Download URLs
###############################################################################
ZLIB_URL="https://zlib.net/fossils/zlib-${ZLIB_VERSION}.tar.gz"
HDF5_URL="https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.14/hdf5-${HDF5_VERSION}/src/hdf5-${HDF5_VERSION}.tar.gz"
NETCDF_C_URL="https://downloads.unidata.ucar.edu/netcdf-c/${NETCDF_C_VERSION}/netcdf-c-${NETCDF_C_VERSION}.tar.gz"
NETCDF_FORTRAN_URL="https://downloads.unidata.ucar.edu/netcdf-fortran/${NETCDF_FORTRAN_VERSION}/netcdf-fortran-${NETCDF_FORTRAN_VERSION}.tar.gz"
###############################################################################
# Environment
###############################################################################
export PATH="${FUJITSU_DIR}/bin:${INSTALL_DIR}/bin:${PATH}"
export LD_LIBRARY_PATH="${INSTALL_DIR}/lib:${FUJITSU_DIR}/lib64:${LD_LIBRARY_PATH:-}"
mkdir -p "${SRC_DIR}" "${INSTALL_DIR}"
###############################################################################
# Helper: download and extract a tarball
###############################################################################
download_and_extract() {
local url=$1
local filename
filename=$(basename "$url")
cd "${SRC_DIR}"
if [ ! -f "${filename}" ]; then
echo "Downloading ${filename} ..."
wget "${url}" || curl -L -O "${url}"
else
echo "${filename} already downloaded."
fi
echo "Extracting ${filename} ..."
tar -xzf "${filename}"
}
###############################################################################
# zlib
###############################################################################
install_zlib() {
echo ""
echo "=========================================="
echo "Installing zlib ${ZLIB_VERSION}"
echo "=========================================="
download_and_extract "${ZLIB_URL}"
cd "${SRC_DIR}/zlib-${ZLIB_VERSION}"
CC=fcc \
CFLAGS="-Nclang -O2 -fPIC" \
./configure --prefix="${INSTALL_DIR}" --static
make -j 4
make install
echo "✓ zlib installed"
}
###############################################################################
# HDF5
###############################################################################
install_hdf5() {
echo ""
echo "=========================================="
echo "Installing HDF5 ${HDF5_VERSION}"
echo "=========================================="
download_and_extract "${HDF5_URL}"
cd "${SRC_DIR}/hdf5-${HDF5_VERSION}"
echo "Configuring HDF5 (static libraries, parallel Fortran) ..."
CC=mpifcc \
FC=mpifrt \
CFLAGS="-Nclang -O2 -fPIC" \
FCFLAGS="-O2 -fPIC" \
./configure --prefix="${INSTALL_DIR}" \
--enable-fortran \
--enable-parallel \
--disable-shared \
--enable-static \
--enable-hl \
--with-zlib="${INSTALL_DIR}"
if [ $? -ne 0 ]; then
echo "✗ HDF5 configure failed. Last 100 lines of config.log:"
tail -100 config.log
exit 1
fi
echo "Building HDF5 (this may take 10-15 minutes) ..."
make -j 4 || { make clean && make -j 1; }
echo "Installing HDF5 ..."
make install
echo "✓ HDF5 installed"
ls -lh "${INSTALL_DIR}/lib/libhdf5"* | head -5
}
###############################################################################
# NetCDF-C
###############################################################################
install_netcdf_c() {
echo ""
echo "=========================================="
echo "Installing NetCDF-C ${NETCDF_C_VERSION}"
echo "=========================================="
download_and_extract "${NETCDF_C_URL}"
cd "${SRC_DIR}/netcdf-c-${NETCDF_C_VERSION}"
echo "Configuring NetCDF-C ..."
CC=mpifcc \
CFLAGS="-Nclang -O2 -fPIC" \
CPPFLAGS="-I${INSTALL_DIR}/include" \
LDFLAGS="-L${INSTALL_DIR}/lib" \
LIBS="-lhdf5_hl -lhdf5 -lz -lm" \
./configure --prefix="${INSTALL_DIR}" \
--enable-netcdf-4 \
--disable-shared \
--enable-static \
--disable-dap \
--disable-byterange \
--disable-libxml2
if [ $? -ne 0 ]; then
echo "✗ NetCDF-C configure failed. Last 100 lines of config.log:"
tail -100 config.log
exit 1
fi
echo "Building NetCDF-C ..."
make -j 4
echo "Installing NetCDF-C ..."
make install
echo "✓ NetCDF-C installed"
if [ -f "${INSTALL_DIR}/bin/nc-config" ]; then
echo "nc-config --version: $("${INSTALL_DIR}/bin/nc-config" --version)"
echo "nc-config --libs: $("${INSTALL_DIR}/bin/nc-config" --libs)"
fi
}
###############################################################################
# NetCDF-Fortran
###############################################################################
install_netcdf_fortran() {
echo ""
echo "=========================================="
echo "Installing NetCDF-Fortran ${NETCDF_FORTRAN_VERSION}"
echo "=========================================="
download_and_extract "${NETCDF_FORTRAN_URL}"
cd "${SRC_DIR}/netcdf-fortran-${NETCDF_FORTRAN_VERSION}"
export NCDIR="${INSTALL_DIR}"
if [ -f "${INSTALL_DIR}/bin/nc-config" ]; then
NC_LIBS=$(${INSTALL_DIR}/bin/nc-config --libs)
echo "Using nc-config --libs: ${NC_LIBS}"
else
NC_LIBS="-lnetcdf -lhdf5_hl -lhdf5 -lz -lm"
echo "nc-config not available; using default LIBS."
fi
CC=mpifcc \
FC=mpifrt \
F77=mpifrt \
CFLAGS="-Nclang -O2 -fPIC" \
FCFLAGS="-O2 -fPIC" \
FFLAGS="-O2 -fPIC" \
CPPFLAGS="-I${INSTALL_DIR}/include" \
LDFLAGS="-L${INSTALL_DIR}/lib" \
LIBS="${NC_LIBS}" \
./configure --prefix="${INSTALL_DIR}" \
--disable-shared \
--enable-static
if [ $? -ne 0 ]; then
echo "✗ NetCDF-Fortran configure failed. Last 100 lines of config.log:"
tail -100 config.log
exit 1
fi
echo "Building NetCDF-Fortran ..."
make -j 4
echo "Installing NetCDF-Fortran ..."
make install
echo "✓ NetCDF-Fortran installed"
}
###############################################################################
# Write environment file sourced by get_siesta_fj.sh
###############################################################################
create_env_file() {
echo ""
echo "Writing environment file ..."
ENV_FILE="${WORK_DIR}/netcdf_env.sh"
# Use a temporary variable so the heredoc expands MY_* at write time,
# but keeps NETCDF_DIR and FUJITSU_DIR as literals for later sourcing.
cat > "${ENV_FILE}" << ENVEOF
#!/bin/bash
# netcdf_env.sh – sourced by get_siesta_fj.sh to expose NetCDF paths.
# Generated by install_netcdf_fj.sh on $(date).
# Disable HugePages warnings
export XOSOPTION="off"
export XOS_MMM_L_HPAGE_TYPE="none"
export NETCDF_DIR="${INSTALL_DIR}"
export FUJITSU_DIR="/opt/FJSVxtclanga/tcsds-1.2.42"
export PATH="\${FUJITSU_DIR}/bin:\${NETCDF_DIR}/bin:\${PATH}"
export LD_LIBRARY_PATH="\${NETCDF_DIR}/lib:\${FUJITSU_DIR}/lib64:\${LD_LIBRARY_PATH:-}"
export NETCDF_INC="-I\${NETCDF_DIR}/include"
export NETCDF_LIB="-L\${NETCDF_DIR}/lib -lnetcdff -lnetcdf -lhdf5_hl -lhdf5 -lz -lm"
echo "NetCDF environment configured."
echo " NETCDF_DIR : \${NETCDF_DIR}"
ENVEOF
chmod +x "${ENV_FILE}"
echo "✓ Environment file written: ${ENV_FILE}"
}
###############################################################################
# Verify critical libraries
###############################################################################
verify_installation() {
echo ""
echo "=========================================="
echo "Verifying installation"
echo "=========================================="
if [ -f "${INSTALL_DIR}/bin/nc-config" ]; then
echo "nc-config --version: $("${INSTALL_DIR}/bin/nc-config" --version)"
echo "nc-config --libs: $("${INSTALL_DIR}/bin/nc-config" --libs)"
fi
if [ -f "${INSTALL_DIR}/bin/nf-config" ]; then
echo "nf-config --version: $("${INSTALL_DIR}/bin/nf-config" --version)"
echo "nf-config --flibs: $("${INSTALL_DIR}/bin/nf-config" --flibs)"
fi
echo ""
echo "Installed libraries:"
ls -lh "${INSTALL_DIR}/lib/"*.a 2>/dev/null | grep -E "libz|libhdf5|libnetcdf"
echo ""
CRITICAL_FILES=(
"${INSTALL_DIR}/lib/libz.a"
"${INSTALL_DIR}/lib/libhdf5.a"
"${INSTALL_DIR}/lib/libhdf5_hl.a"
"${INSTALL_DIR}/lib/libhdf5_fortran.a"
"${INSTALL_DIR}/lib/libnetcdf.a"
"${INSTALL_DIR}/lib/libnetcdff.a"
)
ALL_OK=true
for f in "${CRITICAL_FILES[@]}"; do
if [ -f "$f" ]; then
echo " ✓ $(basename "$f")"
else
echo " ✗ Missing: $(basename "$f")"
ALL_OK=false
fi
done
if [ "${ALL_OK}" = true ]; then
echo ""
echo "✓ All critical libraries present."
fi
}
###############################################################################
# Main
###############################################################################
main() {
echo "Start: $(date)"
echo ""
install_zlib
install_hdf5
install_netcdf_c
install_netcdf_fortran
create_env_file
verify_installation
echo ""
echo "=========================================="
echo "✓ Installation complete"
echo "=========================================="
echo ""
echo "Elapsed: ${SECONDS} seconds"
echo ""
echo "To use: source ${WORK_DIR}/netcdf_env.sh"
}
LOG_FILE="${WORK_DIR}/install_log_$(date +%Y%m%d_%H%M%S).txt"
mkdir -p "${WORK_DIR}"
main 2>&1 | tee "${LOG_FILE}"
Compilation Script
The get_siesta_fj.sh script automates the full process of downloading,
extracting, patching, configuring, and compiling SIESTA on Fugaku using the
native Fujitsu compiler suite.
Basic usage:
./get_siesta_fj.sh # default version (SIESTA 5.4.2)
./get_siesta_fj.sh 5.4.1 # different SIESTA version
./get_siesta_fj.sh -c # clean extracted directory before starting
./get_siesta_fj.sh -r # re-download tarball if missing and re-extract
./get_siesta_fj.sh -l /path/to/local/repo # use a local source directory
What the script does:
Loads the Spack and NetCDF environments by sourcing the Spack setup script and the NetCDF environment file produced by
install_netcdf_fj.sh.Downloads the SIESTA source tarball from the GitLab release page if not already present. It falls back from
curltowgetif needed.Extracts the tarball and prepares two build directories inside the source tree:
_build_fjfor intermediate build artifacts and_siesta_bin_fjfor the final installed binaries.Loads the software environment by sourcing Spack and loading the required packages: Fujitsu SSL2 (
/fomls7l), netlib-ScaLAPACK (/ldigwm3), Python 3.13.5 (/qhm66vh), CMake (/hn27egk), py-pip (/ptmidr7), Flex (/ei25gqb), FFTW (/latufg2), Bison (/5hspcpy), libxc (/2nmda3o), and py-ruamel-yaml (/h5qnbwj).Applies source patches (PATCH 1–6) to resolve Fujitsu compiler incompatibilities in the following files:
Src/m_ts_voltage.F90— name collision between theparallelmodule and a local entity (PATCH 1)Src/flook_siesta.F90,Src/matel_table.F90,Src/m_elsi_interface.F90,Src/m_new_dm.F90,Src/m_w90_wrapper.F90,Src/Orphans/new_dm.F— analogousparallelmodule collisions in nested scopes (PATCH 2)Src/spinorbit.f— special-case scope treatment for the same collision pattern (PATCH 2b)Src/m_new_dm.F90— case-sensitivity correction fornodevsNodeafter the rename (PATCH 2c)Pseudo/vnl-operator/psop.f90— commented-out assignments between incompatible derived types (PATCH 3)Src/siesta_init.F— narroweduse netcdf_ncdfto avoid theparallelmember variable collision (PATCH 4)Util/QMMM-driver/Src/mm_assign.f90— initialisation of anintent(out)variable that may be unset on some paths (PATCH 5)Src/amn.F90— dissolution of aBLOCK … END BLOCKconstruct unsupported byfrt 4.12.1(PATCH 6)
Each patch is verified after application; the script exits immediately if any check fails.
Configures SIESTA with CMake, using the Fujitsu compilers (
frt,fcc,FCC) and MPI wrappers (mpifrt,mpifcc,mpiFCC). Explicit paths are set for Fujitsu MPI headers and libraries under/opt/FJSVxtclanga/.common/MECA032/, and the build links against Fujitsu SSL2 (for BLAS/LAPACK), netlib-ScaLAPACK, and the previously installed NetCDF libraries. Notable build options include:OpenMP enabled (
-DSIESTA_WITH_OPENMP=ON)MPI enabled via Fujitsu MPI libraries
NetCDF enabled (
-DSIESTA_WITH_NETCDF=ON)ELSI, ELPA, DFTD3, Flook, and LibXC disabled
Compiler flags
-Kopenmp -O2 -Kident_mpifor all languages
Note
SIESTA 5.4.2 does not compile with the
legacyMPI interface. The script automatically sets-DSIESTA_WITH_MPI_INTERFACES=nonefor version 5.4.2 andlegacyfor all other versions.Builds and installs using
cmake --build(with 8 parallel jobs) andcmake --install, placing the final binaries in_siesta_bin_fj. Build output is saved tobuild_log.txt. If the build fails, the script prints a summary of all Fujitsu compiler error codes found in the log and exits with a non-zero status.
You can download get_siesta_fj.sh directly.
Show full script: get_siesta_fj.sh
#!/usr/bin/env bash
#
# get_siesta_fj.sh – download, patch, and compile SIESTA with Fujitsu compilers
#
# Requires the following environment variables (set in ~/.bashrc or exported
# before calling this script):
# MY_USER – your Fugaku username
# MY_PROJECT – your project code
# MY_VOLUME – your storage volume
#
# Usage examples
# ./get_siesta_fj.sh # default version (5.4.2)
# ./get_siesta_fj.sh 5.4.1 # different version
# ./get_siesta_fj.sh -c # delete extracted dir if it exists
# ./get_siesta_fj.sh -r # refresh (re-download if tarball missing)
# ./get_siesta_fj.sh -l /path/to/repo # use a local source directory
#
#set -euo pipefail
###############################################################################
# Helper: display usage
###############################################################################
usage() {
cat <<EOF
Usage: $0 [version] [-c|--clean] [-r|--refresh] [-l|--local <path>]
version SIESTA version to download (default: 5.4.2)
-c, --clean
Delete the extracted directory if it already exists.
-r, --refresh
If the directory exists *and* the tarball does not, download the
tarball, delete the directory, and extract again.
-l, --local <path>
Use a local directory instead of downloading the tarball.
Only one of -c or -r can be supplied at the same time.
EOF
exit 1
}
###############################################################################
# Parse command-line arguments
###############################################################################
VERSION="5.4.2"
CLEAN=false
REFRESH=false
LOCAL_PATH=""
while [[ $# -gt 0 ]]; do
case "$1" in
-c|--clean)
CLEAN=true
;;
-r|--refresh)
REFRESH=true
;;
-l|--local)
LOCAL_PATH="$2"
shift
;;
-h|--help)
usage
;;
-*)
echo "Unknown option: $1" >&2
usage
;;
*)
VERSION="$1"
;;
esac
shift
done
# Reject simultaneous -c and -r
if $CLEAN && $REFRESH; then
echo "Error: -c/--clean and -r/--refresh are mutually exclusive." >&2
exit 1
fi
###############################################################################
# Check required environment variables
###############################################################################
for var in MY_USER MY_PROJECT MY_VOLUME; do
if [[ -z "${!var:-}" ]]; then
echo "Error: environment variable ${var} is not set." >&2
echo "Export it or add it to your ~/.bashrc before running this script." >&2
exit 1
fi
done
###############################################################################
# Variables derived from version and environment
###############################################################################
PKG="siesta-${VERSION}"
TARBALL="${PKG}.tar.gz"
URL="https://gitlab.com/siesta-project/siesta/-/releases/${VERSION}/downloads/${TARBALL}"
SPACK_SETUP="/${MY_VOLUME}/mdt1/data/${MY_PROJECT}/${MY_USER}/tmp/spack/share/spack/setup-env.sh"
NETCDF_ENV="/${MY_VOLUME}/mdt1/data/${MY_PROJECT}/${MY_USER}/netcdf_fujitsu/netcdf_env.sh"
###############################################################################
# Helper: download tarball if absent
###############################################################################
download_tarball() {
echo "Downloading ${TARBALL} ..."
if command -v curl &>/dev/null; then
curl -L -o "${TARBALL}" "${URL}"
elif command -v wget &>/dev/null; then
wget -O "${TARBALL}" "${URL}"
else
echo "Error: neither curl nor wget is available." >&2
exit 1
fi
}
###############################################################################
# 1-3. Obtain source code
###############################################################################
if [[ -n "${LOCAL_PATH}" ]]; then
if [[ ! -d "${LOCAL_PATH}" ]]; then
echo "Error: local directory '${LOCAL_PATH}' does not exist." >&2
exit 1
fi
echo "Using local directory: ${LOCAL_PATH}"
PKG="${LOCAL_PATH}"
else
if $CLEAN && [[ -d "${PKG}" ]]; then
echo "Removing existing directory ${PKG} (requested with --clean) ..."
rm -rf "${PKG}"
fi
if $REFRESH && [[ -d "${PKG}" ]] && [[ ! -f "${TARBALL}" ]]; then
echo "Refresh requested and tarball missing."
download_tarball
echo "Removing existing directory ${PKG} ..."
rm -rf "${PKG}"
fi
if [[ ! -f "${TARBALL}" ]]; then
download_tarball
else
echo "Tarball ${TARBALL} already exists. Skipping download."
fi
if [[ ! -d "${PKG}" ]]; then
echo "Extracting ${TARBALL} ..."
tar -xzf "${TARBALL}"
else
echo "Directory ${PKG} already exists. Re-extracting ..."
rm -rf "${PKG}"
tar -xzf "${TARBALL}"
fi
fi
###############################################################################
# 4. Create the required build directories
###############################################################################
cd "${PKG}"
build_="_build_fj"
bin_="_siesta_bin_fj"
mkdir -p "${build_}" "${bin_}"
echo "Directories ${build_} and ${bin_} are ready in $(pwd)."
###############################################################################
# 5. Load Spack environment
###############################################################################
echo "Loading Spack environment ..."
source "${SPACK_SETUP}"
echo "Spack environment loaded."
###############################################################################
# 6. Load Spack packages
###############################################################################
echo "Loading Spack packages ..."
spack load /fomls7l # fujitsu-ssl2@head
spack load /ldigwm3 # netlib-scalapack@2.2.2
spack load /qhm66vh # python@3.13.5 %fj@4.12.0
spack load /hn27egk # cmake@3.31.8
spack load /ptmidr7 # py-pip@25.1.1
spack load /ei25gqb # flex@2.6.4
spack load /latufg2 # fftw@3.3.10
spack load /5hspcpy # bison@3.8.2
#Those were local installation
spack load /2nmda3o # libxc@6.2.2
spack load /h5qnbwj # py-ruamel-yaml@0.17.32 ^python@3.13.5 /qhm66vh %fj@4.12.0
echo "Spack packages loaded."
ml list
###############################################################################
# 7. Load NetCDF environment
###############################################################################
echo "Loading NetCDF environment ..."
source "${NETCDF_ENV}"
echo "NetCDF environment loaded."
###############################################################################
# 8. Resolve additional paths
###############################################################################
export LD_LIBRARY_PATH=/lib64:${LD_LIBRARY_PATH}
export FLEX_PATH=$(spack location -i flex%fj@4.12.0)
export BISON_PATH=$(spack location -i bison%fj@4.12.0)
export PATH="${FLEX_PATH}/bin:${BISON_PATH}/bin:${PATH}"
export FUJITSU_SSL2_PATH="/opt/FJSVxtclanga/tcsds-ssl2-latest"
export SCALAPACK_PATH=$(spack location -i netlib-scalapack%fj@4.12.0)
echo "Paths resolved."
###############################################################################
# 9. Set MPI interface flag (5.4.2 does not support legacy interface)
###############################################################################
if [ "${VERSION}" == "5.4.2" ]; then
interface="none"
else
interface="legacy"
fi
###############################################################################
# 10. Apply source patches for Fujitsu compiler compatibility
#
# frt 4.12.1 enforces the Fortran standard more strictly than gfortran.
# The patches below fix constructs that gfortran accepts silently but
# frt rejects as errors:
# - jwd1740i: module name collides with a locally imported entity
# - jwd2391i: assignment between derived types without a defined operator
# - jwd2043i: intent(out) variable may be unassigned on some paths
# - jwd1130i: USE inside BLOCK...END BLOCK is not supported
###############################################################################
echo "Applying frt 4.12.1 compatibility patches ..."
# ============================================================
# PATCH 1: m_ts_voltage.F90
# jwd1740i: 'parallel' is both a module name and a local entity
# in ts_ncdf_voltage_assert. Rename IONode with an explicit alias
# and pass ts_IONode as an argument to the inner subroutine.
# ============================================================
sed -i 's/ use parallel, only : IONode$/ use parallel, only : ts_IONode => IONode/' \
Src/m_ts_voltage.F90
sed -i 's/ use parallel, only : IONode$/ use parallel, only : ts_IONode => IONode/' \
Src/m_ts_voltage.F90
sed -i 's/if ( IONode ) then/if ( ts_IONode ) then/g' Src/m_ts_voltage.F90
sed -i 's/if ( IONode .and./if ( ts_IONode .and./g' Src/m_ts_voltage.F90
sed -i 's/else if ( IONode .and./else if ( ts_IONode .and./g' Src/m_ts_voltage.F90
sed -i 's/if ( .not. IONode ) return/if ( .not. ts_IONode ) return/g' Src/m_ts_voltage.F90
sed -i 's/if ( IONode ) &/if ( ts_IONode ) \&/g' Src/m_ts_voltage.F90
sed -i 's/call ts_ncdf_voltage_assert(Hartree_fname,cell,nmesh)/call ts_ncdf_voltage_assert(Hartree_fname,cell,nmesh,ts_IONode)/' \
Src/m_ts_voltage.F90
sed -i 's/subroutine ts_ncdf_voltage_assert(fname, cell, nmesh)/subroutine ts_ncdf_voltage_assert(fname, cell, nmesh, ts_IONode)/' \
Src/m_ts_voltage.F90
awk 'BEGIN{c=0} /use parallel/{c++; if(c==3)next} 1' \
Src/m_ts_voltage.F90 > /tmp/m_ts_voltage.F90 && \
mv /tmp/m_ts_voltage.F90 Src/m_ts_voltage.F90
grep -q "logical, intent(in) :: ts_IONode" Src/m_ts_voltage.F90 || \
sed -i 's/ integer, intent(in) :: nmesh(3)$/ integer, intent(in) :: nmesh(3)\n logical, intent(in) :: ts_IONode/' \
Src/m_ts_voltage.F90
echo " PATCH 1 applied: Src/m_ts_voltage.F90"
# ============================================================
# PATCH 2: mass rename of imported entities in nested scopes
# jwd1740i: same collision pattern in 6 additional files.
# Python handles inline comments correctly during the rename.
# Note: spinorbit.f receives special treatment in PATCH 2b.
# ============================================================
python3 << 'PYEOF'
import re
def rename_entities_in_use(line):
m = re.match(r'(\s*use\s+parallel\s*,\s*only\s*:\s*)(.*)', line, re.IGNORECASE)
if not m:
return line, {}
prefix = m.group(1)
rest = m.group(2)
comment_match = re.search(r'\s*!.*$', rest)
comment = comment_match.group(0) if comment_match else ''
entities_str = rest[:comment_match.start()].rstrip() if comment_match else rest.rstrip()
has_continuation = entities_str.endswith('&')
if has_continuation:
entities_str = entities_str[:-1].rstrip()
entities = [e.strip() for e in entities_str.split(',') if e.strip()]
renamed = {}
new_entities = []
for e in entities:
if '=>' in e:
new_entities.append(e)
else:
new_name = f'par_{e}'
new_entities.append(f'{new_name} => {e}')
renamed[e] = new_name
new_line = prefix + ', '.join(new_entities)
if has_continuation:
new_line += ' &'
new_line += comment + '\n'
return new_line, renamed
problems = {
"Src/flook_siesta.F90": [964],
"Src/matel_table.F90": [666, 739],
"Src/m_elsi_interface.F90": [267, 413, 886, 1491],
"Src/m_new_dm.F90": [1369, 1686, 1812, 1905, 1998],
"Src/m_w90_wrapper.F90": [212, 1730],
"Src/Orphans/new_dm.F": [458],
}
for fname, problem_lines in problems.items():
try:
with open(fname, 'r') as fh:
lines = fh.readlines()
except FileNotFoundError:
print(f" WARNING: {fname} not found, skipping...")
continue
all_renamed = {}
for pline in problem_lines:
idx = pline - 1
if idx >= len(lines):
continue
new_line, renamed = rename_entities_in_use(lines[idx])
if renamed:
lines[idx] = new_line
all_renamed.update(renamed)
if not all_renamed:
continue
for old, new in all_renamed.items():
pattern = re.compile(r'\b' + re.escape(old) + r'\b')
for i, line in enumerate(lines):
if i+1 in problem_lines:
continue
stripped = line.lstrip()
if stripped.startswith('!') or stripped.startswith('#'):
continue
new_line = pattern.sub(new, line)
if new_line != line:
lines[i] = new_line
with open(fname, 'w') as fh:
fh.writelines(lines)
print(f" PATCH 2 applied: {fname}")
PYEOF
# ============================================================
# PATCH 2b: spinorbit.f – special-case scope handling
# jwd1740i: inner subroutine uses 'Node' which already exists
# at module level. Manual rename only in the inner scope to
# avoid clobbering the module-level references.
# ============================================================
sed -i 's/ use parallel, only: par_Node, Nodes/ use parallel, only: Node, Nodes/' \
Src/spinorbit.f
sed -i 's/ use parallel, only: Node$/ use parallel, only: par_Node => Node/' \
Src/spinorbit.f
sed -i 's/if (par_Node .eq. 0) then/if (Node .eq. 0) then/g' \
Src/spinorbit.f
sed -i 's/call LocalToGlobalOrb(io_l,par_Node,Nodes,io_u)/call LocalToGlobalOrb(io_l,Node,Nodes,io_u)/g' \
Src/spinorbit.f
echo " PATCH 2b applied: Src/spinorbit.f"
# ============================================================
# PATCH 2c: m_new_dm.F90 – case correction after mass rename
# The mass rename changed Node->par_Node but the source also
# uses 'node' (lowercase) which frt treats as a distinct entity.
# ============================================================
sed -i 's/if (node==0) print \*, " # of linearly independent vectors: ", m/if (par_Node==0) print *, " # of linearly independent vectors: ", m/' \
Src/m_new_dm.F90
sed -i 's/if (node==0) print \*, " Rank of DIIS matrix: ", m/if (par_Node==0) print *, " Rank of DIIS matrix: ", m/' \
Src/m_new_dm.F90
sed -i 's/if (node==0) print \*, " Estimated Rank of xi\*xj matrix: ", m/if (par_Node==0) print *, " Estimated Rank of xi*xj matrix: ", m/' \
Src/m_new_dm.F90
sed -i 's/if (node==0) then/if (par_Node==0) then/g' \
Src/m_new_dm.F90
echo " PATCH 2c applied: Src/m_new_dm.F90"
# ============================================================
# PATCH 3: psop.f90
# jwd2391i: assignment between ps_annotation_t (alias of
# assoc_list_t) without a defined assignment operator.
# These are metadata annotations only; commenting them out
# does not affect physical calculations.
# ============================================================
sed -i 's/^ gannot = grid_annotation/ !gannot = grid_annotation ! patched: frt 4.12.1/' \
Pseudo/vnl-operator/psop.f90
sed -i 's/^ ps%local%annotation = annotation/ !ps%local%annotation = annotation ! patched: frt 4.12.1/' \
Pseudo/vnl-operator/psop.f90
sed -i 's/^ nlp%annotation = annotation/ !nlp%annotation = annotation ! patched: frt 4.12.1/' \
Pseudo/vnl-operator/psop.f90
echo " PATCH 3 applied: Pseudo/vnl-operator/psop.f90"
# ============================================================
# PATCH 4: siesta_init.F
# jwd1740i: netcdf_ncdf has a member variable named 'parallel'
# which collides with the 'parallel' module imported on lines
# 55-57. Narrow the USE to import only what is actually needed.
# ============================================================
sed -i 's/ use netcdf_ncdf$/ use netcdf_ncdf, only: ncdf_IONode/' \
Src/siesta_init.F
echo " PATCH 4 applied: Src/siesta_init.F"
# ============================================================
# PATCH 5: mm_assign.f90
# jwd2043i: intent(out) variable atxres may not be assigned on
# all execution paths in subroutine paramats.
# Initialise to 0 at the start of the subroutine.
# ============================================================
python3 << 'PYEOF'
fname = "Util/QMMM-driver/Src/mm_assign.f90"
with open(fname, 'r') as fh:
lines = fh.readlines()
target = "type(temp_residue), allocatable :: ff_residues(:)"
for i, line in enumerate(lines):
if target in line:
insert_idx = i + 2
new_line = " atxres = 0 ! patched: frt 4.12.1 intent(out) must be assigned\n"
if new_line not in lines[insert_idx]:
lines.insert(insert_idx, new_line)
break
with open(fname, 'w') as fh:
fh.writelines(lines)
print(" PATCH 5 applied: Util/QMMM-driver/Src/mm_assign.f90")
PYEOF
# ============================================================
# PATCH 6: amn.F90
# jwd1130i: USE inside BLOCK...END BLOCK is not supported by
# frt 4.12.1. Dissolve the block, move USE statements and
# declarations to subroutine scope, and rename the local
# variable orb_gindex -> blk_orb_gindex to avoid a collision
# with the orb_gindex function imported from atmfuncs.
# ============================================================
python3 << 'PYEOF'
fname = "Src/amn.F90"
with open(fname, 'r') as fh:
content = fh.read()
old_block = """ block
use radial, only: radial_rescale_radfunc, rad_func
use m_matel_registry, only: peek_at_registered_radfunc
use m_matel_registry, only: register_in_rf_pool
integer :: orb_gindex, l, m
type(rad_func), pointer :: rfunc, func_new => null()
orb_gindex = tf%iorb_gindex
call peek_at_registered_radfunc(orb_gindex,rfunc,l,m)
if ( modulo(m,2) == 1 ) then
allocate(func_new)
call radial_rescale_radfunc(rfunc,func_new,scale=-1.0_dp)
call register_in_rf_pool(func_new, l, m, "wann_twin_orb", [iproj], gindex)
else
call register_in_rf_pool(rfunc, l, m, "wann_orb", [iproj], gindex)
endif
end block"""
new_block = """ blk_orb_gindex = tf%iorb_gindex
call peek_at_registered_radfunc(blk_orb_gindex,rfunc,l,m)
if ( modulo(m,2) == 1 ) then
allocate(func_new)
call radial_rescale_radfunc(rfunc,func_new,scale=-1.0_dp)
call register_in_rf_pool(func_new, l, m, "wann_twin_orb", [iproj], gindex)
else
call register_in_rf_pool(rfunc, l, m, "wann_orb", [iproj], gindex)
endif"""
if old_block in content:
content = content.replace(old_block, new_block)
print(" Step 1 OK: BLOCK...END BLOCK dissolved")
else:
print(" ERROR step 1: block not found")
old_use = " use mpi_siesta"
new_use = """ use radial, only: radial_rescale_radfunc, rad_func ! patched: frt 4.12.1
use m_matel_registry, only: peek_at_registered_radfunc ! patched: frt 4.12.1
use m_matel_registry, only: register_in_rf_pool ! patched: frt 4.12.1
use mpi_siesta"""
if old_use in content:
content = content.replace(old_use, new_use, 1)
print(" Step 2 OK: USE statements added at subroutine scope")
else:
print(" ERROR step 2: 'use mpi_siesta' not found")
old_decl = " integer :: gindex ! Global index of the trial projector function"
new_decl = """ integer :: blk_orb_gindex, l, m ! patched: frt 4.12.1 block not supported
type(rad_func), pointer :: rfunc => null(), func_new => null() ! patched: frt 4.12.1
integer :: gindex ! Global index of the trial projector function"""
if old_decl in content:
content = content.replace(old_decl, new_decl, 1)
print(" Step 3 OK: declarations added at subroutine scope")
else:
print(" ERROR step 3: declaration not found")
with open(fname, 'w') as fh:
fh.write(content)
print(" PATCH 6 applied: Src/amn.F90")
PYEOF
###############################################################################
# 11. Verify all patches
###############################################################################
echo ""
echo "Verifying patches ..."
errors=0
count=$(grep -c "use parallel" Src/m_ts_voltage.F90)
if [ "$count" -eq 2 ]; then
echo " ✓ Src/m_ts_voltage.F90"
else
echo " ✗ Src/m_ts_voltage.F90 – 'use parallel' count: $count (expected: 2)"
errors=$((errors+1))
fi
for f in Src/flook_siesta.F90 Src/matel_table.F90 Src/m_elsi_interface.F90 \
Src/m_new_dm.F90 Src/m_w90_wrapper.F90 Src/Orphans/new_dm.F; do
count=$(grep -c "par_" "$f" 2>/dev/null)
if [ "$count" -gt 0 ]; then
echo " ✓ $f"
else
echo " ✗ $f – no par_ references found"
errors=$((errors+1))
fi
done
if grep -q "use parallel, only: Node, Nodes" Src/spinorbit.f && \
grep -q "par_Node => Node" Src/spinorbit.f; then
echo " ✓ Src/spinorbit.f"
else
echo " ✗ Src/spinorbit.f"
errors=$((errors+1))
fi
if ! grep -q "node==0" Src/m_new_dm.F90 && \
grep -q "par_Node==0" Src/m_new_dm.F90; then
echo " ✓ Src/m_new_dm.F90 (PATCH 2c)"
else
echo " ✗ Src/m_new_dm.F90 (PATCH 2c)"
errors=$((errors+1))
fi
count=$(grep -c "patched: frt 4.12.1" Pseudo/vnl-operator/psop.f90)
if [ "$count" -eq 4 ]; then
echo " ✓ Pseudo/vnl-operator/psop.f90"
else
echo " ✗ Pseudo/vnl-operator/psop.f90 – patched count: $count (expected: 4)"
errors=$((errors+1))
fi
if grep -q "use netcdf_ncdf, only: ncdf_IONode" Src/siesta_init.F; then
echo " ✓ Src/siesta_init.F"
else
echo " ✗ Src/siesta_init.F"
errors=$((errors+1))
fi
count=$(grep -c "patched: frt 4.12.1" Util/QMMM-driver/Src/mm_assign.f90)
if [ "$count" -eq 1 ]; then
echo " ✓ Util/QMMM-driver/Src/mm_assign.f90"
else
echo " ✗ Util/QMMM-driver/Src/mm_assign.f90 – patched count: $count (expected: 1)"
errors=$((errors+1))
fi
if grep -q "use radial, only: radial_rescale_radfunc, rad_func ! patched" Src/amn.F90 && \
! grep -q "end block" Src/amn.F90 && \
grep -q "blk_orb_gindex, l, m ! patched" Src/amn.F90; then
echo " ✓ Src/amn.F90"
else
echo " ✗ Src/amn.F90"
errors=$((errors+1))
fi
if [ $errors -eq 0 ]; then
echo ""
echo "All patches applied successfully."
else
echo ""
echo "ERROR: $errors patch(es) failed. Aborting."
exit 1
fi
###############################################################################
# 12. Configure SIESTA with CMake
###############################################################################
echo ""
echo "Starting CMake configuration ..."
FC=frt CC=fcc CXX=FCC cmake -S . -B "${build_}" \
-DCMAKE_Fortran_COMPILER=frt \
-DCMAKE_C_COMPILER=fcc \
-DCMAKE_CXX_COMPILER=FCC \
-DCMAKE_INSTALL_PREFIX="${bin_}" \
-DCMAKE_Fortran_FLAGS="-Kopenmp -O2 -Kident_mpi -w -X9 -I/opt/FJSVxtclanga/.common/MECA032/include/mpi/fujitsu ${NETCDF_INC}" \
-DCMAKE_C_FLAGS="-Kopenmp -O2 -Kident_mpi -Nclang -I/opt/FJSVxtclanga/.common/MECA032/include/mpi/fujitsu ${NETCDF_INC}" \
-DCMAKE_CXX_FLAGS="-Kopenmp -O2 -Kident_mpi -I/opt/FJSVxtclanga/.common/MECA032/include/mpi/fujitsu -DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX -DMPI_NO_CPPBIND" \
-DMPI_Fortran_COMPILER=mpifrt \
-DMPI_C_COMPILER=mpifcc \
-DMPI_CXX_COMPILER=mpiFCC \
-DMPI_Fortran_LIBRARIES="/opt/FJSVxtclanga/.common/MECA032/lib64/libmpi_usempif08.so;/opt/FJSVxtclanga/.common/MECA032/lib64/libmpi_mpifh.so;/opt/FJSVxtclanga/.common/MECA032/lib64/libmpi.so" \
-DMPI_C_LIBRARIES="/opt/FJSVxtclanga/.common/MECA032/lib64/libmpi.so" \
-DMPI_CXX_LIBRARIES="/opt/FJSVxtclanga/.common/MECA032/lib64/libmpi_cxx.so;/opt/FJSVxtclanga/.common/MECA032/lib64/libmpi.so" \
-DCMAKE_EXE_LINKER_FLAGS="-L/opt/FJSVxtclanga/.common/MECA032/lib64 -Wl,-rpath,/opt/FJSVxtclanga/.common/MECA032/lib64 -lfjstring_internal ${NETCDF_LIB}" \
-DMPIEXEC_EXECUTABLE="/opt/FJSVxtclanga/tcsds-1.2.42/bin/mpiexec" \
-DMPIEXEC_MAX_NUMPROCS=4 \
-DBLAS_LIBRARY="${FUJITSU_SSL2_PATH}/lib64/libfjlapack.so" \
-DLAPACK_LIBRARY="${FUJITSU_SSL2_PATH}/lib64/libfjlapack.so" \
-DSCALAPACK_LIBRARY="${SCALAPACK_PATH}/lib/libscalapack.so" \
-DFLEX_EXECUTABLE="${FLEX_PATH}/bin/flex" \
-DBISON_EXECUTABLE="${BISON_PATH}/bin/bison" \
-DSIESTA_WITH_LIBXC=OFF \
-DSIESTA_WITH_NETCDF=ON \
-DSIESTA_WITH_OPENMP=ON \
-DSIESTA_WITH_MPI_INTERFACES="${interface}" \
-DCMAKE_BUILD_TYPE=Release \
-DSIESTA_WITH_ELPA=OFF \
-DSIESTA_WITH_ELSI=OFF \
-DSIESTA_WITH_DFTD3=OFF \
-DSIESTA_WITH_FLOOK=OFF
###############################################################################
# 13. Build and install
###############################################################################
if [ $? -eq 0 ]; then
echo ""
echo "CMake configuration successful. Building ..."
cmake --build "${build_}" -j 8 2>&1 | tee build_log.txt
build_status=${PIPESTATUS[0]}
if [ ${build_status} -eq 0 ]; then
echo ""
echo "Build successful. Installing ..."
cmake --install "${build_}"
else
echo ""
echo "ERROR: Build failed (exit code: ${build_status})"
echo ""
echo "========================================"
echo "Source files with Fujitsu errors:"
echo "========================================"
grep "jwd1740i" build_log.txt | \
grep -oP '"[^"]+\.f90|[^"]+\.F90|[^"]+\.F|[^"]+\.f"' | \
sort -u
echo ""
echo "All compiler errors:"
echo "========================================"
grep -E "jwd[0-9]+i-s|Error [0-9]+" build_log.txt | \
grep -v "^gmake" | \
sort -u
echo "========================================"
echo "Full log: cat build_log.txt"
exit 1
fi
else
echo ""
echo "ERROR: CMake configuration failed."
exit 1
fi