Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

developed controllers for power-heat coupled network and plot it #653

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
88 changes: 88 additions & 0 deletions tutorials/coupled_nets_power_heat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import pandapipes as pp
import pandapower as ppower
from pandapower.control.basic_controller import Controller
from pandapower import networks as pandasnet
from pandapipes import networks as pipenet
from pandapipes.multinet.create_multinet import create_empty_multinet, add_net_to_multinet
from pandapipes.multinet.control.run_control_multinet import run_control
import pandapower.plotting as pp_plot
import os
import matplotlib.pyplot as plt
from pandapower.plotting.plotly import simple_plotly
import pandas as pd
import pandapower.plotting.plotly as pplotly
import sys
from multinet_control_power2heat import *

import matplotlib.pyplot as plt
# ----------------------------------------
# Step 1: Creating the power network using pandapower's predefined simple network example
power_net = pandasnet.example_simple() # Loading a predefined simple electrical network.

# ----------------------------------------
# Step 2: Creating a heat network using pandapipes
# This defines a thermal (fluid) network that models the heat system.

heat_net = pp.create_empty_network(fluid="water") # Create an empty heat network with water as the fluid.

# Create junctions (nodes) in the heat network:
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.
j1 = pp.create_junction(heat_net, pn_bar=5, tfluid_k=293.15, name="junction 1") # Junction 1 with same pressure and temperature.
j2 = pp.create_junction(heat_net, pn_bar=5, tfluid_k=293.15, name="junction 2") # Junction 2 with same pressure and temperature.
j3 = pp.create_junction(heat_net, pn_bar=5, tfluid_k=293.15, name="junction 3") # Junction 3 with same pressure and temperature.

# Create a pump to circulate fluid between junctions j0 and j3, with a constant mass flow rate.
pp.create_circ_pump_const_mass_flow(heat_net, return_junction=j3, flow_junction=j0, p_flow_bar=5,
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.

# Create a heat exchanger between junctions j1 and j2
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.

# Create pipes to connect the junctions and form the network.
pp.create_pipe_from_parameters(heat_net, from_junction=j0, to_junction=j1, length_km=1,
diameter_m=200e-3, k_mm=.1, alpha_w_per_m2k=10, sections=5, text_k=283) # Pipe from j0 to j1.
pp.create_pipe_from_parameters(heat_net, from_junction=j2, to_junction=j3, length_km=1,
diameter_m=200e-3, k_mm=.1, alpha_w_per_m2k=10, sections=5, text_k=283) # Pipe from j2 to j3.

# ----------------------------------------
# Step 3: Create a multinet (multi-network) and add power and heat networks
multinet = create_empty_multinet('multinet') # Create an empty multinet system.
add_net_to_multinet(multinet, power_net, 'power') # Add the power network to the multinet system.
add_net_to_multinet(multinet, heat_net, 'heat') # Add the heat network to the multinet system.

# ----------------------------------------
# Step 4: Define conversion units (power-to-heat and heat-to-power) within the networks.
# These elements will facilitate energy conversions between the power and heat networks.

# Power-to-Heat (P2H) conversion: Creating a load in the power network (consuming power) and a heat exchanger in the heat network.
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).
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")

# Heat-to-Power (H2P) conversion: Creating a heat exchanger in the heat network and a generator in the power network.
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")
h2p_id_el = ppower.create_sgen(power_net, bus=6, p_mw=0, name="fuel cell feed in")

# ----------------------------------------
# Step 5: Define control objects for the power-to-heat and heat-to-power conversions.

# Power-to-Heat control: A control object to manage the energy transfer between power and heat networks.
p2h_ctrl = P2HControlMultiEnergy(multinet, p2h_id_el, p2h_id_heat, efficiency=3,
name_power_net="power", name_heat_net="heat")

# Heat-to-Power control: Another control object for managing the reverse flow (heat to power).
h2p_ctrl = H2PControlMultiEnergy(multinet, h2p_id_el, h2p_id_heat, efficiency=2,
name_power_net="power", name_heat_net="heat")

# ----------------------------------------
# Step 6: Print initial values of power-to-heat and heat-to-power elements.
print(heat_net.heat_exchanger.loc[p2h_id_heat, 'qext_w']) # Print the initial power-to-heat exchange rate.
print(power_net.sgen.loc[h2p_id_el, 'p_mw']) # Print the initial power generation from the fuel cell.

# ----------------------------------------
# Step 7: Run the control simulation on the multinet system.
run_control(multinet) # This runs the control logic for the power and heat networks based on the defined conversions.

# ----------------------------------------
# Step 8: Print updated values after running the simulation.
print(heat_net.heat_exchanger.loc[p2h_id_heat, 'qext_w']) # Print the updated power-to-heat exchange rate after running control.
print(power_net.sgen.loc[h2p_id_el, 'p_mw']) # Print the updated power generation after running control.
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.
85 changes: 85 additions & 0 deletions tutorials/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)



136 changes: 136 additions & 0 deletions tutorials/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