NEMOmodmap¶
Scripts for creating module and subprograms maps from NEMO source
Introduction¶
These pages describe a pair of bash scripts which can be used to generate module and subprogram maps from the NEMO source files. The process is not fully automated since a small amount of hand editing is required in some cases. These special cases will be explained in greater detail but generally the process of creating a map such as:

requires just a few steps:
#
# set modmap_dir to the working directory containing copies of
# the NEMOmodmap scripts and a (initially empty) build subdirectory
#
cd src/OCE/OFF
$modmap_dir/mksubmodlist
#
# Hand edit newsubmod.list if necessary
#
mv newsubmod.list $modmap_dir/OFF_submod.list
cd $modmap_dir
./submod.sh OFF_submod.list > OFF_submod.tex
#
pdflatex -output-directory=./build OFF_submod.tex
mv ./build/OFF_submod.pdf ./
#
The two bash scripts: mksubmodlist and submod.sh are merely manipulating textual information gleaned from the code and wrapping this with latex commands. The final map is rendered by the pdflatex command. This process makes use of the TikZ latex package which comes as standard with most modern latex installations.
The mksubmodlist script¶
This first script is little more than an extended grep command designed to extract the module name and list the names of any contained subprograms within any .F90 or .h90 files with the current directory. This script relies on the NEMO coding conventions to provide correct information but could be easily adapted for other styles. The script is simply:
#!/bin/bash
for f in *.[Fh]90
do
echo $f >> newsubmod.list
grep -e'^ *SUBROUTINE' -e'FUNCTION' -e'^ *MODULE' -e'CONTAINS' \
-e'^ *INTERFACE' -e'^ *RECURSIVE SUB' $f \
| grep -v 'END FUNCT' | grep -v '^#' | grep -v 'PROCEDURE' \
| sed -e 's/(.*) FUN/ FUN/1' | sed -e 's/(.*)//' \
| sed -e 's/(.*$//' | grep -v '^ *!' >> newsubmod.list
echo " " >> newsubmod.list
done
which, when executed in, for example, the OFF directory produces the following newsubmod.list file:
dtadyn.F90
MODULE dtadyn
CONTAINS
SUBROUTINE dta_dyn
SUBROUTINE dta_dyn_init
SUBROUTINE dta_dyn_sed
SUBROUTINE dta_dyn_sed_init
SUBROUTINE dta_dyn_swp
SUBROUTINE dta_dyn_ssh
SUBROUTINE dta_dyn_hrnf
SUBROUTINE dta_dyn_slp
SUBROUTINE compute_slopes
nemogcm.F90
MODULE nemogcm
CONTAINS
SUBROUTINE nemo_gcm
SUBROUTINE nemo_init
SUBROUTINE nemo_ctl
SUBROUTINE nemo_closefile
SUBROUTINE nemo_alloc
SUBROUTINE nemo_set_cfctl
SUBROUTINE istate_init
SUBROUTINE stp_ctl
This file conforms to the expected structure and requires no hand-editing. Other examples which require some manual intervention will be described later but the required structure is a series of blocks each containing:
- The name of the source file followed by
- A MODULE statement giving the name of the module followed by
- A CONTAINS statement followed by
- A list of SUBROUTINE, RECURSIVE SUBROUTINE or FUNCTION statements followed by
- A blank line
The submod.sh script¶
Conversion of these simple lists into appropriate latex instructions is done by the submod.sh script. Whilst the final Latex document can appear long and complex there is much repetition. At its heart the script is writing a latex pre- and post-amble for each map and converting each entry in each list to a labelled node in a TikZ tree diagram. Ignoring the preamble, the heart of the OFF directory example looks like this:
\usepackage{tikz}
\usepackage{adjustbox}
\usetikzlibrary{trees}
.
.
\begin{tikzpicture}[%
grow via three points={one child at (0.5,-0.8) and
two children at (0.5,-0.8) and (0.5,-1.6)},
edge from parent path={(\tikzparentnode.south) |- (\tikzchildnode.west)}]
\node {./OFF}
child { node [f90fil] {dtadyn.F90}
child [gright] { node [f90mod] {dtadyn}
[gdown] child { node [f90sub] {dta\_dyn}}
child { node [f90sub] {dta\_dyn\_init}}
child { node [f90sub] {dta\_dyn\_sed}}
child { node [f90sub] {dta\_dyn\_sed\_init}}
child { node [f90sub] {dta\_dyn\_swp}}
child { node [f90sub] {dta\_dyn\_ssh}}
child { node [f90sub] {dta\_dyn\_hrnf}}
child { node [f90sub] {dta\_dyn\_slp}}
child { node [f90sub] {compute\_slopes}}
}
}
child [missing] {}
child [missing] {}
child [missing] {}
child [missing] {}
child [missing] {}
child [missing] {}
child [missing] {}
child [missing] {}
child [missing] {}
child { node [f90fil] {nemogcm.F90}
.
.
;
\end{tikzpicture}
There are some subtle complexities, such as: offsetting single subprogram names so that they stand out better if sandwiched between lists for modules containing multiple subprograms; but otherwise the logic for converting lists into latex commands is quite straight-forward.
The main style elements are defined in the preamble and are:
\tikzstyle{every node}=[draw=black,thick,anchor=west]
\tikzstyle{f90fil}=[rectangle, minimum height=0.65cm, minimum width=3.5cm, draw=black,fill=yellow!30]
\tikzstyle{f90mod}=[rectangle, minimum height=0.65cm, minimum width=3.5cm,draw=black,fill=red!30]
\tikzstyle{f90sub}=[minimum height=0.65cm, draw=black,fill=green!30]
\tikzstyle{f90fun}=[minimum height=0.65cm, draw=black,fill=blue!30]
\tikzstyle{f90gen}=[minimum height=0.65cm, draw=black,fill=orange!35]
\tikzstyle{gright}=[grow=right, level distance=2cm, edge from parent path={(\tikzparentnode.east) |- (\tikzchildnode.west)}]
\tikzstyle{gdown}=[ grow via three points={one child at (2.5,0.0) and
two children at (2.5,0.0) and (2.5,-0.8)},
edge from parent path={(\tikzparentnode.east) |- (\tikzchildnode.west)}]
These can be easily altered if colours or sizes are not to your taste.
Much of the more obscure latex within the pre- and post-amble parts deals with splitting oversize maps across multiple pages (thanks Stack exchange!). This happens frequently and is handled by drawing the tikzpicture within a virtual box environment and comparing its height to the page’s textheight. When necessary, the image is split and rendered across however many pages are required. The image is continuous across pages but the splitting will not necessarily occur between nodes:
\begin{lrbox}{\mysavebox}%
\begin{tikzpicture}
.
.
\end{tikzpicture}
\end{lrbox}%
%
\ifdim\ht\mysavebox>\textheight
\setlength{\myrest}{\ht\mysavebox}%
\loop\ifdim\myrest>\textheight
\newpage\par\noindent
\clipbox{0 {\myrest-\textheight} 0 {\ht\mysavebox-\myrest}}{\usebox{\mysavebox}}%
\addtolength{\myrest}{-\textheight}%
\repeat
\newpage\par\noindent
\clipbox{0 0 0 {\ht\mysavebox-\myrest}}{\usebox{\mysavebox}}%
\else
\usebox{\mysavebox}%
\fi