12  Developing iLand

12.1 Introduction

We believe that the results of research - especially when publicly funded - should also be available to the public. Furthermore, we believe that a fundamental principle of science is that research should be replicable by peers (which gets increasingly harder the more complex the applied tools become, and the more restricted traditional publication outlets become).

That’s why we chose to release the full iLand software suite under the GNU GPL (General Public licence). The GNU General Public Licence (GPL) is one of the most commonly used licenses for open-source projects. The GPL grants and guarantees a wide range of rights to developers and users working with open-source software. Basically, it allows users to legally copy, distribute and modify software. This means you can:

Copy the software.
Copy it onto your own computers or servers, pretty much anywhere you want. There’s no limit to the number of copies you can make.

Make whatever modifications to the software you want.
If you want to add or remove functionality, go ahead. If you want to use a portion of the code in another project, you can. The only catch is that the other project must also be released under the GPL.

One dedicated goal is to use as much open-source/free software as possible to not restrict the potential use of iLand by licenses etc. This includes:

  • cross platform toolkit for (not only) the user interface (Qt)

  • IDE (Qt creator), and compiler (Gnu C++)

  • the SQLite database

  • tools to organize source code (subversion, git) and documentation (doxygen, YUIdoc)

12.2 Getting iLand source code

The source code of iLand is available either as .ZIP package file bundled with the iLand download, or from our GitHub repository.

To get a copy of the iLand source code using git, type:

git clone https://github.com/edfm-tum/iland-model.git

This will get you the newest “stable” release of the model. To switch to the latest version currently under development, you can switch to the dev branch:

cd iland-model  # Navigate into the repository directory
git checkout dev # Switch to the "dev" branch

It is generally recommended to use the stable version (unless communicated otherwise).

12.3 Setting up Qt and basic requirements

To compile iLand on your target machine, or to develop iLand you need the Qt framework and other tools such as compilers.

Let us assume, that we use a Windows-based sytem and that the iLand source code is located in c:\dev\iLand. (see also below for other operating systems).

  • Get and install Qt
    In order to be able to modify and compile iLand, you will need Qt and the QtCreator IDE. Both packages are freely available at http://qt.io/. The current release is compiled with Qt 6.5 for Windows (MSVC 64Bit). Note that it is also possible (but not tested) to work with another development system such as Microsoft Visual Studio.

  • Get a compiler
    iLand is known to work with different compilers (Intel icc, msvc, gcc), but the most typical setup is either using Microsoft MSVC or the open source GCC compiler suite. The Microsoft compilers can be freely downloaded and used, and work very well on Windows (e.g., fast compile times), but are typically slightly complicated to install.
    https://doc.qt.io/qt-6/windows.html
    https://doc.qt.io/qt-6/linux.html

  • Setup in Qt Creator
    After installing the Qt Creator IDE, start it and open the “iland.pro” project in the src/iland folder (be sure to preserve file paths when extracting the source code from a ZIP file). iLand uses no external libraries (except the Qt libraries) which should simplify the building process considerably – a click to “build” should suffice (in principle). iLand is split in three projects: plugins (disturbance modules), iland (the model with graphical user interface), and ilandc (the console version of the model). Both iland and ilandc depend on plugins.

