Skip to content

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.