Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions pandapipes/multinet/control/multinet_control_power2heat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
from pandapower.control import ConstControl
from pandapipes.properties.fluids import get_fluid
from pandapower.control.basic_controller import Controller
from pandas.errors import InvalidIndexError

import pandapower as ppower
class P2HControlMultiEnergy(Controller):
def __init__(self, multinet, element_index_power, element_index_heat, efficiency,
name_power_net='power', name_heat_net='heat',
in_service=True, order=0, level=0,
drop_same_existing_ctrl=False, initial_run=True, **kwargs):
super().__init__(multinet, in_service, order, level,
drop_same_existing_ctrl=drop_same_existing_ctrl, initial_run=initial_run,
**kwargs)

self.elm_idx_power = element_index_power
self.elm_idx_heat = element_index_heat
self.name_net_power = name_power_net
self.name_net_heat = name_heat_net
self.efficiency = efficiency
self.qext_w = None
self.fluid = get_fluid(multinet['nets'][name_heat_net])
self.applied = False

def initialize_control(self, multinet):
self.applied = False

def get_all_net_names(self):
return [self.name_net_power, self.name_net_heat]

def control_step(self, multinet):
ppower.runpp(multinet['nets'][self.name_net_power])

try:
power_load = \
multinet['nets'][self.name_net_power].res_load.at[self.elm_idx_power, 'p_mw']
except (ValueError, TypeError, InvalidIndexError):
power_load = \
multinet['nets'][self.name_net_power].res_load.loc[self.elm_idx_power, 'p_mw'].values
self.qext_w = - (power_load * self.conversion_factor_mw_to_w() * self.efficiency)

self.write_to_net(multinet)
self.applied = True

def write_to_net(self, multinet):
try:
multinet['nets'][self.name_net_heat].heat_exchanger.at[self.elm_idx_heat, 'qext_w'] \
= self.qext_w
except (ValueError, TypeError, InvalidIndexError):
multinet['nets'][self.name_net_heat].heat_exchanger.loc[self.elm_idx_heat,
'qext_w'] = self.qext_w

def is_converged(self, multinet):
return self.applied

def conversion_factor_mw_to_w(self):
return 1e6


class H2PControlMultiEnergy(Controller):
def __init__(self, multinet, element_index_power, element_index_heat, efficiency,
name_power_net='power', name_heat_net='heat', element_type_power="sgen",
in_service=True, order=0,
level=0, drop_same_existing_ctrl=False, initial_run=True,
calc_heat_from_power=False, **kwargs):
super().__init__(multinet, in_service, order, level,
drop_same_existing_ctrl=drop_same_existing_ctrl, initial_run=initial_run,
**kwargs)

self.elm_idx_power = element_index_power
self.elm_idx_heat = element_index_heat
self.elm_type_power = element_type_power
self.name_net_power = name_power_net
self.name_net_heat = name_heat_net
self.efficiency = efficiency
self.qext_w = None
self.fluid = get_fluid(multinet['nets'][name_heat_net])
self.el_power_led = calc_heat_from_power
self.applied = False

def initialize_control(self, multinet):
self.applied = False

def get_all_net_names(self):
return [self.name_net_heat, self.name_net_power]

def control_step(self, multinet):
if self.el_power_led:
try:
power_gen = multinet['nets'][self.name_net_power][self.elm_type_power].at[
self.elm_idx_power, 'p_mw'] * multinet['nets'][self.name_net_power][
self.elm_type_power].at[self.elm_idx_power, 'scaling']

except (ValueError, TypeError, InvalidIndexError):
power_gen = multinet['nets'][self.name_net_power][self.elm_type_power].loc[
self.elm_idx_power, 'p_mw'].values[:] \
* multinet['nets'][self.name_net_power][self.elm_type_power].loc[
self.elm_idx_power, 'scaling'].values[:]

self.heat_cons = power_gen / (self.conversion_factor_w_to_mw() * self.efficiency)

