Skip to content

Commit

Permalink
Merge 26b37d1 into 8771b05
Browse files Browse the repository at this point in the history
  • Loading branch information
fwitte committed Jan 15, 2019
2 parents 8771b05 + 26b37d1 commit 08448f9
Show file tree
Hide file tree
Showing 5 changed files with 384 additions and 235 deletions.
273 changes: 112 additions & 161 deletions tespy/components/characteristics.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

from scipy.interpolate import interp1d
import numpy as np
import math

# %%


class characteristics:
Expand Down Expand Up @@ -56,6 +57,11 @@ def __init__(self, **kwargs):
if self.y is None:
self.y = self.default(method)[1]

if len(self.x) != len(self.y):
msg = ('Please provide the same amount of x-values and y-values. Number of x-values: ' +
str(len(self.x)) + ', number of y-values: ' + str(len(self.y)) + '.')
raise ValueError(msg)

self.char = interp1d(self.x, self.y, kind='cubic', bounds_error=True)

def default(self, key):
Expand Down Expand Up @@ -225,6 +231,15 @@ def default(self, key):
y['GENERIC'] = np.array(
[0.500, 0.900, 1.000, 1.025])

elif self.comp == 'pump':

x['GENERIC'] = np.array(
[0.071, 0.282, 0.635, 0.776, 0.917, 1.000, 1.128, 1.270,
1.410, 1.763, 2.115, 2.500])
y['GENERIC'] = np.array(
[0.250, 0.547, 0.900, 0.965, 0.995, 1.000, 0.990, 0.959,
0.911, 0.737, 0.519, 0.250])

elif self.comp == 'cogeneration unit':

x['TI'] = np.array([0.50, 0.75, 0.90, 1.00])
Expand Down Expand Up @@ -373,112 +388,12 @@ def get_attr(self, key):
else:
return None

# %%

class pump(characteristics):
r"""
generic characteristic for pumps
- links isentropic efficiency :math:`\eta_{s,p}` to volumetric flow
:math:`\dot{V}`
- uses a distorted quadratic function:
.. math::
\eta_{s,p} = \left( a \cdot \dot{V}^2 + b \cdot \dot{V}+c \right) \cdot
e^{k \cdot \dot{V}}
- constraints
.. math::
\eta_{s,p}\left(0 \right) = 0
\eta_{s,p}\left(\dot{V}_0 \right) = 0
\eta_{s,p}\left(\dot{V}_{ref} \right) = 1
\frac{\partial \eta_{s,p}}
{\partial \dot{V}}\left(\dot{V}_{ref} \right) = 0

- function parameters
.. math::
k = \frac{\dot{V}_0 - 2 \cdot \dot{V}_{ref}}
{\dot{V}_{ref}^2-\dot{V}_0 \cdot \dot{V}_{ref}}
a = \frac{1}{\left( \dot{V}_{ref}^2 - \dot{V}_0 \cdot \dot{V}_{ref}
\right) \cdot e^{k \cdot \dot{V}_{ref}}}
b = -a \cdot \dot{V}_0
c = 0
- volume flow without pressure rise :math:`\dot{V}_0`:
.. math::
\dot{V}_0 = \dot{V}_{ref} \cdot 3.1 \cdot n_q ^{-0.15}
- specific rotational speed :math:`n_q`:
.. math::
n_q = \frac{333 \cdot n \cdot \sqrt{\dot{V}_{ref}}}
{\left(g \cdot H_{ref}\right)^{0,75}}\\
\text{assuming n=}\frac{50}{s}
.. note::
In order to stabilize the calculation with pump characteristics
the minimum value for isentropic efficiency is limited to a quater
of reference state efficiency!
**literature**
- Wolfgang Wesche (2012): Radiale Kreiselpumpen - Berechnung und
Konstruktion der hydrodynamischen Komponenten. Berlin: Springer.
- KSB SE & Co. KGaA (2018): Kreiselpumpenlexikon - Spezifische Drehzahl.
Available at:
https://www.ksb.com/kreiselpumpenlexikon/spezifische-drehzahl/186490,
accessed on 04.04.2018.
"""

