Transformations

Contents

Overview | Fields | Types | Constructors | Methods | Examples

Overview

Transformations balance flows of several Commodities, handling the conversion of one or more Commodities into one or more others. They are one of the four primary components in Macro, alongside Nodes, Edges, and Storage. They are sub-types of the Vertex type.

Unlike Nodes, which balance flows of a single Commodity, Transformations manage multi-commodity conversion processes. They rely on user-defined stoichiometric balances to govern these multi-flow relationships. They are essential for modeling energy conversion technologies, chemical processes, and other systems that transform one form of energy or material into another.

Transformations in Assets

Transformation components are typically incorporated into Assets, representing the ability of those Assets to convert between different Commodities. This could be used to model:

  • Power Plants: Converting fuel (natural gas, coal, uranium) into electricity and emissions
  • Chemical Plants: Converting raw materials and fuel into chemical products
  • Gas Pipelines: Electricty is required to run compressors and pumps, facilitating the flow of gases. This can be modeled as a Transformation that converts Electricity and NaturalGas into a second flow of NaturalGas.

Natural Gas Power Plant Asset

A natural gas power plant Asset can be modeled using a Transformation component that converts NaturalGas into Electricity, CO2. Other formulations may account for oxidizer and waste heat. The Transformation component uses stoichiometric balances to define the conversion ratios, such as the heat rate (fuel consumption per unit electricity) and emission factor (CO2 per unit fuel). The Edges connected to the Transformation handle the actual flows, including flow / capacity limits, while the Transformation enforces the conversion relationships.

Multi-Product Refineries

Complex industrial processes like refineries can use multiple Transformation components to model different conversion units. Each Transformation handles a specific conversion process (e.g., distillation, cracking, reforming) with its own stoichiometric relationships, allowing for detailed modeling of multi-product facilities.

Transformations Outside of Assets

Transformation components can be used outside of Assets, but there is no standard input file format to do so currently. Most Users will be better served by using Transformation components within Assets, as this allows for more complex interactions and standardized input formats. However, it is possible to define Transformations directly in the Julia script you use to build and solve your model. Please feel free to reach out to the development team via a GitHub issue if you have a use case for this.

Key Concepts

  • Multi-Commodity Conversion: Transformations handle conversion between flows of several Commodity using multi-commodity balance constraints
  • Stoichiometric Balances: User-defined relationships govern the conversion ratios between input and output flows
  • Asset Integration: Transformations are typically used within Assets to model conversion technologies

Transformation Fields

Transformations have the following fields. When running a model, the fields are set by the input files. When creating an Asset, the defaults below can be altered using the @transform_data macro. The internal fields are used by Macro and are not intended to be set by users in most circumstances.

Moreso than other components, Transformations rely heavily on additional inputs defined as part of the Asset they are a part of. These additional inputs are used to define the stoichiometric balances of the Transformation. These are not shown in the following tables as they are not part of the Transformation itself, but rather part of the Asset that contains the Transformation.

Units in Macro

We have assumed that your System is using units of MWh for energy, tonnes for mass, and hour-long time steps. You can use any set of units as long as they are consistent across your operations and investment inputs.

Network Structure

FieldTypeDescriptionDefault
idSymbolUnique identifier-
locationUnion{Missing,Symbol}Location where transformation is placedmissing

Stoichiometric Balance Data (Internal)

FieldTypeDescriptionUnitsDefault
balance_dataDict{Symbol,Dict{Symbol,Float64}}Stoichiometric equation coefficientsvariesDict{Symbol,Dict{Symbol,Float64}}()
constraintsVector{AbstractTypeConstraint}Additional constraints-Vector{AbstractTypeConstraint}()
operation_exprDictOperational JuMP expressions-Dict()
FieldTypeDescriptionUnitsDefault
timedataTimeDataTime-related modeling data--

Types

Type Hierarchy

Transformation types follow a hierarchical structure rooted in the abstract AbstractVertex type:

AbstractVertex
├── Node{T}
├── AbstractStorage{T}
│   ├── Storage{T}
│   └── LongDurationStorage{T}
└── Transformation

Transformation

The Transformation type represents conversion processes between different commodities. Unlike other vertex types that are parameterized by commodity type, Transformations handle multiple commodities simultaneously through stoichiometric balance equations.

Constructors

Keyword Constructors

Transformation(; id::Symbol, timedata::TimeData, [additional_fields...])

Direct constructors using keyword arguments for all fields.

ParameterTypeDescriptionRequired
idSymbolUnique identifierYes
timedataTimeDataTime-related data structureYes
locationUnion{Missing,Symbol}Location where transformation is placedNo
balance_dataDict{Symbol,Dict{Symbol,Float64}}Stoichiometric equation coefficientsNo
constraintsVector{AbstractTypeConstraint}Additional constraintsNo
operation_exprDictOperational JuMP expressionsNo

Primary Constructors

Transformation(id::Symbol, data::Dict{Symbol,Any}, time_data::TimeData)

Creates Transformation components from input data dictionary and time data.

