Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
output.jl 12.28 KiB
### Persefone.jl - a model of agricultural landscapes and ecosystems in Europe.
###
### This file contains functions for saving the model output. This includes logging
### facilities, but also functions for collecting and outputting data from the
### different submodels.
###

"Log output is saved to `simulation.log` in the output directory"
const LOGFILE = "simulation.log"

"All input data are copied to the `inputs` folder within the output directory"
const RECORDDIR = "inputs"

## Much of this code was adapted from the GeMM model by Leidinger et al.
## (https://github.com/CCTB-Ecomods/gemm/blob/master/src/output.jl)

"""
    createdatadir(outdir, overwrite)

Creates the output directory, dealing with possible conflicts.
"""
function createdatadir(outdir::String, overwrite::Union{Bool,String})
    if isdir(outdir)
        if overwrite == "ask"
            println("The chosen output directory $(outdir) already exists.")
            println("Type 'yes' to overwrite this directory. Otherwise, the simulation will abort.")
            print("Overwrite? ")
            answer = readline()
            overwrite = (answer == "yes" || answer == "y")
        end
        !overwrite ? Base.error("Output directory exists, will not overwrite. Aborting.") :
            @warn "Overwriting existing output directory $(outdir)."
        #TODO replace with exception
    end
    @debug "Setting up output directory $outdir."
    mkpath(outdir)
end

"""
    modellogger(loglevel, outdir, output="both")

Create a logger object that writes output to screen and/or a logfile.
This object is stored as `model.logger` and can then be used with `with_logger()`.
Note: requires [`createdatadir`](@ref) to be run first.
"""
function modellogger(loglevel::String, outdir::String, output::String="both")
    !isdir(outdir) && #TODO replace with exception
        Base.error("$(outdir) does not exist. Call `createdatadir()` before `modellogger()`.")
    loglevel == "debug" ? loglevel = Logging.Debug :
        loglevel == "warn" ? loglevel = Logging.Warn :
        loglevel == "info" ? loglevel = Logging.Info :
        Base.error("Invalid loglevel $loglevel, should be debug/info/warn.") #TODO make exception
    (output in ["file", "both"]) && (logfile = open(joinpath(outdir, LOGFILE), "w+"))
    if output == "both"
        return TeeLogger(ConsoleLogger(logfile, loglevel),
                         ConsoleLogger(stdout, loglevel))
    elseif output == "file"
        return ConsoleLogger(logfile, loglevel)
    elseif output == "screen"
        return ConsoleLogger(stdout, loglevel)
    elseif output == "none"
        return NullLogger()
    else
        Base.error("Invalid log output target $output, should be file/screen/both.")
    end
end

"""
    withtestlogger(model)