# Source code architecture

# Model components

Persephone is divided into four components, three of which are semi-independent submodels:

1. `core`: This is the foundation of the model software, which sets up and executes
   simulation runs. It also reads in the configuration file and landscape maps, and
   provides data output functionality.

2. `nature`: This is an individual-based model of species in agricultural landscapes.
   It defines the [`Animal`](@ref) agent type, and a set of macros that can be used to rapidly
   create new species. It also includes ecological process functions that are useful
   for all species.

3. `farm`: This is an agent-based model of farmer decision making. It is not yet implemented,
   but will provide the [`Farmer`](@ref) agent type.

4. `crop`: This is a mathematical growth model for various crops. It is not yet implemented,
   but already provides the agent type [`FarmPlot`](@ref), representing one field and its associated
   extent and crop type.

Conceptually, `core` provides functionality that is needed by all of the submodels.
Decisions made by `Farmer`s affect the `FarmPlot`s they own, and (directly or indirectly)
the `Animal`s in the model landscape.

# Important implementation details

1. **The `model` object:** A cursory reading of the source code will quickly show that
   most functions take an `AgentBaseModel` 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`).

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`.
   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` for details.)

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`. (See `src/core/output.jl` for details.)

4. **Farm events:** The [`FarmEvent`](@ref) struct is used to communicate farming-related
   events between submodels. An event can be triggered with `createevent!()` and affects
   all pixels within a `FarmPlot`. (See `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 parallel runs), the `model` object stores
   a local logger and a local RNG. *Whenever you need to use a random number, you must
   use the `model.rng`! The easiest way to do this is with the [`@rand`](@ref) and 
   [`@shuffle!`](@ref) macros.* The local logger generally does not change the way the model
   uses [log statements](https://docs.julialang.org/en/v1/stdlib/Logging/), this is only
   important in some functions in `src/core/simulation.jl`.

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/).