Skip to content
Snippets Groups Projects
Select Git revision
  • 4f5e7f932d049cd2686d513688579925f8eb3192
  • 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

ttoolbox.cpp

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    simulation.jl 5.73 KiB
    ### Persefone.jl - a model of agricultural landscapes and ecosystems in Europe.
    ###
    ### This file includes the core functions for initialising and running simulations.
    ###
    
    #XXX How can I make the model output during a parallel run clearer?
    
    """
        simulate(config=PARAMFILE, seed=nothing)
    
    Initialise one or more model objects and carry out a full simulation experiment,
    optionally specifying a configuration file and a seed for the RNG.
    
    This is the default way to run a Persefone simulation.
    """
    function simulate(config::String=PARAMFILE, seed::Union{Int64,Nothing}=nothing)
        models = initialise(config, seed)
        isa(models, Vector) ? 
            map(simulate!, models) : #TODO parallelise
            simulate!(models)
    end
    
    """
        simulate!(model)
    
    Carry out a complete simulation run using a pre-initialised model object.
    """
    function simulate!(model::AgentBasedModel)
        runtime = Dates.value(@param(core.enddate)-@param(core.startdate))+1
        step!(model, dummystep, stepsimulation!, runtime)
        finalise!(model)
    end
    
    """
        initialise(config=PARAMFILE, seed=nothing)
    
    Initialise the model: read in parameters, create the output data directory,
    and instantiate the AgentBasedModel object(s). Optionally allows specifying the
    configuration file and overriding the `seed` parameter. This returns a single
    model object, unless the config file contains multiple values for one or more
    parameters, in which case it creates a full-factorial simulation experiment
    and returns a vector of model objects.
    """
    function initialise(config::String=PARAMFILE, seed::Union{Int64,Nothing}=nothing)
        @info "Simulation run started at $(Dates.now())."
        settings = getsettings(config, seed)
        scanparams = settings["internal.scanparams"]
        delete!(settings, "internal.scanparams")
        isempty(scanparams) ?
            initmodel(settings) :
            map(initmodel, paramscan(settings, scanparams)) #TODO parallelise
    end
    
    """
        initmodel(settings)
    
    Initialise a model object using a ready-made settings dict. This is
    a helper function for `initialise()`.
    """
    function initmodel(settings::Dict{String, Any})
        @debug "Initialising model object."
        createdatadir(settings["core.outdir"], settings["core.overwrite"])
        logger = modellogger(settings["core.loglevel"], settings["core.outdir"])
        with_logger(logger) do
            events = Vector{FarmEvent}()
            dataoutputs = Vector{DataOutput}()
            landscape = initlandscape(settings["world.landcovermap"],
                                      settings["world.farmfieldsmap"])
            weather = initweather(settings["world.weatherfile"],
                                  settings["core.startdate"],
                                  settings["core.enddate"])
            crops = readcropparameters(settings["crop.cropfile"],
                                       settings["crop.growthfile"])
            space = GridSpace(size(landscape), periodic=false)
            properties = Dict{Symbol,Any}(:settings=>settings,
                                          :logger=>logger,
                                          :date=>settings["core.startdate"],
                                          :landscape=>landscape,
                                          :weather=>weather,
                                          :crops=>crops,
                                          :dataoutputs=>dataoutputs,
                                          :events=>events)
            model = AgentBasedModel(Union{Farmer,Animal,FarmPlot}, space, properties=properties,
                                    rng=StableRNG(settings["core.seed"]), warn=false)
            saveinputfiles(model)
            initfields!(model)
            initfarms!(model)
            initnature!(model)
            model
        end
    end
    
    """
        paramscan(settings)
    
    Create a list of settings dicts, covering all possible parameter combinations
    given by the input settings (i.e. a full-factorial experiment). This is a helper
    function for `initialise()`.
    """
    function paramscan(settings::Dict{String,Any}, scanparams::Vector{String})
        isempty(scanparams) && return [settings]
        param = pop!(scanparams)
        combinations = Vector{Dict{String,Any}}()
        # recursively generate a set of settings dicts covering all combinations
        for comb in paramscan(settings, scanparams)
            for value in settings[param]
                newcombination = deepcopy(comb)
                newcombination[param] = value
                if comb["core.outdir"] == settings["core.outdir"]
                    outdir = joinpath(comb["core.outdir"], "$(split(param, ".")[2])_$(value)")
                else
                    outdir = "$(comb["core.outdir"])_$(split(param, ".")[2])_$(value)"
                end
                newcombination["core.outdir"] = outdir
                push!(combinations, newcombination)
            end
        end
        combinations
    end
    
    """
        stepsimulation!(model)
    
    Execute one update of the model.
    """
    function stepsimulation!(model::AgentBasedModel)
        with_logger(model.logger) do
            @info "Simulating day $(model.date)."
            for a in Schedulers.ByType((Farmer,FarmPlot,Animal), true)(model)
                try #The animal may have been killed
                    stepagent!(model[a], model)
                catch exc
                    # check if the KeyError comes from the `model[a]` or the function call
                    isa(exc, KeyError) && isa(exc.key, Int) ? continue : throw(exc)
                end
            end
            updateevents!(model)
            outputdata(model)
            model.date += Day(1)
            model
        end
    end
    
    """
        finalise!(model)
    
    Wrap up the simulation. Currently doesn't do anything except print some information.
    """
    function finalise!(model::AgentBasedModel)
        with_logger(model.logger) do
            @info "Simulated $(model.date-@param(core.startdate))."
            @info "Simulation run completed at $(Dates.now()),\nwrote output to $(@param(core.outdir))."
            #XXX is there anything to do here?
            model
        end
    end