diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..27143cb1220409cd7d7c1649f9c837155bd59f27 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +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." diff --git a/README.md b/README.md index 94f45f52b67afd610289fda433ec2d6cc14150b0..e80ef367b3760ab40de9ded94b62942c0f2eb179 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ framework. It is currently in the very early stages of development. ## Usage +*For the full documentation, open `docs/documentation.html` in a browser.* + ### Installation 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 ### 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 @@ -52,11 +54,15 @@ optional arguments: -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 -> julia runtests.jl +> make run # run a simulation with default values +> make test # run the test suite +> make docs # build the documentation +> make release # create a release ``` ### Running from within Julia diff --git a/docs/src/architecture.md b/docs/src/architecture.md index 7dccdb98b416343c07f2aac6e3b2ff31d9633cde..7fbbfdec8e866f9bc40c4b6d01c6b610202d457d 100644 --- a/docs/src/architecture.md +++ b/docs/src/architecture.md @@ -30,28 +30,34 @@ the `Animal`s in the model landscape.  -1. **The `model` object:** A cursory reading of the source code will quickly show that - 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), - and holds all state that is in any way relevant to a simulation run. (Persephone has - a strict "no global state" policy to avoid state-dependent bugs and allow parallelisation.) - The model object gives access to all agent instances (via `model[id]`, where `id` is the - unique identifier of this agent). It also stores the configuration (`model.settings`), - 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`). - (See [`initmodel`](@ref) for details.) - -2. **Model configuration/the [`@param`](@ref) macro:** The model is configured via a - [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). - An individual run can be configured using a user-defined configuration file, commandline - 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.settings["parameter"]`. 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.) +### The `model` object + +A cursory reading of the source code will quickly show that 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), +and holds all state that is in any way relevant to a simulation run. (Persephone has +a strict "no global state" policy to avoid state-dependent bugs and allow parallelisation.) +The model object gives access to all agent instances (via `model[id]`, where `id` is the +unique identifier of this agent). It also stores the configuration (`model.settings`), +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`). +(See [`initmodel`](@ref) for details.) + +For more information about working with agent objects, see the +[Agents.jl API](https://juliadynamics.github.io/Agents.jl/stable/api/). + +### Model configuration/the `@param` macro + +The model is configured via a [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). +An individual run can be configured using a user-defined configuration file, commandline +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" As `@param(parameter)` expands to `model.settings["parameter"]`, it can obviously @@ -60,28 +66,33 @@ the `Animal`s in the model landscape. 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). -3. **Output data:** Persephone can output model data into text files with a specified - 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.) +### Output data -4. **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`. (See [`src/core/landscape.jl`](https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/landscape.jl) - for details.) +Persephone can output model data into text files with a specified +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.) + +### 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) - 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` - 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). +### Random numbers and logging + +By default in Julia, the [random number generator](https://docs.julialang.org/en/v1/stdlib/Random/) +(RNG) and the [system logger](https://docs.julialang.org/en/v1/stdlib/Logging/#Logging.global_logger) +are two globally accessible variables. As Persephone needs to avoid all global data (since +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" 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) 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/). diff --git a/docs/src/developing.md b/docs/src/developing.md index 4e42cf72c8776fcdf10b38c13355a10bba434d5d..8451bf76cb54028d1ba77f27ed13b5c0c8a04ad8 100644 --- a/docs/src/developing.md +++ b/docs/src/developing.md @@ -2,16 +2,16 @@ ## 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). 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. -4. Run `example.sh` to make sure the model executes without crashing. Also run the test suite - (`cd test; julia runtests.jl`). +4. Run an example simulation and the test suite to make sure everything works without crashing + (`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 relevant tests to the test suite. @@ -22,11 +22,13 @@ 8. Repeat :-) -The Gitlab issue tracker can be used to create, discuss, and assign tasks, as well as to monitor -progress towards milestones/releases. Once we have a first release, we will start using -[semantic versioning](https://semver.org/). +The Gitlab [issue tracker](https://git.idiv.de/xo30xoqa/persephone/-/boards/373) can be used +to create, discuss, and assign tasks, as well as to monitor progress towards milestones/releases. +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. 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 *Tutorial on collaborating on Julia packages: [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 @@ -68,16 +93,3 @@ See [here](https://www.julia-vscode.org/). *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. - diff --git a/docs/src/index.md b/docs/src/index.md index 3b5ef53ab6342ef9185bdfe3e786aea95061ebbe..b7c8257194277bf3b2e08bce24863e30442fd907 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -13,7 +13,7 @@ an ecological submodels. ## Running the model -To run a single experiment, execute: +To run a single experiment, execute `run.jl`: ``` julia run.jl -c <CONFIG> @@ -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) ``` -!!! tip "Parameter scanning" +!!! info "Parameter scanning" 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 combination of parameters that you entered (i.e. do a full-factorial simulation experiment). -*Last updated: 2023-02-07 (commit 600bbd3)* +*Last updated: 2023-02-07 (commit b402c07)* diff --git a/src/nature/nature.jl b/src/nature/nature.jl index 9bdbd347644de485f3e161d6e2f7e39e1b5d69b4..4a2698f09329b37d5f5a9962ff4ab9cf1ac96cb1 100644 --- a/src/nature/nature.jl +++ b/src/nature/nature.jl @@ -65,7 +65,7 @@ Update an animal by one day, executing it's currently active phase function. """ function stepagent!(animal::Animal, model::AgentBasedModel) animal.age += 1 - animal.phase(animal,model) + animal.traits[animal.phase](animal,model) #FIXME end """