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

Separate data export from writing to filesystem #605

Open
wants to merge 8 commits into
base: dev
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
2 changes: 1 addition & 1 deletion docs/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ What's New

Discover notable new features and improvements in each release

.. include:: whats_new/v0-7-9.rst
.. include:: whats_new/v0-8-0.rst
.. include:: whats_new/v0-7-8-002.rst
.. include:: whats_new/v0-7-8-001.rst
.. include:: whats_new/v0-7-8.rst
Expand Down
14 changes: 0 additions & 14 deletions docs/whats_new/v0-7-9.rst

This file was deleted.

36 changes: 36 additions & 0 deletions docs/whats_new/v0-8-0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
v0.8.0 - Under development
++++++++++++++++++++++++++

New Features
############
- Implement a new property for connections to report the phase of the fluid,
i.e. :code:`"l"` for liquid, :code:`"tp"` for two-phase and :code:`"g"` for
gaseous. The phase is only reported in subcritical pressure
(`PR #592 <https://github.com/oemof/tespy/pull/592>`__).
- Change the export of a :py:class:`tespy.networks.network.Network` instance to
separate writing to the filesystem from creating the data to export. This
breaks the API of the :py:meth:`tespy.networks.network_reader.load_network`
method, meaning exported network data based on :code:`tespy<0.8` are not
compatible with how :code:`tespy>=0.8` is handling the data
(`PR #605 <https://github.com/oemof/tespy/pull/605>`__).

.. code-block:: python

>>> from tespy.networks import Network
>>> from tespy.connections import Connection
>>> from tespy.components import Source, Sink
>>> nwk = Network()
>>> so = Source("source")
>>> si = Sink("sink")
>>> c1 = Connection(so, "out1", si, "in1")
>>> nwk.add_conns(c1)
>>> data = nwk.export()
>>> list(data.keys())
['Network', 'Connection', 'Component', 'Bus']
>>> list(data["Component"])
['Source', 'Sink']

Contributors
############
- Francesco Witte (`@fwitte <https://github.com/fwitte>`__)
- `@tlmerbecks <https://github.com/tlmerbecks>`__
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ exclude = ["docs/_build"]

