Skip to content
Sindbad.Simulation Module
julia
Simulation

The Simulation module provides the core functionality for running the SINDBAD Terrestrial Ecosystem Model (TEM). It includes utilities for preparing model-ready objects, managing spinup processes and running models.

Purpose

This module integrates various components and utilities required to execute the SINDBAD TEM, including precomputations, spinup, and time loop simulations. It supports parallel execution and efficient handling of large datasets.

Dependencies

Related (SINDBAD ecosystem)

  • TimeSamplers: Temporal helpers used in time-loop workflows.

  • OmniTools: Shared utilities used during simulation and output handling.

External (third-party)

  • ComponentArrays: Hierarchical state/parameter containers.

  • ProgressMeter: Progress bars for long-running simulations.

  • ThreadPools: Threaded parallelism helpers.

Internal (within Sindbad)

  • Sindbad.DataLoaders

  • Sindbad.Setup

  • Sindbad.Types

  • SindbadTEM

Included Files

  • utilsSimulation.jl: Core helpers for forcing slices, output handling, progress/logging, and simulation orchestration.

  • deriveSpinupForcing.jl: Derive spinup forcing data for steady-state initialization.

  • prepTEMOut.jl: Prepare output containers/structures for efficient writing.

  • prepTEM.jl: Prepare model-ready inputs and configuration for runs.

  • runTEMForLocation.jl: Run the TEM for a single location (optional spinup + main loop).

  • runTEMInSpace.jl: Run the TEM across spatial grids (parallel execution).

  • runTEMOnCube.jl: Run the TEM on 3D YAXArrays cubes (large-scale spatial runs).

  • spinupTEM.jl: Spinup routines to initialize the model to steady state.

  • spinupSequence.jl: Sequential spinup loops for iterative refinement.

Notes

  • The package is designed to be modular and extensible, allowing users to customize and extend its functionality for specific use cases.

  • It integrates tightly with the SINDBAD framework, leveraging shared types and utilities from Setup.

  • Some spinup solvers are enabled via an optional extension:

    • NLsolveSindbadNLsolveExt (see ext/SindbadNLsolveExt/).

Functions

TEMYax

Sindbad.Simulation.TEMYax Function
julia
TEMYax(map_cubes; loc_land::NamedTuple, tem::NamedTuple, selected_models::Tuple, forcing_vars::AbstractArray)

Arguments:

  • map_cubes: collection/tuple of all input and output cubes from mapCube

  • loc_land: initial SINDBAD land with all fields and subfields

  • tem: a nested NT with necessary information of helpers, models, and spinup needed to run SINDBAD TEM and models

  • selected_models: a tuple of all models selected in the given model structure

  • forcing_vars: forcing variables

Code
julia
function TEMYax(map_cubes...;selected_models::Tuple, forcing_vars::AbstractArray, loc_land::NamedTuple, output_vars, tem::NamedTuple)
    outputs, inputs = unpackYaxForward(map_cubes; output_vars, forcing_vars)
    loc_forcing = (; Pair.(forcing_vars, inputs)...)
    land_out = coreTEMYax(selected_models, loc_forcing, loc_land, tem)

    i = 1
    foreach(output_vars) do var_pair
        # @show i, var_pair
        data = land_out[first(var_pair)][last(var_pair)]
            fillOutputYax(outputs[i], data)
            i += 1
    end
end

coreTEM

Sindbad.Simulation.coreTEM Function
julia
coreTEM(selected_models, loc_forcing, loc_spinup_forcing, loc_forcing_t, loc_land, tem_info, spinup_mode)

Runs the SINDBAD Terrestrial Ecosystem Model (TEM) for a single location, with or without spinup, based on the specified spinup_mode.

Arguments:

  • selected_models: A tuple of all models selected in the given model structure.

  • loc_forcing: A forcing NamedTuple containing the time series of environmental drivers for a single location.

  • loc_spinup_forcing: A forcing NamedTuple for spinup, used to initialize the model to a steady state (only used if spinup is enabled).

  • loc_forcing_t: A forcing NamedTuple for a single location and a single time step.

  • loc_land: Initial SINDBAD land NamedTuple with all fields and subfields.

  • tem_info: A helper NamedTuple containing necessary objects for model execution and type consistencies.

  • spinup_mode: A type that determines whether spinup is included or excluded

Returns:

  • land_time_series: A vector of SINDBAD land states for each time step after the model simulation.
Code
julia
function coreTEM end

function coreTEM(selected_models, loc_forcing, loc_spinup_forcing, loc_forcing_t, loc_land, tem_info, spinup_mode)

    land_prec = precomputeTEM(selected_models, loc_forcing_t, loc_land, tem_info.model_helpers)

    land_spin = spinupTEM(selected_models, loc_spinup_forcing, loc_forcing_t, land_prec, tem_info, spinup_mode)

    land_time_series = timeLoopTEM(selected_models, loc_forcing, loc_forcing_t, land_spin, tem_info, tem_info.run.debug_model)
    return land_time_series
end

function coreTEM(selected_models, loc_forcing, loc_spinup_forcing, loc_forcing_t, loc_land, tem_info, spinup_mode)

    land_prec = precomputeTEM(selected_models, loc_forcing_t, loc_land, tem_info.model_helpers)

    land_spin = spinupTEM(selected_models, loc_spinup_forcing, loc_forcing_t, land_prec, tem_info, spinup_mode)

    land_time_series = timeLoopTEM(selected_models, loc_forcing, loc_forcing_t, land_spin, tem_info, tem_info.run.debug_model)
    return land_time_series
end

function coreTEM(selected_models, loc_forcing, loc_spinup_forcing, loc_forcing_t, land_time_series, loc_land, tem_info, spinup_mode)
    land_prec = precomputeTEM(selected_models, loc_forcing_t, loc_land, tem_info.model_helpers)

    land_spin = spinupTEM(selected_models, loc_spinup_forcing, loc_forcing_t, land_prec, tem_info, spinup_mode)

    timeLoopTEM(selected_models, loc_forcing, loc_forcing_t, land_time_series, land_spin, tem_info, tem_info.run.debug_model)
    return nothing
end

coreTEM!

Sindbad.Simulation.coreTEM! Function
julia
coreTEM!(selected_models, loc_forcing, loc_spinup_forcing, loc_forcing_t, loc_output, loc_land, tem_info)

Executes the core SINDBAD Terrestrial Ecosystem Model (TEM) for a single location, including precomputations, spinup, and the main time loop.

Arguments:

  • selected_models: A tuple of all models selected in the given model structure.

  • loc_forcing: A forcing NamedTuple containing the time series of environmental drivers for a single location.

  • loc_spinup_forcing: A forcing NamedTuple for spinup, used to initialize the model to a steady state (only used if spinup is enabled).

  • loc_forcing_t: A forcing NamedTuple for a single location and a single time step.

  • loc_output: An output array or view for storing the model outputs for a single location.

  • loc_land: Initial SINDBAD land NamedTuple with all fields and subfields.

  • tem_info: A helper NamedTuple containing necessary objects for model execution and type consistencies.

Details

Executes the main TEM simulation logic with the provided parameters and data. Handles both regular simulation and spinup modes based on the spinup_mode flag.

Extended help

  • Precomputations:
    • The function runs precomputeTEM to prepare the land state for the simulation.
