-
Notifications
You must be signed in to change notification settings - Fork 65
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
NonReturnValveController created, test in pipeflow_internals added and docu updated #118
base: develop
Are you sure you want to change the base?
Changes from 2 commits
4066fbe
8e1e22b
e7d6e16
90f0940
f00af59
f0c7877
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics | ||
# and Energy System Technology (IEE), Kassel. All rights reserved. | ||
# Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. | ||
|
||
import pandapipes as pp | ||
import numpy | ||
from pandapower.control.basic_controller import Controller | ||
|
||
try: | ||
import pplog as logging | ||
except ImportError: | ||
import logging | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class NonReturnValveController(Controller): | ||
""" | ||
Controller for implementing a non-return valve. | ||
|
||
:param net: The net in which the controller resides | ||
:type net: pandapipesNet | ||
:param element_index: IDs of controlled valves | ||
:type element_index: int[] | ||
:param in_service: Indicates if the controller is currently in_service | ||
:type in_service: bool, default True | ||
:param recycle: Re-use of internal-data | ||
:type recycle: bool, default True | ||
:param drop_same_existing_ctrl: Indicates if already existing controllers of the same type and with the same matching parameters (e.g. at same element) should be dropped | ||
:type drop_same_existing_ctrl: bool, default False | ||
:param kwargs: Parameters for pipeflow | ||
:type kwargs: dict | ||
|
||
:Example: | ||
>>> kwargs = {'stop_condition': 'tol', 'iter': 100, 'tol_p': 1e-7, 'tol_v': 1e-7, 'friction_model': 'colebrook', | ||
>>> 'mode': 'hydraulics', 'only_update_hydraulic_matrix': False} | ||
>>> NonReturnValveController(net, element_index=[0, 1, 3], **kwargs) | ||
>>> run_control(net) | ||
|
||
""" | ||
|
||
def __init__(self, net, element_index, profile_name=None, | ||
scale_factor=1.0, in_service=True, recycle=True, order=0, level=0, | ||
drop_same_existing_ctrl=False, set_q_from_cosphi=False, matching_params=None, initial_pipeflow=False, | ||
**kwargs): | ||
|
||
if matching_params is None: | ||
matching_params = {"element_index": element_index} | ||
|
||
# just calling init of the parent | ||
super().__init__(net, in_service=in_service, recycle=recycle, order=order, level=level, | ||
drop_same_existing_ctrl=drop_same_existing_ctrl, | ||
matching_params=matching_params, initial_powerflow=initial_pipeflow, | ||
**kwargs) | ||
|
||
self.matching_params = {"element_index": element_index} | ||
if numpy.isscalar(element_index): | ||
self.element_index = [element_index] | ||
else: | ||
self.element_index = element_index | ||
self.values = None | ||
self.profile_name = profile_name | ||
self.scale_factor = scale_factor | ||
self.initial_pipeflow = initial_pipeflow | ||
self.kwargs = kwargs | ||
self.v_m_per_s = [] # current flow velocities at valves | ||
self.opened = [] # remember original user-defined values of opened | ||
|
||
if set_q_from_cosphi: | ||
logger.error("Parameter set_q_from_cosphi deprecated!") | ||
raise ValueError | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't have q-values in pandapipes. Q-values stands for reactive power. |
||
|
||
def initialize_control(self): | ||
""" | ||
First calculation of a pipeflow. \n | ||
Saving the user-defined values, determine valves with negative flow velocities, | ||
set opened to False for these. | ||
""" | ||
pp.pipeflow(self.net, self.kwargs) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't do a pipeflow within a controller. Do it with the flag initial_run |
||
|
||
self.opened = self.net.valve.loc[self.element_index, "opened"] | ||
|
||
j = 0 | ||
for i in self.element_index: | ||
self.v_m_per_s.append(self.net.res_valve.loc[i, "v_mean_m_per_s"]) | ||
|
||
if self.net.valve.loc[i, "opened"] and self.v_m_per_s[j] < 0: | ||
# use the element indices, where opened = True, otherwise NaN would be in self.v_m_per_s | ||
self.net.valve.loc[i, "opened"] = False | ||
j += 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be solved without a loop which would make it much more performant! Should me something like: Furthermore, I think, in the initial step you should only do one thing: Open all non return valves. Following reason: Right now I don't think the controller acts the way it should. Imagine following thing. Right now you only consider the valves which are open. But if you run it once, you close all valves which have a v_mean <0. Now you change something in your grid and run it again. Now, the valves you closed in the first run are not considered anymore. However, I think they still should. I would rather do it like this: All valves covered in the element_index should be considered. |
||
|
||
def is_converged(self): | ||
""" | ||
Convergence Condition: If all flow velocities at the non-return valves are >= 0 or opened equal False. \n | ||
Resetting the variable opened to user defaults. | ||
""" | ||
|
||
for i in range(len(self.element_index)): | ||
if self.net.valve.loc[self.element_index[i], "opened"] and self.v_m_per_s[i] < 0: | ||
return False | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above: converged = np.all(self.net.valve.loc[self.element_index, 'v_mean_m_per_s')>=0) |
||
|
||
self.net.valve.loc[self.element_index, "opened"] = self.opened | ||
return True | ||
|
||
def control_step(self): | ||
""" | ||
Check whether negative flow velocities are still present at non-return valves. | ||
""" | ||
pp.pipeflow(self.net, self.kwargs) | ||
|
||
j = 0 | ||
for i in self.element_index: | ||
self.v_m_per_s.append(self.net.res_valve.loc[i, "v_mean_m_per_s"]) | ||
|
||
if self.net.valve.loc[i, "opened"] and self.v_m_per_s[j] < 0: | ||
# use the element indices, where opened = True, otherwise NaN would be in self.v_m_per_s | ||
self.net.valve.loc[i, "opened"] = False | ||
j += 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see above There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another thing what I was thinking about: I would return to the initial state, meaning all valves should have the same values before you used the controller. Meaning, if the user set some non return valves on open and you closed the now, I would in a finalizing step return to a open valve, as only if you really want to use the controller the controller should also have an effect. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Copyright (c) 2020 by Fraunhofer Institute for Energy Economics | ||
# and Energy System Technology (IEE), Kassel. All rights reserved. | ||
# Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. | ||
|
||
import pandapipes | ||
import pytest | ||
from pandapipes.control import NonReturnValveController, run_control | ||
|
||
|
||
def test_nrv(): | ||
net = pandapipes.create_empty_network("net", fluid="water", add_stdtypes=True) | ||
|
||
j0 = pandapipes.create_junction(net, pn_bar=3, tfluid_k=293.15) | ||
j1 = pandapipes.create_junction(net, pn_bar=3, tfluid_k=293.15) | ||
j2 = pandapipes.create_junction(net, pn_bar=3, tfluid_k=293.15) | ||
j3 = pandapipes.create_junction(net, pn_bar=3, tfluid_k=283.15) | ||
j4 = pandapipes.create_junction(net, pn_bar=3, tfluid_k=283.15) | ||
|
||
pandapipes.create_ext_grid(net, j0, p_bar=3, t_k=293.15, type="pt") | ||
|
||
pandapipes.create_sink(net, j1, mdot_kg_per_s=1) | ||
pandapipes.create_sink(net, j4, mdot_kg_per_s=0.5) | ||
|
||
pandapipes.create_source(net, j2, mdot_kg_per_s=0.05) | ||
pandapipes.create_source(net, j3, mdot_kg_per_s=1) | ||
|
||
pandapipes.create_pipe_from_parameters(net, j1, j0, diameter_m=0.75, k_mm=0.1, length_km=15) | ||
pandapipes.create_pipe_from_parameters(net, j4, j2, diameter_m=0.1, k_mm=0.1, length_km=10) | ||
|
||
pandapipes.create_valve(net, j4, j3, diameter_m=0.1, opened=True) | ||
pandapipes.create_valve(net, j1, j3, diameter_m=0.07, opened=True) | ||
pandapipes.create_valve(net, j1, j2, diameter_m=0.05, opened=True) | ||
pandapipes.create_valve(net, j3, j0, diameter_m=0.01, opened=True) | ||
|
||
kwargs = {'stop_condition': 'tol', 'iter': 100, 'tol_p': 1e-7, 'tol_v': 1e-7, 'friction_model': 'colebrook', | ||
'mode': 'hydraulics', 'only_update_hydraulic_matrix': False} | ||
|
||
NonReturnValveController(net, element_index=[1, 3], **kwargs) | ||
|
||
run_control(net) | ||
|
||
|
||
if __name__ == "__main__": | ||
pytest.main([r'pandapipes/test/pipeflow_internals/test_non_return_valve_controller.py']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we changed the attribute from initial_powerflow to initial_run. Please update your pandapower and pandapipes version!