FPL - Fortran Processing Library

February 28, 2026 · View on GitHub

Documentation: https://pimentafm.github.io/FortranProcessingLibrary/

Legacy documentation: http://www.biosfera.dea.ufv.br/fpl/

Copyright (C) 2015 Fernando Martins Pimenta. Licensed under the GNU General Public License v3.0.

Author: Fernando Martins Pimenta — Research Group on Atmosphere-Biosphere Interaction, Federal University of Viçosa, Brazil

Contact: fernando.m.pimenta@gmail.com | fernando.m.pimenta@ufv.br

GitHub stars GitHub issues GitHub repo size GitHub language count License: GPL v3 Made by Fernando Pimenta

Fortran NetCDF OpenMP HDF5


Requirements

DependencyDescription
GFortranGNU Fortran compiler (part of GCC)
NetCDFNetwork Common Data Form libraries
NetCDF-FortranFortran bindings for NetCDF (libnetcdff)
OpenMPMulti-threading support (included with GFortran)
MakeBuild automation tool
Python 3Code generation script (generate_cpp.py)

Installation of dependencies

Debian / Ubuntu:

sudo apt install gfortran libnetcdf-dev libnetcdff-dev make python3

Fedora / RHEL:

sudo dnf install gcc-gfortran netcdf-devel netcdf-fortran-devel make python3

How to build and install

Download FPL from GitHub.

Build the library (local):

cd FortranProcessingLibrary
make

Install to system directories (needs root):

sudo make install

Other targets:

make clean       # Remove local build artifacts
make uninstall   # Remove from system dirs
make help        # Show all targets and overridable variables

You can override paths if needed:

make LIBDIR=/custom/lib MODDIR=/custom/include NETCDF="-I/custom/include -lnetcdff -lnetcdf"

Architecture

The main module src/FPL.f90 aggregates all source files via CPP #include directives, using omp_lib, netcdf, and iso_c_binding. It is compiled as a shared library (libFPL.so) with gfortran -O3 -shared -fPIC -fopenmp -cpp.

Source Modules

Generated .f90 files use CPP #define/#include/#undef blocks that expand templates from src/templates/*.inc at compile time.

FileLinesDescription
FPL_setfillvalue.f904,033FillValue mask application (parallelized with OpenMP !$omp parallel do)
FPL_zonalstats.f904,033Zonal statistics with OpenMP parallelization (reduction, parallel do, collapse)
FPL_writegrid.f901,133Grid writing to NetCDF (HDF5 format), with custom header file support
FPL_interfaces.f901,557Generic interfaces (static polymorphism)
FPL_datatypes.f901,133Definition of 100 derived types via CPP templates
FPL_readgrid.f90833Variable and coordinate reading from NetCDF
FPL_gengrid.f90833Regular grid generation from Xmin/Ymin/Xmax/Ymax/resolution
FPL_griddims.f90633Dimension reading (lon, lat, time, level) from NetCDF files
FPL_dealloc.f90633Memory deallocation for all types (with stat= error handling)
FPL_checkerror.f90205Error handling with colored messages, print_filename, check_alloc (pure Fortran, no system)
FPL_fileutils.f90111Utilities: file_exists, countkeys, readheader, row counter
FPL_datetime.f9077System date/time (fdate_time, exec_time)
FPL_sort.f9057Bubble sort for dimension ID ordering
FPL_constants.f9049Physical constants (pi, Earth radius, Boltzmann, etc.) and type aliases via iso_c_binding
FPL_misc.f9039Library version
`templates/*.inc$1{,}08424 \text{CPP} \text{template} \text{files} (8 \text{modules} \times 3 \text{dimensionalities})
$generate_cpp.py`271Python script to generate .f90 from templates

Type System

The core of the library is a combinatorial scheme of derived types. Each type name encodes:

  • Dimensionality: nc2d (lon, lat), nc3d (lon, lat, time), nc4d (lon, lat, time, level)
  • Variable type: byte, short, int, float, double
  • Coordinate type: llf (lon/lat float), lld (lon/lat double)
  • Time type: ti (int), tf (float), td (double)
  • Level type: li (int), lf (float)

Example: nc4d_float_llf_tf_lf = float variable, 4D, float coordinates, float time, float level.

Each type stores: varname, longitudes(:), latitudes(:), ncdata(:,:,...), FillValue, metadata, dimension IDs, etc.


Generic Interfaces (Polymorphism)

The interfaces in FPL_interfaces.f90 allow calling the same generic procedure for any type:

  • checkcheckerror, checktype, checkatt
  • griddims → get dimensions from NetCDF (dispatch by type)
  • readgrid → read data from NetCDF
  • writegrid → write NetCDF (HDF5 format)
  • setFillValue → apply FillValue mask between two variables
  • zonalStats → compute per-zone aggregate statistics
  • gengrid → generate regular grid
  • dealloc → deallocate memory

Parallelization (OpenMP)

The setFillValue and zonalStats routines use OpenMP parallelization:

  • setFillValue: !$omp parallel do on the lon/lat loops
  • zonalStats (2D): !$omp parallel do with reduction on accumulation arrays across the latitude loop
  • zonalStats (3D): !$omp parallel do on the time loop (each timestep is independent)
  • zonalStats (4D): !$omp parallel do collapse(2) on the level/time loops

Loop order follows Fortran column-major convention (inner loop over the first array dimension) for optimal cache performance. The Makefile compiles with -fopenmp.


Typical Usage Pipeline

program main
  use fpl
  implicit none

  type(nc4d_float_llf_tf_lf) :: temp

  temp%varname   = "temp"
  temp%lonname   = "longitude"
  temp%latname   = "latitude"
  temp%timename  = "time"
  temp%levelname = "level"

  call readgrid("input.nc", temp)        ! read all data
  temp%ncdata = temp%ncdata * 1.8 + 32   ! process (e.g., Celsius to Fahrenheit)
  call writegrid("output.nc", temp)      ! write output
  call dealloc(temp)                     ! free memory
end program main

Code Generation

FPL uses the C preprocessor (CPP) to generate the combinatorial explosion of subroutines for each type/dimension combination. The system has two layers:

  1. Template files (src/templates/*.inc) — Fortran source with CPP macro placeholders (FPL_TYPE, FPL_SUBR, etc.)
  2. Generator script (src/generate_cpp.py) — Python script that produces .f90 files with #define/#include/#undef blocks for every type combination

The compiler flag -cpp tells gfortran to expand the macros at compile time.

To regenerate after modifying templates or type definitions:

python3 src/generate_cpp.py
make clean && make

Examples

The examples/ directory contains complete programs demonstrating all library features:

ExampleDescription
ex0Library test
ex1Read and write NetCDF grids
ex2Get variable info from NetCDF
ex3Date and time utilities
ex4Generate regular grids
ex5File utilities
ex6Memory deallocation
ex7Zonal statistics (2D)
ex8Zonal statistics (3D)
ex9Zonal statistics with spatial masking (2D)
ex10Zonal statistics with spatial masking (3D)

Build and run an example:

make
cd examples
gfortran -o ex1.out ex1_readwrite.f90 -I../build -L../build -lFPL $(nf-config --fflags --flibs) -fopenmp
./ex1.out