Multi-energy coupling¶
A multi-energy system (MES) combines two or more energy carriers (typically electricity, gas, and heat) into a single network. monee models the coupling points between these carriers as specialised compound components that sit at the intersection of grids.
Note
Compound components are created automatically by the express API functions below. You do not need to assemble them manually unless you are writing a custom coupling model.
Available coupling components¶
EL → Water
Heat pump or electric boiler. Draws electricity from a bus and injects thermal energy into a district heating supply pipe.
EL → Gas
Electrolysis unit. Converts electricity to gas (e.g. green hydrogen).
Gas → EL
Gas turbine or engine. Converts gas to electricity.
Gas → Water
Gas boiler. Converts gas to district heat without generating electricity.
Gas → EL + Water
Simultaneously produces electricity and heat from gas. Connects to three grids.
Water ↔ Water
Transfers thermal energy between two water circuits without mass transfer.
Power-to-Heat (P2H)¶
A P2H unit (e.g. a heat pump or electric boiler) draws electrical power from a bus and injects thermal power into a district heating supply pipe. The return pipe closes the thermal loop.
import monee.express as mx
net = mx.create_multi_energy_network()
# Electricity side
bus_el = mx.create_bus(net)
mx.create_ext_power_grid(net, bus_el)
# Heating side (supply/return loop)
junc_supply = mx.create_water_junction(net)
junc_return = mx.create_water_junction(net)
mx.create_ext_hydr_grid(net, junc_supply)
# Couple electricity to heat
mx.create_p2h(
net,
power_node_id=bus_el,
heat_node_id=junc_supply,
heat_return_node_id=junc_return,
heat_energy_mw=0.5, # thermal output setpoint [MW]
diameter_m=0.1, # heat-exchange pipe diameter
efficiency=0.95, # electrical-to-thermal efficiency
)
Key parameters:
heat_energy_mw: thermal output setpoint in megawatts. The solver derives the required electrical input asheat_energy_mw / efficiency.efficiency: ratio of thermal output to electrical input (≤ 1 for resistive heating, > 1 for heat pumps modelled with a fixed COP).diameter_m: internal pipe diameter of the connecting heat-exchange branch.
Power-to-Gas (P2G)¶
A P2G unit (electrolysis) converts electricity into gas (e.g. green hydrogen).
import monee.express as mx
net_p2g = mx.create_multi_energy_network()
bus_el = mx.create_bus(net_p2g)
junc_gas = mx.create_gas_junction(net_p2g)
mx.create_p2g(
net_p2g,
from_node_id=bus_el,
to_node_id=junc_gas,
efficiency=0.7, # electrical-to-chemical efficiency
mass_flow_setpoint_kgs=0.05, # target gas production [kg/s]
)
P2G is a plain two-endpoint branch coupler; its conversion loss is exposed
as loss_percent(), which returns
1 - efficiency.
Gas-to-Power (G2P)¶
A G2P unit (gas turbine, gas engine) converts gas to electricity.
import monee.express as mx
net_g2p = mx.create_multi_energy_network()
junc_gas = mx.create_gas_junction(net_g2p)
bus_el = mx.create_bus(net_g2p)
mx.create_g2p(
net_g2p,
from_node_id=junc_gas,
to_node_id=bus_el,
efficiency=0.40, # gas-to-electrical efficiency
p_mw_setpoint=2.0, # target electrical output [MW]
q_mvar_setpoint=0.0,
)
Like P2G, G2P is a branch coupler and reports its conversion loss via
loss_percent() (= 1 - efficiency).
Combined Heat and Power (CHP)¶
A CHP unit simultaneously produces electricity and heat from gas. It connects to three grids: gas (fuel input), electricity (power output), and district heating (heat output).
import monee.express as mx
net = mx.create_multi_energy_network()
# Gas grid
junc_gas = mx.create_gas_junction(net)
mx.create_source(net, junc_gas, mass_flow_kgs=0.5)
# Electricity grid
bus_el = mx.create_bus(net)
mx.create_ext_power_grid(net, bus_el)
# Heating grid (supply + return)
junc_heat_supply = mx.create_water_junction(net)
junc_heat_return = mx.create_water_junction(net)
mx.create_ext_hydr_grid(net, junc_heat_supply)
# CHP coupling
mx.create_chp(
net,
power_node_id=bus_el,
heat_node_id=junc_heat_supply,
heat_return_node_id=junc_heat_return,
gas_node_id=junc_gas,
diameter_m=0.15,
efficiency_power=0.35, # gas → electricity
efficiency_heat=0.45, # gas → heat
mass_flow_setpoint_kgs=0.1, # gas consumption [kg/s]
)
Key parameters:
efficiency_powerandefficiency_heat: individual efficiencies for electrical and thermal output. Their sum must not exceed 1 (total fuel utilisation).mass_flow_setpoint_kgs: gas consumption setpoint in kg/s.regulation: a factor in [0, 1] that scales all outputs. Set as aVarto let the optimiser dispatch the unit.
Compound couplers such as CHP also implement set_active(flag), which
deactivate() uses to switch the whole unit
off cleanly (zeroing gas flow and regulation) and to restore the previous
setpoints on reactivation.
Gas-to-Heat (G2H)¶
A gas boiler converts gas to district heat without producing electricity.
import monee.express as mx
net_g2h = mx.create_multi_energy_network()
junc_gas = mx.create_gas_junction(net_g2h)
junc_heat_supply = mx.create_water_junction(net_g2h)
junc_heat_return = mx.create_water_junction(net_g2h)
mx.create_g2h(
net_g2h,
gas_node_id=junc_gas,
heat_node_id=junc_heat_supply,
heat_return_node_id=junc_heat_return,
heat_energy_mw=0.5, # thermal output [MW]
diameter_m=0.1,
efficiency=0.90,
)
Node-based heat couplers (HG variants)¶
The heat-producing couplers above (CHP, G2H, P2H) deliver their thermal output
through an internal heat-exchanger branch that bridges the supply and return
sides of the heating network. That is why they require a heat_return_node_id
and a diameter_m. Each of them has a node-based “HG” variant (heat
generator) that injects the thermal power directly at a single heat junction.
The heat appears as a q_mw_heat term that the
Junction heat balance picks up, exactly like a
node-level HeatGenerator child.
Gas → EL + Water
CHP variant. Compound with an internal control node; injects heat via a
hidden SubHG child at the heat node.
EL → Water
Power-to-Heat variant. A plain two-endpoint multi-grid branch from a bus to a heat junction.
Gas → Water
Gas boiler variant. A plain two-endpoint multi-grid branch from a gas junction to a heat junction.
The variants differ structurally from their classic counterparts:
CHPHGis still a compound:create(gas_node, heat_node, power_node)wires gas and power through an internal control node, but the heat side is a subordinateSubHGheat-generator child placed atheat_nodeinstead of a heat-exchanger branch. It therefore needs noheat_return_nodeand nodiameter_m.GasToHeatHG(heat_energy_mw, efficiency, regulation=1) andPowerToHeatHG(heat_energy_mw, efficiency, q_mvar_setpoint=0, regulation=1) are plain two-endpoint branch couplers, just like G2P and P2G. They withdraw gas or electricity at the from-node and carryq_mw_heatdirectly on the branch, where the junction heat balance at the to-node picks it up. Both also exposeloss_percent()(=1 - efficiency).
Prefer the HG variants when
you want simpler wiring: one heat junction instead of a supply/return pair, no heat-exchange pipe geometry to choose; or
you use the McCormick-DHS formulation (
HEAT_CONVEX_MILP_FORMULATION) or a network built with node-based heat loads (e.g.node_based_heat_loads=Truein themonee.networkheat builders), where they are required: this formulation owns the nodal heat balance and only understands node-based heat injections, not heat-exchanger branches.
import monee.express as mx
net_hg = mx.create_multi_energy_network()
# Gas grid (fuel input)
junc_gas = mx.create_gas_junction(net_hg)
mx.create_gas_ext_grid(net_hg, junc_gas)
# Electricity grid (power output)
bus_el = mx.create_bus(net_hg)
mx.create_ext_power_grid(net_hg, bus_el)
# Heating grid - a single supply junction; no return node needed
junc_heat = mx.create_water_junction(net_hg)
mx.create_water_ext_grid(net_hg, junc_heat)
# CHP coupling, node-based heat injection
mx.create_chp_hg(
net_hg,
power_node_id=bus_el,
heat_node_id=junc_heat,
gas_node_id=junc_gas,
efficiency_power=0.35, # gas → electricity
efficiency_heat=0.45, # gas → heat
mass_flow_setpoint_kgs=0.1, # gas consumption [kg/s]
)
The single-branch variants follow the same pattern as
create_g2p():
mx.create_p2h_hg(
net_hg,
power_node_id=bus_el,
heat_node_id=junc_heat,
heat_energy_mw=0.5, # thermal output setpoint [MW]
efficiency=0.95,
)
mx.create_g2h_hg(
net_hg,
gas_node_id=junc_gas,
heat_node_id=junc_heat,
heat_energy_mw=0.5,
efficiency=0.90,
)
Note
The internal control-node models (CHPControlNode, CHPHGControlNode,
GasToHeatControlNode, PowerToHeatControlNode) and the subordinate
SubHE / SubHG components you may encounter in result dataframes are
implementation details. They are wired up automatically by the compounds’
create(); you never instantiate them directly.
Heat exchanger¶
A heat exchanger transfers thermal energy between two water circuits (for example between a primary transmission network and a secondary distribution loop) without mass transfer.
import monee.express as mx
net_hx = mx.create_multi_energy_network()
junc_primary = mx.create_water_junction(net_hx)
junc_secondary = mx.create_water_junction(net_hx)
mx.create_heat_exchanger(
net_hx,
from_node_id=junc_primary,
to_node_id=junc_secondary,
q_mw=0.2, # heat transfer setpoint [MW]; positive draws heat at from-node
)
Regulation and dispatch¶
All coupling components have a regulation attribute that scales their
output between 0 (off) and 1 (full setpoint). In a plain energy flow it is
fixed at 1. For optimisation, declare it as a solver variable:
import monee.problem as mp
problem = mp.OptimizationProblem()
problem.controllable_cps([
(
"regulation",
mp.AttributeParameter(
min=lambda a, v: 0,
max=lambda a, v: 1,
val=lambda a, v: 1,
),
)
])
The optimiser then freely dispatches each coupling unit within its capacity.
Tip
See 01 · Minimum-cost load curtailment and Load shedding for end-to-end worked examples of coupling unit dispatch in an optimisation problem.