This is the water quality calculation core of the FInnish COaStal nutrient load model or FICOS. It is meant for flexible and fast water quality calculations using precalculated hydrodynamic data. The code reads settings data (settings.ini: global model settings and water quality model parameters) and simulation data (hd_files.hdf5: hydrodynamic data and initial conditions, loading.hdf5: nutrient loading data) and writes simulation results to results.hdf5. The code is a single-threaded Fortran code (mix of F90+, F2003+) that implements transport of nutrients between calculation cells using precalculated hydrodynamic data, and a biogeochemical nutrient cycle model that implements algae growth and decay that are driven by nutrient availability and physical conditions such as temperature and light availability.
The code implements a custom geometry where the calculation blocks can be of any size and shape. The input data, including e.g. transports between calculation blocks, water temperature and nutrient loads, must be provided as precalculated 24h averages for each block. Currently two layers, a productive top layer and a deep layer, are supported.
Description of the biogeochemical equations is published in Lignell et al. (2025). Model parameter estimation and calibration process is published in Kaurila et al. (2025).
This is the first public release of the FICOS code. Earlier versions have been in use in the Finnish Environment Institute since 2014 to support coastal management planning and research.
While this implementation of the biogeochemistry is tuned for the Archipelago Sea at the Finnish coast, the parameterisation and equations could be changed to suit other geographical locations as well. The code itself is location-agnostic, i.e., all the location-specific details are already implicit in the precomputed input data.
Requires
- Development environment (tested with Ubuntu 18)
- Fortran compiler (tested with gfortran v7.5.0)
- HDF5 library (Tested with 1.8.19 which might need to be compiled locally and might require -fdefault-integer-8. Requires -enable-fortran and/or -enable-fortran2003.)
- GNU make (tested with v4.1)
How to compile
- Install or compile the HDF5 library if needed
- Edit the Makefile to reflect the current environment (note: use h5fc from the HDF5 installation to compile instead of using gfortran directly!)
- make
How to run
wqficos <resultdir> <hdfile> <loadfile> <ini-file> <modelname> <start timestep> <end timestep>- E.g.
./wqficos . hd_files.hdf5 loading.hdf5 wqficos.ini ficostest 0 0
In the current implementation modelname can be anything. In the future it might used for selecting a different set of equations. Start and end timesteps, while partly implemented, have not been tested, so it is still recommended to use 0 for both (=simulate all timesteps in the data set).
Calculation time is dependent on the resolution, length of the simulation, number of interfaces and minimum time step. In general, water formation (referring to the EU Water Framework Directive coastal water formations) resolution runs should complete in less than a minute on modern hardware. The current code is optimized for speed at the cost of memory. FICOS is a single-thread application. Multiple different runs can be done in parallel as long as there is enough memory for it.
| File | Description |
|---|---|
settings.ini |
Model flags and water quality equation parameters |
equations_ficos.f90 |
FICOS model equations |
errors.f90 |
Error messages for certain cases |
hdfio.f90 |
HDF5 I/O routines |
iniparser.f90 |
Settings file parser |
Makefile |
Compiling instructions for GNU Make |
prec.f90 |
Precision (kind) definitions |
rk4.f90 |
Runge-Kutta 4th order integration routine |
sample_input.zip |
Minimal hdf5 input files for testing. |
wqficos_tc.f90 |
Main program and main loop |
wqficos_helper.f90 |
Various helper subroutines |
wqficos_names.f90 |
Declarations of model equation state variables and some model flags |
How to generate the input files (hd_files.hdf5, loading.hdf5)
- Input files are generated by separate tools that require specific environment and access to original data
- Minimal input files are provided for testing purposes in sample_input_hdf5.zip
How to interpret the output file (results.hdf5)
- Postprocessing depends on what the data is used for
- Results have the same geometry as implicit in hd_files.hdf5
- The results (and inputs) are not in raster format but can be rasterized with the help of further grid definitions not included in the input files
Below is a short description of the groups and datasets required in the input files.
- Usually named hd_files.hdf5.
- Contains daily hydrodynamic data (temperature, salinity, transports) and related metadata such as layer areas and volumes divided into two layers, the top layer being approximately 10 meters (or less) and the deep layer containing the rest of the water column.
- Spatially the data is divided into blocks, which can represent areas of arbitrary shape.
- Block should be internally spatially connected (no separate parts)
- Deep layer volume should be large enough in relation to the top layer for numerical stability. Actual threshold varies based on flow conditions.
- Data is recorded as daily averages and the datasets inside the file should be of equal length of timesteps, where applicable.
- Water is exchanged with neighboring blocks through interfaces, which contain data about the horizontal transports and diffusion.
List of required Datasets in hd_files.hdf5
- Note: nt = number of days in the data
- /Block_list (int) array [number_of_blocks]: Block_id
- block id can be arbitrary integer-type unique id.
- /Blocks/<block_id>/
- AD (float) array [nt]: (Vertical) diffusion of the block. Not used at this time.
- Area (float) array [nt,2]: Area of the top and deep blocks. Unit: m2.
- Aw_dw (float) array [nt]: Vertical transport downwards. Always ≤0. Unit: m3/s.
- Aw_up (float) array [nt]: Vertical transport upwards. Always ≥0. Unit: m3/s.
- Ice (float) array [nt]: Ice thickness. Unit: m.
- Init_inside (float) array [8,2]. Initial data for *, DIN, DIP, *, *, totP, totN, * and top and deep layers. Note: this setting will be changed in a later version of FICOS, possibly moving to loading data tile.
- Sl (float) array [nt,2]: Salinity. Unit: PSU. Not used at this time.
- Tp (float) array [nt,2]: Temperature. Unit: °C.
- Tp_bottom (float) array [nt]: Bottom temperature. Unit: °C.
- V_bottom (float) array [nt]: Flow velocity at bottom. Unit: m3/s.
- Volume (float) array [nt,2]: Volume of the top and deep blocks. Unit: m3.
- /Boundary_block_list (int) array [number_of_boundary_blocks]: Boundary block_id
- /Init_datum (string): Simulation starting date in format YYYY-MM-DD
- /Inter_list (int) array [number_of_interfaces, 2]: All block interfaces: left block_id right_block_id
- /Interfaces/<left_block>_<right_block>/
- ADd (float) array [nt,2]: Diffusion between blocks for top and deep layer. Unit: m3/s.
- Av_l (float) array [nt,2]: Transport from right to left block for top and deep layer. Always ≥0. Unit: m3/s.
- Av_r (float) array [nt,2]: Transport from left to right block for top and deep layer. Always ≤0. Unit: m3/s.
- Tmin (float) array [nt]: Maximum time step for the interface. Unit: s.
- /Simu_start_datum (int) array [6]: Simulation start year, month, date, 0, 0, 0
- /Solar_radiation: (float) array [nt]: Global solar radiation in MJ m-2 d-1
- Same for every block.
- Note that in future versions of FICOS Solar_radiation will be moved inside the /Blocks/ group and will be unique to each block.
- It is required to keep block ids and data internally consistent throughout the input datasets.
- Usually named loading.hdf5.
- Contains daily nutrient loading data and metadata for each block as defined in hd_files.hdf5.
- Each block can have multiple loads and the load names can be arbitrary.
- If the attribute of the load is “cyclical”, the load contains only data for the first year that is then repeated for each subsequent year of the model run but the water quality code.
The internal HDF5 format of loading.hdf5 is:
- /Blocks/<block_id>/Loads/
- load (float) array [nt,4]: DIN, DIP, totN, totP nutrient loads for the block. Unit: kg/d.
- Required attributes for each load:
- Category: (string) Load category, e.g. atmdep
- Cyclical: (integer) Reuse first year data for subsequent years. Yes (1)/no (0).
- Layer: (integer) Layer number. Top = 0, Deep = 1.
- Description: (string) Freeform description of the load.
- results.hdf5
- Contains daily concentrations (and other data) after simulation for each block as defined in hd_files.hdf5.
- Includes one extra timestep compared to input data (results after last day’s input data is integrated).
The datasets in the result file are:
- /Blocks/<block_id>/
- cA (float) array [nt+1]: Surface layer “other” algae, unit: µg N/L.
- cC (float) array [nt+1]: Surface layer cyanobacteria, unit: µg N/L.
- chla_0 (float) array [nt+1]: Surface chlorophyll-a, unit: µg/L.
- cDIN_0 (float) array [nt+1]: Surface layer dissolved inorganic nitrogen, unit: µg/L.
- cDIN_1 (float) array [nt+1]: Deep layer dissolved inorganic nitrogen, unit: µg/L.
- cDIP_0 (float) array [nt+1]: Surface layer dissolved inorganic phosphorus, unit: µg/L.
- cDIP_1 (float) array [nt+1]: Deep layer dissolved inorganic phosphorus, unit: µg/L.
- totN_0 (float) array [nt+1]: Surface layer total nitrogen, unit: µg/L.
- totN_1 (float) array [nt+1]: Deep layer total nitrogen, unit: µg/L.
- totP_0 (float) array [nt+1]: Surface layer total phosphorus, unit: µg/L.
- totP_1 (float) array [nt+1]: Deep layer total phosphorus, unit: µg/L.
- height_0 (float) array [nt+1]: Surface layer height [m].
- height_1 (float) array [nt+1]: Deep layer height [m].
- /Time_array (int) array [nt+1,6]: Date for each timestep. Columns: year, month, day, hour, minute, day of year. Note that hour and minute are not currently used (0).
- There might also be other Datasets in the results file, but they are either for internal, debugging or other use and should not be used.
- A text file containing basic model settings and parameters for the water quality model
- Each setting is on separate line as a parameter=value pair
- Comments can be added after a hash (#) or a semicolon (;) character
- Not all settings are currently implemented in the code and not all settings in the code are implemented in the settings file.
FICOS code is made available with the MIT license. Please check the LICENSE files and code for details.
FICOS wouldn't have been possible without the Python Water Quality Model (PyWQM) originally developed in the EU ERDF Central Baltic Interreg IV A Programme project SEABED at KTH, Sweden. Special thanks to prof. Vladimir Cvetkovic and Dr. Guillaume Vigouroux. Many internal design choices of FICOS have their origin in PyWQM. See e.g. Vigouroux et al. (2019)
The first Fortran version of FICOS (originally Python) was written by Dr. Kai Rasmus at Luode Consulting. This dramatically improved the performance of FICOS by orders of magnitude.
FICOS uses the HDF5 library (BSD-3-Clause License). See THIRD_PARTY_LICENSES.txt for details.
FICOS uses the Runge-Kutta method integration code by John Burkardt (MIT License).
Sources for data in the sample input files: Finnish Environment Institute, Finnish Meteorological Institute, Åbo Akademi, SMHI, HELCOM, Finnish Supervisory Agency.
For the initial public release of FICOS, please cite the archived version V2.0.0 in Zenodo:
Finnish Environment Institute, 2026. Finnish coastal nutrient model (FICOS), V2.0.0. Zenodo. https://doi.org/10.5281/zenodo.18755596
The code is provided as is with no support and no warranty of any kind.