Usage#

Introduction#

After installation of fluprodia you can easily create fluid property diagrams for all pure and pseudo-pure fluids from the CoolProp fluid property database. For a list of available fluids please refer to the online documentation of CoolProp.

In order to start, import the package and create an object of the class fluprodia.fluid_property_diagram.FluidPropertyDiagram by passing the alias of the fluid. After that, it is possible to specify a unit system for all fluid properties available with the fluprodia.fluid_property_diagram.FluidPropertyDiagram.set_unit_system() method. The fluid properties available are:

  • pressure p

  • specific enthalpy h

  • specific entropy s

  • specific volume v

  • temperature T

  • vapor mass fraction Q

>>> from fluprodia import FluidPropertyDiagram
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> diagram = FluidPropertyDiagram('R290')
>>> diagram.set_unit_system(T='°C', p='bar', h='kJ/kg')

After that, you can use the default isolines or specify your own lines by using the fluprodia.fluid_property_diagram.FluidPropertyDiagram.set_isolines() method. If you do not specify custom isolines, generic isolines will be used instead. Next step is to calculate the isolines, drawing them and exporting the diagram in your favorite format. The formats available are the matplotlib file formats for figures. You will also need to specify the limits in order to determine the view. Also, different diagrams will have different value ranges for their x- and y-axes.

>>> iso_T = np.arange(-75, 151, 25)
>>> diagram.set_isolines(T=iso_T)
>>> diagram.calc_isolines()
>>> fig, ax = plt.subplots(1, figsize=(16, 10))
>>> diagram.draw_isolines(fig, ax, "Ts", x_min=500, x_max=3000, y_min=-50, y_max=150)
>>> plt.tight_layout()
>>> fig.savefig('Ts_diagram.svg')
_images/Ts_diagram.svg

As all fluid properties will be stored in the object referenced by diagram, it is possible to change the diagram type and export a new diagram without recalculating the isolines. Only if you wish to draw a different set of isolines unlike specified in the set_isolines() method call, you need to recalculate the isolines.

>>> fig, ax = plt.subplots(1, figsize=(16, 10))
>>> diagram.draw_isolines(fig, ax, "logph", x_min=0, x_max=750, y_min=1e-1, y_max=1e2)
>>> plt.tight_layout()
>>> fig.savefig('logph_diagram.svg')
_images/logph_diagram.svg

All available diagram types can be displayed by printing the following line.

>>> list(diagram.supported_diagrams.keys())
['Ts', 'hs', 'logph', 'Th', 'plogv']

Customizing the Display#

Customization is possible regarding

  • the isovalues of the isolines,

  • the isolines displayed,

  • the linestyle of the isolines and

  • the position of the isolines’ labels.

Isoline values available#

As already mentioned, you can set the isolines for your diagram like this. All isolines you specify are available for drawing the diagram later. Therefore, the more values you specify, the more lines can be displayed. Also, the computation time will rise.

Still, it might be useful to specify a lot of values. E.g., if we want to create a full view of a logph diagram for R290 and a zoomed view in the two phase region with lines of constant vapor mass fraction for every 2.5 % and lines of constant temperature every 5 K.

>>> T = np.arange(-75, 151, 5)
>>> Q = np.linspace(0, 1, 41)
>>> diagram.set_isolines(T=T, Q=Q)
>>> diagram.calc_isolines()

The following sections shows how to select from all isolines available.

Lines displayed and Linestyle#

As we do not want to display all values for temperature and vapor mass fraction for the full view diagram, we specify the values to be displayed for these properties. This is done by using the isoline_data property, which must be a dictionary holding the required information.

>>> fig, ax = plt.subplots(1, figsize=(16, 10))
>>> mydata = {
...    'Q': {'values': np.linspace(0, 1, 11)},
...    'T': {'values': np.arange(-75, 151, 25)}
... }
>>> diagram.draw_isolines(fig, ax, 'logph', isoline_data=mydata, x_min=0, x_max=750, y_min=1e-1, y_max=1e2)
>>> plt.tight_layout()
>>> fig.savefig('logph_R290_full.svg')
_images/logph_R290_full.svg

Now, for the zoomed diagram we want the full temperature and vapor mass fraction data. At the same time, you might want to change the color or the linestyle of an isoline. For this example, we will color the lines of constant temperature in red. Additionally, the lines of constant specific volume should not be displayed at all. This can be done by passing an empty list or an empty numpy array.

>>> fig, ax = plt.subplots(1, figsize=(16, 10))
>>> mydata = {
...     'T': {
...         'style': {'color': '#ff0000'},
...         'values': T
...     },
...     'v': {'values': np.array([])}
... }
>>> diagram.draw_isolines(fig, ax, 'logph', isoline_data=mydata, x_min=300, x_max=600, y_min=1, y_max=1e2)
>>> plt.tight_layout()
>>> fig.savefig('logph_R290_zoomed.svg')
_images/logph_R290_zoomed.svg

Note

For changing the style of a specific isoline pass the respective keyword and value pairs in a dictionary. The keywords available are the keywords of a matplotlib.lines.Line2D object. See https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html#matplotlib.lines.Line2D for more information.