Code
julia
function coreTEM!(selected_models, loc_forcing, loc_spinup_forcing, loc_forcing_t, loc_output, loc_land, tem_info)
    # update the loc_forcing with the actual location
    loc_forcing_t = getForcingForTimeStep(loc_forcing, loc_forcing_t, 1, tem_info.vals.forcing_types)
    # run precompute
    land_prec = precomputeTEM(selected_models, loc_forcing_t, loc_land, tem_info.model_helpers) 
    # run spinup
    land_spin = spinupTEM(selected_models, loc_spinup_forcing, loc_forcing_t, land_prec, tem_info, tem_info.run.spinup_TEM)

    timeLoopTEM!(selected_models, loc_forcing, loc_forcing_t, loc_output, land_spin, tem_info.vals.forcing_types, tem_info.model_helpers, tem_info.vals.output_vars, tem_info.n_timesteps, tem_info.run.debug_model)
    return nothing
end

getAllSpinupForcing

Sindbad.Simulation.getAllSpinupForcing Function
julia
getAllSpinupForcing(forcing, spin_seq, tem_helpers)

prepare the spinup forcing all forcing setups in the spinup sequence

Arguments:

  • forcing: a forcing NT that contains the forcing time series set for ALL locations

  • spin_seq: a sequence of information to carry out spinup at different steps with information on models to use, forcing, stopping critera, etc.

  • tem_helpers: helper NT with necessary objects for model run and type consistencies

Returns:

  • spinup_forcing::NamedTuple: A NamedTuple containing aggregated forcing data for each spinup sequence

Examples

julia
julia> using Sindbad

julia> # Prepare spinup forcing for all sequences
julia> # spinup_forcing = getAllSpinupForcing(forcing, spin_sequences, tem_helpers)
Code
julia
function getAllSpinupForcing(forcing, spin_sequences::Vector{SpinupSequenceWithAggregator}, tem_helpers)
    spinup_forcing = (;)
    for seq  spin_sequences
        forc = getfield(seq, :forcing)
        forc_name = forc
        if forc_name  keys(spinup_forcing)
            seq_forc = getSpinupForcing(forcing, seq, tem_helpers.vals.forcing_types)
            spinup_forcing = set_namedtuple_field(spinup_forcing, (forc_name, seq_forc))
        end
    end
    return spinup_forcing
end

getForcingForTimeStep

Sindbad.Simulation.getForcingForTimeStep Function
julia
getForcingForTimeStep(forcing, loc_forcing_t, ts, Val{forc_with_type})

Get forcing values for a specific time step based on the forcing type.

Arguments:

  • forcing: a forcing NT that contains the forcing time series set for ALL locations

  • loc_forcing_t: a forcing NT for a single timestep to be reused in every time step

  • ts: time step to get the forcing for

  • forc_with_type: Value type parameter specifying the forcing type


getLocData

Sindbad.Simulation.getLocData Function
julia
getLocData(forcing, output_array, loc_ind)

Arguments:

  • forcing: a forcing NT that contains the forcing time series set for ALL locations

  • output_array: an output array/view for ALL locations

  • loc_ind: a tuple with the spatial indices of the data for a given location

julia
getLocData(forcing, output_array, loc_ind)

Arguments:

  • output_array: an output array/view for ALL locations

  • loc_ind: a tuple with the spatial indices of the data for a given location

julia
getLocData(forcing, output_array, loc_ind)

Arguments:

  • forcing: a forcing NT that contains the forcing time series set for ALL locations

  • loc_ind: a tuple with the spatial indices of the data for a given location

Code
julia
function getLocData(forcing::NamedTuple, output_array::AbstractArray, loc_ind)
    loc_forcing = getLocData(forcing, loc_ind)
    loc_output = getLocData(output_array, loc_ind)
    return loc_forcing, loc_output
end

function getLocData(output_array::AbstractArray, loc_ind)
    loc_output = map(output_array) do a
        view_at_trailing_indices(a, loc_ind)
    end
    return loc_output
end

function getLocData(forcing::NamedTuple, loc_ind)
    loc_forcing = map(forcing) do a
        view_at_trailing_indices(a, loc_ind) |> Array
    end
    return loc_forcing
end

getOutDims

Sindbad.Simulation.getOutDims Function
julia
getOutDims(info, forcing_helpers[, ::OutputArray | ::OutputMArray | ::OutputSizedArray | ::OutputYAXArray])

Retrieves the dimensions for SINDBAD output based on the specified array backend.

Arguments:

  • info: A SINDBAD NamedTuple containing all information needed for setup and execution of an experiment.

  • forcing_helpers: A NamedTuple with information on forcing sizes and dimensions.

  • ::OutputArray: (Optional) A type dispatch for using a base Array as the array backend.

  • ::OutputMArray: (Optional) A type dispatch for using MArray as the array backend.

  • ::OutputSizedArray: (Optional) A type dispatch for using SizedArray as the array backend.

  • ::OutputYAXArray: (Optional) A type dispatch for using YAXArray as the array backend.

Returns:

  • A vector of output dimensions, where each dimension is represented as a tuple of Dim objects.

Notes:

  • For OutputArray, OutputMArray, and OutputSizedArray, all dimensions are included.

  • For OutputYAXArray, spatial dimensions are excluded, and metadata is added for each variable.

Examples

julia
julia> using Sindbad

julia> # Get output dimensions with default array type
julia> # outdims = getOutDims(info, forcing_helpers)

julia> # Get output dimensions with YAXArray
julia> # outdims = getOutDims(info, forcing_helpers, OutputYAXArray())
Code
julia
function getOutDims end

function getOutDims(info, forcing_helpers)
    outdims = getOutDims(info, forcing_helpers, info.helpers.run.output_array_type)
    return outdims
end

function getOutDims(info, forcing_helpers)
    outdims = getOutDims(info, forcing_helpers, info.helpers.run.output_array_type)
    return outdims
end

function getOutDims(info, forcing_helpers, ::Union{OutputArray, OutputMArray, OutputSizedArray})
    outdims_pairs = getOutDimsPairs(info.output, forcing_helpers)
    outdims = map(outdims_pairs) do dim_pairs
        od = []
        for _dim in dim_pairs
            push!(od, YAXArrays.Dim{first(_dim)}(last(_dim)))
        end
        Tuple(od)
    end
    return outdims
end

function getOutDims(info, forcing_helpers, ::OutputYAXArray)
    outdims_pairs = getOutDimsPairs(info.output, forcing_helpers);
    space_dims = Symbol.(info.experiment.data_settings.forcing.data_dimension.space)
    var_dims = map(outdims_pairs) do dim_pairs
        od = []
        for _dim in dim_pairs
            if first(_dim)  space_dims
                push!(od, YAXArrays.Dim{first(_dim)}(last(_dim)))
            end
        end
        Tuple(od)
    end
    v_index = 1
    outdims = map(info.output.variables) do vname_full
        vname = string(last(vname_full))
        _properties = collectMetadata(info, vname_full)
        vdims = var_dims[v_index]
        outformat = info.settings.experiment.model_output.format
        backend = outformat == "nc" ? :netcdf : :zarr
        out_dim = YAXArrays.OutDims(vdims...;
        properties = _properties,
        path=info.output.file_info.file_prefix * "_$(vname).$(outformat)",
        backend=backend,
        overwrite=true)
        v_index += 1
        out_dim
    end
    return outdims
end

function getOutDimsArrays end

function getOutDimsArrays(info, forcing_helpers)
    outdims, outarray = getOutDimsArrays(info, forcing_helpers, info.helpers.run.output_array_type)
    return outdims, outarray
end

function getOutDimsArrays(info, forcing_helpers)
    outdims, outarray = getOutDimsArrays(info, forcing_helpers, info.helpers.run.output_array_type)
    return outdims, outarray
end

function getOutDimsArrays(info, forcing_helpers, oarr::OutputArray)
    outdims = getOutDims(info, forcing_helpers, oarr)
    outarray = getNumericArrays(info, forcing_helpers.sizes)
    return outdims, outarray
