Linking components

Sometimes, two or more components need to be linked together. While this can be achieved using addons, it can be achieved using custom functionality within a template. Consider the following (shortened) version of the CHP template:

parameters:
  p_max: null
  h_max: null
  power_ratio: 0.55
  power_loss_ratio: 0.20
  efficiency: 0.40
  fuel: gas
  fuel_co2_emission_factor: 0.2
  fuel_in: null
  power_out: null
  heat_out: null
  co2_out: null

components:
  power:
    type: Unit
    inputs: {<fuel>: <fuel_in>}
    outputs: {electricity: <power_out>, co2: <co2_out>}
    conversion: 1 <fuel> -> <efficiency> electricity + <fuel_co2_emission_factor> co2
    capacity: <p_max> out:electricity

  heat:
    type: Unit
    inputs: {<fuel>: <fuel_in>}
    outputs: {heat: <heat_out>, co2: <co2_out>}
    conversion: 1 <fuel> -> <efficiency>/<power_loss_ratio> heat + <fuel_co2_emission_factor> co2
    capacity: <h_max> out:heat

functions:
  finalize: |
    # Parameters.
    cm = get("power_ratio")
    cv = get("power_loss_ratio")
    p_max = get("p_max")

    # Output expressions.
    out_heat = access("heat").exp.out_heat
    out_elec = access("power").exp.out_electricity

    # Add constraints.
    @constraint(MODEL.model, cm .* out_heat .<= out_elec)
    @constraint(MODEL.model, out_elec .<= p_max .- cv .* out_heat)

This makes use of the finalize(...) function to link the power and heat components. Using an addon can be complicated, because the components do not inherently know about each other. The finalize(...) function however is attached to the template itself, can access both components, and is called after both are fully constructed, which means it can freely access their variables and expressions.

Note: A similar approach is possible by using the build_priority parameter in the component definition. This parameter allows you to specify the order in which components are built, which can be used to ensure that one component is built before another.