Something went wrong on our end
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
architecture.html 14.26 KiB
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><title>Source code architecture · Persefone</title><script data-outdated-warner src="assets/warner.js"></script><link href="https://cdnjs.cloudflare.com/ajax/libs/lato-font/3.0.0/css/lato-font.min.css" rel="stylesheet" type="text/css"/><link href="https://cdnjs.cloudflare.com/ajax/libs/juliamono/0.045/juliamono.min.css" rel="stylesheet" type="text/css"/><link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/fontawesome.min.css" rel="stylesheet" type="text/css"/><link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/solid.min.css" rel="stylesheet" type="text/css"/><link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/brands.min.css" rel="stylesheet" type="text/css"/><link href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.13.24/katex.min.css" rel="stylesheet" type="text/css"/><script>documenterBaseURL="."</script><script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" data-main="assets/documenter.js"></script><script src="siteinfo.js"></script><script src="../versions.js"></script><link class="docs-theme-link" rel="stylesheet" type="text/css" href="assets/themes/documenter-dark.css" data-theme-name="documenter-dark" data-theme-primary-dark/><link class="docs-theme-link" rel="stylesheet" type="text/css" href="assets/themes/documenter-light.css" data-theme-name="documenter-light" data-theme-primary/><script src="assets/themeswap.js"></script></head><body><div id="documenter"><nav class="docs-sidebar"><a class="docs-logo" href="index.html"><img src="assets/logo.png" alt="Persefone logo"/></a><div class="docs-package-name"><span class="docs-autofit"><a href="index.html">Persefone</a></span></div><form class="docs-search" action="search.html"><input class="docs-search-query" id="documenter-search-query" name="q" type="text" placeholder="Search docs"/></form><ul class="docs-menu"><li><a class="tocitem" href="index.html">Introduction</a></li><li><a class="tocitem" href="odd.html">Overview, Design, Details (ODD)</a></li><li><span class="tocitem">Developing</span><ul><li><a class="tocitem" href="developing.html">Developing Persefone</a></li><li><a class="tocitem" href="adapting.html">Adapting Persefone</a></li><li class="is-active"><a class="tocitem" href="architecture.html">Source code architecture</a><ul class="internal"><li class="toplevel"><a class="tocitem" href="#Model-components"><span>Model components</span></a></li><li class="toplevel"><a class="tocitem" href="#Important-implementation-details"><span>Important implementation details</span></a></li></ul></li><li><a class="tocitem" href="gis.html">GIS data</a></li><li><a class="tocitem" href="species-dsl.html">Defining new species</a></li></ul></li><li><span class="tocitem">Core</span><ul><li><a class="tocitem" href="simulation.html">Simulation</a></li><li><a class="tocitem" href="io.html">Input, Output, and Settings</a></li></ul></li><li><span class="tocitem">Nature</span><ul><li><a class="tocitem" href="nature.html">Nature</a></li><li><a class="tocitem" href="species.html">Species</a></li></ul></li><li><a class="tocitem" href="crops.html">Crop submodel</a></li><li><a class="tocitem" href="farm.html">Farm submodel</a></li></ul><div class="docs-version-selector field has-addons"><div class="control"><span class="docs-label button is-static is-size-7">Version</span></div><div class="docs-selector control is-expanded"><div class="select is-fullwidth is-size-7"><select id="documenter-version-selector"></select></div></div></div></nav><div class="docs-main"><header class="docs-navbar"><nav class="breadcrumb"><ul class="is-hidden-mobile"><li><a class="is-disabled">Developing</a></li><li class="is-active"><a href="architecture.html">Source code architecture</a></li></ul><ul class="is-hidden-tablet"><li class="is-active"><a href="architecture.html">Source code architecture</a></li></ul></nav><div class="docs-right"><a class="docs-edit-link" href="https://git.idiv.de/xo30xoqa/persephone/-/blob/master//docs/src/architecture.md#" title="Edit source"><span class="docs-icon fa"></span><span class="docs-label is-hidden-touch">Edit source</span></a><a class="docs-settings-button fas fa-cog" id="documenter-settings-button" href="#" title="Settings"></a><a class="docs-sidebar-button fa fa-bars is-hidden-desktop" id="documenter-sidebar-button" href="#"></a></div></header><article class="content" id="documenter-page"><h1 id="Source-code-architecture"><a class="docs-heading-anchor" href="#Source-code-architecture">Source code architecture</a><a id="Source-code-architecture-1"></a><a class="docs-heading-anchor-permalink" href="#Source-code-architecture" title="Permalink"></a></h1><h1 id="Model-components"><a class="docs-heading-anchor" href="#Model-components">Model components</a><a id="Model-components-1"></a><a class="docs-heading-anchor-permalink" href="#Model-components" title="Permalink"></a></h1><p><img src="assets/architecture.png" alt=""model architecture""/></p><p>Persefone is divided into four components, three of which are semi-independent submodels:</p><ol><li><p><code>core</code>: 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. (Eventually, it will also provide weather data.)</p></li><li><p><code>nature</code>: This is an individual-based model of species in agricultural landscapes. It defines the <a href="nature.html#Persefone.Animal"><code>Animal</code></a> 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.</p></li><li><p><code>farm</code>: This is an agent-based model of farmer decision making. It is not yet implemented, but will provide the <a href="farm.html#Persefone.Farmer"><code>Farmer</code></a> agent type.</p></li><li><p><code>crop</code>: This is a mathematical growth model for various crops. It is not yet implemented, but already provides the agent type <a href="crops.html#Persefone.FarmPlot"><code>FarmPlot</code></a>, representing one field and its associated extent and crop type.</p></li></ol><p>Conceptually, <code>core</code> provides functionality that is needed by all of the submodels. Decisions made by <code>Farmer</code>s affect the <code>FarmPlot</code>s they own, and (directly or indirectly) the <code>Animal</code>s in the model landscape.</p><h1 id="Important-implementation-details"><a class="docs-heading-anchor" href="#Important-implementation-details">Important implementation details</a><a id="Important-implementation-details-1"></a><a class="docs-heading-anchor-permalink" href="#Important-implementation-details" title="Permalink"></a></h1><p><img src="assets/model_object.png" alt=""the model object""/></p><h3 id="The-model-object"><a class="docs-heading-anchor" href="#The-model-object">The <code>model</code> object</a><a id="The-model-object-1"></a><a class="docs-heading-anchor-permalink" href="#The-model-object" title="Permalink"></a></h3><p>A cursory reading of the source code will quickly show that most functions take an <code>AgentBasedModel</code> object as one of their arguments. This is the key data structure of <a href="https://juliadynamics.github.io/Agents.jl/stable/tutorial/#.-The-model-1">Agents.jl</a>, and holds all state that is in any way relevant to a simulation run. (Persefone 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 <code>model[id]</code>, where <code>id</code> is the unique identifier of this agent). It also stores the configuration (<code>model.settings</code>), the landscape (<code>model.landscape</code>, a matrix of <a href="simulation.html#Persefone.Pixel"><code>Pixel</code></a> objects that store the local land cover, amongst other things), and the current simulation date (<code>model.date</code>). (See <a href="@ref"><code>initmodel</code></a> for details.)</p><p>For more information about working with agent objects, see the <a href="https://juliadynamics.github.io/Agents.jl/stable/api/">Agents.jl API</a>.</p><h3 id="Model-configuration/the-@param-macro"><a class="docs-heading-anchor" href="#Model-configuration/the-@param-macro">Model configuration/the <code>@param</code> macro</a><a id="Model-configuration/the-@param-macro-1"></a><a class="docs-heading-anchor-permalink" href="#Model-configuration/the-@param-macro" title="Permalink"></a></h3><p>The model is configured via a <a href="https://toml.io/en/">TOML</a> file, the default version of which is at <a href="https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/parameters.toml"><code>src/parameters.toml</code></a>. An individual run can be configured using a user-defined configuration file, commandline arguments, or function calls (when Persefone is used as a package rather than an application). During a model run, the <a href="io.html#Persefone.@param-Tuple{Any}"><code>@param</code></a> 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 <code>outdir</code> parameter belongs to the <code>[core]</code> section of the TOML file, and must therefore be referenced as <code>@param(core.outdir)</code>. (See <a href="https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/input.jl"><code>src/core/input.jl</code></a> for details.)</p><div class="admonition is-info"><header class="admonition-header">@param and other macros</header><div class="admonition-body"><p>As <code>@param(parameter)</code> expands to <code>model.settings["parameter"]</code>, it can obviously only be used in a context where the <code>model</code> object is actually available. (This is the case for most functions in Persefone, but not for all.) Similarly, many of the <code>nature</code> 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).</p></div></div><h3 id="Output-data"><a class="docs-heading-anchor" href="#Output-data">Output data</a><a id="Output-data-1"></a><a class="docs-heading-anchor-permalink" href="#Output-data" title="Permalink"></a></h3><p>Persefone can output model data into text files with a specified frequency (daily, monthly, yearly, or at the simulation end). Submodels can use <a href="@ref"><code>newdataoutput!</code></a> to plug into this system. For an example of how to use this, see <a href="https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/nature/ecologicaldata.jl"><code>src/nature/ecologicaldata.jl</code></a>. (See <a href="https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/output.jl"><code>src/core/output.jl</code></a> for details.)</p><h3 id="Farm-events"><a class="docs-heading-anchor" href="#Farm-events">Farm events</a><a id="Farm-events-1"></a><a class="docs-heading-anchor-permalink" href="#Farm-events" title="Permalink"></a></h3><p>The <a href="simulation.html#Persefone.FarmEvent"><code>FarmEvent</code></a> struct is used to communicate farming-related events between submodels. An event can be triggered with <a href="simulation.html#Persefone.createevent!"><code>createevent!</code></a> and affects all pixels within a <a href="crops.html#Persefone.FarmPlot"><code>FarmPlot</code></a>. (See <a href="https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/landscape.jl"><code>src/core/landscape.jl</code></a> for details.)</p><h3 id="Random-numbers-and-logging"><a class="docs-heading-anchor" href="#Random-numbers-and-logging">Random numbers and logging</a><a id="Random-numbers-and-logging-1"></a><a class="docs-heading-anchor-permalink" href="#Random-numbers-and-logging" title="Permalink"></a></h3><p>By default in Julia, the <a href="https://docs.julialang.org/en/v1/stdlib/Random/">random number generator</a> (RNG) and the <a href="https://docs.julialang.org/en/v1/stdlib/Logging/#Logging.global_logger">system logger</a> are two globally accessible variables. As Persefone needs to avoid all global data (since this would interfere with reproducibility in parallel runs), the <code>model</code> object stores a local logger and a local RNG. The local logger generally does not change the way the model uses <a href="https://docs.julialang.org/en/v1/stdlib/Logging/">log statements</a>, it is only relevant for some functions in <a href="https://git.idiv.de/xo30xoqa/persephone/-/blob/master/src/core/simulation.jl"><code>src/core/simulation.jl</code></a>.</p><div class="admonition is-info"><header class="admonition-header">Using the model RNG</header><div class="admonition-body"><p>Whenever you need to use a <a href="https://docs.julialang.org/en/v1/stdlib/Random/#Base.rand">random number</a>, you must use the <code>model.rng</code>. The easiest way to do this is with the <a href="io.html#Persefone.@rand-Tuple"><code>@rand</code></a> and <a href="io.html#Persefone.@shuffle!-Tuple{Any}"><code>@shuffle!</code></a> macros. (Note that these, too, require access to the <code>model</code> object.)</p></div></div></article><nav class="docs-footer"><a class="docs-footer-prevpage" href="adapting.html">« Adapting Persefone</a><a class="docs-footer-nextpage" href="gis.html">GIS data »</a><div class="flexbox-break"></div><p class="footer-message">Powered by <a href="https://github.com/JuliaDocs/Documenter.jl">Documenter.jl</a> and the <a href="https://julialang.org/">Julia Programming Language</a>.</p></nav></div><div class="modal" id="documenter-settings"><div class="modal-background"></div><div class="modal-card"><header class="modal-card-head"><p class="modal-card-title">Settings</p><button class="delete"></button></header><section class="modal-card-body"><p><label class="label">Theme</label><div class="select"><select id="documenter-themepicker"><option value="documenter-light">documenter-light</option><option value="documenter-dark">documenter-dark</option></select></div></p><hr/><p>This document was generated with <a href="https://github.com/JuliaDocs/Documenter.jl">Documenter.jl</a> version 0.27.23 on <span class="colophon-date" title="Sunday 28 May 2023 23:20">Sunday 28 May 2023</span>. Using Julia version 1.9.0-alpha1.</p></section><footer class="modal-card-foot"></footer></div></div></div></body></html>