end

function getOutDimsArrays(info, forcing_helpers, omarr::OutputMArray)
    outdims = getOutDims(info, forcing_helpers, omarr)
    outarray = getNumericArrays(info, forcing_helpers.sizes)
    marray = MArray{Tuple{size(outarray)...},eltype(outarray)}(undef)
    return outdims, marray
end

function getOutDimsArrays(info, forcing_helpers, osarr::OutputSizedArray)
    outdims = getOutDims(info, forcing_helpers, osarr)
    outarray = getNumericArrays(info, forcing_helpers.sizes)
    sized_array = SizedArray{Tuple{size(outarray)...},eltype(outarray)}(undef)
    return outdims, sized_array
end

function getOutDimsArrays(info, forcing_helpers, oayax::OutputYAXArray)
    outdims = getOutDims(info, forcing_helpers, oayax)
    outarray = nothing
    return outdims, outarray
end

function getOutDimsPairs(tem_output, forcing_helpers; dthres=1)
    forcing_axes = forcing_helpers.axes
    dim_loops = first.(forcing_axes)
    axes_dims_pairs = []
    if !isnothing(forcing_helpers.dimensions.permute)
        dim_perms = Symbol.(forcing_helpers.dimensions.permute)
        if dim_loops !== dim_perms
            for ix in eachindex(dim_perms)
                dp_i = dim_perms[ix]
                dl_ind = findall(x -> x == dp_i, dim_loops)[1]
                f_a = forcing_axes[dl_ind]
                ax_dim = Pair(first(f_a), last(f_a))
                push!(axes_dims_pairs, ax_dim)
            end
        end
    else
        axes_dims_pairs = map(x -> Pair(first(x), last(x)), forcing_axes)
    end
    opInd = 1
    outdims_pairs = map(tem_output.variables) do vname_full
        depth_info = tem_output.depth_info[opInd]
        depth_size = first(depth_info)
        depth_name = last(depth_info)
        od = []
        push!(od, axes_dims_pairs[1])
        if depth_size > dthres
            if depth_size == 1
                depth_name = "idx"
            end
            push!(od, Pair(Symbol(depth_name), (1:depth_size)))
        end
        foreach(axes_dims_pairs[2:end]) do f_d
            push!(od, f_d)
        end
        opInd += 1
        Tuple(od)
    end
    return outdims_pairs
end

getOutDimsArrays

Sindbad.Simulation.getOutDimsArrays Function
julia
getOutDimsArrays(info, forcing_helpers[, ::OutputArray | ::OutputMArray | ::OutputSizedArray | ::OutputYAXArray])

Retrieves the dimensions and corresponding data for SINDBAD output based on the specified array backend.

Arguments:

  • info: A SINDBAD NamedTuple containing all information needed for setup and execution of an experiment.

  • forcing_helpers: A NamedTuple with information on forcing sizes and dimensions.

  • ::OutputArray: (Optional) A type dispatch for using a base Array as the array backend.

  • ::OutputMArray: (Optional) A type dispatch for using MArray as the array backend.

  • ::OutputSizedArray: (Optional) A type dispatch for using SizedArray as the array backend.

  • ::OutputYAXArray: (Optional) A type dispatch for using YAXArray as the array backend.

Returns:

  • A tuple (outdims, outarray):
    • outdims: A vector of output dimensions, where each dimension is represented as a tuple of Dim objects.

    • outarray: The corresponding data array, initialized based on the specified array backend.

Notes:

  • For OutputArray, OutputMArray, and OutputSizedArray, the data array is initialized with the appropriate backend type.

  • For OutputYAXArray, the data array is set to nothing, as YAXArray handles data differently.

Examples:

  1. Using a base Array:
julia
outdims, outarray = getOutDimsArrays(info, forcing_helpers, OutputArray())
  1. Using MArray:
julia
outdims, outarray = getOutDimsArrays(info, forcing_helpers, OutputMArray())
  1. Using SizedArray:
julia
outdims, outarray = getOutDimsArrays(info, forcing_helpers, OutputSizedArray())
  1. Using YAXArray:
julia
outdims, outarray = getOutDimsArrays(info, forcing_helpers, OutputYAXArray())
  1. Default behavior:
julia
outdims, outarray = getOutDimsArrays(info, forcing_helpers)
Code
julia
function getOutDimsArrays end

function getOutDimsArrays(info, forcing_helpers)
    outdims, outarray = getOutDimsArrays(info, forcing_helpers, info.helpers.run.output_array_type)
    return outdims, outarray
end

function getOutDimsArrays(info, forcing_helpers)
    outdims, outarray = getOutDimsArrays(info, forcing_helpers, info.helpers.run.output_array_type)
    return outdims, outarray
end

function getOutDimsArrays(info, forcing_helpers, oarr::OutputArray)
    outdims = getOutDims(info, forcing_helpers, oarr)
    outarray = getNumericArrays(info, forcing_helpers.sizes)
    return outdims, outarray
end

function getOutDimsArrays(info, forcing_helpers, omarr::OutputMArray)
    outdims = getOutDims(info, forcing_helpers, omarr)
    outarray = getNumericArrays(info, forcing_helpers.sizes)
    marray = MArray{Tuple{size(outarray)...},eltype(outarray)}(undef)
    return outdims, marray
end

function getOutDimsArrays(info, forcing_helpers, osarr::OutputSizedArray)
    outdims = getOutDims(info, forcing_helpers, osarr)
    outarray = getNumericArrays(info, forcing_helpers.sizes)
    sized_array = SizedArray{Tuple{size(outarray)...},eltype(outarray)}(undef)
    return outdims, sized_array
end

function getOutDimsArrays(info, forcing_helpers, oayax::OutputYAXArray)
    outdims = getOutDims(info, forcing_helpers, oayax)
    outarray = nothing
    return outdims, outarray
end

getSequence

Sindbad.Simulation.getSequence Function
julia
getSequence(year_disturbance, nrepeat_base=200, year_start = 1979)

Arguments:

  • year_disturbance: a year date, as an string

  • nrepeat_base=200 [default]

  • year_start: 1979 [default] start year, as an interger

Outputs

  • new spinup sequence object
Code
julia
function getSequence(year_disturbance, info_helpers_dates; nrepeat_base=200, year_start = 1979)
    nrepeat_age = nrepeatYearsAge(year_disturbance; year_start)
    sequence = [
        Dict("spinup_mode" => "sel_spinup_models", "forcing" => "all_years", "n_repeat" => 1),
        Dict("spinup_mode" => "sel_spinup_models", "forcing" => "day_MSC", "n_repeat" => nrepeat_base),
        Dict("spinup_mode" => "eta_scale_AH", "forcing" => "day_MSC", "n_repeat" => 1),
    ]
    if nrepeat_age == 0
        sequence = [
            Dict("spinup_mode" => "sel_spinup_models", "forcing" => "all_years", "n_repeat" => 1),
            Dict("spinup_mode" => "sel_spinup_models", "forcing" => "day_MSC", "n_repeat" => nrepeat_base),
            Dict("spinup_mode" => "eta_scale_A0H", "forcing" => "day_MSC", "n_repeat" => 1),
        ]
    elseif nrepeat_age > 0
        sequence = [
            Dict("spinup_mode" => "sel_spinup_models", "forcing" => "all_years", "n_repeat" => 1),
            Dict("spinup_mode" => "sel_spinup_models", "forcing" => "day_MSC", "n_repeat" => nrepeat_base),
            Dict("spinup_mode" => "eta_scale_A0H", "forcing" => "day_MSC", "n_repeat" => 1),
            Dict("spinup_mode" => "sel_spinup_models", "forcing" => "day_MSC", "n_repeat" => nrepeat_age),
        ]
    end
    new_sequence = getSpinupTemLite(getSpinupSequenceWithTypes(sequence, info_helpers_dates))
    return new_sequence
