Skip to content
Snippets Groups Projects
Select Git revision
  • 57264494452da78432cb0fefa16932e606c6eef6
  • master default protected
  • development
  • marco-development
  • fix-missing-weatherdata
  • fix-eichsfeld-weather
  • marco/dev-aquacrop
  • precompile-statements
  • precompile-tools
  • tmp-faster-loading
  • skylark
  • testsuite
  • code-review
  • v0.7.0
  • v0.6.1
  • v0.6.0
  • v0.5.5
  • v0.5.4
  • v0.5.3
  • v0.5.2
  • v0.2
  • v0.3.0
  • v0.4.1
  • v0.5
24 results

species-dsl.html

Blame
  • Daniel Vedder's avatar
    xo30xoqa authored
    57264494
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    species-dsl.html 13.70 KiB
    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><title>Defining new species · 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><a class="tocitem" href="architecture.html">Source code architecture</a></li><li><a class="tocitem" href="gis.html">Maps and weather data</a></li><li class="is-active"><a class="tocitem" href="species-dsl.html">Defining new species</a><ul class="internal"><li><a class="tocitem" href="#The-Persefone-species-DSL"><span>The Persefone species DSL</span></a></li><li><a class="tocitem" href="#Implementation-details"><span>Implementation details</span></a></li></ul></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="energy.html">Dynamic Energy Budgets</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="species-dsl.html">Defining new species</a></li></ul><ul class="is-hidden-tablet"><li class="is-active"><a href="species-dsl.html">Defining new species</a></li></ul></nav><div class="docs-right"><a class="docs-edit-link" href="https://git.idiv.de/xo30xoqa/persephone/-/blob/master//docs/src/species-dsl.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="Defining-new-species"><a class="docs-heading-anchor" href="#Defining-new-species">Defining new species</a><a id="Defining-new-species-1"></a><a class="docs-heading-anchor-permalink" href="#Defining-new-species" title="Permalink"></a></h1><h2 id="The-Persefone-species-DSL"><a class="docs-heading-anchor" href="#The-Persefone-species-DSL">The Persefone species DSL</a><a id="The-Persefone-species-DSL-1"></a><a class="docs-heading-anchor-permalink" href="#The-Persefone-species-DSL" title="Permalink"></a></h2><p>In order to make implementing new species as easy as possible, Persefone includes a <a href="https://doi.org/10.1016/j.ecoinf.2015.02.005">domain-specific language</a> (DSL) built from a collection of macros and functions.</p><p>Here is an example of what this looks like, using a hypothetical mermaid species:</p><pre><code class="language-julia hljs">@species Mermaid begin
        ageofmaturity = 2
        pesticidemortality = 1.0
        @initialise(@habitat(@landcover() == water), pairs=true)
    	
        @phase life begin
            @debug &quot;$(animalid(animal)) is swimming happily in its pond.&quot;
            @respond pesticide @kill(@trait(pesticidemortality), &quot;poisoning&quot;)
            @respond harvest @setphase(drought)
            @debug &quot;Animal: $animal&quot;
            if @trait(sex) == female &amp;&amp; @countanimals() &lt; 3 &amp;&amp;
                @trait(age) &gt;= @trait(ageofmaturity) &amp;&amp; @landcover() == water
                @reproduce()
            end
        end
    	
        @phase drought begin
            n = sum(1 for a in @neighbours(0))
            @debug &quot;$(animalid(animal)) is experiencing drought with $n neighbour(s).&quot;
            @respond sowing @setphase(life)
        end
    end</code></pre><p>The two most important macros are <a href="nature.html#Persefone.@species-Tuple{Any, Any}"><code>@species</code></a> and <a href="nature.html#Persefone.@phase-Tuple{Any, Any}"><code>@phase</code></a>,  followed by <a href="nature.html#Persefone.@initialise-Tuple{Any, Vararg{Any}}"><code>@initialise</code></a>, <a href="nature.html#Persefone.@trait-Tuple{Any}"><code>@trait</code></a>, <a href="nature.html#Persefone.@respond-Tuple{Any, Any}"><code>@respond</code></a>,  and <a href="nature.html#Persefone.@habitat-Tuple{Any}"><code>@habitat</code></a>. Other macros provide convenience wrappers for common  functions. (See <code>src/nature/nature.jl</code> for details.)</p><p>The top-level macro is <a href="nature.html#Persefone.@species-Tuple{Any, Any}"><code>@species</code></a>. This takes two arguments: a species  name and a definition block (enclosed in <code>begin</code> and <code>end</code> tags). At the start of the definition block, species-specific variables can be defined that should be available throughout a species&#39; lifetime. Code in this section has access to the <code>model</code> object and can thus reference the current model state. In this section, the user also has to call the <a href="nature.html#Persefone.@initialise-Tuple{Any, Vararg{Any}}"><code>@initialise</code></a> macro. This wraps the <a href="@ref"><code>initpopulation</code></a> function, and takes a habitat descriptor (see <a href="nature.html#Persefone.@habitat-Tuple{Any}"><code>@habitat</code></a> below) and several  options to specify how the species&#39; population should be distributed in the landscape during model initialisation.</p><p>Following this section, each species must define one or more <a href="nature.html#Persefone.@phase-Tuple{Any, Any}"><code>@phase</code></a> blocks. The concept behind this is that species show different behaviours at different phases of their lifecycle. Each <code>@phase</code> block defines the behaviour in one of these phases. (Technically, it defines a function that will be called daily, so long as the species&#39; <code>phase</code> variable is set to the name of this phase.) Code in this section has access to the <code>model</code> object as well as an <code>animal</code> object, which is the currently active animal agent. Properties of the <code>animal</code> agent, regardless of whether they were defined by the user or by Persefone, can be accessed using the <a href="nature.html#Persefone.@trait-Tuple{Any}"><code>@trait</code></a> macro. Within a phase block, <a href="nature.html#Persefone.@respond-Tuple{Any, Any}"><code>@respond</code></a>  can be used to define the species&#39; response to a <a href="@ref"><code>FarmEvent</code></a> that affects  the species&#39; current location, while a variety of other macros provide wrappers to  ecological process functions from <code>src/nature/populations.jl</code>.</p><p>Another important macro is <a href="nature.html#Persefone.@habitat-Tuple{Any}"><code>@habitat</code></a>. This defines a &quot;habitat descriptor&quot;, i.e. a predicate function that tests whether or not a given landscape pixel is  suitable for a specified purpose. Such habitat descriptors are used as arguments to various functions, for example for population initialisation or movement. The argument to <code>@habitat</code> consists of a logical expression, which has access to the animal&#39;s current position (the <code>pos</code> tuple variable) and the <code>model</code>. Various macros are available to easily reference information about the current location, such as <a href="nature.html#Persefone.@landcover-Tuple{}"><code>@landcover</code></a> or <a href="nature.html#Persefone.@distancetoedge-Tuple{}"><code>@distancetoedge</code></a>.</p><h2 id="Implementation-details"><a class="docs-heading-anchor" href="#Implementation-details">Implementation details</a><a id="Implementation-details-1"></a><a class="docs-heading-anchor-permalink" href="#Implementation-details" title="Permalink"></a></h2><p>Due to a known <a href="https://juliadynamics.github.io/Agents.jl/stable/performance_tips/#Avoid-Unions-of-many-different-agent-types-(temporary!)-1">performance problem</a>  with multi-agent models, the underlying implementation of species is  rather complicated (see <code>src/nature/nature.jl</code> for details.)</p><p>Rather than creating a new type/struct for each species, all <a href="@ref">Animal</a> agents have the same type. Instead, they are differentiated by a <code>traits</code> dict, which stores both species-specific parameters and run-time variables. Note that due to a redefinition of the <code>getproperty()/setproperty!()</code> methods, variables from the trait dict can be accessed and modified just like normal struct fields (i.e. although <code>phase</code> is defined in the dict, not the struct, <code>animal.phase = &quot;newphase&quot;</code> works just fine - one does not have to use <code>animal.traits[&quot;phase&quot;] = &quot;newphase&quot;</code>.)</p><p>Under the hood, the <a href="nature.html#Persefone.@species-Tuple{Any, Any}"><code>@species</code></a> macro generates a function (with the name of the species), which in turn creates the trait dict when called. Thus, adding a new animal agent to the model involves instantiating an <a href="nature.html#Persefone.Animal"><code>Animal</code></a> object, then calling the relevant species function and attaching the returned dict to the agent object.</p><p>Similarly, the <a href="nature.html#Persefone.@phase-Tuple{Any, Any}"><code>@phase</code></a> macro too works by defining a new function, which is stored in the species&#39; trait dict. These functions take an animal object and the model object as input, and define what the species does during its daily update.</p><p>Once again, <a href="nature.html#Persefone.@habitat-Tuple{Any}"><code>@habitat</code></a> creates a function that takes <code>model</code> and <code>pos</code> as input and returns a boolean response. Functions that require a habitat descriptor thus take in this (anonymous) function and call it internally.</p><p>Finally, the <a href="nature.html#Persefone.@initialise-Tuple{Any, Vararg{Any}}"><code>@initialise</code></a> macro is a wrapper around <a href="@ref"><code>initpopulation</code></a>, which (yet again) creates a function that specifies how a species&#39; population is to be initialised at the beginning of a simulation run. This function is stored in the species trait dict and accessed during model setup.</p></article><nav class="docs-footer"><a class="docs-footer-prevpage" href="gis.html">« Maps and weather data</a><a class="docs-footer-nextpage" href="simulation.html">Simulation »</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="Thursday 27 July 2023 10:12">Thursday 27 July 2023</span>. Using Julia version 1.9.1.</p></section><footer class="modal-card-foot"></footer></div></div></div></body></html>