ParameterTypeDescription
idSymbolUnique identifier for the transformation
dataDict{Symbol,Any}Dictionary of transformation configuration data
time_dataTimeDataTime-related data structure

Factory Constructors

make_transformation(id::Symbol, data::Dict{Symbol,Any}, time_data::TimeData)

Internal factory methods for creating Transformation components with data processing.

ParameterTypeDescription
idSymbolUnique identifier for the transformation
dataDict{Symbol,Any}Configuration data for the transformation
time_dataTimeDataTime-related data structure

Methods

Accessor Methods

Methods for accessing transformation data and properties.

MethodDescriptionReturn Type
id(transformation)Get transformation identifierSymbol
balance_ids(transformation)Get IDs of all balance equationsVector{Symbol}
balance_data(transformation, i)Get input data for balance equation iDict{Symbol,Float64}
get_balance(transformation, i)Get balance equation expression for iJuMP.Expression
get_balance(transformation, i, t)Get balance equation expression for i at time tJuMP.Expression

Balance and Constraint Methods (Inherited from AbstractVertex)

Methods for managing balance equations and constraints.

MethodDescriptionReturn Type
all_constraints(transformation)Get all constraints applied to the transformationVector{AbstractTypeConstraint}
all_constraints_types(transformation)Get types of all constraintsVector{DataType}
get_constraint_by_type(transformation, constraint_type)Get constraint of specified typeUnion{AbstractTypeConstraint,Vector{AbstractTypeConstraint},Nothing}

Model Building Methods

Methods used internally during model construction.

MethodDescriptionReturn Type
add_linking_variables!(transformation, model)Add linking variables to JuMP modelNothing
define_available_capacity!(transformation, model)Define available capacity constraintsNothing
planning_model!(transformation, model)Add planning model constraintsNothing
operation_model!(transformation, model)Add operational model constraintsNothing

Factory Methods

Methods for creating transformation components.

MethodDescriptionReturn Type
make_transformation(id, data, time_data)Create transformation componentTransformation

Utility Methods

Additional utility methods for working with Transformations.

MethodDescriptionReturn Type
@transform_data(new_defaults)Macro to set new default fields for an AssetDict{Symbol,Any}

Examples

Natural Gas Power Plant Asset

The ThermalPower Asset is an example of how to use Transformation components to model a natural gas power plant. It converts NaturalGas into Electricity and CO2.

The stochiometric balances of the Transformation are defined by the fuel_consumption and emission_rate fields, which represent the heat rate (fuel consumption per unit electricity) and emission factor (CO2 per unit fuel), respectively.

The following code snippets show how the Transformation is defined as part of the ThermalPower Asset and how the stochiometric balances are set. Further information about how to create new Assets can be found in the Assets manual page.

The Transformation is one of the components which make up the ThermalPower Asset.

struct ThermalPower{T} <: AbstractAsset
    id::AssetId
    thermal_transform::Transformation
    elec_edge::Union{Edge{<:Electricity},EdgeWithUC{<:Electricity}}
    fuel_edge::Edge{<:T}
    co2_edge::Edge{<:CO2}
end

The make() function of the ThermalPower Asset is responsible for creating the Transformation and connecting it to the appropriate Nodes via Edges. The make() function processes the input data and sets up the Transformation with the necessary stoichiometric balances.

function make(asset_type::Type{ThermalPower}, data::AbstractDict{Symbol,Any}, system::System)
    # Assign a unique ID and set up the default data
    id = AssetId(data[:id])
    @setup_data(asset_type, data, id)

    # Parse the Transformation data and create the Transformation component
    thermal_key = :transforms
    @process_data(
        transform_data, 
        data[thermal_key], 
        [
            (data[thermal_key], key),
            (data[thermal_key], Symbol("transform_", key)),
            (data, Symbol("transform_", key)),
            (data, key),
        ]
    )
    thermal_transform = Transformation(;
        id = Symbol(id, "_", thermal_key),
        timedata = system.time_data[Symbol(transform_data[:timedata])],
        constraints = get(transform_data, :constraints, [BalanceConstraint()]),
    )

    elec_edge_key = :elec_edge
    # ... Process the electricity edge data
    elec_start_node = thermal_transform
    @end_vertex(
        elec_end_node,
        elec_edge_data,
        Electricity,
        [(elec_edge_data, :end_vertex), (data, :location)],
    )
    # Check if the edge has unit commitment constraints
    has_uc = get(elec_edge_data, :uc, false)
    EdgeType = has_uc ? EdgeWithUC : Edge
    # Create the elec edge with the appropriate type
    elec_edge = EdgeType(
        Symbol(id, "_", elec_edge_key),
        elec_edge_data,
        system.time_data[:Electricity],
        Electricity,
        elec_start_node,
        elec_end_node,
    )
    if has_uc
        uc_constraints = [MinUpTimeConstraint(), MinDownTimeConstraint()]
        for c in uc_constraints
            if !(c in elec_edge.constraints)
                push!(elec_edge.constraints, c)
            end
        end
        elec_edge.startup_fuel_balance_id = :energy
    end
    
    fuel_edge_key = :fuel_edge
    # ... Process the fuel edge data
    fuel_end_node = thermal_transform
    fuel_edge = Edge(
        Symbol(id, "_", fuel_edge_key),
        fuel_edge_data,
        system.time_data[commodity_symbol],
        commodity,
        fuel_start_node,
        fuel_end_node,
    )

    co2_edge_key = :co2_edge
    # ... Process the CO2 edge data
    co2_edge = Edge(
        Symbol(id, "_", co2_edge_key),
        co2_edge_data,
        system.time_data[:CO2],
        CO2,
        co2_start_node,
        co2_end_node,
    )

    # Set the Transformation's stochiometric balance constraints. 
    
    # The first constraint sets the fuel -> electricity conversion ratio, which is the heat rate of the power plant.

    # The second constraint sets the fuel -> CO2 conversion ratio, which is the emission factor of the power plant.
    thermal_transform.balance_data = Dict(
        :energy => Dict(
            elec_edge.id => get(transform_data, :fuel_consumption, 1.0),
            fuel_edge.id => 1.0,
            co2_edge.id => 0.0,
        ),
        :emissions => Dict(
            fuel_edge.id => get(transform_data, :emission_rate, 0.0),
            co2_edge.id => 1.0,
            elec_edge.id => 0.0,
        ),
    )

    # Finally, we create and return the ThermalPower Asset
    return ThermalPower(id, thermal_transform, elec_edge, fuel_edge, co2_edge)