end

getSpatialInfo

Sindbad.Simulation.getSpatialInfo Function
julia
getSpatialInfo(forcing_helpers)
getSpatialInfo(forcing, filterNanPixels)

get the information of the indices of the data to run the model for. The second variant additionally filter pixels with all nan data

Arguments:

  • forcing: a forcing NT that contains the forcing time series set for ALL locations
Code
julia
function getSpatialInfo end

function getSpatialInfo(forcing_helpers)
    @debug "     getting the space locations to run the model loop"
    forcing_sizes = forcing_helpers.sizes
    loopvars = collect(keys(forcing_sizes))
    additionaldims = setdiff(loopvars, [Symbol(forcing_helpers.dimensions.time)])
    spacesize = values(forcing_sizes[additionaldims])
    loc_space_maps = vec(collect(Iterators.product(Base.OneTo.(spacesize)...)))
    loc_space_maps = map(loc_space_maps) do loc_names
        map(zip(loc_names, additionaldims)) do (loc_index, lv)
            lv => loc_index
        end
    end
    loc_space_maps = Tuple(loc_space_maps)
    space_ind = Tuple([Tuple(last.(loc_space_map)) for loc_space_map  loc_space_maps])
    return space_ind, loc_space_maps
end

function getSpatialInfo(forcing_helpers)
    @debug "     getting the space locations to run the model loop"
    forcing_sizes = forcing_helpers.sizes
    loopvars = collect(keys(forcing_sizes))
    additionaldims = setdiff(loopvars, [Symbol(forcing_helpers.dimensions.time)])
    spacesize = values(forcing_sizes[additionaldims])
    loc_space_maps = vec(collect(Iterators.product(Base.OneTo.(spacesize)...)))
    loc_space_maps = map(loc_space_maps) do loc_names
        map(zip(loc_names, additionaldims)) do (loc_index, lv)
            lv => loc_index
        end
    end
    loc_space_maps = Tuple(loc_space_maps)
    space_ind = Tuple([Tuple(last.(loc_space_map)) for loc_space_map  loc_space_maps])
    return space_ind, loc_space_maps
end

function getSpatialInfo(forcing, filter_nan_pixels)
    space_ind, loc_space_maps = getSpatialInfo(forcing.helpers)
    loc_space_maps = filterNanPixels(forcing, loc_space_maps, filter_nan_pixels)
    space_ind = Tuple([Tuple(last.(loc_space_map)) for loc_space_map  loc_space_maps])
    return space_ind
end

prepTEM

Sindbad.Simulation.prepTEM Function
julia
prepTEM(forcing::NamedTuple, info::NamedTuple)
prepTEM(selected_models, forcing::NamedTuple, info::NamedTuple)
prepTEM(selected_models, forcing::NamedTuple, observations::NamedTuple, info::NamedTuple)

Prepares the SINDBAD Terrestrial Ecosystem Model (TEM) for execution by setting up the necessary inputs, outputs, and configurations with different variants for different experimental setups.

Arguments:

  • selected_models: A tuple of all models selected in the given model structure.

  • forcing::NamedTuple: A forcing NamedTuple containing the time series of environmental drivers for all locations.

  • observations::NamedTuple: A NamedTuple containing observational data for model validation.

  • info::NamedTuple: A nested NamedTuple containing necessary information, including:

    • Helpers for running the model.

    • Model configurations.

    • Spinup settings.

Returns:

  • run_helpers: A NamedTuple containing preallocated data and configurations required to run the TEM, including:
    • Spatial forcing data.

    • Spinup forcing data.

    • Output arrays.

    • Land variables.

    • Temporal and spatial indices.

    • Model and helper configurations.

Notes:

  • The function dynamically prepares the required data structures based on the specified PreAllocputType in info.helpers.run.land_output_type.

  • It handles spatial and temporal data preparation, including filtering NaN pixels, initializing land variables, and setting up forcing and output arrays.

  • This function is a key step in preparing the SINDBAD TEM for execution.

Examples:

  1. Preparing TEM with observations:
julia
selected_models = (model1, model2)
forcing = (data = ..., variables = ...)
observations = (data = ..., variables = ...)
info = (helpers = ..., models = ..., spinup = ...)
run_helpers = prepTEM(selected_models, forcing, observations, info)
  1. Preparing TEM without observations:
julia
selected_models = (model1, model2)
forcing = (data = ..., variables = ...)
info = (helpers = ..., models = ..., spinup = ...)
run_helpers = prepTEM(selected_models, forcing, info)
Code
julia
function prepTEM end

function prepTEM(forcing::NamedTuple, info::NamedTuple)
    selected_models = info.models.forward
    return prepTEM(selected_models, forcing, info)
end

function prepTEM(forcing::NamedTuple, info::NamedTuple)
    selected_models = info.models.forward
    return prepTEM(selected_models, forcing, info)
end

function prepTEM(selected_models, forcing::NamedTuple, info::NamedTuple)
    print_info(prepTEM, @__FILE__, @__LINE__, "preparing to run terrestrial ecosystem model (TEM)", n_f=1)
    output = prepTEMOut(info, forcing.helpers)
    print_info(prepTEM, @__FILE__, @__LINE__, "  preparing helpers for running model experiment", n_f=4)
    run_helpers = helpPrepTEM(selected_models, info, forcing, output, info.helpers.run.land_output_type)
    print_info_separator()

    return run_helpers
end

function prepTEM(selected_models, forcing::NamedTuple, observations::NamedTuple, info::NamedTuple)
    print_info(prepTEM, @__FILE__, @__LINE__, "preparing to run terrestrial ecosystem model (TEM)", n_f=1)
    output = prepTEMOut(info, forcing.helpers)
    run_helpers = helpPrepTEM(selected_models, info, forcing, observations, output, info.helpers.run.land_output_type)
    print_info_separator()

    return run_helpers
end

prepTEMOut

Sindbad.Simulation.prepTEMOut Function
julia
prepTEMOut(info::NamedTuple, forcing_helpers::NamedTuple)

Prepares the output NamedTuple required for running the Terrestrial Ecosystem Model (TEM) in SINDBAD.

Arguments:

  • info: A SINDBAD NamedTuple containing all information needed for setup and execution of an experiment.

  • forcing_helpers: A NamedTuple with information on forcing sizes and dimensions.

Returns:

A NamedTuple output_tuple containing:

  • land_init: The initial land state from info.land_init.

  • dims: A vector of output dimensions, where each dimension is represented as a tuple of Dim objects.

  • data: A vector of numeric arrays initialized for output variables.

  • variables: A list of output variable names.

  • Additional fields for optimization output if optimization is enabled.

Notes:

  • The function initializes the output dimensions and data arrays based on the specified array backend (info.helpers.run.output_array_type).

  • If optimization is enabled (info.helpers.run.run_optimization), additional fields for optimized parameters are added to the output.

  • The function uses helper functions like getOutDimsArrays and setupOptiOutput to prepare the output.

Examples:

  1. Basic usage:
julia
output_tuple = prepTEMOut(info, forcing_helpers)
  1. Accessing output fields:
