Commit 22ad605a authored by Sergey.Budaev's avatar Sergey.Budaev
Browse files

Reference model R1, from HEDG_2_04


git-svn-id: https://tegsvn.uib.no/svn/tegsvn/tags/AHA_R/R1@6991 ad98353e-09f0-4531-9f56-ca5884d0cf98
parents
syntax: glob
#---------------------------------------------------------
# Don't forget to set ignore properties for this to work:
# svn propset svn:ignore -F .svnignore .
#---------------------------------------------------------
# PDF files are not included into the Mercurial repos
*.pdf
# Git files
.git
.gitignore
# Version information, hg hook
# [hooks]
# commit = hg -q id > .hg.version
.hg.version
# AHA output
outputs_*
BUILD-ERR-GCC.txt
BUILD_*
errors.txt
# Swap files
*.swp
*~
# exe files
*.exe
# compiler and Fortran-specific temporary files
*.mod
*.o
*.obj
# automatically generated include files
*.inc
# codeblocks project files
*.bmarks
*.layout
*.cbp
bin/*
obj/*
# Geany project files
*_PRJ?
# syncthing conflicting files
*.sync-conflict-*
# Tests and experiments
ztests/*
# Various lock and tmp files
.~lock
HEDG2.bmarks
HEDG2.layout
HEDG2.cbp
# Don't forget to set ignore properties for this to work:
# svn propset svn:ignore -F .svnignore .
#---------------------------------------------------------
# Hidden files on Linux
.hidden
# Git files
.git
.gitignore
# Mercurial files
.hg
.hgignore
# AHA output
outputs_*
BUILD-ERR-GCC.txt
BUILD_*
errors.txt
# Swap files
*.swp
*~
# exe files
*.exe
# compiler and Fortran-specific temporary files
*.mod
*.o
*.obj
# automatically generated include files
*.inc
# codeblocks project files
*.bmarks
*.layout
*.cbp
bin/*
obj/*
# Geany project files
*_PRJ?
# syncthing conflicting files
*.sync-conflict-*
# Tests and experiments
tests*
# Various lock and tmp files
.~lock
This diff is collapsed.
This diff is collapsed.
# Introduction and Getting Started #
## The AHA Model ###
This is a large scale simulation model (under development) that implements
a general **decision-making architecture** in **evolutionary agents**. Each
agent is programmed as a whole virtual organism including the genome,
rudimentary physiology, the hormonal system, a cognitive architecture and
behavioural repertoire. They "live" in a stochastic spatially explicit
virtual environment with physical gradients, predators and prey. The primary
aim of the whole modelling machinery is to understand the evolution of
decision making mechanisms, personality, emotion and behavioural plasticity
within a realistic ecological framework. An object-oriented approach coupled
with a highly modular design not only allows to cope with increasing layers
of complexity inherent in such a model system but also provides a framework
for the system generalizability to a wide variety of systems. We also use
a "physical-machine-like" implementation philosophy and a coding standard
integrating the source code with parallel detailed documentation that
increases understandability, replicability and reusability of this model
system.
The cognitive architecture of the organism is based on a set of
motivational (emotional) systems that serves as a common currency for
decision making. Then, the decision making is based on **predictive
assessment** of external and internal stimuli as well as the agent's own
motivational (emotional) state. The agent makes a subjective assessment
and selects, from the available repertoire, the behaviour that would reduce
the expected motivational (emotional) arousal. Thus, decision making is
based on predicting one's own internal state. As such, the decision-making
architecture integrates motivation, emotion, and a very simplistic model
of consciousness.
The **purpose** of the AHA model is to investigate a general framework
for modelling proximate decision-making and behavior. From this we will
investigate adaptive goal-directed behaviour that is both guided by the
external environment and still is endogeneously generated.
Other research topics include individual differences, personality as well
as consequences of emotion and personality to population ecology.
We think that understanding and modelling complex adaptive behaviour requires
both extraneous (environmental) factors and stimuli as well as endogeneous
mechanisms that produce the behaviour. Explicit proximate representation
of the motivation and emotion systems, self-prediction can be an important
component in linking environment, genes, physiology, behavior, personality
and consciousness.
Fortran is used due to its simplicity and efficiency. For example, check out
[this paper](http://www.moreisdifferent.com/2015/07/16/why-physicsts-still-use-fortran).
--------------------------------------------------------------------------------
## Subdirectories of the AHA Model code ##
- `\dox` -- contains pictures, plots and other resources for the full Doxygen
documentation that is extracted from the source code.
- `\pfunit` -- unit tests using [pFUnit](http://pfunit.sourceforge.net/), so
far rather rudimentary.
- `\tools` -- various accessory tools, post-processing of the data generated
by the model etc.
.
--------------------------------------------------------------------------------
## Getting started ##
Building and running the mode is based on the GNU Make. Both the **AHA Model**
code and the **HEDTOOLS** (code or static library) are needed to build the
model. These two components of the AHA Model framework are described in the
[Overview of the AHA Fortran modules](http://ahamodel.uib.no/doxydoc/index.html#intro_overview_modules).
Normally, the *AHA Model* code and the *HEDTOOLS* code are placed in two
subdirectories of the working directory using two separate commands to get the
code of the AHA Model and HEDTOOLS from the repositories (`svn co https://...`
or `hg clone ssh://...` if Mercurial is used -- check out
[Subversion](http://ahamodel.uib.no/doc/ar01s04.html)).
With the current main Subversion repository, getting the code requires these
commands:
svn co https://subversion.uib.no/repos/aha-fortran/branches/budaev/HEDG2_01
svn co https://subversion.uib.no/repos/aha-fortran/branches/budaev/HEDTOOLS
or these, if Mercurial is used (here local folders are capital):
hg clone ssh://hg@bitbucket.org/ahaproject/hedg2_01 HEDG2_01
hg clone ssh://hg@bitbucket.org/ahaproject/hedtools HEDTOOLS
Thus, the layout of the working directory after `HEDG2_01` and `HEDTOOLS` are
downloaded is like this:
workdir
|
|-- HEDG2_01
| |-- dox
| |-- pfunit
| `-- tools
|
`-- HEDTOOLS
Building the AHA Model is done in the model directory (here `HEDG2_01`). If
you use the terminal, go there with
cd HEDG2_01
Here are the main commands to build and run the AHA Model:
- *Build* the model from the source code: `make`;
- Build and *run* the model:`make run`;
- Delete all build-related, data and temporary files `make distclean`;
- Get a quick help from the make system: `make help`.
See [Makefile](http://ahamodel.uib.no/doxydoc/Makefile.html) for build
configuration. To get more information on the GNU Make see
[AHA Modelling Tools Manual](http://ahamodel.uib.no/doc/ar01s13.html),
[Using Microsoft Visual Studio](http://ahamodel.uib.no/doc/ar01s14.html) and
[Using Code::Blocks IDE](http://ahamodel.uib.no/doc/ar01s15.html).
## Environment variables ##
The model makes use of several environment variables to control certain
global aspects of the execution. These variables have the `AHA_` prefix
and are listed below.
- `AHA_DEBUG=TRUE` sets the "debug mode";
- `AHA_SCREEN=NO` sets logger to write to the standard output as well
as in the log file;
- `AHA_DEBUG_PLOTS=YES` enables generation of debug plots;
- `AHA_ZIP_FILES=YES` enables background compression of big output data files;
- `AHA_CHECK_EXTERNALS=NO` disables checking for external executable
modules (this is a workaround against Intel Fortran compiler bug).
## Makefile: GNU Make build configuration ##
[Makefile](http://ahamodel.uib.no/doxydoc/Makefile.html) to build the model
executable from the source code.
This is a standard GNU Make
[Makefile](http://ahamodel.uib.no/doxydoc/Makefile.html) to build the model from
the sources. It also automatically generates some platform and
compiler specific include files for the `BASE_RANDOM` and the
IEEE math modules. See
[Working with the model](http://ahamodel.uib.no/doxydoc/index.html#intro_main)
section for details.
In addition to the GNU Make, this
[Makefile](http://ahamodel.uib.no/doxydoc/Makefile.html) also depends on the
`grep`, `cut`, `sed` and `awk` utilities that are installed on any
Unix/Linux system, but usually absent on Windows. For Windows
they can be obtained from several locations on the web, e.g.
Cygwin or GnuWin32. See
[AHA Modelling Tools Manual](http://ahamodel.uib.no/doc/ar01s01.html)
for more information.
### Main adjustable parameters ###
- **FC** sets the default compiler type. Normally GNU `gfortran` or Intel
`ifort`.
- **HOST_HPC_ROOT** is the hostname to run the model executable in the
HPC batch mode. If the hostname the
[Makefile](http://ahamodel.uib.no/doxydoc/Makefile.html) is called in is this
system, `make run` starts a new batch task. Otherwise, the model
executable is just started normally.
- **SRC** is the name of the main source code (can be several files).
- **DRV** is the source code of the model "driver", that is the main
Fortran program that produces the executable. It should be very
very small. The "driver" is a separate file from the AHA Model
modules.
- **OUT** is the executable file name that is actually run, on the
Windows platform must have the `.exe` suffix. By default, the
executable name is set to `MODEL.exe` for maximum portability.
- **DOXYCFG** the Doxygen documentation system configuration file name.
- **DOXYPATH** defines the Doxygen output directory where the
documentation is generated. This could be set manually or parsed
automatically using the `grep` command. Note that the output
directory is set in the `Doxyfile` as:
`OUTPUT_DIRECTORY = ./model_docs`.
- **HEDTOOLS** is the list of HEDTOOLS Fortran source files that are
used in the AHA Model. Note that `BASE_STRINGS` in the list must
go before `BASE_CSV_IO` because `BASE_CSV_IO` depends on
procedures from `BASE_STRINGS`.
- **HEDTOOLSDIR** defines the path to the HEDTOOLS source code.
- **IEEEPATH** defines the path to the IEEE non-intrinsic math modules
(part of HEDTOOLS).
- **WINRM** defines the command that is used to delete files and
directories on the Windows platform. The native file delete command on
the Windows platform is `del` or `erase`. However, if Cygwin is used,
this native file removal command may not call with a "command not found"
error. In such a case, use the Unix `rm` tool provided by Cygwin.
.
The source code of the [Makefile](http://ahamodel.uib.no/doxydoc/Makefile.html)
contains many other parameters and is well documented throughout.
# Modern Fortran features #
The AHA Model is implemented in the modern Fortran **F2003** and partially
**F2008** standards. Because not all widespread compilers support the full
set of these language standards, the model code uses only those that are
supported by the following minimum compiler versions:
- GNU gfortran 4.8
- Intel Fortran 17
Modern Fortran fully supports object oriented programming with polymorphic
objects and rich set of array functions which are also usable in the object
oriented code.
This document provides a very brief overview of the main features of modern
Fortran that are widely used in the AHA Model code.
## Object oriented programming and type-bound procedures ##
Stated simply, the object-oriented programming paradigm is based on the
notion of **object.** Here object is an entity that integrates **data**
and **procedures** that are implemented to manipulate these data. In the
simplest case, data can be considered as the "properties"" or "attributes"
that describe the object. Procedures that are linked with the object, on the
other hand, provide other derived attributes of the object or describe what
the object can "do".
Different objects can be arranged in various ways (e.g. form more complex
objects like arrays). For instance a population of agents (another object)
can be simply formed by arranging individual agents (other objects) into an
array. Various agents can also interact with each other.
For example, a single "agent" object is an entity having such attributes as
sex, spatial position, body mass, body length etc. It can also have such
boolean attributes as "is alive" (true or false). For any such object,
one can calculate instantaneous risk of predation and other transient derived
properties. Also, the agent can interact with objects of various other kinds.
For example, an agent can change its spatial position (its position attribute
is changed), approach a food item and "eat" it (basically, absorb the mass
attribute of the item, the item is destroyed thereafter). Agent can also do
many other things, e.g. "die". The functions that are linked to the object
are usually called **methods.**
When an instance of the object is created, it is initialised in a function
(e.g. `init`) that is often called the **constructor**. Another procedure is
sometimes implemented to destroy and deallocate the object, it is the
**destructor**.
Object-oriented code in modern Fortran is based on what is called
**type-bound procedures**.
Briefly, a derived type is declared using the `type` keyword; it can contain
several intrinsic and other derived types. Thus, a **data structure** is
implemented.
type, public :: SPATIAL_POINT
real(SRP) :: x, y, depth
character(len=LABEL_LENGTH) :: label
....
end type SPATIAL_POINT
Any **instances** of the object can be declared using `type` keyword.
type(SPATIAL_POINT) :: some_point, another_point
A procedure can then be declared that operates specifically on this type. The
first parameter `this` refers to the object that the procedure operates on.
The base object `this` is declared as `class` in the procedure, which allows
to accept any **extension** of the `this` object as the first parameter. This
is called "polymorphic objects."
Note that the other parameters (non `this`) can be declared as `class` or as
`type`. In the former case, the procedure could accept any extensions (the
procedure is then **polymorphic**) of the object, while in the latter, only
this specific `type` (non-polymorphic procedure).
Components of the object are separated from its name with the percent sign
`%`, e.g. the `x` coordinate is this\%x.
function spatial_distance_3d (this, other) result (distance_euclidean)
class(SPATIAL_POINT), intent(in) :: this
real(SRP) :: distance_euclidean
class(SPATIAL_POINT), intent(in) :: other
distance_euclidean = dist( [this%x, this%y, this%depth], &
[other%x, other%y, other%depth] )
end function spatial_distance_3d
The procedure is then included into the derived type declaration.
The name of the procedure that is implemented (e.g. `spatial_distance_3d`
in the example above) is not called directly in calculations and can be
declared `private`. Instead, a **public interface** name is declared in the
derived type that defines how the procedure should be called, in the example
below it is `distance`.
Note that the interface name can coincide for several different objects,
however the actual procedure name (`spatial_distance_3d`) must be unique
within the module that defines the derived type and its procedures.
type, public :: SPATIAL_POINT
real(SRP) :: x, y, depth
character(len=LABEL_LENGTH) :: label
....
contains
procedure, public :: distance => spatial_distance_3d
....
end type SPATIAL_POINT
Now, the procedure is called for the specific instance of the object (it comes
to the procedure as the `this` first "self" parameter) using the public
interface name (`distance`) rather than the "actual" procedure name
(`spatial_distance_3d`).
type(SPATIAL_POINT) :: point_a, point_b
...
distance_between_points = point_a%distance( point_b )
An **extension** object can be declared using `extends` keyword, that will
use all the properties and type-bound procedures of the base object and add
its own additional ones. This allows creating complex inheritance hierarchies
across objects.
type, public, extends(SPATIAL_POINT) :: SPATIAL_MOVING
! The following component adds an array of history of the object
! movements:
type(SPATIAL_POINT), dimension(HISTORY_SIZE_SPATIAL) :: history
...
contains
....
procedure, public :: go_up => spatial_moving_go_up
procedure, public :: go_down => spatial_moving_go_down
....
end type SPATIAL_MOVING
Thus, the structure of the module that defines an inheritance hierarchy of
objects and their type-bound functions is like this:
module SPATIAL_OBJECTS
! Declarations of objects:
type, public :: SPATIAL_POINT
real(SRP) :: x, y, depth
character(len=LABEL_LENGTH) :: label
....
contains
procedure, public :: distance => spatial_distance_3d
....
end type SPATIAL_POINT
....
type, public, extends(SPATIAL_POINT) :: SPATIAL_MOVING
! The following component adds an array of history of the object
! movements:
type(SPATIAL_POINT), dimension(HISTORY_SIZE_SPATIAL) :: history
...
contains
....
procedure, public :: go_up => spatial_moving_go_up
procedure, public :: go_down => spatial_moving_go_down
....
end type SPATIAL_MOVING
.....
! other declarations
.....
contains
! Here go all the procedures declared in this module
function spatial_distance_3d (this, other) result (distance_euclidean)
class(SPATIAL_POINT), intent(in) :: this
real(SRP) :: distance_euclidean
class(SPATIAL_POINT), intent(in) :: other
distance_euclidean = dist( [this%x, this%y, this%depth], &
[other%x, other%y, other%depth] )
end function spatial_distance_3d
....
! Any other procedures
......
end module SPATIAL_OBJECTS
Relationships between different kinds of objects can be represented graphically
in a [class diagram](http://158.37.63.57/doc/ar01s05.html#_class_diagram). See
[Object-oriented programming and modelling](http://158.37.63.57/doc/ar01s05.html)
section of the HEDTOOLS manual for more information.
## Elemental procedures ##
Modern Fortran includes a powerful concept of **elemental procedures**. Such
procedures (subroutines of functions) are declared using simple scalar
parameters. However, they can also accept parameters that are arbitrary
**arrays**.
There are strict limits on the procedures that can be `elemental`. Basically,
there should be no side effects in the procedure code (the code should only
affect the defined parameters that are in the parameter list), if the code
calls any procedures or functions, these should be declared as `pure` (free of
any side effects), each parameter must have explicit `intent` declared.
Notably, calling random numbers (`random_number`) or any input/output are
not allowed.
Here is an example of a simple elemental function:
elemental function add (a,b) result (sum)
real :: a, b, sum
sum = a + b
end function add
It can be used with scalar arguments as normal:
real :: x, y, z
z = add(x, y)
However, it can also be used with arrays and combinations of arrays and scalars:
real :: a
real, dimension(100,100) :: x, y, z1, z2
z1 = add(a, x) ! scalar added to array
z2 = add(x, y) ! two arrays are added element by element
In such a case, the function is executed in element-wise manner. For this
reason, the arrays should have conforming dimensionality and sizes.
Elemental procedures also work with the object oriented code. This allows
implementation complex algorithm in a very concise manner, avoiding code
duplication across different-sized arrays.
For example, the simple function below allows to get the spatial position of
a spatial object or any extension.
elemental function spatial_get_current_pos_3d_o(this) result(coordinates)
class(SPATIAL_POINT), intent(in) :: this
type(SPATIAL_POINT) :: coordinates
coordinates%x = this%x
coordinates%y = this%y
coordinates%depth = this%depth
end function spatial_get_current_pos_3d_o
However, it can also be used with an array of such spatial objects and returns
an array of their positions. For example, it can return an array of spatial
positions for a whole population of agents, or for its slice.
call LOG_DBG("Coordinates: " // TOSTR(parents%individual(1:10)%location()))
Using elemental procedures in the object oriented Fortran code allows to
substitute such loop-based code:
do i = 1, size(neighbours)
dist_here(i) = this%distance(neighbours(i))
end do
by a shorter, simpler (and usually better optimised compiled code) whole-array
based code:
dist_here = this%distance(neighbours)
## Whole array procedures ##
Most arithmetic functions in modern Fortran accept scalar as well as array
arguments (usually elemental). There are also many other useful intrinsic
array functions that allow writing very concise and easily understandable code.
An additional advantage is that these procedures are usually highly optimised
by the compiler and can be executed in parallel multi-threading mode if
automatic parallelisation is enabled.
! Maximum and minimum value of an array:
a = maxval(array)
b = minval(array)
! ... and their locations:
i = maxloc(array)
j = minloc(array)
! array sum:
total = sum(array)
! count elements with a mask:
i = count( x > y )
! masked array assignment:
where ( x == missing ) x = y
! indexed parallel array assignment:
forall ( i=1:popsize ) x(i) = 1.0/i
! ... and many more
Using such whole-array based functions allows implementation of very concise
and comprehensible code that is also highly optimised for multithreading
execution.
! Number of agents alive
call csv_record_append(file_record, count(parents%individual%is_alive()))
....
! Average body mass
call csv_record_append(file_record, average(parents%individual%body_mass))
## User defined operators ##
Modern Fortran allows to define arbitrary operators and redefine intrinsic
operators.
User defined operators are declared using `interface operator` and must
refer to a specific function that implements the operator.
interface operator (.above.)
procedure spatial_check_located_below
end interface operator (.above.)
....
....
function spatial_check_located_below(this, check_object) result (are_below)
class(SPATIAL_POINT), intent(in) :: this
class(SPATIAL_POINT), intent(in) :: check_object
logical :: are_below
if ( check_object%dpos() > this%dpos() ) then
are_below = .TRUE.
else
are_below = .FALSE.
end if
end function spatial_check_located_below
Once defined, such operators can be used with object oriented code like the
intrinsic operators:
do i=1, max
if ( this%perceive_consp%conspecifics_seen(i) .above. the_agent ) then
number_above = number_above + 1
end if
end do
or using whole-array operators even simpler:
number_above=count(this%perceive_consp%conspecifics_seen .above. the_agent)
User-defined operators can refer to elemental functions, however can be used
only with scalar arguments.
## The associate construct ##