Add costs for imported/exported power

This how-to guide explains how to add an ImportExportCost to a Source component to model imports and exports with neighboring areas or external grids.

This guide assumes a System is already defined.

Overview

A Source component represents an infinite bus with constant voltage output, commonly used to represent:

  • Very large machines on a single bus in dynamics simulations
  • Import/export connections in operational simulations

The ImportExportCost operating cost allows you to specify:

  • Import offer curves (buy prices for importing power)
  • Export offer curves (sell prices for exporting power)
  • Weekly energy limits for imports and exports
  • Ancillary service offers

Step 1: Define Import and Export Curves

You can define import and export curves in several ways, depending on your data format.

Option A: Simple Single-Price Curves

For a simple constant price over a power range:

# Import curve: buy power at $25/MWh up to 200 MW
import_curve = make_import_curve(; power = 200.0, price = 25.0)

# Export curve: sell power at $30/MWh up to 200 MW
export_curve = make_export_curve(; power = 200.0, price = 30.0)
CostCurve:
  value_curve: PiecewiseIncrementalCurve where value at zero is 0.0, initial value is 0.0, derivative function f is: f(x) =
    30.0 for x in [0.0, 200.0)
  power_units: UnitSystem.NATURAL_UNITS = 2
  vom_cost: LinearCurve (a type of InputOutputCurve) where function is: f(x) = 0.0 x + 0.0

Option B: Piecewise Linear Curves

For more complex pricing with multiple segments:

# Import curve with increasing prices as more power is imported
import_curve = make_import_curve(;
    power = [0.0, 100.0, 105.0, 120.0, 200.0],
    price = [5.0, 10.0, 20.0, 40.0],
)

# Export curve with decreasing prices as more power is exported
export_curve = make_export_curve(;
    power = [0.0, 100.0, 105.0, 120.0, 200.0],
    price = [40.0, 20.0, 10.0, 5.0],
)
CostCurve:
  value_curve: PiecewiseIncrementalCurve where value at zero is 0.0, initial value is 0.0, derivative function f is: f(x) =
    40.0 for x in [0.0, 100.0)
    20.0 for x in [100.0, 105.0)
    10.0 for x in [105.0, 120.0)
    5.0 for x in [120.0, 200.0)
  power_units: UnitSystem.NATURAL_UNITS = 2
  vom_cost: LinearCurve (a type of InputOutputCurve) where function is: f(x) = 0.0 x + 0.0
Note
  • Import curves must have non-decreasing (convex) slopes
  • Export curves must have non-increasing (concave) slopes
  • Power values must have one more entry than price values

Step 2: Create the ImportExportCost

Use the curves to create an ImportExportCost:

ie_cost = ImportExportCost(;
    import_offer_curves = import_curve,
    export_offer_curves = export_curve,
    energy_import_weekly_limit = 10000.0,  # MWh per week (optional)
    energy_export_weekly_limit = 10000.0,  # MWh per week (optional)
)
ImportExportCost: 
  import_offer_curves: CostCurve:
    value_curve: PiecewiseIncrementalCurve where value at zero is 0.0, initial value is 0.0, derivative function f is: f(x) =
      5.0 for x in [0.0, 100.0)
      10.0 for x in [100.0, 105.0)
      20.0 for x in [105.0, 120.0)
      40.0 for x in [120.0, 200.0)
    power_units: UnitSystem.NATURAL_UNITS = 2
    vom_cost: LinearCurve (a type of InputOutputCurve) where function is: f(x) = 0.0 x + 0.0
  export_offer_curves: CostCurve:
    value_curve: PiecewiseIncrementalCurve where value at zero is 0.0, initial value is 0.0, derivative function f is: f(x) =
      40.0 for x in [0.0, 100.0)
      20.0 for x in [100.0, 105.0)
      10.0 for x in [105.0, 120.0)
      5.0 for x in [120.0, 200.0)
    power_units: UnitSystem.NATURAL_UNITS = 2
    vom_cost: LinearCurve (a type of InputOutputCurve) where function is: f(x) = 0.0 x + 0.0
  energy_import_weekly_limit: 10000.0
  energy_export_weekly_limit: 10000.0
  ancillary_service_offers: Service[]

Step 3: Add the Cost to the Source Component

Define a Source component with the import/export cost, or alternatively use set_operation_cost! to add the cost to an existing source:

source = Source(;
    name = "external_grid",
    available = true,
    bus = get_component(ACBus, sys, "nodeC"),
    active_power = 0.0,
    reactive_power = 0.0,
    active_power_limits = (min = -200.0, max = 200.0),  # Negative for export
    reactive_power_limits = (min = -100.0, max = 100.0),
    R_th = 0.01,
    X_th = 0.02,
    internal_voltage = 1.0,
    internal_angle = 0.0,
    base_power = 100.0,
    operation_cost = ie_cost,
)

Source: external_grid:
   name: external_grid
   available: true
   bus: ACBus: nodeC
   active_power: 0.0
   reactive_power: 0.0
   active_power_limits: (min = -20000.0, max = 20000.0)
   reactive_power_limits: (min = -10000.0, max = 10000.0)
   R_th: 0.01
   X_th: 0.02
   internal_voltage: 1.0
   internal_angle: 0.0
   base_power: 100.0
   operation_cost: ImportExportCost composed of import_offer_curves: CostCurve{PiecewiseIncrementalCurve}, export_offer_curves: CostCurve{PiecewiseIncrementalCurve}
   dynamic_injector: nothing
   services: 0-element Vector{Service}
   ext: Dict{String, Any}()
   internal: InfrastructureSystems.InfrastructureSystemsInternal
   has_supplemental_attributes: false
   has_time_series: false
Tip

The active_power_limits should span negative (for export) to positive (for import) values. Negative power indicates exporting power to the external grid.

Step 4: Add the Source to the System

Add the source component to your system:

add_component!(sys, source)

Verify the source was added correctly:

get_component(Source, sys, "external_grid")
get_operation_cost(get_component(Source, sys, "external_grid"))
ImportExportCost: 
  import_offer_curves: CostCurve:
    value_curve: PiecewiseIncrementalCurve where value at zero is 0.0, initial value is 0.0, derivative function f is: f(x) =
      5.0 for x in [0.0, 100.0)
      10.0 for x in [100.0, 105.0)
      20.0 for x in [105.0, 120.0)
      40.0 for x in [120.0, 200.0)
    power_units: UnitSystem.NATURAL_UNITS = 2
    vom_cost: LinearCurve (a type of InputOutputCurve) where function is: f(x) = 0.0 x + 0.0
  export_offer_curves: CostCurve:
    value_curve: PiecewiseIncrementalCurve where value at zero is 0.0, initial value is 0.0, derivative function f is: f(x) =
      40.0 for x in [0.0, 100.0)
      20.0 for x in [100.0, 105.0)
      10.0 for x in [105.0, 120.0)
      5.0 for x in [120.0, 200.0)
    power_units: UnitSystem.NATURAL_UNITS = 2
    vom_cost: LinearCurve (a type of InputOutputCurve) where function is: f(x) = 0.0 x + 0.0
  energy_import_weekly_limit: 10000.0
  energy_export_weekly_limit: 10000.0
  ancillary_service_offers: Service[]

See Also