Redesign phase 1

Michel Wortmann

11 Feb 2021

The brave developers

Mark Florisson (UK)Luciano Darriba (Argentina)
Computer ScienceAstronomy
Since Feb 2020, ~160hrsSince Dec 2020, ~45hrs
  • no change in output and functionality šŸ¤žšŸ¼
  • relies on automated testing

Testing

sha1 hash of output files:

cd project/
make
git diff output.sha1

Problems

  • precision issues (btw systems, minor changes)
  • legitimate input/output changes
  • doesnā€™t cover different input configurations
  • tests based on balance of storages and fluxes required

MS1 Uniform code standard to Fortran 95

  • normalised indentation (2 spaces) and other whitespace (semi-automatically)
  • adherance to -std=f95
  • removed deprecated statements
    • e.g. goto, data, pause
  • removed compiler warnings
  • global real type (dp)

MS2 Modularisation

  • implementation of new modules based on processes and function (n = 43 -> 20)
  • variables/data moved to module variables dissolving common.f
  • dependencies according to a module hierarchy
  • argument passing with intend(in/out/inout)
  • distributed initialisation/file opening/allocation
  • done semi-automatically, will continue to need detangling (also by us in the future)

Module hierarchy

Explicit module dependency and argument passing

  • argument passing with intent
    • left to right in hierarchy
    • e.g.: swim.f95 ā†’ hydrotope.f95
  • use <module>, only: ...
    • from right to left in hieararchy
    • e.g. hydrotope.f95 ā† utilities.f95
subroutine hydrotope_open_files(input_dir, output_path)
  use utilities, only : open_file
  character(len=*), intent(in) :: input_dir
  character(len=*), intent(out) :: output_path

MS3 Parameters

  • all key = value parameters read via fortran namelist
    • .bsn, .cod, wgen, wam.ctrl, swim.conf
    • other hardcoded variables, e.g. input file names
  • grouped by modules
  • defaults defined in the code, i.e. values are not mandatory
  • flexibility for new developments

.nml file

 ! snow
&snow_parameters
 prcor =  1.0,
 snow1 =  0.0,
 ! elevation-based correction for precip and temperature
 xgrad1 =    0.0,
 tgrad1 =    -0.0,
 ulmax0 =    1.0,
 rnew =      0.08,
 tmelt0 =    0.0,
 bsnowmodule =    .true.,
 /
&soil_parameters
 ab       = 0.02083,
 cnum1=  2.0000000000000000     ,
 cnum3=  2.0000000000000000     ,
 ekc0=  1.0000000000000000     ,
 icn=          0,
 icurn=          1,
 icursb=          1,
 ipehd=          1,
 iperc=          1,
 ipesb=          1,
 isc=          0,
 isolt=          1,
 isosb=          1,
 itran=          1,
 ml=         10,
 nn=         10,
 psp=         0.5,
 rtn=         0.15,
 sccor_=  1.5000000000000000     ,
 stinco= 0.90000000000000002     ,
 /
 ! subbasin
&subbasin_parameters
 mb=         11,
 sub= 30*0.0000000000000000       ,
 nqobs=1,
 /

MS4 Uniform and tidy input

  • all files converted to CSV
  • tidy data: samples in rows, variables in columns
  • all files with column names and integer index
  • input of same spatial unit aggregated
  • columns are identified by name (not index)
  • columns may be optional with default in code
  • names according to unit or module

New input files

catchment.csv             river_routing.csv         
climate.csv               soil.csv                  
crop.csv                  subbasin.csv             
crop_management.csv       subbasin_climate_grid.csv
discharge.csv             watch_era40.nc4
hydrotope.csv             soils/         
landuse.csv                 soil01.dat   
management.csv              soil02.dat    
output.nml                water_users/    
reservoir.csv               user_1.csv     
reservoir_monthly.csv       user_2.csv    
reservoir_storage.csv       user_4.csv 
  • remember the hierarchy?
  • all path configurable via nml parameters