def __init__(self, v_opt, H_opt):

n_q = 333 * 50 * math.sqrt(v_opt) / ((9.81 * H_opt) ** 0.75)
v_0 = v_opt * 3.1 * n_q ** (-0.15)
self.k = (v_0 - 2 * v_opt) / (v_opt ** 2 - v_0 * v_opt)
self.a = 1 / ((v_opt ** 2 - v_0 * v_opt) * math.exp(self.k * v_opt))
self.b = -self.a * v_0

def char(self, v):
eta = (self.a * v ** 2 + self.b * v) * math.exp(self.k * v)
if eta < 0.25:
eta = 0.25
return eta

def f_x(self, x):
return self.char(x)


class compressor(characteristics):
class char_map(characteristics):
r"""
Generic characteristic map for axial compressors.
**literature**
compressor map:
- Marcin Plis, Henryk Rusinowski (2016): Mathematical modeling of an
axial compressor in a gas turbine cycle. Journal of Power
Technologies 96 (3), pp. 194-199.
vigv:
- GasTurb GmbH (2015): GasTurb 12.
Class for characteristic maps.
Parameters
----------
Expand All @@ -489,27 +404,21 @@ class compressor(characteristics):
An array of the y-values of the map.
z1 : ndarray
An array of the z1-values of the map (pressure ratio to nominal pressure ratio).
An array of the z1-values of the map.
z2 : ndarray
An array of the z2-values of the map (isentropic efficiency to nominal isentropic efficiency).
An array of the z2-values of the map.
method : String
Specify a method to choose from the default characteristic maps. If you specify custom x, y, z1 and z2 values, this parameter will be ignored.
Note
----
This class generates a lookup table from the given input data x, y, z1 and z2, then performs linear interpolation.
The output parameters are z1 and z2 to be calculated as functions from x and y. The x, y, z1 and z2 values may be specified by the user. There is a default characteristic map (GENERIC),
see :func:`tespy.components.characteristics.compressor.default` method.
**Want to use your own characteristic map?**
The output parameters are z1 and z2 to be calculated as functions from x and y. The x, y, z1 and z2 values may be specified by the user.
There is a default characteristic map for axial compressors (GENERIC), see :func:`tespy.components.characteristics.char_map.default` method.
x are the speedlines, is the corrected mass flow for each speedline. Thus, the number of points in the x-array equals the number of dimensions of the y-array.
E. g., if you specify 5 speedline in the x-array, you will need to have an y-array with 5 dimensions, where the points of each dimension represent one of the speedlines.
The same logic applies for the z1 and z2 arrays!
For calculation/equations see :func:`tespy.components.characteristics.compressor.get_pr_eta`.
If you want to use your own map, see the :func:`tespy.components.characteristics.char_map.default` method for more information.
"""

def __init__(self, **kwargs):
Expand All @@ -527,6 +436,7 @@ def __init__(self, **kwargs):
self.y = kwargs.get('y', None)
self.z1 = kwargs.get('z1', None)
self.z2 = kwargs.get('z2', None)
self.comp = kwargs.get('comp', None)

if self.x is None:
self.x = self.default(method)[0]
Expand All @@ -538,10 +448,21 @@ def __init__(self, **kwargs):
if self.z2 is None:
self.z2 = self.default(method)[3]

if np.array(self.x).shape[0] != np.array(self.y).shape[0]:
msg = ('The number of x-values determines the number of dimension for the characteristic map. You have provided ' +
str(len(self.x)) + 'x-values. Thus, the y-, z1- and z2-arrays must have ' + str(len(self.x)) +' number of dimensions.')
raise ValueError(msg)
elif np.array(self.y).shape != np.array(self.z1).shape or np.array(self.y).shape != np.array(self.z2).shape:
msg = 'Make sure that the number of dimensions and the number of values in the y-, z1- and z2-arrays are identical!'
raise ValueError(msg)

