Skip to content
Snippets Groups Projects
Select Git revision
  • 7201cda8bb44ecc3eafc2ba70f0c243998e786f0
  • master default protected
  • beta
  • dev
  • andrewssobral-patch-1
  • update
  • thomas-fork
  • 2.0
  • v3.2.0
  • v3.1.0
  • v3.0
  • bgslib_py27_ocv3_win64
  • bgslib_java_2.0.0
  • bgslib_console_2.0.0
  • bgslib_matlab_win64_2.0.0
  • bgslib_qtgui_2.0.0
  • 2.0.0
  • bgs_console_2.0.0
  • bgs_matlab_win64_2.0.0
  • bgs_qtgui_2.0.0
  • v1.9.2_x86_mfc_gui
  • v1.9.2_x64_java_gui
  • v1.9.2_x86_java_gui
23 results

run_video.bat

  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    marbled_white.jl 10.91 KiB
    ### Persefone.jl - a model of agricultural landscapes and ecosystems in Europe.
    ###
    ### This file holds the code for the Marbled White (Melanargia galathea).
    ###
    
    ##TODO
    ## - population initialisation
    ## - agglomeration?
    
    
    """
        Marbled White
    
    *Melanargia galathea* is a grassland specialist butterfly.
    
    **Sources:**
        - Baguette et al. (2000). Population spatial structure and migration
          of three butterfly species within the same habitat network: Consequences
          for conservation. Journal of Applied Ecology, 37(1), 100–108.
          https://doi.org/10.1046/j.1365-2664.2000.00478.x
        - Dennis (Ed.). (1992). The ecology of butterflies in Britain.
          Oxford University Press.
        - Ebert & Rennwald (1991). Die Schmetterlinge Baden-Württembergs,
          Bd.2, Tagfalter: Satyridae, Libytheidae, Lycaenidae, Hesperiidae.
          Verlag Eugen Ulmer.
        - Evans et al. (2019). Integrating the influence of weather into mechanistic
          models of butterfly movement. Movement Ecology, 7(1), 24.
          https://doi.org/10.1186/s40462-019-0171-7
        - Gotthard et al. (2007). What Keeps Insects Small? Time Limitation during
          Oviposition Reduces the Fecundity Benefit of Female Size in a Butterfly.
          The American Naturalist, 169(6), 768–779. https://doi.org/10.1086/516651
        - Hannappel & Fischer (2020). Grassland intensification strongly reduces
          butterfly diversity in the Westerwald mountain range, Germany. Journal
          of Insect Conservation, 24(2), 279–285. https://doi.org/10.1007/s10841-019-00195-1
        - Lenda & Skórka (2010). Patch occupancy, number of individuals and population
          density of the Marbled White in a changing agricultural landscape. Acta
          Oecologica, 36(5), 497–506. https://doi.org/10.1016/j.actao.2010.07.002
        - Reinhardt et al. (2007): Tagfalter von Sachsen. In: Klausnitzer & Reinhardt
          (Hrsg.) Beiträge zur Insektenfauna Sachsens Band 6. – Entomologische Nachrichten
          und Berichte, Beiheft 11, 696 + 48 Seiten. Dresden.
        - Roy et al. (2001). Butterfly numbers and weather: Predicting historical
          trends in abundance and the future effects of climate change. Journal of
          Animal Ecology, 70(2), 201–217. https://doi.org/10.1111/j.1365-2656.2001.00480.x
        - Vandewoestijne et al. (2004). Dispersal, landscape occupancy and population
          structure in the butterfly Melanargia galathea. Basic and Applied Ecology,
          5(6), 581–591. https://doi.org/10.1016/j.baae.2004.07.004
    """
    @species MarbledWhite begin
        ## SPECIES PARAMETERS
    
        # habitat/environmental requirements
        # (Height parameters from Vandewoestijne et al. 2004. For temperature parameters
        #  see Ebert & Rennwald 1991, Gotthard et al., 2007, and Evans et al. 2019)
        const minheight = 30cm # minimum height of vegetation for egg-laying
        const maxheight = 60cm # maximum height of vegetation for egg-laying
        const mintemp = 18 # minimum temperature for activity (°C)
        const maxtemp = 30 # maximum temperature for activity (°C)
    
        # movement parameters
        #FIXME these are arbitrary guesses!
        const maxstepsperday = 100 # daily movement steps under optimal temperatures
        const selfavoidance = 0.9
        const habitatpreference = 0.9
        const perception = 100m # perceptual range (cf. Cant et al. 2005)
    
        # lifecycle parameters
        # (eggsperday and time parameters from Reinhardt et al. 2007)
        const maxeggsperday = 15 # number of eggs laid under optimal conditions
        const eggtime = 18:22 # days as egg
        const larvatime = 290:320 # days as larva
        const pupatime = 16:29 # days as pupa
        const adulttime = 17:34 # days as adult
        const maturationtime = 5:8 # days from hatching to first oviposition
        const juvenilesurvival = 0:25 # in percent (Wilson 1985, Dennis 1992)
        const earliesteclosure::AnnualDate = (June, 15) # (Ebert & Rennwald 1991)
        const latesteclosure::AnnualDate = (August, 15) # (Ebert & Rennwald 1991)
        
        const enforceflyingperiod = true # make sure all pupa eclose in the flying period?
    
        ## INDIVIDUAL VARIABLES
        birthdate::Date = Date(2000, July, 1) # is redefined in @create
        # how many days this individual spends in each phase
        daysinphase::Vector{Int64} = [20, 300, 19, 25] # is redefined in @create
        # following::Int64 = -1 # ID of the individual being followed #XXX include this?
    end
    
    
    ## LIFE PHASES
    
    """
    Juvenile individuals (i.e. eggs, larvae, pupae) simply wait for the eclosing day.
    """
    @phase MarbledWhite egg begin
        if self.age >= self.daysinphase[1]
            @setphase(larva)
        end
    end
    
    """
    Juvenile individuals (i.e. eggs, larvae, pupae) simply wait for the eclosing day.
    """
    @phase MarbledWhite larva begin
        if self.age >= self.daysinphase[1]+self.daysinphase[2]
            @setphase(pupa)
        end
    end
    
    """
    Juvenile individuals (i.e. eggs, larvae, pupae) simply wait for the eclosing day.
    """
    @phase MarbledWhite pupa begin
        if self.age >= self.daysinphase[1]+self.daysinphase[2]+self.daysinphase[3]
            @setphase(adult)
        end
    end
    
    """
    **Adult marbled whites (we only simulate females) fly around more or less randomly
    on days with good weather, laying eggs on suitable habitat.**
    
    ### Movement
    
    Adults move a given number of steps each day, depending on the temperature (see below).
    Each step, an individual scans its surroundings in concentric circles, looking for
    the closest spot that offers suitable habitat which it hasn't visited today. (Depending
    on the `habitatpreference` and `selfavoidance` parameters, spots that are not suitable
    habitat or have been visited before may also be selected.) After each step, if it
    is in a suitable habitat, the individual lays an egg, up to `maxeggsperday` (depending
    on temperature, see below).
    
    ### Temperature
    
    Temperature affects both the distance moved and the number of eggs laid each day.
    The optimal temperature is taken to be the midway point between the species' minimum
    and maximum temperatures (i.e. 24°C). Outside the species' temperature range (18-30°C),
    neither movement nor oviposition take place. Within that range, the number of steps
    each day peaks at the optimum temperature and declines linearly on either side of it.
    (cf. Evans et al., 2019). The number of eggs laid declines linearly if the temperature
    is below the optimum, but stays stable above it (cf. Gotthard et al., 2007).
    The daily maximum temperature (rather than mean or minimum) is used as the measure of
    choice, as this is most relevant for butterfly activity, and we don't have sub-daily
    weather data.
    """
    @phase MarbledWhite adult begin
        # temperature dependence
        opttemp = (self.mintemp + self.maxtemp)/2
        optimality = bounds(1 - (abs(opttemp-@maxtemp()) / (opttemp-self.mintemp)))
        stepsremaining::Int64 = Int(round(self.maxstepsperday*optimality))
        eggsremaining::Int64 = self.maxeggsperday
        if @maxtemp() < opttemp || @maxtemp() > self.maxtemp
            eggsremaining = Int(round(self.maxeggsperday*optimality))
        end
        # movement
        path::Vector{Tuple{Int64,Int64}} = [pos]
        width, height = size(model.landscape)
        while stepsremaining > 0
            radius = 1
            while radius <= self.perception
                coords = []
                xrange = (self.pos[1]-radius, self.pos[1]+radius)
                yrange = (self.pos[2]-radius, self.pos[2]+radius)
                for x in xrange[1]:xrange[2]
                    push!(coords, (x, yrange[1]))
                    push!(coords, (x, yrange[2]))
                end
                for y in (yrange[1]+1):(yrange[2]-1) #avoid duplicating the corners
                    push!(coords, (y, xrange[1]))
                    push!(coords, (y, xrange[2]))
                end
                for c in @shuffle!(coords)
                    (c[1] <= 0 || c[2] <= 0 || c[1] > width || c[2] > height) && continue
                    (c in path && @chance(self.selfavoidance)) && continue
                    (!suitablehabitat(self, mode, c) && @chance(habitatpreference)) && continue
                    radius = self.perception
                    @move(c)
                    break
                end
                radius += 1
            end
            # lay an egg if possible
            if eggsremaining > 0 && suitablehabitat(self, model, pos)
                if @chance(@randn(self.juvenilesurvival)/100)
                    @reproduce() # only create an individual that will survive to adulthood
                end
                eggsremaining -= 1
            end
            push!(path, self.pos)
            stepsremaining -= 1
        end
        # die once the lifespan has been reached
        if self.age >= sum(self.daysinphase)
            @kill()
        end
    end
    
    ## SUPPORTING FUNCTIONS
    
    """
        suitablehabitat(butterfly, model, pos)
    
    Check whether the given position is suitable for oviposition. This means:
    the land cover must be either grass or fallow, and if grass, must either not
    be managed, or not have been fertilised and be a certain height.
    """
    function suitablehabitat(butterfly::MarbledWhite, model::SimulationModel, pos::Tuple{Int64,Int64})
        (@landcover() == agriculture && @cropname() == "set-aside") ||
            (@landcover() == grass && (@cropname() == "NA" ||
            (!(fertiliser in model.landscape[pos...].events) &&
            @cropheight() >= butterfly.minheight &&
            @cropheight() <= butterfly.maxheight)))
    end
        
    
    ## INITIALISATION
    
    """
    Initialise a marbled white individual. Mainly defines the time this individual
    will spend in each phase. (This ought to be temperature-dependent rather than
    random, but I don't have data for that.)
    """
    @create MarbledWhite begin
        @debug "Added $(animalid(self)) at $(self.pos)"
        # set the birthdate (during initialisation, pick a random date last year)
        if model.date >= self.earliesteclosure && model.date <= self.latesteclosure
            self.birthdate = model.date
        else
            self.birthdate = @lastyear(@randn(self.earliesteclosure:self.latesteclosure))
            self.age = (model.date - self.birthdate).value
        end
        # choose a normally-distributed random number of days to spend in each phase
        self.daysinphase = [@randn(self.eggtime), @randn(self.larvatime),
                            @randn(self.pupatime), @randn(self.adulttime)]
        # check whether eclosure is during the flight period, change the larval time if not
        if self.enforceflyingperiod
            eclose = self.birthdate + Day(sum(self.daysinphase))
            if eclose < self.earliesteclosure
                diff = @thisyear(self.earliesteclosure) - eclose
                self.daysinphase[2] += diff.value
                @debug("Increased larval time by $(diff) to stay in flying period.")
            elseif eclose > self.latesteclosure
                diff = eclose - self.latesteclosure
                self.daysinphase[2] -= diff.value
                @debug("Reduced larval time by $(diff) to stay in flying period.")
            end
        end
    end
    
    """
    Initialise the marbled white population with one individual on every grassland pixel.
    """
    @populate MarbledWhite begin
        habitat = @habitat(@landcover() == grass) #XXX too simple? (cf. suitablehabitat())
        initphase = egg # this should advance within a few days to the correct phase
        birthphase = egg
        popsize = -1 # one individual per suitable location
        sex = female
    end