CSV column reader

  • universal input reading based on column name
  • required columns, optional columns with defaults
 use utilities, only: open_file
 use input, only: read_real_column, read_integer_column

 integer :: file_id, soil_id(mb), reference_elev(mb)

 file_id = open_file("subbasin.csv")

 ! required column
 call read_integer_column(file_id, "soil_id", soil_id)

 ! not required column with default value
 call read_real_column(
   file_id, "reference_elev", reference_elev, default=0
 )

MS4 Abstract and tidy output

  • common interface for all output (abstracted)
  • flexible output by user request via .nml file
  • tidy CSV file output
  • variable nomenclature,
  • work in progress, input needed from us all

Output module interface

  1. Register variable at initialisation
  2. Store variable at runtime
  3. Request discharge output
 ! module variables
 integer :: discharge_oid, discharge(mb)

 use output, only: ouput_register_subbasin_var

 discharge_oid = output_register_subbasin_var("discharge")

 use output, only: output_store_subbasin_values

 call output_store_subbasin_values(discharge_oid)

(allows purging large parts of cluttered code)

Requesting output

input/output.nml

&file
    name = "<string>"
    space = "(catchment|subbasin|hydrotope)"
    time = "(daily|monthly|annual)"
    variables = "<list of output variable names>"
   [label = "<column name>"]
   [format = "(csv|bin)"]
/
&file
...

Example

input/output.nml

&file
    name = "river_discharge"
    space = "subbasin"
    time = "daily"
    variables = "discharge", "river_runoff"
/

subbasin_daily_river_discharge.csv

time,    subbasin,   discharge, river_runoff
1991-01-01,     1,     13.0788,      3.0653
1991-01-01,     2,      6.4894,      2.2969
1991-01-01,     3,      3.6155,      2.7090
1991-01-01,     4,      5.1870,      2.7598

Phase 2

work in progress

Work in progress

  • Refactor initialisation - process - terminate phasing
    • formerly SwimEngineDll.f, SwimEngineMain.f, monthly.f90
  • Small commandline interface
  • Finalise previous steps
  • Break up of monolithic subroutines (aim 60l.)
  • Update docs
    • tables for parameters, input files, output variables
    • developer guide

Comandline interface

Michels-MBP:prototypes wortmann$ ./swim -h

  + . . . . . . . . . . . . . . . . . . . . . . . . . . +
  .                                                     .
  .      .      //////// \\    \\      // ||  ||    ||  .
  .     / \     \\        \\    \\    //  ||  ||\\//||  .
  .    /   \     \\\\\\\   \\  //\\  //   ||  || \/ ||  .
  .   /~~~~~\         //    \\//  \\//    ||  ||    ||  .
  .  (~~~~~~~)  ///////      \\    \\     ||  ||    ||  .
  .   \~~~~~/   --------------------------------------  .
  .    ~~~~~    Soil   and   Water  Integrated   Model  .
  .                                                     .
  .                     * v2021.1 *                     .
  + . . . . . . . . . . . . . . . . . . . . . . . . . . +

usage: swim [options] [parameter-nml]

  parameter-nml               path to the parameter namelist

options:
  -h, --help                  show this help message
  -v, --version               print version
  -m, --modules               print module names
  -i, --module-info [module]  print module/s info
  -d, --defaults [module]     print default parameters
  -o, --output-variables      print available output variables

Developer guide

  • call trees
  • code standards
  • implementation guide
    • new parameter
      • new subcatchment parameter
    • new output variable
    • new input
    • new module
  • versioning and releasing

If time permitsā€¦

  • linear hydrotope variables
  • implementation of openMP (hydrot./subb. loops)
  • shiny front end
  • refactor, refactor, refactorā€¦

The end

  • What is essential output and what can be purged?

    • Already implemented: GIS/*, Q_gauges_routed_*, ba*.prn
    • Provide expanded variable names and root variables in code
  • Track progress on Gitlab