def attr(self):
return ['x', 'y', 'z1', 'z2', 'method', 'comp']

def default(self, key):
r"""
Default characteristic map for compressor.
Generic characteristic map for axial compressors.
.. image:: _images/CMAP_GENERIC_PR.svg
:scale: 100 %
Expand All @@ -552,6 +473,28 @@ def default(self, key):
:scale: 100 %
:alt: alternative text
:align: center
**literature**
compressor map:
- Marcin Plis, Henryk Rusinowski (2016): Mathematical modeling of an
axial compressor in a gas turbine cycle. Journal of Power
Technologies 96 (3), pp. 194-199.
vigv:
- GasTurb GmbH (2015): GasTurb 12.
.. note::
The x-values represent the speedlines, y-values represent the corrected mass flow for each speedline.
The z1-values are the pressure ratio to nominal pressure ratio and z2-values are the isentropic efficiency to nominal isentropic efficiency.
Thus, the number of points in the x-array equals the number of dimensions of the y, z1 and z2-array.
E. g., if you specify 5 speedlines in the x-array, you will need to have an y-array with 5 dimensions,
where the points of each dimension represent one of the speedlines. The same logic applies for the z1 and z2 arrays!
For calculation/equations see :func:`tespy.components.characteristics.char_map.get_pr_eta`.
"""

if key == 'default':
Expand All @@ -566,51 +509,59 @@ def default(self, key):
z1 = {}
z2 = {}

x['GENERIC'] = np.array([0.810, 0.870, 0.946, 0.971, 1, 1.029, 1.062])
y['GENERIC'] = np.array([[0.460, 0.481, 0.502, 0.523, 0.543,
0.562, 0.583, 0.598, 0.606, 0.612],
[0.590, 0.605, 0.620, 0.640, 0.660,
0.685, 0.703, 0.710, 0.711, 0.713],
[0.767, 0.805, 0.838, 0.859, 0.87,
0.876, 0.878, 0.878, 0.879, 0.88],
[0.874, 0.908, 0.93, 0.943, 0.953,
0.961, 0.962, 0.963, 0.963, 0.964],
[0.948, 0.974, 0.987, 0.995, 1.0,
1.002, 1.005, 1.005, 1.006, 1.006],
[1.014, 1.017, 1.02, 1.023, 1.026,
1.028, 1.03, 1.032, 1.034, 1.036],
[1.045, 1.047, 1.049, 1.051, 1.052,
1.053, 1.054, 1.054, 1.055, 1.056]])

z1['GENERIC'] = np.array([[0.502, 0.493, 0.485, 0.467, 0.442,
0.411, 0.378, 0.344, 0.31, 0.276],
[0.65, 0.637, 0.617, 0.589, 0.556,
0.519, 0.482, 0.445, 0.407, 0.37],
[0.931, 0.917, 0.893, 0.859, 0.82,
0.779, 0.738, 0.698, 0.657, 0.616],
[1.05, 1.02, 0.982, 0.939, 0.895,
0.851, 0.806, 0.762, 0.717, 0.672],
[1.195, 1.151, 1.102, 1.052, 1.0,
0.951, 0.9, 0.85, 0.799, 0.748],
[1.34, 1.276, 1.213, 1.149, 1.085,
1.022, 0.958, 0.894, 0.831, 0.767],
[1.441, 1.37, 1.3, 1.229, 1.158,
1.088, 1.017, 0.946, 0.876, 0.805]])