Load iland, ilandc and plugins in Qt Creator
  • There are different ways how one can manage build locations. When you open a .pro-file for the first time, Creator asks for the “Kit” (or Kits) that you want to use. After selecting a Kit (e.g., Qt 6.5 MSVC) Creator creates build folders for each project (iland, ilandc, plugins) and configuration (debug / release builds). Using just the defaults should work - when you build the project iland (and when you built plugins earlier or set plugins as a dependency of iland), you should end up with a built executable (located in a folder such as C:\dev\iland-model\src\build-iland-Desktop_Qt_6_5_0_MSVC2019_64bit-Release\release).

  • Alternatively, you can create a common build directory, typically on the same level than the src folder (e.g., c:\dev\iLand\build). Now you need to change the build paths in Qt Creator. (Project settings, build path): use the common build-folder created earlier and build the subprojects (plugins, iland, ilandc) to the folders \<build-folder\>/plugins, \<build-folder\>/iland, \<build-folder\>/ilandc (e.g. c:\dev\iland\build\iland). The compiled executable file will then be saved to e.g. c:/build/iland/release/iland.exe. Make sure to also compile all sub projects with the same compiler version (see Figure 12.1). In this setting, the paths look a bit nicer, but your build build files are overwritten when switching between debug and release build.

    Figure 12.1: Use the “Project” tab to set build options. Change the path for every projects (iland, ilandc, plugins) (Note that the path differs from the text)
  • Select a “Release” configuration when you just want to run the model, or “Debug” if you want to use breakpoints and step-by-step-debugging (Note that a debug build runs typically much slower!).

  • Check the Qt documentation for more details on how to work with Qt and Qt creator!

12.4 Compiling iLand for different operating systems

12.4.1 Building iLand on systems with graphical user interface

iLand is supported on platforms that run Qt, which is Windows, Linux and Mac operating systems. For a Linux system with a graphical user interface (e.g., Ubuntu) the approach is very similar to using Windows (see above): install Qt and Qt Creator and build from within the IDE. Typically, you’d use gcc compilers on that platform. Mac systems should work, but we never actually tried it. If you have experience with compiling and running iLand on Mac, we’d be happy to hear about it!

12.4.2 Compiling iLand on Linux clusters

This is applicably mostly on large server infrastructure, for example high performance computing clusters. In such an environment you typically only want to build the console version of iLand.

While almost all HPC cluster installations use Linux, some subtle differences may apply. But see also this example for a Windows cluster environment!

In order to build iLand, you need:

  • Qt installed on the cluster (Qt6) - check the cluster documentation how third-party packages are used!

  • a suitable compiler - typically compilers are already available, check the cluster documentation which ones and how they are selected!

  • The iLand code (from GitHub or a ZIP)

Example for a build_iland.sh bash script file to (re-) build iLand. In this case the “module” commands load specific software packages (here: intel compiler, qt). Note that there are likely differences depending on the cluster environment! This script builds the ilandc executable.

# build iLand on Linux cluster
# using Intel compiler (the -spec linux-icc-64 -> this might differ)
# Note: run in a build folder (on the same level as “src” of iLand)

module load intel
module load qt

mkdir plugins
mkdir ilandc

cd plugins
qmake ../src/plugins/plugins.pro -spec linux-icc-64
make

cd ../ilandc
qmake ../src/ilandc/ilandc.pro -spec linux-icc-64
make

cd ..

12.4.3 Building iLand on a standard Linux server

This is a build script to build iLand for Ubuntu. In this particular case, a local Qt installation is used (/home/werner/Qt/6.5.3). This script builds both the console and the UI version.

echo "Building iLand..."

QTDIR=/home/werner/Qt/6.5.3/gcc_64/bin
PATH=$QTDIR:$PATH

mkdir build
cd build
mkdir plugins
mkdir iland
mkdir ilandc

cd plugins
qmake ../../src/plugins/plugins.pro
make

cd ../iland
qmake ../../src/iland/iland.pro
make

cd ../ilandc
qmake ../../src/ilandc/ilandc.pro
make

cd ..

12.5 High level source code overview

The source code is organized into several sub directories:

  • core - this includes the core logic of iLand. If you look for how a specific ecological process is implemented, than start here

  • abe - code for the agent base forest management engine

  • bite - code for the BITE module

  • output - code that creates the different output tables of iLand.

  • tools - Infrastructure and helping code for iLand (for example, classes to work with spatial grids)

Many objects/classes/elements of the model share a similar structure. Very often, there is a setup() function, and an execute() (or run() or calculateXXX() ) function. The former is used to create model structures (and typically here values from the project file are used), and the latter when the model runs.

