Utility functions

    all_constraints

    MacroEnergy.all_constraintsFunction
    all_constraints(v::AbstractVertex)

    Get all constraints on a vertex.

    Arguments

    • v: A vertex object that is a subtype of AbstractVertex

    Returns

    • A vector of all constraint objects on the vertex

    Examples

    constraints = all_constraints(elec_node)
    source

    all_constraints_types

    MacroEnergy.all_constraints_typesFunction
    all_constraints_types(v::AbstractVertex)

    Get the types of all constraints on a vertex.

    Arguments

    • v: A vertex object that is a subtype of AbstractVertex

    Returns

    • A vector of types of all constraints on the vertex

    Examples

    constraint_types = all_constraints_types(elec_node)
    source

    asset_ids

    MacroEnergy.asset_idsFunction
    asset_ids(system::System; source::String="assets")

    Get the set of asset IDs from a system, either from loaded assets or input files.

    Arguments

    • system::System: The system to get asset IDs from
    • source::String: The source to get asset IDs from. Can be either:
      • "assets" (default): Get IDs from already loaded assets in the system
      • "inputs": Get IDs from input files

    Returns

    • Set{AssetId}: A set of asset IDs

    Examples

    # Get IDs from loaded assets
    ids = asset_ids(system)

    Notes

    • If source="assets" and no assets are loaded, a warning is issued
    • If an invalid source is provided, an error is thrown
    source

    balance_ids

    MacroEnergy.balance_idsFunction
    balance_ids(v::AbstractVertex)

    Get the IDs of all balance equations in a vertex.

    Arguments

    • v: A vertex object that is a subtype of AbstractVertex

    Returns

    • A vector of Symbols representing the IDs of all balance equations

    Examples

    balance_ids = balance_ids(elec_node)
    source

    balance_data

    MacroEnergy.balance_dataFunction
    balance_data(v::AbstractVertex, i::Symbol)

    Get the input data for a specific balance equation in a vertex.

    Arguments

    • v: A vertex object that is a subtype of AbstractVertex
    • i: Symbol representing the ID of the balance equation

    Returns

    • The input data (usually stoichiometric coefficients) for the specified balance equation

    Examples

    demand_data = balance_data(elec_node, :demand)
    source

    create_output_path

    MacroEnergy.create_output_pathFunction
    create_output_path(system::System, path::String=system.data_dirpath)

    Create and return the path to the output directory for storing results based on system settings.

    Arguments

    • system::System: The system object containing settings and configuration
    • path::String: Base path for the output directory (defaults to system.data_dirpath)

    Returns

    • String: Path to the created output directory

    The function creates an output directory based on system settings. If OverwriteResults is false, it will avoid overwriting existing directories by appending incremental numbers (e.g., "001", "002") to the directory name. The directory is created if it doesn't exist.

    Example

    julia> system.settings
    (..., OverwriteResults = true, OutputDir = "result_dir")
    julia> output_path = create_output_path(system)
    # Returns "path/to/system.data_dirpath/result_dir" or "path/to/system.data_dirpath/result_dir_001" if original exists
    julia> output_path = create_output_path(system, "path/to/output")
    # Returns "path/to/output/result_dir" or "path/to/output/result_dir_001" if original exists
    source

    get_asset_by_id

    MacroEnergy.get_asset_by_idFunction
    get_asset_by_id(system::System, id::Symbol)

    Find an asset in the system by its ID.

    Arguments

    • system: A System object containing various assets
    • id: Symbol representing the ID of the asset to find

    Returns

    • The asset object if found
    • nothing if no asset with the given ID exists

    Examples

    # Find a battery asset
    battery = get_asset_by_id(system, :battery_SE)
    
    # Find a thermal power plant
    thermal_plant = get_asset_by_id(system, :natural_gas_SE)
    source

    get_assets_sametype

    MacroEnergy.get_assets_sametypeFunction
    get_assets_sametype(system::System, asset_type::T) where T<:Type{<:AbstractAsset}

    Get all assets of a specific type from the system.

    Arguments

    • system: A System object containing various assets
    • asset_type: The type of assets to retrieve (must be a subtype of AbstractAsset)

    Returns

    • A vector of assets of the specified type

    Examples

    # Get all battery assets
    batteries = get_assets_sametype(system, Battery)
    battery = batteries[1]  # first battery in the list
    
    # Get all natural gas thermal power plants
    thermal_plants = get_assets_sametype(system, ThermalPower{NaturalGas})
    source

    get_asset_types

    MacroEnergy.get_asset_typesFunction
    get_asset_types(system::System)

    Get a vector of the types of all assets in the system.

    Arguments

    • system: A System object containing various assets

    Returns

    • A vector of DataTypes representing the type of each asset in the system

    Examples

    asset_types = get_asset_types(system)
    unique(asset_types)  # Get unique asset types in the system
    source

    get_balance

    MacroEnergy.get_balanceFunction
    get_balance(v::AbstractVertex, i::Symbol)

    Get the mathematical expression of a balance equation in a vertex.

    Arguments

    • v: A vertex object that is a subtype of AbstractVertex
    • i: Symbol representing the ID of the balance equation

    Returns

    • The mathematical expression of the balance equation

    Examples

    # Get the demand balance expression
    demand_expr = get_balance(elec_node, :demand)
    source

    get_constraint_by_type

    MacroEnergy.get_constraint_by_typeFunction
    get_constraint_by_type(v::AbstractVertex, constraint_type::Type{<:AbstractTypeConstraint})

    Get a constraint on a vertex by its type.

    Arguments

    • v: A vertex object that is a subtype of AbstractVertex
    • constraint_type: The type of constraint to find

    Returns

    • If exactly one constraint of the specified type exists: returns that constraint
    • If multiple constraints of the specified type exist: returns a vector of those constraints
    • If no constraints of the specified type exist: returns nothing

    Examples

    balance_constraint = get_constraint_by_type(elec_node, BalanceConstraint)
    source

    get_component_by_fieldname

    MacroEnergy.get_component_by_fieldnameFunction
    get_component_by_fieldname(asset::AbstractAsset, fieldname::Symbol)

    Get a component of an asset by its field name (i.e., fieldname of the asset struct).

    Arguments

    • asset: An asset object that is a subtype of AbstractAsset
    • fieldname: Symbol representing the field name of the component to get (i.e., fieldname of the asset struct)

    Returns

    • The component object stored in the specified field

    Examples

    elec_edge = get_component_by_fieldname(thermal_plant, :elec_edge)
    source

    get_component_ids

    MacroEnergy.get_component_idsFunction
    get_component_ids(asset::AbstractAsset)

    Get the IDs of all components in an asset.

    Arguments

    • asset: An asset object that is a subtype of AbstractAsset

    Returns

    • A vector of Symbols representing the IDs of all components in the asset

    Examples

    component_ids = get_component_ids(thermal_plant)
    source

    get_component_by_id

    MacroEnergy.get_component_by_idFunction
    get_component_by_id(asset::AbstractAsset, component_id::Symbol)

    Find a component (e.g., edges, storages, transformations) of an asset by its ID.

    Arguments

    • asset: An asset object that is a subtype of AbstractAsset
    • component_id: Symbol representing the ID of the component to find

    Returns

    • The component object if found
    • nothing if no component with the given ID exists

    Examples

    elec_edge = get_component_by_id(thermal_plant, :SE_natural_gas_elec_edge)
    source

    get_edges

    MacroEnergy.get_edgesFunction
    get_edges(asset::AbstractAsset; return_ids_map::Bool=false)
    get_edges(assets::Vector{<:AbstractAsset}; return_ids_map::Bool=false)

    Get all edges from an asset or a vector of assets. If return_ids_map=true, a Dict is also returned mapping edge ids to the corresponding asset objects.

    Arguments

    • asset or assets: An asset object or vector of assets that are subtypes of AbstractAsset
    • return_ids_map: If true, also return a Dict mapping edge IDs to their corresponding assets (default: false)

    Returns

    • If return_ids_map=false: A vector of edges
    • If return_ids_map=true: A tuple of (vector of edges, Dict mapping edge IDs to assets)

    Examples

    # Get all edges from a single asset
    edges = get_edges(thermal_plant)
    source

    get_output_layout

    MacroEnergy.get_output_layoutFunction
    get_output_layout(system::System, variable::Union{Nothing,Symbol}=nothing)::String

    Get the output layout ("wide" or "long") for a specific variable from system settings.

    Arguments

    • system::System: System containing output layout settings
    • variable::Union{Nothing,Symbol}=nothing: Variable to get layout for (e.g., :Cost, :Flow)

    Returns

    String indicating layout format: "wide" or "long"

    Settings Format

    The OutputLayout setting can be specified in three ways:

    1. Global string setting:

      settings = (OutputLayout="wide",)  # Same layout for all variables
    2. Per-variable settings using NamedTuple:

      settings = (OutputLayout=(Cost="wide", Flow="long"),)
    3. Default behavior:

      • Returns "long" if setting is missing or invalid
      • Logs warning for unsupported types or missing variables

    Examples

    # Global layout
    system = System(settings=(OutputLayout="wide",))
    get_output_layout(system, :Cost)  # Returns "wide"
    
    # Per-variable layout
    system = System(settings=(OutputLayout=(Cost="wide", Flow="long"),))
    get_output_layout(system, :Cost)  # Returns "wide"
    get_output_layout(system, :Flow)  # Returns "long"
    get_output_layout(system, :Other) # Returns "long" with warning
    source

    get_value

    MacroEnergy.get_valueFunction
    get_value(dict::AbstractDict, keys::Vector{Symbol})

    Get the value from a dictionary based on a sequence of keys.

    Arguments

    • dict::AbstractDict: The dictionary from which to retrieve the value.
    • keys::Vector{Symbol}: The sequence of keys to traverse the dictionary.

    Returns

    • The value retrieved from the dictionary based on the given keys.

    Examples

    dict = Dict(:a => Dict(:b => 1, :c => Dict(:b => 2)))
    get_value(dict, [:a, :b]) # returns 1
    get_value(dict, [:a, :c, :b]) # returns 2
    source

    get_value_and_keys

    MacroEnergy.get_value_and_keysFunction
    get_value_and_keys(dict::AbstractDict, target_key::Symbol, keys=Symbol[])

    Recursively searches for a target key in a dictionary and returns a list of tuples containing the value associated with the target key and the keys leading to it. This function is used to replace the path to a timeseries file with the actual vector of data.

    Arguments

    • dict::AbstractDict: The (nested) dictionary to search in.
    • target_key::Symbol: The key to search for.
    • keys=Symbol[]: (optional) The keys leading to the current dictionary.

    Returns

    • value_keys: A list of tuples, where each tuple contains - the value associated with the target key - the keys leading to it in the nested dictionary.

    Examples

    dict = Dict(:a => Dict(:b => 1, :c => Dict(:b => 2)))
    get_value_and_keys(dict, :b) # returns [(1, [:a, :b]), (2, [:a, :c, :b])]

    Where the first element of the tuple is the value of the key :b and the second element is the list of keys to reach that value.

    source

    filter_edges_by_asset_type!

    MacroEnergy.filter_edges_by_asset_type!Function
    filter_edges_by_asset_type!(edges::Vector{AbstractEdge}, asset_type::Union{Symbol,Vector{Symbol}}, edge_asset_map::Dict{Symbol,Base.RefValue{<:AbstractAsset}})

    Filter edges and their associated assets by asset type.

    Arguments

    • edges::Vector{AbstractEdge}: Edges to filter
    • asset_type::Union{Symbol,Vector{Symbol}}: Target asset type(s)
    • edge_asset_map::Dict{Symbol,Base.RefValue{<:AbstractAsset}}: Mapping of edges to assets

    Effects

    • Modifies edges in-place to keep only edges matching the asset type
    • Modifies edge_asset_map to keep only matching assets

    Throws

    • ArgumentError: If none of the requested asset types are found in the system

    Example

    filter_edges_by_asset_type!(edges, :Battery, edge_asset_map)
    source

    filter_edges_by_commodity!

    MacroEnergy.filter_edges_by_commodity!Function
    filter_edges_by_commodity!(edges::Vector{AbstractEdge}, commodity::Union{Symbol,Vector{Symbol}}, edge_asset_map::Dict{Symbol,Base.RefValue{<:AbstractAsset}}=Dict{Symbol,Base.RefValue{<:AbstractAsset}}())

    Filter the edges by commodity and update the edgeassetmap to match the filtered edges (optional).

    Arguments

    • edges::Vector{AbstractEdge}: The edges to filter
    • commodity::Union{Symbol,Vector{Symbol}}: The commodity to filter by
    • edge_asset_map::Dict{Symbol,Base.RefValue{<:AbstractAsset}}: The edgeassetmap to update (optional)

    Effects

    • Modifies edges in-place to keep only edges matching the commodity type
    • If edge_asset_map is provided, filters it to match remaining edges

    Example

    filter_edges_by_commodity!(edges, :Electricity)
    filter_edges_by_commodity!(edges, [:Electricity, :NaturalGas], edge_asset_map)
    source

    find_available_path

    MacroEnergy.find_available_pathFunction
    find_available_path(path::String, basename::String="results"; max_attempts::Int=999)

    Choose an available output directory with the name "basename_<number>" by appending incremental numbers to the base path.

    Arguments

    • path::String: Base path for the output directory.
    • basename::String: Base name of the output directory.
    • max_attempts::Int: Maximum number of attempts to find an available directory (default is 999).

    Returns

    • String: Full path to the chosen output directory.

    The function first expands the given path to its full path and then attempts to find an available directory by appending incremental numbers (e.g., "basename001", "basename002") up to max_attempts times. If an available directory is found, it returns the full path to that directory. If no available directory is found after max_attempts attempts, it raises an error.

    Example

    julia> path = "path/to/output"
    julia> output_path = find_available_path(path)
    # Returns "path/to/output/results_001" or "path/to/output/results_002" etc.
    source

    find_node

    MacroEnergy.find_nodeFunction
    find_node(nodes_list::Vector{Union{Node, Location}}, id::Symbol, commodity::Union{Missing,DataType}=missing)

    Search for a node with the specified id and optional commodity type in a list of nodes and locations.

    Arguments

    • nodes_list: Vector of nodes and locations to search through
    • id: Symbol representing the ID of the node to find
    • commodity: Optional DataType specifying the commodity type of the node (default: missing)

    Returns

    • The found node if it exists
    • Throws an error if no matching node is found

    Examples

    # Find a node by ID only
    node = find_node(system.locations, :co2_sink)
    source

    id

    MacroEnergy.idFunction
    id(v::AbstractVertex)

    Get the unique identifier (ID) of a vertex.

    Arguments

    • v: A vertex object that is a subtype of AbstractVertex (i.e., Node, Storage, Transformation)

    Returns

    • A Symbol representing the vertex's unique identifier

    Examples

    vertex_id = id(elec_node)
    source
    id(asset::AbstractAsset)

    Get the unique identifier (ID) of an asset.

    Arguments

    • asset: An asset object that is a subtype of AbstractAsset

    Returns

    • A Symbol representing the asset's unique identifier

    Examples

    thermal_plant = get_asset_by_id(system, :SE_natural_gas)
    asset_id = id(thermal_plant)  # Returns the ID of the thermal plant
    source

    json_to_csv

    MacroEnergy.json_to_csvFunction
    json_to_csv(json_data::AbstractDict{Symbol, Any}, vec_data::VectorData=VectorData(), nesting_str::AbstractString="--")
    
    Convert a JSON object to a CSV file. The Dict should contain a single 
    asset described by :type, :instance_data, and possibly :global_data fields.
    
    # Arguments
    - `json_data`: The JSON object to convert.
    - `vec_data`: The VectorData object to store the timeseries or other vector data in.
    - `nesting_str`: The string used to denote nested properties.
    
    # Returns
    - A vector of OrderedDicts containing the data for each instance
    source

    location_ids

    MacroEnergy.location_idsFunction
    location_ids(system::System)

    Get a vector of the IDs of all locations in the system.

    Arguments

    • system: A System object containing various locations

    Returns

    • A vector of Symbols representing the IDs of all locations in the system

    Examples

    ids = location_ids(system)
    source
    MacroEnergy.print_struct_infoFunction
    print_struct_info(asset::AbstractAsset)

    Print fields and types of a given asset.

    Arguments

    • asset: An asset object that is a subtype of AbstractAsset

    Examples

    thermal_plant = get_asset_by_id(system, :SE_natural_gas_fired_combined_cycle_1)
    print_struct_info(thermal_plant)  # Prints the fields and types of the asset
    source

    reshape_wide

    MacroEnergy.reshape_wideFunction
    reshape_wide(df::DataFrame; variable_col::Symbol=:variable, value_col::Symbol=:value)

    Reshape a DataFrame from long to wide format.

    Arguments

    • df::DataFrame: Input DataFrame
    • variable_col::Symbol: Column name containing variable names
    • value_col::Symbol: Column name containing values

    Examples

    df_long = DataFrame(id=[1,1,2,2], variable=[:a,:b,:a,:b], value=[10,30,20,40])
    df_wide = reshape_wide(df_long)
    source
    reshape_wide(df::DataFrame, id_cols::Union{Vector{Symbol},Symbol}, variable_col::Symbol, value_col::Symbol)

    Reshape a DataFrame from long to wide format.

    Arguments

    • df::DataFrame: DataFrame in long format to be reshaped
    • id_cols::Union{Vector{Symbol},Symbol}: Column(s) to use as identifiers
    • variable_col::Symbol: Column containing variable names that will become new columns
    • value_col::Symbol: Column containing values that will fill the new columns

    Returns

    • DataFrame: Reshaped DataFrame in wide format

    Throws

    • ArgumentError: If required columns are not present in the DataFrame

    Examples

    df_wide = reshape_wide(df, :year, :variable, :value)
    source

    reshape_long

    MacroEnergy.reshape_longFunction
    reshape_long(df::DataFrame; id_cols::Vector{Symbol}=Symbol[], view::Bool=true)

    Reshape a DataFrame from wide to long format.

    Arguments

    • df::DataFrame: Input DataFrame
    • id_cols::Vector{Symbol}: Columns to use as identifiers when stacking
    • view::Bool: Whether to return a view of the DataFrame instead of a copy

    Examples

    df_wide = DataFrame(id=[1,2], a=[10,20], b=[30,40])
    df_long = reshape_long(df_wide, :time, :component_id, :value)
    source

    search_assets

    MacroEnergy.search_assetsFunction
    search_assets(asset_type, available_types)

    Search for asset types in a list of available assets, supporting wildcards and parametric types.

    Arguments

    • asset_type::Union{AbstractString,Vector{<:AbstractString}}: Type(s) to search for
    • available_types::Vector{<:AbstractString}: Available asset types to search from

    Returns

    Tuple of two vectors:

    1. Vector{Symbol}: Found asset types
    2. Vector{Symbol}: Missing asset types (only if no matches found)

    Pattern Matching

    Supports three types of matches:

    1. Exact match: "Battery" matches "Battery"
    2. Parametric match: "ThermalPower" matches "ThermalPower{Fuel}"
    3. Wildcard match: "ThermalPower*" matches both "ThermalPower{Fuel}" and "ThermalPowerCCS{Fuel}"

    Examples

    # Available assets
    assets = ["Battery", "ThermalPower{Coal}", "ThermalPower{Gas}"]
    
    # Exact match
    found, missing = search_assets("Battery", assets)
    # found = [:Battery], missing = []
    
    # Parametric match
    found, missing = search_assets("ThermalPower", assets)
    # found = [:ThermalPower{Coal}, :ThermalPower{Gas}], missing = []
    
    # Wildcard match
    found, missing = search_assets("ThermalPower*", assets)
    # found = [:ThermalPower{Coal}, :ThermalPower{Gas}], missing = []
    
    # Multiple types
    found, missing = search_assets(["Battery", "Solar"], assets)
    # found = [:Battery], missing = [:Solar]
    source

    search_commodities

    MacroEnergy.search_commoditiesFunction
    search_commodities(commodities, available_commodities)

    Search for commodity types in a list of available commodities, supporting wildcards and subtypes.

    Arguments

    • commodities::Union{AbstractString,Vector{<:AbstractString}}: Commodity type(s) to search for
    • available_commodities::Vector{<:AbstractString}: Available commodity types to search from

    Returns

    Tuple of two vectors:

    1. Vector{Symbol}: Found commodity types
    2. Vector{Symbol}: Missing commodity types (only if no matches found)

    Pattern Matching

    Supports two types of matches:

    1. Exact match: "Electricity" matches only "Electricity"
    2. Wildcard match: "CO2*" matches both CO2 and its subtypes (e.g., CO2Captured)

    Examples

    # Available commodities
    commodities = ["Electricity", "CO2", "CO2Captured"]
    
    # Exact match
    found, missing = search_commodities("Electricity", commodities)
    # found = [:Electricity], missing = []
    
    # Wildcard match
    found, missing = search_commodities("CO2*", commodities)
    # found = [:CO2, :CO2Captured], missing = []
    
    # Multiple types
    found, missing = search_commodities(["Electricity", "Heat"], commodities)
    # found = [:Electricity], missing = [:Heat]
    Note

    Wildcard searches check against registered commodity types in MacroEnergy.jl.

    source

    set_value

    MacroEnergy.set_valueFunction
    set_value(dict::AbstractDict, keys::Vector{Symbol}, new_value)

    Set the value of a nested dictionary given a list of keys.

    Arguments

    • dict::AbstractDict: The dictionary to modify.
    • keys::Vector{Symbol}: A list of keys representing the path to the value to

    be modified.

    • new_value: The new value to set.

    Examples

    dict = Dict(:a => Dict(:b => 1, :c => Dict(:b => 2)))
    set_value(dict, [:a, :b], 3)
    get_value(dict, [:a, :b]) # returns 3
    source

    struct_info

    timestepbefore

    MacroEnergy.timestepbeforeFunction
    timestepbefore(t::Int, h::Int,subperiods::Vector{StepRange{Int64,Int64})

    Determines the time step that is h steps before index t in subperiod p with circular indexing.

    source

    collect_flow_results

    collect_local_flows

    collect_distributed_flows

    evaluate_vtheta_in_expression

    MacroEnergy.evaluate_vtheta_in_expressionFunction

    Evaluate the expression expr for a specific period using operational subproblem solutions.

    Arguments

    • m::Model: JuMP model containing vTHETA variables and the expression expr to evaluate
    • expr::Symbol: The expression to evaluate
    • subop_sol::Dict: Dictionary mapping subproblem indices to their operational costs
    • subop_indices::Vector{Int64}: The subproblem indices to evaluate

    Returns

    The evaluated expression for the specified period

    source