julia
dims = output_tuple.dims
data = output_tuple.data
variables = output_tuple.variables
Code
julia
function prepTEMOut(info::NamedTuple, forcing_helpers::NamedTuple)
    print_info(prepTEMOut, @__FILE__, @__LINE__, "preparing output helpers for Terrestrial Ecosystem Model (TEM)", n_f=4)
    land = info.helpers.land_init
    output_tuple = (;)
    output_tuple = set_namedtuple_field(output_tuple, (:land_init, land))
    @debug "     prepTEMOut: getting out variables, dimension and arrays..."
    outdims, outarray = getOutDimsArrays(info, forcing_helpers, info.helpers.run.output_array_type)
    output_tuple = set_namedtuple_field(output_tuple, (:dims, outdims))
    output_tuple = set_namedtuple_field(output_tuple, (:data, outarray))
    output_tuple = set_namedtuple_field(output_tuple, (:variables, info.output.variables))

    output_tuple = setupOptiOutput(info, output_tuple, info.helpers.run.run_optimization)
    @debug "\n----------------------------------------------\n"
    return output_tuple
end

runTEM

Sindbad.Simulation.runTEM Function
julia
runTEM(forcing::NamedTuple, info::NamedTuple)
runTEM(selected_models::Tuple, forcing::NamedTuple, loc_spinup_forcing, loc_forcing_t, loc_land::NamedTuple, tem_info::NamedTuple)
runTEM(selected_models::Tuple, loc_forcing::NamedTuple, loc_spinup_forcing, loc_forcing_t, land_time_series, loc_land::NamedTuple, tem_info::NamedTuple)

Runs the SINDBAD Terrestrial Ecosystem Model (TEM) for a single location, with or without spinup, based on the provided configurations. The two main variants are the ones with and without the preallocated land time series. The shorthand version with two input arguments calls the one without preallocated land time series.

Arguments:

  • selected_models: A tuple of all models selected in the given model structure.

  • forcing::NamedTuple: A forcing NamedTuple containing the time series of environmental drivers for all locations.

  • loc_spinup_forcing: A forcing NamedTuple for spinup, used to initialize the model to a steady state.

  • loc_forcing_t: A forcing NamedTuple for a single location and a single time step.

  • loc_land::NamedTuple: Initial SINDBAD land NamedTuple with all fields and subfields.

  • tem_info::NamedTuple: A nested NamedTuple containing necessary information, including:

    • Model helpers.

    • Spinup configurations.

    • Debugging options.

    • Output configurations.

Returns:

  • LandWrapper: A wrapper containing the time series of SINDBAD land states for each time step after the model simulation.

Notes:

  • The function internally calls coreTEM to handle the main simulation logic.

  • If spinup is enabled (DoSpinupTEM), the function runs the spinup process before the main simulation.

  • If spinup is disabled (DoNotSpinupTEM), the function directly runs the main simulation.

  • The function prepares the necessary inputs and configurations using prepTEM before executing the simulation.

Examples

julia
julia> using Sindbad

julia> # Run TEM with spinup (shorthand version)
julia> # land_time_series = runTEM(forcing, info)

julia> # Run TEM with spinup (detailed version)
julia> # land_time_series = runTEM(selected_models, forcing, loc_spinup_forcing, loc_forcing_t, loc_land, tem_info)

julia> # Run TEM without spinup
julia> # land_time_series = runTEM(selected_models, forcing, nothing, loc_forcing_t, loc_land, tem_info)
Code
julia
function runTEMOne(selected_models, loc_forcing, land_init, tem)
    loc_forcing_t = getForcingForTimeStep(loc_forcing, loc_forcing, 1, tem.vals.forcing_types)
    loc_land = definePrecomputeTEM(selected_models, loc_forcing_t, land_init,
        tem.model_helpers)
    loc_land = computeTEM(selected_models, loc_forcing_t, loc_land, tem.model_helpers)
    # loc_land = drop_empty_namedtuple_fields(loc_land)
    loc_land = addSpinupLog(loc_land, tem.spinup_sequence, tem.run.store_spinup)
    # loc_land = definePrecomputeTEM(selected_models, loc_forcing_t, loc_land,
        # tem.model_helpers)
    # loc_land = precomputeTEM(selected_models, loc_forcing_t, loc_land,
        # tem.model_helpers)
    # loc_land = computeTEM(selected_models, loc_forcing_t, loc_land, tem.model_helpers)
    return loc_forcing_t, loc_land
end

runTEM!

Sindbad.Simulation.runTEM! Function
julia
runTEM!(selected_models, forcing::NamedTuple, info::NamedTuple)
runTEM!(forcing::NamedTuple, info::NamedTuple)
runTEM!(selected_models, space_forcing, space_spinup_forcing, loc_forcing_t, space_output, space_land, tem_info::NamedTuple)

Runs the SINDBAD Terrestrial Ecosystem Model (TEM) for all locations and time steps using preallocated arrays as the model data backend. This function supports multiple configurations for efficient execution.

Arguments:

  1. For the first variant:
  • selected_models: A tuple of all models selected in the given model structure.

  • forcing::NamedTuple: A forcing NamedTuple containing the time series of environmental drivers for all locations.

  • info::NamedTuple: A SINDBAD NamedTuple containing all information needed for setup and execution of an experiment.

  1. For the second variant:
  • forcing::NamedTuple: A forcing NamedTuple containing the time series of environmental drivers for all locations.

  • info::NamedTuple: A SINDBAD NamedTuple containing all information needed for setup and execution of an experiment.

  1. For the third variant:
  • selected_models: A tuple of all models selected in the given model structure.

  • space_forcing: A collection of forcing NamedTuples for multiple locations, replicated to avoid data races during parallel execution.

  • space_spinup_forcing: A collection of spinup forcing NamedTuples for multiple locations, replicated to avoid data races during parallel execution.

  • loc_forcing_t: A forcing NamedTuple for a single location and a single time step.

  • space_output: A collection of output arrays/views for multiple locations, replicated to avoid data races during parallel execution.

  • space_land: A collection of initial SINDBAD land NamedTuples for multiple locations, ensuring that the model states for one location do not overwrite those of another.

  • tem_info::NamedTuple: A helper NamedTuple containing necessary objects for model execution and type consistencies.

Returns:

  • output_array: A preallocated array containing the simulation results for all locations and time steps.

Notes:

  • Precomputations:

    • The function uses prepTEM to prepare the necessary inputs and configurations for the simulation.
  • Parallel Execution:

    • The function uses parallelizeTEM! to distribute the simulation across multiple locations using the specified parallelization backend (Threads.@threads or qbmap).
  • Core Execution:

    • For each location, the function calls coreTEM! to execute the TEM simulation, including spinup (if enabled) and the main time loop.
  • Data Safety:

    • The function ensures data safety by replicating forcing, output, and land data for each location, avoiding data races during parallel execution.

Examples

julia
julia> using Sindbad

julia> # Run TEM with preallocated arrays (shorthand)
julia> # output_array = runTEM!(forcing, info)

julia> # Run TEM with preallocated arrays (detailed)
julia> # output_array = runTEM!(selected_models, forcing, info)

julia> # Run TEM with precomputed helpers
julia> # runTEM!(selected_models, space_forcing, space_spinup_forcing, loc_forcing_t, space_output, space_land, tem_info)
Code
julia
function runTEM! end

function runTEM!(selected_models, forcing::NamedTuple, info::NamedTuple)
    run_helpers = prepTEM(selected_models, forcing, info)
    runTEM!(run_helpers.space_selected_models, run_helpers.space_forcing, run_helpers.space_spinup_forcing, run_helpers.loc_forcing_t, run_helpers.space_output, run_helpers.space_land, run_helpers.tem_info)
    return run_helpers.output_array
end

function runTEM!(selected_models, forcing::NamedTuple, info::NamedTuple)
    run_helpers = prepTEM(selected_models, forcing, info)
    runTEM!(run_helpers.space_selected_models, run_helpers.space_forcing, run_helpers.space_spinup_forcing, run_helpers.loc_forcing_t, run_helpers.space_output, run_helpers.space_land, run_helpers.tem_info)
    return run_helpers.output_array