Many elements are organized hierarchically - this is particularly true for the classes representing spatial entities. For instance, the Model class represents the full forest landscape; it holds a grid (and a list) of ResourceUnits. This class represents a 100x100m cell. The ResourceUnit contains a list of Tree objects (yes, you guessed correctly), and structures that represent information on species level (e.g., ResourceUnitSpecies) and links to other objects (such as WaterCycle). For example, the function WaterCycle::setup() initializes the water cycle for a resource unit, which is influenced by a number of settings (e.g, percentage of sand in the soil, model.site.pctSand) . On the other hand, the WaterCycle::run() function is called for each year and resource unit during a simulation and calculates soil-water related processes (such as evapotranspiration).

The entry point for the simulation of a single year in iLand is the Model::runYear() function (in core/model.cpp). All other steps are invoked from there directly or indirectly. However, the specific route to a specific line of code can be complicated. Here it is often useful to either use breakpoints or search for code references (see below).

There is a single class for each available output of the model. These are found in the output folder of the source code tree. For example, the waterout.h and waterout.cpp files include code and definition of the WaterOut class. Each of these output classes defines the columns (typically in the constructor, for example WaterOut::WaterOut()) and documentation for the output (the content of the https://iland-model.org/outputs is generated by iLand - this is what the “Output table description” action in the “Misc” menu is doing). The exec() function of each output creates the actual data, typically be extracting information from other model parts.

12.6 Tips for getting started

  • Look at the names of the code files first - for example, an individual tree in iLand is represented by a “Tree” object which is defined in tree.h and tree.cpp.

  • Use strings from error messages or the log file to quickly find the relevant parts of the code. Note that messages are often composed of multiple parts (e.g. file names) - be sure to look for the right parts of a string! This is also a quick way to find where a specific setting (in the project file) is used in the model.

  • Use the tools provided by Qt Creator: in particular, Use the “find references” (Ctrl+Shift+U) - this allows you to quickly find from where a particular function is called (or a variable used)!

  • Use the debugger and breakpoints: for this you need to compile iLand in “Debug” mode. Having done that, you can set breakpoints to stop the model at a specific point. From there, you can run the model step-by-step and view values of variables.

Example - make something “editable”

Consider you want to make something that is currently “hard coded” editable from the project file (for example, you want to run some sort of sensitivity analysis, or you want to enable / disable a certain process).

The strategy would be to first locate the relevant part of the code (see above):

const double factor = 0.05; // hard coded factor
// ... some code that uses factor

Now, change to read a value from the project file:

    // find an appropriate spot in the project file - but you can also use
    // the "user" section:
    QString setting_key = "user.my_factor"; 
    double factor = GlobalSettings::instance()->settings().valueDouble(setting_key);
    // ... unchanged code that uses factor 

Consider that reading from the settings is relatively slow; if this is a time-critical part of the model, it is better to read the setting once (for example, in the setup() function) and save to a member variable of the class!

Example - extend an output

Consider you want some extra information in one of the outputs that is currently not included.

The strategy would be to first think about which output to extend - is it the right spatial and temporal resolution? Next would be to locate the correct output class. Within each output class are two crucial spots:

Change the definition of the output:

// in the constructor of the output you'll find a statement like this:
columns() << OutputColumn::year() <<
....

// each column is created by an object that defines the column name, a column description and a data type
<< OutputColumn("maxSnowCover", "Permafrost: maximum snow height (m) in a year.", OutDouble)

// to extend, add a definition, for example after "maxSnowCover":
columns() << OutputColumn("myOutput", "this is …", OutDouble); 

// that's it!

Change the exec() function to alter what information is written to the output table.

// look for statements as:
*this << <some data>

// in our case, we need to take care of the right sequence, so look for "maxSnowCover"
msd += wc->permafrost()->stats.maxSnowDepth;

// add your data and make sure it is in the right order and *before* writeRow()
*this << my_numeric_value;
...
writeRow(); // indicates the end of one row

This is also straightforward - the difficult past is often to have the information that you want to write somewhere available (it might be very well feasible to copy what iLand is doing anyway - for example, you could extend a data structure that already keeps stats on a process which you are interested in).