end

Nat Gas, Standard JSON Input Format

{
    "type": "ThermalPower",
    "global_data": {},
    "instance_data": {
        "id": "example_natural_gas_power_plant",
        "location": "boston",
        "timedata": "NaturalGas",
        "fuel_commodity": "NaturalGas",
        "co2_sink": "co2_sink",
        "uc": true,
        "elec_constraints": {
            "CapacityConstraint": true,
            "RampingLimitConstraint": true,
            "MinFlowConstraint": true,
            "MinUpTimeConstraint": true,
            "MinDownTimeConstraint": true,
        },
        "emission_rate": 0.181048235160161,
        "fuel_consumption": 2.249613533,
        "can_expand": false,
        "existing_capacity": 4026.4,
        "investment_cost": 0.0,
        "fixed_om_cost": 16001,
        "variable_om_cost": 4.415,
        "capacity_size": 125.825,
        "startup_cost": 89.34,
        "startup_fuel_consumption": 0.58614214,
        "min_up_time": 6,
        "min_down_time": 6,
        "ramp_up_fraction": 0.64,
        "ramp_down_fraction": 0.64,
        "min_flow_fraction": 0.444
    }
}

Nat Gas, Advanced JSON Input Format

{
    "type": "ThermalPower",
    "global_data": {},
    "instance_data": {
        "id": "example_natural_gas_power_plant",
        "transforms": {
            "emission_rate": 0.181048235160161,
            "fuel_consumption": 2.249613533
        },
        "edges": {
            "elec_edge": {
                "commodity": "Electricity",
                "unidirectional": true,
                "has_capacity": true,
                "uc": true,
                "integer_decisions": false,
                "constraints": {
                    "CapacityConstraint": true,
                    "RampingLimitConstraint": true,
                    "MinFlowConstraint": true,
                    "MinUpTimeConstraint": true,
                    "MinDownTimeConstraint": true
                },
               "end_vertex": "boston_elec",
                "can_retire": true,
                "can_expand": false,
                "existing_capacity": 4026.4,
                "investment_cost": 0.0,
                "fixed_om_cost": 16001,
                "variable_om_cost": 4.415,
                "capacity_size": 125.825,
                "startup_cost": 89.34,
                "startup_fuel_consumption": 0.58614214,
                "min_up_time": 6,
                "min_down_time": 6,
                "ramp_up_fraction": 0.64,
                "ramp_down_fraction": 0.64,
                "min_flow_fraction": 0.444
            },
            "fuel_edge": {
                "commodity": "NaturalGas",
                "unidirectional": true,
                "has_capacity": false,
                "start_vertex": "boston_natgas"
            },
            "co2_edge": {
                "commodity": "CO2",
                "unidirectional": true,
                "has_capacity": false,
                "end_vertex": "co2_sink"
            }
        }
    }
}

Gas Storage Asset

GasStorage Assets are an interesting example of how Transformations can be used to model Electricity flows used to energize another flow, instead of converting between Commodities. The Edges manual page includes an explanation of the make() function and inputs of this Asset.

See Also

  • Edges - Components that connect Vertices and carry flows
  • Nodes - Network nodes that allow for import and export of commodities
  • Storage - Components that store commodities for later use
  • Vertices - Network nodes that edges connect
  • Assets - Higher-level components made from edges, nodes, storage, and transformations
  • Commodities - Types of resources stored by Commodities
  • Time Data - Temporal modeling framework
  • Constraints - Additional constraints for Storage and other components