end

function runTEM!(forcing::NamedTuple, info::NamedTuple)
    run_helpers = prepTEM(forcing, info)
    runTEM!(run_helpers.space_selected_models, run_helpers.space_forcing, run_helpers.space_spinup_forcing, run_helpers.loc_forcing_t, run_helpers.space_output, run_helpers.space_land, run_helpers.tem_info)
    return run_helpers.output_array
end

function runTEM!(space_selected_models, space_forcing, space_spinup_forcing, loc_forcing_t, space_output, space_land, tem_info::NamedTuple)
    parallelizeTEM!(space_selected_models, space_forcing, space_spinup_forcing, loc_forcing_t, space_output, space_land, tem_info, tem_info.run.parallelization)
    return nothing
end

runTEMYax

Sindbad.Simulation.runTEMYax Function
julia
runTEMYax(forcing::NamedTuple, output::NamedTuple, tem::NamedTuple, selected_models::Tuple; max_cache = 1.0e9)

Arguments:

  • forcing: a forcing NT that contains the forcing time series set for ALL locations

  • output: an output NT including the data arrays, as well as information of variables and dimensions

  • tem: a nested NT with necessary information of helpers, models, and spinup needed to run SINDBAD TEM and models

  • selected_models: a tuple of all models selected in the given model structure

  • max_cache: cache size to use for mapCube

Code
julia
function runTEMYax(selected_models::Tuple, forcing::NamedTuple, info::NamedTuple)

    # forcing/input information
    incubes = forcing.data;
    indims = forcing.dims;
    
    # information for running model
    run_helpers = prepTEM(forcing, info);
    loc_land = deepcopy(run_helpers.loc_land);

    outcubes = mapCube(TEMYax,
        (incubes...,);
        selected_models=selected_models,
        forcing_vars=forcing.variables,
        output_vars = run_helpers.output_vars,
        loc_land=loc_land,
        tem=run_helpers.tem_info,
        indims=indims,
        outdims=run_helpers.output_dims,
        max_cache=info.settings.experiment.exe_rules.yax_max_cache,
        ispar=true)
    return outcubes
end

setOutputForTimeStep!

Sindbad.Simulation.setOutputForTimeStep! Function
julia
setOutputForTimeStep!(outputs, land, ts, Val{output_vars})

Arguments:

  • outputs: vector of model output vectors

  • land: a core SINDBAD NT that contains all variables for a given time step that is overwritten at every timestep

  • ts: time step

  • ::Val{output_vars}: a dispatch for vals of the output variables to generate the function


setSequence

Sindbad.Simulation.setSequence Function
julia
setSequence(tem_info, new_sequence)

Arguments:

  • tem_info: Tuple with the field spinup_sequence

  • new_sequence

Outputs

  • an updated tem_info object with new spinup sequence modes
Code
julia
function setSequence(tem_info, new_sequence)
    return @set tem_info.spinup_sequence = new_sequence
end

setupOptiOutput

Sindbad.Simulation.setupOptiOutput Function
julia
setupOptiOutput(info::NamedTuple, output::NamedTuple[, ::DoRunOptimization | ::DoNotRunOptimization])

Creates the output fields needed for the optimization experiment.

Arguments:

  • info: A SINDBAD NamedTuple containing all information needed for setup and execution of an experiment.

  • output: A base output NamedTuple to which optimization-specific fields will be added.

  • ::DoRunOptimization: (Optional) A type dispatch indicating that optimization is enabled. Adds fields for optimized parameters.

  • ::DoNotRunOptimization: (Optional) A type dispatch indicating that optimization is not enabled. Returns the base output unchanged.

Returns:

  • A NamedTuple containing the base output fields, with additional fields for optimization if enabled.

Notes:

  • When optimization is enabled, the function:

    • Adds a parameter_dim field to the output, which includes the parameter dimension and metadata.

    • Creates an OutDims object for storing optimized parameters, with the appropriate backend and file path.

  • When optimization is not enabled, the function simply returns the input output NamedTuple unchanged.

Examples:

  1. With optimization enabled:
julia
output = setupOptiOutput(info, output, DoRunOptimization())
  1. Without optimization:
julia
output = setupOptiOutput(info, output, DoNotRunOptimization())
Code
julia
function setupOptiOutput end

function setupOptiOutput(info::NamedTuple, output::NamedTuple, ::DoRunOptimization)
    @debug "     setupOptiOutput: getting parameter output for optimization..."
    params = info.optimization.parameter_table.name_full    
    paramaxis = YAXArrays.Dim{:parameter}(params)
    outformat = info.output.format
    backend = outformat == "nc" ? :netcdf : :zarr
    od = YAXArrays.OutDims(paramaxis;
        path=joinpath(info.output.dirs.optimization,
            "optimized_parameters.$(outformat)"),
        backend=backend,
        overwrite=true)
    # list of parameter
    output = set_namedtuple_field(output, (:parameter_dim, od))
    return output
end

function setupOptiOutput(info::NamedTuple, output::NamedTuple, ::DoRunOptimization)
    @debug "     setupOptiOutput: getting parameter output for optimization..."
    params = info.optimization.parameter_table.name_full    
    paramaxis = YAXArrays.Dim{:parameter}(params)
    outformat = info.output.format
    backend = outformat == "nc" ? :netcdf : :zarr
    od = YAXArrays.OutDims(paramaxis;
        path=joinpath(info.output.dirs.optimization,
            "optimized_parameters.$(outformat)"),
        backend=backend,
        overwrite=true)
    # list of parameter
    output = set_namedtuple_field(output, (:parameter_dim, od))
    return output
end

function setupOptiOutput(info::NamedTuple, output::NamedTuple, ::DoNotRunOptimization)
    return output
end

spinup

Sindbad.Simulation.spinup Function
julia
spinup(spinup_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps, spinup_mode::SpinupMode)

Runs the spinup process for the SINDBAD Terrestrial Ecosystem Model (TEM) to initialize the model to a steady state. The spinup process updates the state variables (e.g., pools) using various spinup methods.

Arguments:

  • spinup_models: A tuple of a subset of all models in the given model structure that are selected for spinup.

  • spinup_forcing: A forcing NamedTuple containing the time series of environmental drivers for the spinup process.

  • loc_forcing_t: A forcing NamedTuple for a single location and a single time step.

  • land: A SINDBAD NamedTuple containing all variables for a given time step, which is overwritten at every timestep.

  • tem_info: A helper NamedTuple containing necessary objects for model execution and type consistencies.

  • n_timesteps: The number of timesteps for the spinup process.

  • spinup_mode::SpinupMode: A type dispatch that determines the spinup method to be used.

Returns:

  • land: The updated SINDBAD NamedTuple containing the final state of the model after the spinup process.

SpinupMode

Abstract type for model spinup modes in SINDBAD

