WPS¶
Build WPS¶
Required libraries¶
WPS (specifically ungrib.exe) uses three external libraries: JasPer, zlib, and PNG (libpng). For most users using NetCDF for file I/O, the NetCDF libraries are also required; while building WPS, the environment variable NETCDF needs to be set to the path of the NetCDF installation. We can use the environment variable $NETCDF_DIR set by the cray-netcdf module:
export NETCDF=$NETCDF_DIR
On Perlmutter, zlib and libpng are available in /usr (/usr/include and /usr/lib64), so the configure tool can find them automatically without needing Lmod modules. JasPer is not available in a standard system path nor as a default module, so a user needs to install it from the downloaded source code (example script below).
Note
Under the current Perlmutter GNU environment (gcc-native/14 in cpe/26.03), GCC 14 enforces stricter C99 checks by default. When compiling legacy C code in jasper-1.900.1 and WPS, pass -Wno-error=implicit-function-declaration -Wno-error=incompatible-pointer-types -Wno-error=int-conversion (and -Wno-error=implicit-int in configure.wps) in CFLAGS, as shown in the example scripts below. Also note that available module versions change over time; the specific module versions shown in the example scripts below are for the Perlmutter software environment in October 2026.
Example build script for the JasPer external library¶
#!/bin/bash
set -e
set -o pipefail
#build the three libraries used by WPS's ungrib.exe
#the script is based on the direction here:
#http://www2.mmm.ucar.edu/wrf/OnLineTutorial/compilation_tutorial.php
#on Perlmutter, zlib and libpng are available in /usr (/usr/include and /usr/lib64),
#so configure should find them without needing Lmod modules.
#jasper can be compiled by this script, or
#one could use the one installed under the Spack module/environment
#%module load cpu
#%module load spack
#%spack load jasper
#(will be tested)
imach="pm" #system name, pm for perlmutter
inst_jasper=true #install JasPer (true) or not (false)
inst_zlib=false #install zlib (true) or not (false)
inst_libpng=false #install libpng (true) or not (false)
# WRF/WPS directories (user needs to change these paths)
export WRF_DIR="PATH_TO_YOUR_WRFcode_LOCATION"
export WPS_DIR="PATH_TO_YOUR_WPScode_LOCATION"
#Load the same modules used for WRF -----------------------------------------
#Note: module versions change with time; these specific versions are examples
#for the Perlmutter environment in October 2026
module load cpu/1.0
module load cpe/26.03
module load PrgEnv-gnu/8.7.0
module load gcc-native/14
module load cray-mpich/9.1.0
module load craype/2.7.36
module load cray-hdf5/1.14.3.9
module load cray-netcdf/4.9.2.3
module load cray-parallel-netcdf/1.12.3.21
#directory where the external libraries will be installed
export EXDIR="PATH_TO_YOUR_INSTALL_DIR"
mkdir -p ${EXDIR}
libcodedir="PATH_TO_YOUR_EXTERNAL_LIB_SRC_DIR" #where source code of external library is downloaded
#compiler wrappers fail when the configure script checks for cross-compilation
#so use the base compiler to build the external library
export CC=gcc
export CXX=g++
export FC=gfortran
export F77=gfortran
export FCFLAGS="-m64"
export FFLAGS="-m64"
# Relax GCC 14 default C99/pointer errors when compiling legacy jasper-1.900.1 / libpng-1.2.50 / zlib-1.2.7
export CFLAGS="-m64 -Wno-error=implicit-function-declaration -Wno-error=incompatible-pointer-types -Wno-error=int-conversion"
#grab include/library paths from the netcdf module's environment variable
export NETCDF=$NETCDF_DIR
export LDFLAGS="-L$EXDIR/grib2/lib"
export CPPFLAGS="-I$EXDIR/grib2/include"
export JASPERLIB="$EXDIR/grib2/lib"
export JASPERINC="$EXDIR/grib2/include"
#zlib (available in /usr on Perlmutter; build before libpng if inst_zlib=true)
if [ "$inst_zlib" = true ]; then
echo "installing zlib"
cd ${libcodedir}/zlib-1.2.7
if [ -f Makefile ]; then
make clean
fi
./configure --prefix=${EXDIR}/grib2
make
make install
cd ..
fi
#libpng (available in /usr on Perlmutter)
if [ "$inst_libpng" = true ]; then
echo "installing libpng"
cd ${libcodedir}/libpng-1.2.50
if [ -f Makefile ]; then
make clean
fi
./configure --prefix=${EXDIR}/grib2
make
make install
cd ..
fi
#JasPer
if [ "$inst_jasper" = true ]; then
echo "installing JasPer"
cd ${libcodedir}/jasper-1.900.1
if [ -f Makefile ]; then
make clean
fi
./configure --prefix=${EXDIR}/grib2
make
make install
cd ..
fi
Compile WPS¶
To build the three WPS programs: geogrid.exe, ungrib.exe, and metgrid.exe, we first run the configure script in the top WPS directory. configure collects system information and also asks a user to select a model configuration. For a standard use-case of running WPS on a login node, option #1 (in WPS v4.7.0) is appropriate for Perlmutter:
1. Linux x86_64, gfortran (serial)
After the system information and WPS configuration are saved in configure.wps, we use the compile script in the top WPS directory to compile the three WPS programs. The compile script has to be run while loading the same modules (libraries) as those used to build WRF, because WPS uses WRF's I/O libraries. See below for an example script for Perlmutter.
Note
If WRF was compiled with the dm+sm option, then we need to add a compiler flag related to the shared-memory library (-lgomp) to WRF_LIB in configure.wps (see this WRF forum post).
#!/bin/bash
set -e
set -o pipefail
#based on the direction here
#http://www2.mmm.ucar.edu/wrf/OnLineTutorial/compilation_tutorial.php
imach="pm" #system name, pm for perlmutter
config_wps=true #set true to run configure script
build_wps=true #set true to compile WPS
# set the top directories of the WRF and WPS source code
export WRF_DIR="PATH_TO_YOUR_WRFcode_LOCATION"
export WPS_DIR="PATH_TO_YOUR_WPScode_LOCATION"
#Modules --------------------------------------------------------------------
#Load the same modules used for WRF
#Note: module versions change with time; these specific versions are examples
#for the Perlmutter environment in October 2026
module load cpu/1.0
module load cpe/26.03
module load PrgEnv-gnu/8.7.0
module load gcc-native/14
module load cray-mpich/9.1.0
module load craype/2.7.36
module load cray-hdf5/1.14.3.9
module load cray-netcdf/4.9.2.3
module load cray-parallel-netcdf/1.12.3.21
##capture starting time for log file name
idate=$(date "+%Y-%m-%d-%H_%M")
echo $idate
#directory where the external libraries are installed
#only jasper needs to be installed on Perlmutter
export WRF_EXTERNAL_LIBS="PATH_TO_YOUR_INSTALL_DIR"
export FCFLAGS="-m64"
export FFLAGS="-m64"
#from the netcdf module
export NETCDF=$NETCDF_DIR
#jasper path to be used to set COMPRESSION_LIBS and COMPRESSION_INC
#environment variables, which are used by the configure script
#local installation
export JASPERLIB="$WRF_EXTERNAL_LIBS/grib2/lib"
export JASPERINC="$WRF_EXTERNAL_LIBS/grib2/include"
########### build WPS; requires WRF being built first to use the WRF I/O routines
if [ "$config_wps" = true ]; then
echo "Configuring WPS"
cd ${WPS_DIR}
pwd
./clean -a
./configure SCC=gcc SFC=gfortran #using base compilers for serial run
#other compilers are set equal to SCC and SFC in the configure script
#choose option 1 to run WPS on a login node as a serial executable
# 1. Linux x86_64, gfortran (serial)
#if using compute node with MPI, then
#./configure SCC=cc SFC=ftn
# 3. Linux x86_64, gfortran (dmpar)
#if WRF was compiled with the dm+sm option, then we
#need to add a compiler flag related to shared-memory library to "WRF_LIB" in configure.wps
#based on a WRF forum post
#https://forum.mmm.ucar.edu/threads/resolved-wrf-dm-sm-referencia-a-__kmpc_dispatch_next_4-sin-definir.927/
sed -i 's/lnetcdff/lnetcdff -lgomp/' configure.wps
# Replace mpif90/mpicc with Cray wrappers ftn/cc (used if dmpar option 3 is selected; no-op for serial option 1)
sed -i 's/mpif90/ftn/' configure.wps
sed -i 's/mpicc/cc/' configure.wps
# Relax GCC 14 default C99/pointer errors for legacy C routines in WPS
sed -i 's/^CFLAGS[[:space:]]*=/CFLAGS = -Wno-error=implicit-function-declaration -Wno-error=implicit-int -Wno-error=incompatible-pointer-types -Wno-error=int-conversion /' configure.wps
fi
if [ "$build_wps" = true ]; then
echo "Building WPS"
cd ${WPS_DIR}
pwd
#save the compile log in the WPS top directory
bldlog=compile_wps_${idate}_${imach}.log
echo "compile log file is ${bldlog}"
module list &> ${bldlog}
./compile &>> ${bldlog}
if [ -s "$WPS_DIR/geogrid/src/geogrid.exe" ] && \
[ -s "$WPS_DIR/ungrib/src/ungrib.exe" ] && \
[ -s "$WPS_DIR/metgrid/src/metgrid.exe" ]; then
echo "compile success"
else
echo "compile failed (missing one or more WPS executables), check ${bldlog}"
exit 1
fi
fi
Static data¶
Most of the geographical static data for geogrid.exe are stored on NERSC CFS; you can find the location through the $WPS_STATIC_DATA environment variable, which becomes available when loading the WPS module.