Positioning of the isoline lables#

In the last section we briefly describe, how to change the placing of the labels for the isolines. Looking at the zoomed diagram, you see that some of the temperature labels are missing.

You can specify a positioning value between 0 and 1. Every label of an isoline type (e.g. constant temerature) will be placed at the relative position of each isoline within the limits of the view.

>>> fig, ax = plt.subplots(1, figsize=(16, 10))
>>> mydata = {
...     'T': {
...         'style': {'color': '#ff0000'},
...         'values': T,
...         'label_position': 0.8
...     },
...     'v': {'values': np.array([])}
... }
>>> diagram.draw_isolines(fig, ax, 'logph', isoline_data=mydata, x_min=300, x_max=600, y_min=1, y_max=1e2)
>>> plt.tight_layout()
>>> fig.savefig('logph_R290_zoomed_temperature_labels.svg')
_images/logph_R290_zoomed_temperature_labels.svg

Note

The placing method of the labels is not fully satisfactory at the moment. If you have ideas, how to place the labels in an improved way, we are looking forward for you suggestions.

Plotting individual isolines (and isolike lines)#

FluProDia offers a method to generate data for individual isolines with a specified starting and a specified ending point. Use the method fluprodia.fluid_property_diagram.FluidPropertyDiagram.calc_individual_isoline() to create datapoints for the isoline. The method returns a dictionary containing the datapoints in numpy arrays using the property name as respective key. Therefore, independent of the diagram you want to draw, you will have all data available. Following, we will draw all available isolines into a Ts and a logph diagram. Each property value must be passed in the diagram’s respective unit system.

>>> data = {
...     'isobaric': {
...         'isoline_property': 'p',
...         'isoline_value': 10,
...         'starting_point_property': 'T',
...         'starting_point_value': -50,
...         'ending_point_property': 'T',
...         'ending_point_value': 150
...     },
...     'isochoric': {
...         'isoline_property': 'v',
...         'isoline_value': 0.035,
...         'starting_point_property': 'h',
...         'starting_point_value': 250,
...         'ending_point_property': 'T',
...         'ending_point_value': 125
...     },
...     'isothermal': {
...         'isoline_property': 'T',
...         'isoline_value': 50,
...         'starting_point_property': 'Q',
...         'starting_point_value': 0.1,
...         'ending_point_property': 'v',
...         'ending_point_value': 0.5
...     },
...     'isenthalpic': {
...         'isoline_property': 'h',
...         'isoline_value': 500,
...         'starting_point_property': 'p',
...         'starting_point_value': 95,
...         'ending_point_property': 'p',
...         'ending_point_value': 5
...     },
...     'isentropic': {
...         'isoline_property': 's',
...         'isoline_value': 2500,
...         'starting_point_property': 'p',
...         'starting_point_value': 1,
...         'ending_point_property': 'p',
...         'ending_point_value': 80
...     }
... }

>>> for name, specs in data.items():
...    data[name]['datapoints'] = diagram.calc_individual_isoline(**specs)

With these data, it is possible to plot to your diagram simply by plotting on the diagram.ax object, which is a matplotlib.axes._subplots.AxesSubplot object. Therefore all matplolib plotting functionalities are available. Simply pass the data of the x and y property of your diagram, e.g. to the plot() method.

>>> fig, ax = plt.subplots(1, figsize=(16, 10))
>>> mydata = {
...     'Q': {'values': np.linspace(0, 1, 11)},
...     'T': {'values': np.arange(-75, 150, 25)}
... }
>>> diagram.draw_isolines(fig, ax, 'logph', isoline_data=mydata, x_min=0, x_max=1000, y_min=1e-1, y_max=1.5e2)
>>> for key, specs in data.items():
...     datapoints = specs['datapoints']
...     _ = ax.plot(specs['datapoints']['h'], specs['datapoints']['p'], label=key)
>>> _ = ax.legend(loc='lower right')
>>> plt.tight_layout()
>>> fig.savefig('logph_R290_isolines.svg')

>>> fig, ax = plt.subplots(1, figsize=(16, 10))
>>> diagram.draw_isolines(fig, ax, 'Ts', x_min=750, x_max=3000, y_min=-50, y_max=150)
>>> for key, specs in data.items():
...     datapoints = specs['datapoints']
...     _ = ax.plot(specs['datapoints']['s'], specs['datapoints']['T'], label=key)
>>> _ = ax.legend(loc='lower right')
>>> plt.tight_layout()
>>> fig.savefig('Ts_R290_isolines.svg')
_images/logph_R290_isolines.svg
_images/Ts_R290_isolines.svg

Note

Note that the starting_point_property and the ending_point_property do not need to be identical! E.g., you can draw an isobaric line starting at a specific entropy and ending at a specific temperature.

