Flows Output

Contents

Overview | Columns | Sign Convention | Configuration | Assumptions | Examples | See Also

Overview

File: flows.csv

flows.csv records the optimal commodity flow along every edge in the system at every representative time step. It is the primary operational output — it shows how much of each commodity is produced, transported, or consumed by each asset component at each point in time.

The file uses long format by default: each row is a single (component, time step) observation. An optional wide format pivots time steps into columns.

Representative time steps vs. full year

flows.csv contains only the time steps used in the optimization (the representative periods). If time-domain reduction (TDR) is active, this is a subset of the full year. To obtain full-year (8760-hour) flows, enable WriteFullTimeseries = true in case_settings.json. See Full Time Series Output for details.

Columns

ColumnTypeDescription
commodityStringCommodity type carried by the edge (e.g., Electricity, NaturalGas, CO2)
node_inStringIdentifier of the vertex at the start (origin) of the edge
node_outStringIdentifier of the vertex at the end (destination) of the edge
resource_idStringUnique identifier of the parent asset
component_idStringUnique identifier of the edge component
resource_typeStringAsset type of the parent asset (e.g., ThermalPower{NaturalGas}, Battery, VRE)
component_typeStringType of the edge (e.g., UnidirectionalEdge{Electricity}, BidirectionalEdge{NaturalGas})
variableStringAlways "flow"
timeIntRepresentative time step index (1-based integer, matches time in other output files)
valueFloat64Flow value at this time step, in commodity units per hour (see Sign Convention)

Sign Convention (only for unidirectional edges)

Flow values can be positive or negative. The sign indicates the direction of flow relative to the edge's defined direction (from node_in to node_out). The interpretation of the sign depends on the types of the "vertices" (nodes, transformations, storage) connected by the edge. The table below summarizes the sign convention for unidirectional edges:

node_in typenode_out typeSignInterpretation
NodeNodePositiveCommodity moves between two network nodes
NodeTransformationNegativeCommodity flows into a conversion process (e.g., fuel input to a power plant)
NodeStorageNegativeCommodity is being charged into storage (leaving the node)
TransformationNodePositiveCommodity flows out of a conversion process (e.g., electricity output from a power plant)
TransformationStorageNegativeConverted commodity flows into storage
TransformationTransformationPositiveCommodity passes between two conversion stages
StorageNodePositiveCommodity is being discharged from storage (entering the node)
StorageStoragePositiveCommodity moves between two storage components
StorageTransformationPositiveStored commodity flows into a conversion process
Bidirectional edges

For bidirectional edges, the flow is determined by the optimization and can be positive or negative.

Interpreting storage flows

For a Battery asset, the charge edge (grid → storage) will show negative values when charging, and the discharge edge (storage → grid) will show positive values when discharging.

Configuration

SettingFileDefaultEffect
OutputLayout (or OutputLayout.Flow)macro_settings.json"long"Set to "wide" to pivot time steps into columns (rows become components, columns become time step indices).
WriteFullTimeseriescase_settings.jsonfalseWhen true and TDR is active, also write expanded 8760-hour flows to full_time_series/flows.csv.

Assumptions

  • Units. Flow values are in commodity units per hour. For electricity this is MW (megawatts); for biomass, or other mass-based commodities this is in the mass units used in your inputs (e.g., tonnes/hour).
  • Annual totals. To compute the annual total flow for a component, multiply each time step's flow value by its weight from time_weights.csv and sum. This accounts for how many full-year hours each representative time step represents:
    Annual flow = Σ_t  value(t) × weight(t) × hours_per_timestep
  • Time step index. The time column is an integer index (1, 2, 3, …) corresponding to the representative time steps used in the optimization. It matches the time column in storage_level.csv, curtailment.csv, non_served_demand.csv, and time_weights.csv. It does not represent a calendar hour, unless you are using a full-year (8760-hour) time representation without TDR.
  • Filtering. write_flow and get_optimal_flow support filtering by commodity and asset_type. Use these to reduce file size when you only need a subset of results.

Examples

Default Long Format (example rows)

commoditynode_innode_outresource_idcomponent_idresource_typecomponent_typevariabletimevalue
Electricityelec_SESE_thermalpower_transformsSE_thermalpowerSE_thermalpower_elec_edgeThermalPower{NaturalGas}UnidirectionalEdge{Electricity}flow1450.5
Electricityelec_SESE_thermalpower_transformsSE_thermalpowerSE_thermalpower_elec_edgeThermalPower{NaturalGas}UnidirectionalEdge{Electricity}flow2380.2

Wide Format (OutputLayout.Flow = "wide")

commoditynode_innode_outresource_idcomponent_idresource_typecomponent_typevariable123
Electricityelec_SESE_thermalpower_transformsSE_thermalpowerSE_thermalpower_elec_edgeThermalPower{NaturalGas}UnidirectionalEdge{Electricity}flow450.5380.2

Writing and Reading Flows

  • write_flow allows you to write flow data to a custom file path, with optional filters for commodity, asset type, or component type. This is useful for exporting subsets of the flow data or for writing to a different location.
  • get_optimal_flow returns the flow data as a DataFrame without writing a file. This is useful for programmatic access to flow values within Julia.
# Write flows for the full system
write_flow("flows.csv", system)

# Write only electricity flows
write_flow("flows_elec.csv", system, commodity="Electricity")

# Write flows for thermal power only (parameter-free matching)
write_flow("flows_thermal.csv", system, asset_type="ThermalPower")

# Get flows as a DataFrame
df = get_optimal_flow(system)

# Compute annual electricity generation for each component
using DataFrames, CSV
flows = CSV.read("results/flows.csv", DataFrame)
weights = CSV.read("results/time_weights.csv", DataFrame)
elec_flows = flows[flows.commodity .== "Electricity", :]
# join weights and compute annual total
annual = leftjoin(elec_flows, weights, on=:time)
annual.annual_MWh = annual.value .* annual.weight

See Also