z2['GENERIC'] = np.array([[0.872, 0.885, 0.898, 0.911, 0.925,
0.94, 0.945, 0.926, 0.903, 0.879],
[0.887, 0.909, 0.93, 0.947, 0.963,
0.971, 0.965, 0.939, 0.913, 0.887],
[0.891, 0.918, 0.946, 0.973, 1.001,
1.014, 1.015, 0.986, 0.955, 0.925],
[0.977, 0.977, 0.981, 0.995, 1.007,
1.002, 0.981, 0.961, 0.94, 0.92],
[0.956, 0.959, 0.969, 0.984, 1.0,
0.985, 0.967, 0.95, 0.932, 0.914],
[0.948, 0.959, 0.962, 0.949, 0.935,
0.922, 0.908, 0.895, 0.881, 0.868],
[0.879, 0.888, 0.898, 0.907, 0.916,
0.924, 0.915, 0.906, 0.896, 0.887]])
if self.comp == 'compressor':

x['GENERIC'] = np.array([0.810, 0.870, 0.946, 0.971, 1, 1.029, 1.062])
y['GENERIC'] = np.array([[0.460, 0.481, 0.502, 0.523, 0.543,
0.562, 0.583, 0.598, 0.606, 0.612],
[0.590, 0.605, 0.620, 0.640, 0.660,
0.685, 0.703, 0.710, 0.711, 0.713],
[0.767, 0.805, 0.838, 0.859, 0.87,
0.876, 0.878, 0.878, 0.879, 0.88],
[0.874, 0.908, 0.93, 0.943, 0.953,
0.961, 0.962, 0.963, 0.963, 0.964],
[0.948, 0.974, 0.987, 0.995, 1.0,
1.002, 1.005, 1.005, 1.006, 1.006],
[1.014, 1.017, 1.02, 1.023, 1.026,
1.028, 1.03, 1.032, 1.034, 1.036],
[1.045, 1.047, 1.049, 1.051, 1.052,
1.053, 1.054, 1.054, 1.055, 1.056]])

z1['GENERIC'] = np.array([[0.502, 0.493, 0.485, 0.467, 0.442,
0.411, 0.378, 0.344, 0.31, 0.276],
[0.65, 0.637, 0.617, 0.589, 0.556,
0.519, 0.482, 0.445, 0.407, 0.37],
[0.931, 0.917, 0.893, 0.859, 0.82,
0.779, 0.738, 0.698, 0.657, 0.616],
[1.05, 1.02, 0.982, 0.939, 0.895,
0.851, 0.806, 0.762, 0.717, 0.672],
[1.195, 1.151, 1.102, 1.052, 1.0,
0.951, 0.9, 0.85, 0.799, 0.748],
[1.34, 1.276, 1.213, 1.149, 1.085,
1.022, 0.958, 0.894, 0.831, 0.767],
[1.441, 1.37, 1.3, 1.229, 1.158,
1.088, 1.017, 0.946, 0.876, 0.805]])

z2['GENERIC'] = np.array([[0.872, 0.885, 0.898, 0.911, 0.925,
0.94, 0.945, 0.926, 0.903, 0.879],
[0.887, 0.909, 0.93, 0.947, 0.963,
0.971, 0.965, 0.939, 0.913, 0.887],
[0.891, 0.918, 0.946, 0.973, 1.001,
1.014, 1.015, 0.986, 0.955, 0.925],
[0.977, 0.977, 0.981, 0.995, 1.007,
1.002, 0.981, 0.961, 0.94, 0.92],
[0.956, 0.959, 0.969, 0.984, 1.0,
0.985, 0.967, 0.95, 0.932, 0.914],
[0.948, 0.959, 0.962, 0.949, 0.935,
0.922, 0.908, 0.895, 0.881, 0.868],
[0.879, 0.888, 0.898, 0.907, 0.916,
0.924, 0.915, 0.906, 0.896, 0.887]])
else:
x = np.array([0, 1, 2])
y = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]])
z1 = y
z2 = y
return x, y, z1, z2

return x[key], y[key], z1[key], z2[key]

Expand Down
Loading

0 comments on commit 08448f9

Please sign in to comment.