On top of that, e.g. in order to display a pressure loss in a heat exchanger, you can have different values for the (iso)line at the starting and the ending points. The (then former) isoline property will be changed linearly to either change in entropy (for isobars and isotherms) or change in pressure (for all other lines). This functionality is only supposed to display the change in a beautiful way, it does not represent the actual process connecting your starting point with your ending point as this would require perfect knowledge of the process. In order to generate these data, you need to pass the 'isoline_value_end' keyword to the fluprodia.fluid_property_diagram.FluidPropertyDiagram.calc_individual_isoline() method.

>>> data = {
...     'isoline_property': 'p',
...     'isoline_value': 10,
...     'isoline_value_end': 9,
...     'starting_point_property': 'Q',
...     'starting_point_value': 0,
...     'ending_point_property': 'h',
...     'ending_point_value': 750
... }
>>> datapoints = diagram.calc_individual_isoline(**data)
>>> diagram.draw_isolines(fig, ax, 'Ts', x_min=750, x_max=3000, y_min=-50, y_max=150)
>>> for specs in data.values():
...    _ = ax.plot(datapoints['s'], datapoints['T'])
>>> plt.tight_layout()
>>> fig.savefig('Ts_R290_pressure_loss.svg')
_images/Ts_R290_pressure_loss.svg

Plotting States into the Diagram#

For instance, if you want to plot two different states of R290 into your diagram, you could use the scatter() method. If you want to have connected states, you will need the plot() method. In this example, we will plot from a simple heat pump simulation in TESPy [1] (for more information on TESPy see the online documentation) into a logph and a Ts diagram.

_images/logph_diagram_states.svg
_images/Ts_diagram_states.svg

The script to generate the results is the following code snippet. Just add it into your plotting code, and it will create the results shown. An interface automatically generating a dictionary for every component of the network is planned in future versions of TESPy.

>>> from tespy.components import (Compressor, CycleCloser, SimpleHeatExchanger, Valve)
>>> from tespy.connections import Connection
>>> from tespy.networks import Network


>>> def run_simple_heat_pump_model():
...     nw = Network(T_unit='C', p_unit='bar', h_unit='kJ / kg')
...     nw.set_attr(iterinfo=False)
...     cp = Compressor('compressor')
...     cc = CycleCloser('cycle_closer')
...     cd = SimpleHeatExchanger('condenser')
...     va = Valve('expansion valve')
...     ev = SimpleHeatExchanger('evaporator')
...
...     cc_cd = Connection(cc, 'out1', cd, 'in1')
...     cd_va = Connection(cd, 'out1', va, 'in1')
...     va_ev = Connection(va, 'out1', ev, 'in1')
...     ev_cp = Connection(ev, 'out1', cp, 'in1')
...     cp_cc = Connection(cp, 'out1', cc, 'in1')
...
...     nw.add_conns(cc_cd, cd_va, va_ev, ev_cp, cp_cc)
...
...     cd.set_attr(pr=0.95, Q=-1e6)
...     ev.set_attr(pr=0.9)
...     cp.set_attr(eta_s=0.9)
...
...     cc_cd.set_attr(fluid={'R290': 1})
...     cd_va.set_attr(Td_bp=-5, T=60)
...     ev_cp.set_attr(Td_bp=5, T=15)
...     nw.solve('design')
...
...     result_dict = {}
...     result_dict.update(
...         {cp.label: cp.get_plotting_data()[1] for cp in nw.comps['object']
...          if cp.get_plotting_data() is not None})
...
...     return result_dict
>>> tespy_results = run_simple_heat_pump_model()
>>> for key, data in tespy_results.items():
...    tespy_results[key]['datapoints'] = diagram.calc_individual_isoline(**data)

>>> fig, ax = plt.subplots(1, figsize=(16, 10))
>>> mydata = {
...     'Q': {'values': np.linspace(0, 1, 11)},
...     'T': {
...         'values': np.arange(-25, 150, 25),
...         'style': {'color': '#000000'}
...     }
... }
>>> diagram.set_isolines(T=mydata["T"]["values"], Q=mydata["Q"]["values"])
>>> diagram.calc_isolines()
>>> diagram.draw_isolines(fig, ax, 'logph', isoline_data=mydata, x_min=100, x_max=800, y_min=1e0, y_max=1e2)

>>> for key in tespy_results.keys():
...    datapoints = tespy_results[key]['datapoints']
...    _ = ax.plot(datapoints['h'], datapoints['p'], color='#ff0000')
...    _ = ax.scatter(datapoints['h'][0], datapoints['p'][0], color='#ff0000')
>>> plt.tight_layout()
>>> fig.savefig('logph_diagram_states.svg')

>>> fig, ax = plt.subplots(1, figsize=(16, 10))
>>> diagram.draw_isolines(fig, ax, 'Ts', x_min=750, x_max=2500, y_min=-50, y_max=150)

>>> for key in tespy_results.keys():
...     datapoints = tespy_results[key]['datapoints']
...     _ = ax.plot(datapoints['s'], datapoints['T'], color='#ff0000')
...     _ = ax.scatter(datapoints['s'][0], datapoints['T'][0], color='#ff0000')
>>> plt.tight_layout()
>>> fig.savefig('Ts_diagram_states.svg')

Note

The values for plotting must be passed in the diagrams unit system.