[project]
name = "tespy"
version = "0.7.9.dev0"
version = "0.8.0.dev0"
description = "Thermal Engineering Systems in Python (TESPy)"
readme = "README.rst"
authors = [
Expand Down
2 changes: 1 addition & 1 deletion src/tespy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os

__datapath__ = os.path.join(importlib.resources.files("tespy"), "data")
__version__ = '0.7.9.dev0 - Newton\'s Nature'
__version__ = '0.8.0.dev0'

# tespy data and connections import
from . import connections # noqa: F401
Expand Down
251 changes: 209 additions & 42 deletions src/tespy/networks/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -2663,13 +2663,172 @@ def print_components(self, c, *args):
else:
return np.nan

def export(self, path):
"""Export the network structure and parametrization."""
path, path_comps = self._create_export_paths(path)
self.export_network(path)
self.export_connections(path)
self.export_components(path_comps)
self.export_busses(path)
def export(self, path=None):
"""Export the parametrization and structure of the Network instance

Parameters
----------
path : str, optional
Path for exporting to filesystem. If path is None, the data are
only returned and not written to the filesystem, by default None

Returns
-------
dict
Parametrization and structure of the Network instance.
"""
export = {}
export["Network"] = self._export_network()
export["Connection"] = self._export_connections()
export["Component"] = self._export_components()
export["Bus"] = self._export_busses()

if path:
path, _ = self._create_export_paths(path)
for key, value in export.items():

fn = os.path.join(path, f'{key}.json')
with open(fn, 'w') as f:
json.dump(value, f, indent=4)
logger.debug(f'{key} information saved to {fn}.')

return export

def to_exerpy(self, Tamb, pamb, exerpy_mappings):
"""Export the network to exerpy

Parameters
----------
Tamb : float
Ambient temperature.
pamb : float
Ambient pressure.
exerpy_mappings : dict
Mappings for tespy components to exerpy components

Returns
-------
dict
exerpy compatible input dictionary
"""
component_json = {}
for comp_type in self.comps["comp_type"].unique():
if comp_type not in exerpy_mappings.keys():
msg = f"Component class {comp_type} not available in exerpy."
logger.warning(msg)
continue

key = exerpy_mappings[comp_type]
if key not in component_json:
component_json[key] = {}

for c in self.comps.loc[self.comps["comp_type"] == comp_type, "object"]:
component_json[key][c.label] = {
"name": c.label,
"type": comp_type
}

connection_json = {}
for c in self.conns["object"]:
c.get_physical_exergy(pamb, Tamb)

connection_json[c.label] = {
"source_component": c.source.label,
"source_connector": int(c.source_id.removeprefix("out")) - 1,
"target_component": c.target.label,
"target_connector": int(c.target_id.removeprefix("in")) - 1
}
connection_json[c.label].update({f"mass_composition": c.fluid.val})
connection_json[c.label].update({"kind": "material"})
for param in ["m", "T", "p", "h", "s"]:
connection_json[c.label].update({
param: c.get_attr(param).val_SI,
f"{param}_unit": c.get_attr(param).unit
})
connection_json[c.label].update(
{"e_T": c.ex_therm, "e_M": c.ex_mech, "e_PH": c.ex_physical}
)

from tespy.components.turbomachinery.base import Turbomachine
for label, bus in self.busses.items():

if "Motor" not in component_json:
component_json["Motor"] = {}
if "Generator" not in component_json:
component_json["Generator"] = {}

for i, (idx, row) in enumerate(bus.comps.iterrows()):
if isinstance(idx, Turbomachine):
kind = "power"
else:
kind = "heat"

if row["base"] == "component":
component_label = f"generator_of_{idx.label}"
connection_label = f"{idx.label}__{component_label}"
connection_json[connection_label] = {
"source_component": idx.label,
"source_connector": 999,
"target_component": component_label,
"target_connector": 0,
"mass_composition": None,
"kind": kind,
"energy_flow": abs(idx.bus_func(bus))
}
connection_label = f"{component_label}__{label}"
connection_json[connection_label] = {
"source_component": component_label,
"source_connector": 0,
"target_component": label,
"target_connector": i,
"mass_composition": None,
"kind": kind,
"energy_flow": abs(idx.calc_bus_value(bus))
}
component_json["Generator"][component_label] = {
"name": component_label,
"type": "Generator",
"type_index": None,
}

else:
component_label = f"motor_of_{idx.label}"
connection_label = f"{label}__{component_label}"
connection_json[connection_label] = {
"source_component": label,
"source_connector": i,
"target_component": component_label,
"target_connector": 0,
"mass_composition": None,
"kind": kind,
"energy_flow": idx.calc_bus_value(bus)
}
connection_label = f"{component_label}__{idx.label}"
connection_json[connection_label] = {
"source_component": component_label,
"source_connector": 0,
"target_component": idx.label,
"target_connector": 999,
"mass_composition": None,
"kind": kind,
"energy_flow": idx.bus_func(bus)
}
component_json["Motor"][component_label] = {
"name": component_label,
"type": "Motor",
"type_index": None,
}

return {
"components": component_json,
"connections": connection_json,
"ambient_conditions": {
"Tamb": Tamb,
"Tamb_unit": "K",
"pamb": pamb,
"pamb_unit": "Pa"
}
}

def save(self, path):
r"""
Expand Down Expand Up @@ -2708,20 +2867,6 @@ def _create_export_paths(self, path):

return path, path_comps

def export_network(self, fn):
r"""
Save basic network configuration.

Parameters
----------
fn : str
Path/filename for the network configuration file.
"""
with open(os.path.join(fn, 'network.json'), 'w') as f:
json.dump(self._serialize(), f, indent=4)

logger.debug('Network information saved to %s.', fn)

def save_connections(self, fn):
r"""
Save the connection properties.
Expand Down Expand Up @@ -2768,33 +2913,55 @@ def save_busses(self, fn):
json.dump(bus_data, f, indent=4)
logger.debug('Bus information saved to %s.', fn)

def export_connections(self, fn):
def _export_network(self):
r"""Export network information

Returns
-------
dict
Serialization of network object.
"""
return self._serialize()

def _export_connections(self):
"""Export connection information

Returns
-------
dict
Serialization of connection objects.
"""
connections = {}
for c in self.conns["object"]:
connections.update(c._serialize())
return connections

fn = os.path.join(fn, "connections.json")
with open(fn, "w", encoding="utf-8") as f:
json.dump(connections, f, indent=4)
logger.debug('Connection information exported to %s.', fn)
def _export_components(self):
"""Export component information

def export_components(self, fn):
Returns
-------
dict
Dict of dicts with per class serialization of component objects.
"""
components = {}
for c in self.comps["comp_type"].unique():
components = {}
components[c] = {}
for cp in self.comps.loc[self.comps["comp_type"] == c, "object"]:
components.update(cp._serialize())
components[c].update(cp._serialize())

fname = os.path.join(fn, f"{c}.json")
with open(fname, "w", encoding="utf-8") as f:
json.dump(components, f, indent=4)
logger.debug('Component information exported to %s.', fname)
return components

def export_busses(self, fn):
if len(self.busses) > 0:
busses = {}
for bus in self.busses.values():
busses.update(bus._serialize())
fn = os.path.join(fn, 'busses.json')
with open(fn, "w", encoding="utf-8") as f:
json.dump(busses, f, indent=4)
logger.debug('Bus information exported to %s.', fn)
def _export_busses(self):
"""Export bus information

Returns
-------
dict
Serialization of bus objects.
"""
busses = {}
for bus in self.busses.values():
busses.update(bus._serialize())

return busses
Loading
Loading