Available methods/subtypes:

  • AllForwardModels: Use all forward models for spinup

  • EtaScaleA0H: scale carbon pools using diagnostic scalars for ηH and c_remain

  • EtaScaleA0HCWD: scale carbon pools of CWD (cLitSlow) using ηH and set vegetation pools to c_remain

  • EtaScaleAH: scale carbon pools using diagnostic scalars for ηH and ηA

  • EtaScaleAHCWD: scale carbon pools of CWD (cLitSlow) using ηH and scale vegetation pools by ηA

  • NlsolveFixedpointTrustregionCEco: use a fixed-point nonlinear solver with trust region for carbon pools (cEco)

  • NlsolveFixedpointTrustregionCEcoTWS: use a fixed-point nonlinear solver with trust region for both cEco and TWS

  • NlsolveFixedpointTrustregionTWS: use a fixed-point nonlinearsolver with trust region for Total Water Storage (TWS)

  • ODEAutoTsit5Rodas5: use the AutoVern7(Rodas5) method from DifferentialEquations.jl for solving ODEs

  • ODEDP5: use the DP5 method from DifferentialEquations.jl for solving ODEs

  • ODETsit5: use the Tsit5 method from DifferentialEquations.jl for solving ODEs

  • SSPDynamicSSTsit5: use the SteadyState solver with DynamicSS and Tsit5 methods

  • SSPSSRootfind: use the SteadyState solver with SSRootfind method

  • SelSpinupModels: run only the models selected for spinup in the model structure

  • Spinup_TWS: Spinup spinup_mode for Total Water Storage (TWS)

  • Spinup_cEco: Spinup spinup_mode for cEco

  • Spinup_cEco_TWS: Spinup spinup_mode for cEco and TWS


Extended help

Notes:

  • The spinup process can use different methods depending on the spinup_mode, including fixed-point solvers, ODE solvers, and steady-state solvers.

  • The function dynamically selects the appropriate spinup method based on the spinup_mode dispatch type.

  • For ODE-based methods, the function uses DifferentialEquations.jl to solve the spinup equations.

  • For steady-state solvers, the function uses methods like DynamicSS or SSRootfind to find equilibrium states.

Examples:

  1. Running spinup with selected models:
julia
land = spinup(spinup_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps, SelSpinupModels())
  1. Running spinup with ODE solver (Tsit5):
julia
land = spinup(spinup_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps, ODETsit5())
  1. Running spinup with fixed-point solver for cEco and TWS:
julia
land = spinup(spinup_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps, NlsolveFixedpointTrustregionCEcoTWS())
  1. Running spinup with steady-state solver (SSRootfind):
julia
land = spinup(spinup_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps, SSPSSRootfind())
Code
julia
function spinup(::Any, ::Any, ::Any, land, ::Any, ::Any, x::SpinupMode)
    @warn "
    Spinup mode `$(nameof(typeof(x)))` not implemented. 
    
    To implement a new spinup mode:
    
    - First add a new type as a subtype of `SpinupMode` in `src/Types/SimulationTypes.jl`. 
    
    - Then, add a corresponding method.
      - if it can be implemented as an internal Sindbad method without additional dependencies, implement the method in `src/Simulation/spinupTEM.jl`.     
      - if it requires additional dependencies, implement the method in `ext/<extension_name>/SimulationSpinup.jl` extension.

    
    As a fallback, this function will return the land as is.

    "
    return land
end

function spinup(spinup_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps, ::SelSpinupModels)
    land = timeLoopTEMSpinup(spinup_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps)
    return land
end

function spinup(all_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps, ::AllForwardModels)
    land = timeLoopTEMSpinup(all_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps)
    return land
end

function spinup(_, _, _, land, helpers, _, ::EtaScaleAH)
    @unpack_nt cEco  land.pools
    helpers = helpers.model_helpers
    cEco_prev = copy(cEco)
    ηH = one(eltype(cEco))
    if :ηH propertynames(land.diagnostics)
        ηH = land.diagnostics.ηH
    end
    ηA = one(eltype(cEco))
    if :ηA propertynames(land.diagnostics)
        ηA = land.diagnostics.ηA
    end
    for cSoilZix  helpers.pools.zix.cSoil
        cSoilNew = cEco[cSoilZix] * ηH
        @rep_elem cSoilNew  (cEco, cSoilZix, :cEco)
    end
    for cLitZix  helpers.pools.zix.cLit
        cLitNew = cEco[cLitZix] * ηH
        @rep_elem cLitNew  (cEco, cLitZix, :cEco)
    end
    for cVegZix  helpers.pools.zix.cVeg
        cVegNew = cEco[cVegZix] * ηA
        @rep_elem cVegNew  (cEco, cVegZix, :cEco)
    end
    @pack_nt cEco  land.pools
    land = SindbadTEM.adjustPackPoolComponents(land, helpers, land.models.c_model)
    @pack_nt cEco_prev  land.states
    return land
end

function spinup(_, _, _, land, helpers, _, ::EtaScaleAHCWD)
    @unpack_nt cEco  land.pools
    helpers = helpers.model_helpers
    cEco_prev = copy(cEco)
    ηH = one(eltype(cEco))
    if :ηH propertynames(land.diagnostics)
        ηH = land.diagnostics.ηH
    end
    ηA = one(eltype(cEco))
    if :ηA propertynames(land.diagnostics)
        ηA = land.diagnostics.ηA
    end
    for cLitZix  helpers.pools.zix.cLitSlow
        cLitNew = cEco[cLitZix] * ηH
        @rep_elem cLitNew  (cEco, cLitZix, :cEco)
    end
    for cVegZix  helpers.pools.zix.cVeg
        cVegNew = cEco[cVegZix] * ηA
        @rep_elem cVegNew  (cEco, cVegZix, :cEco)
    end
    @pack_nt cEco  land.pools
    land = SindbadTEM.adjustPackPoolComponents(land, helpers, land.models.c_model)
    @pack_nt cEco_prev  land.states
    return land
end

function spinup(_, _, _, land, helpers, _, ::EtaScaleA0H)
    @unpack_nt cEco  land.pools
    helpers = helpers.model_helpers
    cEco_prev = copy(cEco)
    ηH = one(eltype(cEco))
    c_remain = one(eltype(cEco))
    if :ηH propertynames(land.diagnostics)
        ηH = land.diagnostics.ηH
        c_remain = land.states.c_remain
    end
    for cSoilZix  helpers.pools.zix.cSoil
        cSoilNew = cEco[cSoilZix] * ηH
        @rep_elem cSoilNew  (cEco, cSoilZix, :cEco)
    end

    for cLitZix  helpers.pools.zix.cLit
        cLitNew = cEco[cLitZix] * ηH
        @rep_elem cLitNew  (cEco, cLitZix, :cEco)
    end

    for cVegZix  helpers.pools.zix.cVeg
        cLoss = at_least_zero(cEco[cVegZix] - c_remain)
        cVegNew = cEco[cVegZix] - cLoss
        @rep_elem cVegNew  (cEco, cVegZix, :cEco)
    end

    @pack_nt cEco  land.pools
    land = SindbadTEM.adjustPackPoolComponents(land, helpers, land.models.c_model)
    @pack_nt cEco_prev  land.states
    return land
end

function spinup(_, _, _, land, helpers, _, ::EtaScaleA0HCWD)
    @unpack_nt cEco  land.pools
    helpers = helpers.model_helpers
    cEco_prev = copy(cEco)
    ηH = one(eltype(cEco))
    c_remain = one(eltype(cEco))
    if :ηH propertynames(land.diagnostics)
        ηH = land.diagnostics.ηH
        c_remain = land.states.c_remain
    end

    for cLitZix  helpers.pools.zix.cLitSlow
        cLitNew = cEco[cLitZix] * ηH
        @rep_elem cLitNew  (cEco, cLitZix, :cEco)
    end

    for cVegZix  helpers.pools.zix.cVeg
        cLoss = at_least_zero(cEco[cVegZix] - c_remain)
        cVegNew = cEco[cVegZix] - cLoss
        @rep_elem cVegNew  (cEco, cVegZix, :cEco)
    end

    @pack_nt cEco  land.pools
    land = SindbadTEM.adjustPackPoolComponents(land, helpers, land.models.c_model)
    @pack_nt cEco_prev  land.states
    return land
