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:

julia> # Import curve: buy power at $25/MWh up to 200 MW
       import_curve = make_import_curve(; power = 200.0, price = 25.0)CostCurve:
  value_curve: PiecewiseIncrementalCurve where value at zero is 0.0, initial value is 0.0, derivative function f is: f(x) =
    25.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
julia> # 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:

julia> # 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],
       )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
julia> # 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:

julia> 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:

julia> 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:

julia> add_component!(sys, source)

Verify the source was added correctly:

julia> get_component(Source, sys, "external_grid")Source: external_grid:
   name: external_grid
   available: true
   bus: ACBus: nodeC
   active_power: 0.0
   reactive_power: 0.0
   active_power_limits: (min = -200.0, max = 200.0)
   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: 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}()
   InfrastructureSystems.SystemUnitsSettings:
      base_value: 100.0
      unit_system: UnitSystem.SYSTEM_BASE = 0
   has_supplemental_attributes: false
   has_time_series: false
julia> 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