else:
try:
heat_heat_exchanger = \
multinet['nets'][self.name_net_heat].heat_exchanger.at[self.elm_idx_heat, 'qext_w']

except (ValueError, TypeError, InvalidIndexError):
heat_heat_exchanger = multinet['nets'][self.name_net_heat].heat_exchanger.loc[self.elm_idx_heat,
'qext_w'].values[:]

self.power_gen = heat_heat_exchanger * self.conversion_factor_w_to_mw() * self.efficiency

self.write_to_net(multinet)
self.applied = True

def write_to_net(self, multinet):
if self.el_power_led:
try:
multinet['nets'][self.name_net_heat].heat_exchanger.at[self.elm_idx_heat,
'qext_w'] = self.heat_cons
except (ValueError, TypeError, InvalidIndexError):
multinet['nets'][self.name_net_heat].heat_exchanger.loc[self.elm_idx_heat,
'qext_w'] = self.heat_cons
else:
try:
multinet['nets'][self.name_net_power][self.elm_type_power].at[
self.elm_idx_power, 'p_mw'] = self.power_gen
except (ValueError, TypeError, InvalidIndexError):
multinet['nets'][self.name_net_power][self.elm_type_power].loc[
self.elm_idx_power, 'p_mw'] = self.power_gen

def is_converged(self, multinet):
return self.applied

def conversion_factor_w_to_mw(self):
return 1 / 1e6
85 changes: 85 additions & 0 deletions pandapipes/plotting/coupled_plot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import pandapipes.plotting as plot
from itertools import chain
from pandapower.control import ConstControl
from pandapipes.properties.fluids import get_fluid
from pandapower.control.basic_controller import Controller
from pandas.errors import InvalidIndexError

import matplotlib.pyplot as plt
import pandapipes.plotting as pp_plot

import sys
try:
import matplotlib.pyplot as plt
MATPLOTLIB_INSTALLED = True
except ImportError:
MATPLOTLIB_INSTALLED = False

from pandapower.auxiliary import soft_dependency_error
from pandapower.plotting.plotting_toolbox import get_collection_sizes
from pandapower.plotting.collections import create_bus_collection, create_line_collection, \
create_trafo_collection, create_trafo3w_collection, \
create_line_switch_collection, draw_collections, create_bus_bus_switch_collection, create_ext_grid_collection, create_sgen_collection, \
create_gen_collection, create_load_collection, create_dcline_collection
from pandapower.plotting.generic_geodata import create_generic_coordinates
from pandapipes.component_models.circulation_pump_mass_component import CirculationPumpMass
from pandapipes.component_models.circulation_pump_pressure_component import CirculationPumpPressure
from pandapipes.component_models.pump_component import Pump
from pandapipes.plotting.collections import create_junction_collection, create_pipe_collection, \
create_valve_collection, create_source_collection, create_pressure_control_collection, \
create_heat_exchanger_collection, create_sink_collection, create_pump_collection, \
create_compressor_collection, create_flow_control_collection
from pandapipes.plotting.generic_geodata import create_generic_coordinates
from pandapipes.plotting.plotting_toolbox import get_collection_sizes

try:
import pandaplan.core.pplog as logging
except ImportError:
import logging

logger = logging.getLogger(__name__)

import pandapower.plotting as pp_plot
import pandapipes.plotting as pipes_plot
import matplotlib.pyplot as plt


import pandapower.plotting as pp_plot
import pandapipes.plotting as pipes_plot
import matplotlib.pyplot as plt
import sys
from coupled_nets_power_heat import *
def plot_coupled_network_with_highlighted_bus(multinet, highlighted_bus):
fig, ax = plt.subplots()

# Plot pandapower network
power_network = multinet["nets"]["power"]
pp_plot.simple_plot(power_network, ax=ax)

# Highlight the specific bus in pandapipes network
heat_network = multinet["nets"]["heat"]
highlighted_bus_color = 'red' # Choose your desired color
pipes_plot.simple_plot(heat_network, ax=ax, bus_color=highlighted_bus_color, highlighted_bus=highlighted_bus)