end

function spinupSequence(spinup_models, sel_forcing, loc_forcing_t, land, tem_info, n_timesteps, log_index, n_repeat, spinup_mode)
    land = spinupSequenceLoop(spinup_models, sel_forcing, loc_forcing_t, land, tem_info, n_timesteps, log_index, n_repeat, spinup_mode)
    # end
    return land
end

function spinupSequenceLoop(spinup_models, sel_forcing, loc_forcing_t, land, tem_info, n_timesteps, log_loop, n_repeat, spinup_mode)
    for loop_index  1:n_repeat
        @debug "        Loop: $(loop_index)/$(n_repeat)"
        land = spinup(spinup_models,
            sel_forcing,
            loc_forcing_t,
            land,
            tem_info,
            n_timesteps,
            spinup_mode)
        land = setSpinupLog(land, log_loop, tem_info.run.store_spinup)
        log_loop += 1
    end
    return land
end

function spinupTEM end

function spinupTEM(selected_models, spinup_forcings, loc_forcing_t, land, tem_info, ::DoSpinupTEM)
    land = setSpinupLog(land, 1, tem_info.run.store_spinup)
    log_index = 2
    for spin_seq  tem_info.spinup_sequence
        forc_name = spin_seq.forcing
        n_timesteps = spin_seq.n_timesteps
        n_repeat = spin_seq.n_repeat
        spinup_mode = spin_seq.spinup_mode
        @debug "Spinup: \n         spinup_mode: $(nameof(typeof(spinup_mode))), forcing: $(forc_name)"
        sel_forcing = sequenceForcing(spinup_forcings, forc_name)
        land = spinupSequence(selected_models, sel_forcing, loc_forcing_t, land, tem_info, n_timesteps, log_index, n_repeat, spinup_mode)
        log_index += n_repeat
    end
    return land
end

function spinupTEM(selected_models, spinup_forcings, loc_forcing_t, land, tem_info, ::DoSpinupTEM)
    land = setSpinupLog(land, 1, tem_info.run.store_spinup)
    log_index = 2
    for spin_seq  tem_info.spinup_sequence
        forc_name = spin_seq.forcing
        n_timesteps = spin_seq.n_timesteps
        n_repeat = spin_seq.n_repeat
        spinup_mode = spin_seq.spinup_mode
        @debug "Spinup: \n         spinup_mode: $(nameof(typeof(spinup_mode))), forcing: $(forc_name)"
        sel_forcing = sequenceForcing(spinup_forcings, forc_name)
        land = spinupSequence(selected_models, sel_forcing, loc_forcing_t, land, tem_info, n_timesteps, log_index, n_repeat, spinup_mode)
        log_index += n_repeat
    end
    return land
end

function spinupTEM(selected_models, spinup_forcings, loc_forcing_t, land, tem_info, ::DoNotSpinupTEM)
    return land
end

spinupTEM

Sindbad.Simulation.spinupTEM Function
julia
spinupTEM(selected_models, forcing, loc_forcing_t, land, tem_info, spinup_mode)

The main spinup function that handles the spinup method based on inputs from spinup.json. Either the spinup is loaded or/and run using spinup functions for different spinup methods.

Arguments:

  • selected_models: a tuple of all models selected in the given model structure

  • forcing: a forcing NT that contains the forcing time series set for ALL locations

  • loc_forcing_t: a forcing NT for a single location and a single time step

  • land: SINDBAD NT input to the spinup of TEM during which subfield(s) of pools are overwritten

  • tem_info: helper NT with necessary objects for model run and type consistencies

  • tem_spinup: a NT with information/instruction on spinning up the TEM

  • spinup_mode: A type dispatch that determines whether spinup is included or excluded:

    • ::DoSpinupTEM: Runs the spinup process before the main simulation. Set spinup_TEM to true in the flag section of experiment_json.

    • ::DoNotSpinupTEM: Skips the spinup process and directly runs the main simulation. Set spinup_TEM to false in the flag section of experiment_json.

Examples

julia
julia> using Sindbad

julia> # Run spinup with DoSpinupTEM
julia> # land_spinup = spinupTEM(selected_models, forcing, loc_forcing_t, land, tem_info, DoSpinupTEM())

julia> # Skip spinup with DoNotSpinupTEM
julia> # land = spinupTEM(selected_models, forcing, loc_forcing_t, land, tem_info, DoNotSpinupTEM())

Notes:

  • When DoSpinupTEM is used:

    • The function runs the spinup sequences
  • When DoNotSpinupTEM is used:

    • The function skips the spinup process returns the land as is`
Code
julia
function spinupTEM end

function spinupTEM(selected_models, spinup_forcings, loc_forcing_t, land, tem_info, ::DoSpinupTEM)
    land = setSpinupLog(land, 1, tem_info.run.store_spinup)
    log_index = 2
    for spin_seq  tem_info.spinup_sequence
        forc_name = spin_seq.forcing
        n_timesteps = spin_seq.n_timesteps
        n_repeat = spin_seq.n_repeat
        spinup_mode = spin_seq.spinup_mode
        @debug "Spinup: \n         spinup_mode: $(nameof(typeof(spinup_mode))), forcing: $(forc_name)"
        sel_forcing = sequenceForcing(spinup_forcings, forc_name)
        land = spinupSequence(selected_models, sel_forcing, loc_forcing_t, land, tem_info, n_timesteps, log_index, n_repeat, spinup_mode)
        log_index += n_repeat
    end
    return land
end

function spinupTEM(selected_models, spinup_forcings, loc_forcing_t, land, tem_info, ::DoSpinupTEM)
    land = setSpinupLog(land, 1, tem_info.run.store_spinup)
    log_index = 2
    for spin_seq  tem_info.spinup_sequence
        forc_name = spin_seq.forcing
        n_timesteps = spin_seq.n_timesteps
        n_repeat = spin_seq.n_repeat
        spinup_mode = spin_seq.spinup_mode
        @debug "Spinup: \n         spinup_mode: $(nameof(typeof(spinup_mode))), forcing: $(forc_name)"
        sel_forcing = sequenceForcing(spinup_forcings, forc_name)
        land = spinupSequence(selected_models, sel_forcing, loc_forcing_t, land, tem_info, n_timesteps, log_index, n_repeat, spinup_mode)
        log_index += n_repeat
    end
    return land
end

function spinupTEM(selected_models, spinup_forcings, loc_forcing_t, land, tem_info, ::DoNotSpinupTEM)
    return land
end

timeLoopTEMSpinup

Sindbad.Simulation.timeLoopTEMSpinup Function
julia
timeLoopTEMSpinup(spinup_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps)

do/run the time loop of the spinup models to update the pool. Note that, in this function, the time series is not stored and the land/land is overwritten with every iteration. Only the state at the end is returned

Arguments:

  • spinup_models: a tuple of a subset of all models in the given model structure that is selected for spinup

  • spinup_forcing: a selected/sliced/computed forcing time series for running the spinup sequence for a location

  • loc_forcing_t: a forcing NT for a single location and a single time step

  • land: SINDBAD NT input to the spinup of TEM during which subfield(s) of pools are overwritten

  • tem_info: helper NT with necessary objects for model run and type consistencies

  • n_timesteps: number of time steps

Code
julia
function timeLoopTEMSpinup(spinup_models, spinup_forcing, loc_forcing_t, land, tem_info, n_timesteps)
    for ts  1:n_timesteps
        f_ts = getForcingForTimeStep(spinup_forcing, loc_forcing_t, ts, tem_info.vals.forcing_types)
        land = computeTEM(spinup_models, f_ts, land, tem_info.model_helpers)
    end
    return land
end