Skip to content
Snippets Groups Projects
Commit d4e43d75 authored by xo30xoqa's avatar xo30xoqa
Browse files

Added Makefile

This closes issue #50
parent b402c07f
No related branches found
No related tags found
No related merge requests found
Makefile 0 → 100644
SHELL = /bin/bash
.PHONY: run test docs release install
run:
# running example simulation
if [ -d "example_results" ]; then rm -r example_results; fi
./run.jl -o example_results
src/analysis/analyse_nature.R example_results
test:
# running test suite
cd test; julia runtests.jl
commit = $(shell git log --format="%cd (commit %h)" --date=short -1)
docs:
# building documentation
# include a date stamp with the latest commit
sed -i -e "s/\*Last updated:.*/\*Last updated: ${commit}\*/" docs/src/index.md
cd docs; julia builddocs.jl
release:
echo "Not yet implemented."
install:
echo: "Not relevant. Use `julia run.jl` to run Persephone."
...@@ -14,6 +14,8 @@ framework. It is currently in the very early stages of development. ...@@ -14,6 +14,8 @@ framework. It is currently in the very early stages of development.
## Usage ## Usage
*For the full documentation, open `docs/documentation.html` in a browser.*
### Installation ### Installation
Install the latest version of the [Julia](https://julialang.org/downloads/) programming Install the latest version of the [Julia](https://julialang.org/downloads/) programming
...@@ -24,10 +26,10 @@ To install package dependencies, open a Julia REPL in this folder and run ...@@ -24,10 +26,10 @@ To install package dependencies, open a Julia REPL in this folder and run
### Running from the commandline ### Running from the commandline
This is the normal mode of operation. Simply execute `run.jl`, typically like so (in Linux): This is the normal mode of operation. Simply execute `run.jl` in a terminal, typically like so:
``` ```
> ./run.jl -c <config> > julia run.jl -c <config>
``` ```
where `<config>` specifies the configuration file to use. The recommended workflow is where `<config>` specifies the configuration file to use. The recommended workflow is
...@@ -52,11 +54,15 @@ optional arguments: ...@@ -52,11 +54,15 @@ optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
``` ```
To run the test suite, do the following: To run the test suite, switch to the `test` directory and execute `runtests.jl`.
If you are on Linux or MacOS, you can also use `make`:
``` ```
> cd test > make run # run a simulation with default values
> julia runtests.jl > make test # run the test suite
> make docs # build the documentation
> make release # create a release
``` ```
### Running from within Julia ### Running from within Julia
......
...@@ -30,28 +30,34 @@ the `Animal`s in the model landscape. ...@@ -30,28 +30,34 @@ the `Animal`s in the model landscape.
!["the model object"](assets/model_object.png) !["the model object"](assets/model_object.png)
1. **The `model` object:** A cursory reading of the source code will quickly show that ### The `model` object
most functions take an `AgentBasedModel` object as one of their arguments. This is the
key data structure of [Agents.jl](https://juliadynamics.github.io/Agents.jl/stable/tutorial/#.-The-model-1), A cursory reading of the source code will quickly show that most functions take an
and holds all state that is in any way relevant to a simulation run. (Persephone has `AgentBasedModel` object as one of their arguments. This is the key data structure
a strict "no global state" policy to avoid state-dependent bugs and allow parallelisation.) of [Agents.jl](https://juliadynamics.github.io/Agents.jl/stable/tutorial/#.-The-model-1),
The model object gives access to all agent instances (via `model[id]`, where `id` is the and holds all state that is in any way relevant to a simulation run. (Persephone has
unique identifier of this agent). It also stores the configuration (`model.settings`), a strict "no global state" policy to avoid state-dependent bugs and allow parallelisation.)
the landscape (`model.landscape`, a matrix of [`Pixel`](@ref) objects that store the local The model object gives access to all agent instances (via `model[id]`, where `id` is the
land cover, amongst other things), and the current simulation date (`model.date`). unique identifier of this agent). It also stores the configuration (`model.settings`),
(See [`initmodel`](@ref) for details.) the landscape (`model.landscape`, a matrix of [`Pixel`](@ref) objects that store the local
land cover, amongst other things), and the current simulation date (`model.date`).
2. **Model configuration/the [`@param`](@ref) macro:** The model is configured via a (See [`initmodel`](@ref) for details.)
[TOML](https://toml.io/en/) file, the default version of which is at
[`src/parameters.toml`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/parameters.toml). For more information about working with agent objects, see the
An individual run can be configured using a user-defined configuration file, commandline [Agents.jl API](https://juliadynamics.github.io/Agents.jl/stable/api/).
arguments, or function calls (when Persephone is used as a package rather than an application).
During a model run, the `@param(parameter)` macro can be used as a short-hand for ### Model configuration/the `@param` macro
`model.settings["parameter"]`. Note that parameter names are prepended with the name
of the component they are associated with. For example, the `outdir` parameter belongs The model is configured via a [TOML](https://toml.io/en/) file, the default version of which is at
to the `[core]` section of the TOML file, and must therefore be referenced as [`src/parameters.toml`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/parameters.toml).
`@param(core.outdir)`. (See [`src/core/input.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/input.jl) An individual run can be configured using a user-defined configuration file, commandline
for details.) arguments, or function calls (when Persephone is used as a package rather than an application).
During a model run, the [`@param`](@ref) macro can be used to access parameter values.
Note that parameter names are prepended with the name of the component they are associated
with. For example, the `outdir` parameter belongs to the `[core]` section of the TOML file,
and must therefore be referenced as `@param(core.outdir)`. (See
[`src/core/input.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/input.jl)
for details.)
!!! info "@param and other macros" !!! info "@param and other macros"
As `@param(parameter)` expands to `model.settings["parameter"]`, it can obviously As `@param(parameter)` expands to `model.settings["parameter"]`, it can obviously
...@@ -60,28 +66,33 @@ the `Animal`s in the model landscape. ...@@ -60,28 +66,33 @@ the `Animal`s in the model landscape.
macros depend on specific variables being available where they are called, and can macros depend on specific variables being available where they are called, and can
therefore only be used in specific contexts (this is indicated in their documentation). therefore only be used in specific contexts (this is indicated in their documentation).
3. **Output data:** Persephone can output model data into text files with a specified ### Output data
frequency (daily, monthly, yearly, or at the simulation end). Submodels can use
[`newdataoutput!`](@ref) to plug into this system. For an example of how to use this,
see [`src/nature/ecologicaldata.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/nature/ecologicaldata.jl).
(See [`src/core/output.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/output.jl) for details.)
4. **Farm events:** The [`FarmEvent`](@ref) struct is used to communicate farming-related Persephone can output model data into text files with a specified
events between submodels. An event can be triggered with [`createevent!`](@ref) and affects frequency (daily, monthly, yearly, or at the simulation end). Submodels can use
all pixels within a `FarmPlot`. (See [`src/core/landscape.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/landscape.jl) [`newdataoutput!`](@ref) to plug into this system. For an example of how to use this, see
for details.) [`src/nature/ecologicaldata.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/nature/ecologicaldata.jl).
(See [`src/core/output.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/output.jl) for details.)
### Farm events
The [`FarmEvent`](@ref) struct is used to communicate farming-related events between
submodels. An event can be triggered with [`createevent!`](@ref) and affects all pixels
within a [`FarmPlot`](@ref). (See
[`src/core/landscape.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/landscape.jl)
for details.)
5. **Random numbers and logging:** By default in Julia, the random number generator (RNG) ### Random numbers and logging
and the system logger are two globally accessible variables. As Persephone needs to avoid
all global data (as this would interfere with reproducibility in parallel runs), the `model` By default in Julia, the [random number generator](https://docs.julialang.org/en/v1/stdlib/Random/)
object stores a local logger and a local RNG. The local logger generally does not change the (RNG) and the [system logger](https://docs.julialang.org/en/v1/stdlib/Logging/#Logging.global_logger)
way the model uses [log statements](https://docs.julialang.org/en/v1/stdlib/Logging/), it is are two globally accessible variables. As Persephone needs to avoid all global data (since
only relevant for some functions in [`src/core/simulation.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/simulation.jl). this would interfere with reproducibility in parallel runs), the `model` object stores a
local logger and a local RNG. The local logger generally does not change the way the
model uses [log statements](https://docs.julialang.org/en/v1/stdlib/Logging/), it is
only relevant for some functions in [`src/core/simulation.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/simulation.jl).
!!! info "Using the model RNG" !!! info "Using the model RNG"
Whenever you need to use a [random number](https://docs.julialang.org/en/v1/stdlib/Random/#Base.rand), Whenever you need to use a [random number](https://docs.julialang.org/en/v1/stdlib/Random/#Base.rand),
you must use the `model.rng`. The easiest way to do this is with the [`@rand`](@ref) you must use the `model.rng`. The easiest way to do this is with the [`@rand`](@ref)
and [`@shuffle!`](@ref) macros. (Note that these, too, require access to the `model` object.) and [`@shuffle!`](@ref) macros. (Note that these, too, require access to the `model` object.)
6. **Working with agents:** For more information about working with agent objects, see the
[Agents.jl API](https://juliadynamics.github.io/Agents.jl/stable/api/).
...@@ -2,16 +2,16 @@ ...@@ -2,16 +2,16 @@
## Workflow ## Workflow
1. Pull the current development version from the master branch on Gitlab: 1. Pull the current version from the master branch on Gitlab:
[https://git.idiv.de/xo30xoqa/persephone](https://git.idiv.de/xo30xoqa/persephone). [https://git.idiv.de/xo30xoqa/persephone](https://git.idiv.de/xo30xoqa/persephone).
2. If you are working on a new feature, create a new branch to avoid breaking the `master` branch. 2. If you are working on a new feature, create a new branch to avoid breaking the `master` branch.
(The `master` branch should always be in a runnable and (as far as possible) error-free state.) (The `master` branch on Github should always be in a runnable and error-free state.)
3. Implement your changes. 3. Implement your changes.
4. Run `example.sh` to make sure the model executes without crashing. Also run the test suite 4. Run an example simulation and the test suite to make sure everything works without crashing
(`cd test; julia runtests.jl`). (`make run` and `make test` on Linux, or execute `run.jl` and `test/runtests.jl` manually.)
5. Commit your work frequently, and try to keep each commit small. Don't forget to add 5. Commit your work frequently, and try to keep each commit small. Don't forget to add
relevant tests to the test suite. relevant tests to the test suite.
...@@ -22,11 +22,13 @@ ...@@ -22,11 +22,13 @@
8. Repeat :-) 8. Repeat :-)
The Gitlab issue tracker can be used to create, discuss, and assign tasks, as well as to monitor The Gitlab [issue tracker](https://git.idiv.de/xo30xoqa/persephone/-/boards/373) can be used
progress towards milestones/releases. Once we have a first release, we will start using to create, discuss, and assign tasks, as well as to monitor progress towards milestones/releases.
[semantic versioning](https://semver.org/). Once we have a first release, we will start using [semantic versioning](https://semver.org/).
## Agents.jl ## Libraries
### Agents.jl
Our model uses [Agents.jl](https://juliadynamics.github.io/Agents.jl/stable/) as a framework. Our model uses [Agents.jl](https://juliadynamics.github.io/Agents.jl/stable/) as a framework.
Their [repository](https://github.com/JuliaDynamics/Agents.jl) can be used to inspect the source Their [repository](https://github.com/JuliaDynamics/Agents.jl) can be used to inspect the source
...@@ -36,6 +38,29 @@ code or submit bug reports (the authors are quick to respond). Questions can be ...@@ -36,6 +38,29 @@ code or submit bug reports (the authors are quick to respond). Questions can be
*Tutorial on collaborating on Julia packages: *Tutorial on collaborating on Julia packages:
[https://www.matecdev.com/posts/julia-package-collaboration.html](https://www.matecdev.com/posts/julia-package-collaboration.html).* [https://www.matecdev.com/posts/julia-package-collaboration.html](https://www.matecdev.com/posts/julia-package-collaboration.html).*
### Revise.jl
[`Revise.jl`](https://timholy.github.io/Revise.jl/stable/) allows one to reload code
without restarting the Julia interpreter. Get it with `Pkg.add("Revise")`, then
add `using Revise` to `.julia/config/startup.jl` to have it automatically available.
### Test
Persephone uses the inbuilt Julia [testing framework](https://docs.julialang.org/en/v1/stdlib/Test/).
All new functions should have appropriate tests written for them in the appropriate
file in the `test` directory. (See [`test/runtests.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/test/runtests.jl)
for details.) There are three ways to run the test suite: in the terminal, executing
`make test` or `cd test; julia runtests.jl`; or in the Julia REPL,
`Pkg.activate("."); Pkg.test()`.
### Documenter.jl
The HTML documentation is generated using [Documenter.jl](https://documenter.juliadocs.org).
Therefore, all new functions should have docstrings attached. New files need to be integrated
into the relevant documentation source files in `docs/src`, and if necessary into
[`docs/builddocs.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/docs/builddocs.jl).
To build the documentation, run `make docs`, or `cd docs; julia builddocs.jl`
(if using the latter, don't forget to update the date and commit in `docs/src/index.md`).
## Julia editors ## Julia editors
...@@ -68,16 +93,3 @@ See [here](https://www.julia-vscode.org/). ...@@ -68,16 +93,3 @@ See [here](https://www.julia-vscode.org/).
*TODO: add more detail.* *TODO: add more detail.*
### Other useful stuff
1. [`Revise.jl`](https://timholy.github.io/Revise.jl/stable/) allows one to reload code
without restarting the Julia interpreter. Get it with `Pkg.add("Revise")`, then
add `using Revise` to `.julia/config/startup.jl` to have it automatically available.
2. [`git-bug`](https://github.com/MichaelMure/git-bug) is a commandline bug tracker that
integrates directly with git. It can also be used as a local interface to Gitlab issues.
To install on Linux, download the [binary](https://github.com/MichaelMure/git-bug/releases/tag/v0.8.0),
copy it to `/usr/local/bin/git-bug`, and set it as executable with `chmod +x
/usr/local/bin/git-bug`. To set up Gitlab integration, run `git bug bridge configure`
from within the relevant repository.
...@@ -13,7 +13,7 @@ an ecological submodels. ...@@ -13,7 +13,7 @@ an ecological submodels.
## Running the model ## Running the model
To run a single experiment, execute: To run a single experiment, execute `run.jl`:
``` ```
julia run.jl -c <CONFIG> julia run.jl -c <CONFIG>
...@@ -74,10 +74,10 @@ indoutfreq = "end" # output frequency individual-level data, daily/monthly/yearl ...@@ -74,10 +74,10 @@ indoutfreq = "end" # output frequency individual-level data, daily/monthly/yearl
cropmodel = "linear" # crop growth model to use, "linear" or "aquacrop" (not yet implemented) cropmodel = "linear" # crop growth model to use, "linear" or "aquacrop" (not yet implemented)
``` ```
!!! tip "Parameter scanning" !!! info "Parameter scanning"
You can set any parameter to a list of different values, e.g. `seed = [1,2,3]`. You can set any parameter to a list of different values, e.g. `seed = [1,2,3]`.
Persephone will then set up and run multiple simulations, one for every possible Persephone will then set up and run multiple simulations, one for every possible
combination of parameters that you entered (i.e. do a full-factorial simulation combination of parameters that you entered (i.e. do a full-factorial simulation
experiment). experiment).
*Last updated: 2023-02-07 (commit 600bbd3)* *Last updated: 2023-02-07 (commit b402c07)*
...@@ -65,7 +65,7 @@ Update an animal by one day, executing it's currently active phase function. ...@@ -65,7 +65,7 @@ Update an animal by one day, executing it's currently active phase function.
""" """
function stepagent!(animal::Animal, model::AgentBasedModel) function stepagent!(animal::Animal, model::AgentBasedModel)
animal.age += 1 animal.age += 1
animal.phase(animal,model) animal.traits[animal.phase](animal,model) #FIXME
end end
""" """
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment