Skip to content
Snippets Groups Projects
Select Git revision
  • 0366f2005c28163b74c496f24de64b44b4fd29df
  • master default protected
  • development
  • 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
20 results

nature.jl

  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    nature.jl 4.40 KiB
    ### Persefone.jl - a model of agricultural landscapes and ecosystems in Europe.
    ###
    ### This file is responsible for managing the animal modules and contains functions
    ### and types integrating the nature submodel with the rest of Persefone.
    ###
    
    
    ## An enum used to assign a sex to each animal
    @enum Sex hermaphrodite male female
    #XXX hermaphrodite probably is not needed and its implementation is iffy
    
    """
        Animal
    
    This is the generic agent type for all animals. Individual species are created
    using the [`@species`](@ref) macro. In addition to user-defined, species-specific
    fields, all species contain the following fields:
    
    - `id` An integer unique identifier for this individual.
    - `sex` male, female, or hermaphrodite.
    - `parents` The IDs of the individual's parents.
    - `pos` An (x, y) coordinate tuple.
    - `age` The age of the individual in days.
    - `phase` The update function to be called during the individual's current life phase.
    - `energy` A [DEBparameters](@ref) struct for calculating energy budgets.
    - `offspring` A vector containing the IDs of an individual's children.
    - `territory` A vector of coordinates that comprise the individual's territory.
    """
    abstract type Animal <: ModelAgent end
    
    """
        speciesof(animal)
    
    Return the species name of this animal as a string.
    """
    function speciesof(a::Union{Animal,Type})
        # strip out the module name if necessary (`Persefone.<species>`)
        (a isa Animal) && (a = typeof(a))
        spstrings = split(string(a), ".")
        length(spstrings) == 1 ? String(spstrings[1]) : String(spstrings[2])
    end
    
    """
        speciestype(name)
    
    Return the Type of this species.
    """
    function speciestype(name::String)
        # get the species Type from its namestring by looking in the module namespace
        speciestype = nothing
        for var in names(Persefone, all=true)
            if string(var) == name && getfield(Persefone, var) isa Type
                speciestype = getfield(Persefone, var)
                break
            end
        end
        isnothing(speciestype) && @error("Species $name is not defined.")
        speciestype
    end
        
    """
        animalid(animal)
    
    A small utility function to return a string with the species name and ID of an animal.
    """
    function animalid(a::Animal)
        return "$(speciesof(a)) $(a.id)"
    end
    
    """
        create!(animal, model)
    
    The `create!` function is called for every individual at birth or at model initialisation.
    Species must use [`@create`](@ref) to define a species-specific method. This is the fall-
    back method, in case none is implemented for a species.
    """
    function create!(a::Animal, model::SimulationModel)
        @warn "Species $(speciesof(a)) has no create!() method. Use `@create` to add one."
    end
    
    """
        stepagent!(animal, model)
    
    Update an animal by one day, executing it's currently active phase function.
    """
    function stepagent!(animal::Animal, model::SimulationModel)
        animal.age += 1
        animal.phase(animal, model)
    end
    
    """
        initnature!(model)
    
    Initialise the model with all simulated animal populations.
    """
    function initnature!(model::SimulationModel)
        # The config file determines which species are simulated in this run
        for speciesname in @param(nature.targetspecies)
            # Call each species' initialisation function
            initpopulation!(speciesname, model)
        end
        # Initialise the data output
        initecologicaldata(model)
    end
    
    """
        updatenature!(model)
    
    Run processes that affect all animals.
    """
    function updatenature!(model::SimulationModel)
        # Update all animals. Dead animals are replaced by `nothing`, we can skip these.
        #XXX I assume that keeping all those `nothing`s in the animal vector won't lead
        # to memory bloat, but I will have to check that.
        for a in model.animals #XXX randomise the order?
            !isnothing(a) && stepagent!(a, model)
        end
        # The migrant pool is sorted by date of return, so we can simply look at the top
        # of the stack to check whether any animals are returning today.
        while !isempty(model.migrants) && model.migrants[1].second == model.date
            returnee = model.migrants[1].first
            model.animals[returnee.id] = returnee
            @debug "$(animalid(returnee)) has returned."
            deleteat!(model.migrants, 1)
        end
    end
    
    """
        killallanimals!(model)
    
    Remove all animal individuals from the simulation.
    """
    function killallanimals!(model)
        for a in model.animals
            kill!(a, model)
        end
        model.migrants = Vector{Pair{Animal, Date}}()
        model.animals = Vector{Union{Animal,Nothing}}()
        return
    end