plt.show()

plot_coupled_network_with_highlighted_bus(multinet, highlighted_bus=3)

def plot_coupled_network(multinet):
fig, ax = plt.subplots()

# Plot pandapower network
power_network = multinet["nets"]["power"]
pp_plot.simple_plot(power_network, ax=ax)

# Plot pandapipes network
heat_network = multinet["nets"]["heat"]
pipes_plot.simple_plot(heat_network, ax=ax)

plt.show()

# plotting coupled net
plot_coupled_network(multinet)



147 changes: 147 additions & 0 deletions tutorials/coupled_nets_power_heat.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Coupled Power-Heat Network Example\n",
"\n",
"This tutorial demonstrates how to create a coupled power and heat network using pandapipes, pandapower and pandapipes multinet functionality."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Imports\n",
"\n",
"Import the required pandapipes, pandapower, plotting and controller modules."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import pandapipes as pp\n",
"import pandapower as ppower\n",
"from pandapower.control.basic_controller import Controller\n",
"from pandapower import networks as pandasnet\n",
"from pandapipes import networks as pipenet\n",
"from pandapipes.multinet.create_multinet import create_empty_multinet, add_net_to_multinet\n",
"from pandapipes.multinet.control.run_control_multinet import run_control\n",
"import pandapower.plotting as pp_plot\n",
"import os\n",
"import matplotlib.pyplot as plt\n",
"from pandapower.plotting.plotly import simple_plotly\n",
"import pandas as pd\n",
"import pandapower.plotting.plotly as pplotly\n",
"import sys\n",
"from pandapipes.multinet.control.multinet_control_power2heat import *\n",
"import matplotlib.pyplot as plt\n",
"\n",
"\n",
"# ---## Create the power network\n",
"\n",
"# Step 1: Creating the power network using pandapower's predefined simple network example\n",
"power_net = pandasnet.example_simple() # Loading a predefined simple electrical network.\n",
"\n",
"# ----------------------------------------\n",
"# Step 2: Creating a heat network using pandapipes\n",
"# This defines a thermal (fluid) network that models the heat system.\n",
"\n",
"heat_net = pp.create_empty_network(fluid=\"water\") # Create an empty heat network with water as the fluid.\n",
"\n",
"# Create junctions (nodes) in the heat network:\n",
"j0 = pp.create_junction(heat_net, pn_bar=5, tfluid_k=293.15, name=\"junction 0\") # Junction 0 at 5 bar pressure and 293.15 K temperature.\n",
"j1 = pp.create_junction(heat_net, pn_bar=5, tfluid_k=293.15, name=\"junction 1\") # Junction 1 with same pressure and temperature.\n",
"j2 = pp.create_junction(heat_net, pn_bar=5, tfluid_k=293.15, name=\"junction 2\") # Junction 2 with same pressure and temperature.\n",
"j3 = pp.create_junction(heat_net, pn_bar=5, tfluid_k=293.15, name=\"junction 3\") # Junction 3 with same pressure and temperature.\n",
"\n",
"# Create a pump to circulate fluid between junctions j0 and j3, with a constant mass flow rate.\n",
"pp.create_circ_pump_const_mass_flow(heat_net, return_junction=j3, flow_junction=j0, p_flow_bar=5,\n",
" mdot_flow_kg_per_s=20, t_flow_k=273.15+35) # A pump for fluid flow at 20 kg/s with 5 bar pressure difference.\n",
"\n",
"# Create a heat exchanger between junctions j1 and j2\n",
"pp.create_heat_exchanger(heat_net, from_junction=j1, to_junction=j2, diameter_m=200e-3, qext_w=100000) # Heat exchanger between j1 and j2.\n",
"\n",
"# Create pipes to connect the junctions and form the network.\n",
"pp.create_pipe_from_parameters(heat_net, from_junction=j0, to_junction=j1, length_km=1,\n",
" diameter_m=200e-3, k_mm=.1, alpha_w_per_m2k=10, sections=5, text_k=283) # Pipe from j0 to j1.\n",
"pp.create_pipe_from_parameters(heat_net, from_junction=j2, to_junction=j3, length_km=1,\n",
" diameter_m=200e-3, k_mm=.1, alpha_w_per_m2k=10, sections=5, text_k=283) # Pipe from j2 to j3.\n",
"\n",
"# ----------------------------------------\n",
"# Step 3: Create a multinet (multi-network) and add power and heat networks\n",
"multinet = create_empty_multinet('multinet') # Create an empty multinet system.\n",
"add_net_to_multinet(multinet, power_net, 'power') # Add the power network to the multinet system.\n",
"add_net_to_multinet(multinet, heat_net, 'heat') # Add the heat network to the multinet system.\n",
"\n",
"# ----------------------------------------\n",
"# Step 4: Define conversion units (power-to-heat and heat-to-power) within the networks.\n",
"# These elements will facilitate energy conversions between the power and heat networks.\n",
"\n",
"# Power-to-Heat (P2H) conversion: Creating a load in the power network (consuming power) and a heat exchanger in the heat network.\n",
"p2h_id_el = ppower.create_load(power_net, bus=6, p_mw=.0002, name=\"power to heat consumption\") # Load in the power network at bus 6 (0.2 MW).\n",
"p2h_id_heat = pp.create_heat_exchanger(heat_net, from_junction=0, to_junction=1, diameter_m=200e-3, qext_w=0, name=\"power to heat feed in\")\n",
"\n",
"# Heat-to-Power (H2P) conversion: Creating a heat exchanger in the heat network and a generator in the power network.\n",
"h2p_id_heat = pp.create_heat_exchanger(heat_net, from_junction=2, to_junction=3, diameter_m=200e-3, qext_w=200000, name=\"power to heat feed in\")\n",
"h2p_id_el = ppower.create_sgen(power_net, bus=6, p_mw=0, name=\"fuel cell feed in\")\n",
"\n",
"# ----------------------------------------\n",
"# Step 5: Define control objects for the power-to-heat and heat-to-power conversions.\n",
"\n",
"# Power-to-Heat control: A control object to manage the energy transfer between power and heat networks.\n",
"p2h_ctrl = P2HControlMultiEnergy(multinet, p2h_id_el, p2h_id_heat, efficiency=3,\n",
" name_power_net=\"power\", name_heat_net=\"heat\")\n",
"\n",
"# Heat-to-Power control: Another control object for managing the reverse flow (heat to power).\n",
"h2p_ctrl = H2PControlMultiEnergy(multinet, h2p_id_el, h2p_id_heat, efficiency=2,\n",
" name_power_net=\"power\", name_heat_net=\"heat\")\n",
"\n",
"# ----------------------------------------\n",
"# Step 6: Print initial values of power-to-heat and heat-to-power elements.\n",
"print(heat_net.heat_exchanger.loc[p2h_id_heat, 'qext_w']) # Print the initial power-to-heat exchange rate.\n",
"print(power_net.sgen.loc[h2p_id_el, 'p_mw']) # Print the initial power generation from the fuel cell.\n",
"\n",
"# ----------------------------------------\n",
"# Step 7: Run the control simulation on the multinet system.\n",
"run_control(multinet) # This runs the control logic for the power and heat networks based on the defined conversions.\n",
"\n",
"# ----------------------------------------\n",
"# Step 8: Print updated values after running the simulation.\n",
"print(heat_net.heat_exchanger.loc[p2h_id_heat, 'qext_w']) # Print the updated power-to-heat exchange rate after running control.\n",
"print(power_net.sgen.loc[h2p_id_el, 'p_mw']) # Print the updated power generation after running control.\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.12.3 64-bit",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "9240d949b7e875368571ba59acc67192d2efbcc4561b3c6f94c83d7858e18732"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Binary file added tutorials/coupled_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.