Python Package to import and work with the SIMULTAN Data model
Project description
PySimultan
Python Package to import and work with the SIMULTAN Data model [SIMULTAN REPORT].
This package tries to provide a seamless integration of SIMULTAN in Python. As SIMULTAN is written in C#, the package uses Python.NET to import the Simultan libraries. With Python.NET all functions of the dlls are preserved, and you are able to develop in python without any changes (except for cases that are .NET specific).
To make life easier for developers, we have implemented a typing process that imports components as instances in the type you have defined! Using simple text templates, the type of a SIMULTAN component is assigned to a class in Python. This class then inherits from the imported instance's class using monkey patching.
Best explained with an example:
A component with type 'room' is imported from a project. With the template the class 'EgRoom' is assigned to the type 'Room' in Python. When importing the instance, a new class 'NewRoom' is created, which inherits from EgRoom and the class of the imported object ('SimultanComponent'). Using monkey patching, the EgRoom class is then overwritten with the 'NewRoom' class. Finally, the class 'SimultanComponent' of the imported instance is converted into the new class 'NewRoom' using type-casting.
This way SIMULTAN can be integrated into existing packages with minimal adjustments!
Features:
- fast: use of lazy loading, caching and parallelization
- variable search depth for references
- minimal dependencies
- easy to integrate
To Do:
- Only read access. Write and save has not been tested yet.
Usage
Data model Typing
Since SIMULTAN is a dynamic data model, the data must first be typed. To do this, the TYPE parameter is created in a component to be typed and a corresponding value is set.
For example, the user creates a component 'Living Room 1 Floor', which he can identify and assign as a room on the first floor based on the name. However, for an application it is not clear which data corresponds to what. Therefore, the data must first be typed. For typing, the parameter 'TYPE' is created in a component and a corresponding value is set.
In this example the TYPE
of the component is 'Room' and every application which imports the project
can identify it as of the type 'Room'.
In Python readme_test_1:
from PySimultan import DataModel
data_model = DataModel(project_path='example1.simultan')
print(data_model.data.Items)
print(f'Component type: {data_model.data.Items[0].ContainedParameters.Items[1].TextValue}')
prints a list for the components and the type of the first component:
[<ParameterStructure.Component.Component object at 0x00000157F77AA7C0>]
Component type: Room
Now we can import and determine the type of the component
TemplateParser
We can determine the type of our component, but to do this with a lots
of components and sub-components is getting annoying fast. This is where we
can use the TemplateParser
.
The TemplateParser is a class which scans the data model and creates instances of types, defined in a template.
We want to load the following components in python:
Therefore, we have to define a template which defines how our class should look like. Let's look at this template-file template_example3.yml:
- !Template
template_name: Room
template_id: '1'
inherits_from:
content: [Internal heat gains, Volume, Room Name, Furniture]
documentation: 'Room: defines a Room or a Zone'
units: {Internal heat gains: W, Volume: m³, Room Name: '-', Furniture: '-'}
types: {Internal heat gains: float, Volume: float, Room Name: str}
slots: {Furniture: Element_00}
- !Template
template_name: Table
template_id: '2'
inherits_from:
content: [Number Persons]
documentation: 'Table: defines a table with number of persons'
units: {Number Persons: '-'}
types: {Number Persons: float}
slots: {}
In this yaml-file is one 'Room'-template which defines how components of the TYPE 'Room' should be handled.
There is a entry called content
which defines which content for this type is expected. The content in the
SIMULTAN data model can be a Parameter, a sub-component or a linked component. In this example four items in
the SIMULTAN-component are expected: 'Internal heat gains', 'Volume', 'Room Name' and 'Furniture'.
What the Template parser does is that it checks in SIMULTAN-Component if there is a TYPE-Parameter defined. If the TYPE is found, for each item in the content there is a check if a parameter with the name of the content defined.
For example the first item of the content is 'Internal heat gains'. If a parameter with this name is found in the component, the property of the generated python-component will return the value of the SIMULTAN-parameter 'Internal heat gains'.
If no parameter is found, PySimultan checks if there is a slot defined for the content. Sub-components or linked components in the SIMULTAN data model have a slot and a slot-extension. With this slot- /extension PySimultan can determine which component or sub-component is the value of the content.
In this example for the content 'Furniture' the slot 'Element_00' is defined. If no Parameter 'Furniture' is found, PySimultan checks if there is a entry with the slot 'Element' and the slot-extension '0' in the component and return this instance.
To load the 'Room' component run readme_test_3:
from PySimultan import DataModel, Template, TemplateParser, yaml
# use pkg_resources to load package example files
with pkg_resources.path(readme_examples, 'template_example3.yml') as r_path:
template_file = str(r_path)
# create and write the templates
create_template(template_file)
# create the template parser
template_parser = TemplateParser(template_filepath=template_file)
# load the SIMULTAN project
data_model = DataModel(project_path=project_file)
# create the typed datamodel form the loaded SIMULTAN project and the template_parser
typed_data = data_model.get_typed_data(template_parser=template_parser, create_all=False)
If we inspect typed_data
we can see that there is a instance of the type 'Room' with
the attributes we defined in the template. The attribute 'Furniture' is the linked component
with the Slot 'Element' and the slot-extension 0.
We can easily access all content which was defined in the template with python .dot synatx:
print(typed_data[0].Furniture)
print(typed_data[0].Volume)
# Properties with blanks: use getattr
print(getattr(typed_data[0], 'Internal heat gains'))
Templates
File Description
Template-files are yaml files which define one or more templates. A template has the following keywords:
-
template_name: The name of the template; [str]; This name is also used for the 'TYPE' value of a SIMULTAN-component and the class name in python: Example: 'TestTemplate'
-
template_id: ID of the template; [int]; There is currently no functionality for the ID of the template; Example: 1
-
inherits_from: parent class of the template; [-]; Template from which this template inherits. Can be another Template or the name of another template. Example: see Table and ModifiedTable template
-
content: List of the content names; [-]; this list defines which attributes the python class for this template has. The values of these attributes are either the value of the parameter with the name of the SIMULTAN-component or the value of the defined slot (see slots); Example: [Internal heat gains, Volume, Room Name, Furniture]
-
documentation: Documentation of the template; [str]; Documentation for other developers and users;Example:
-
units: Units of the content; [dict]; dictionary with the name of the content as key and unit as value. No further functionality. Example: {Internal heat gains: W, Volume: m³, Room Name: '-', Furniture: '-'}
-
types: Type of the content; [dict]; The type defines if the current_value or the text_value of a SIMULTAN-component is returned. If the type is str the text_value is returned, otherwise the current_value, the sub-component or the refence is returned; Example: {Internal heat gains: float, Volume: float, Room Name: str}
-
slots: slots of the content; [dict]; if no parameter with the content name is found, the reference or the sub-component with the here defined slot is returned; Example: {Furniture: Element_00}
-
synonyms: synonyme names of the python attributes; [dict]; in python class: the content is accessed through the synonym instead of the content name
Template Example
- !Template
template_name: Room
template_id: '1'
inherits_from:
content: [Internal heat gains, Volume, Room Name, Furniture]
documentation: 'Room: defines a Room or a Zone'
units: {Internal heat gains: W, Volume: m³, Room Name: '-', Furniture: '-'}
types: {Internal heat gains: float, Volume: float, Room Name: str}
slots: {Furniture: Element_00}
- &id001 !Template
template_name: Table
template_id: '2'
inherits_from:
content: [Number Persons]
documentation: 'Table: defines a table with number of persons'
units: {Number Persons: '-'}
types: {Number Persons: float}
slots: {}
- !Template
template_name: ModifiedTable
template_id: '3'
inherits_from: *id001
content:
documentation: See Table
units:
types:
slots: {}
- !Template
template_name: MaterialList
template_id: '4'
inherits_from: List
content: []
documentation: List with Materials. This list inherits from the build-in type List
units: {}
types: {}
slots: {}
- !Template
template_name: MyFace
template_id: '101'
inherits_from: Geometric Area
content: []
documentation: Face. This type inherits from the build-in type Geometric Area
units: {}
types: {}
slots: {}
Template generation in python
With PySimultan template-files can be generated in an easy way. Templates can be created as instances of
PySimultan.Template
and dumped to a file:
from PySimultan import Template, yaml
# create several templates:
face_template = Template(template_name='MyFace',
template_id='1',
content=[],
inherits_from='Geometric Area',
documentation='',
units={},
types={},
slots={}
)
building_template = Template(template_name='Building',
template_id='2',
content=['FloorList'],
documentation='',
units={},
types={},
slots={'FloorList': 'Liste_00'},
inherits_from='SmartCampusBuilding'
)
floor_list_template = Template(template_name='FloorList',
template_id='3',
content=[],
inherits_from='List',
documentation='List with Floors',
units={},
types={},
slots={}
)
# create a list of the templates to write to a file:
templates = [face_template, building_template, floor_list_template]
# write the templates to a file:
yaml.dump(templates, 'test.yml')
Geometry
In SIMULTAN geometry is handled in a different way. The geometry is seperated from the data-model and there can be multiple geometry files and modles. The geometry-model is also loaded separately from the data-model.
When a project with a geometry model is loaded, there are automatically typed_geo_models
generated. These geometry
models are python objects with python objects of vertices, edges, faces ...
These python instances are also used in the typed data model.
Default Types
There are default types for components of these slots (or TYPE):
-
List slot: 'Liste' ('List'); returns a list in python. A list instead a component with subcomponents is easier to handle. Additionaly the items in the list are sorted by their slot extension
-
ValueField slot: 'ValueField'; returns a pandas dataframe for the value-field
-
BuildInFace slot: 'Geometrische_Flächen' ('Geometric Area'); returns a instance of the class BuildInFace, has the link to
GeometricFace
-
BuildInVolume slot: 'Geometrische_Volumina'; returns a instance of the class BuildInVolume, has the link to
GeometricVolume
-
BuildInZone type: 'BuildInZone'; returns a instance of the class BuildInZone (a zone can consist of multiple volumes)
Geometry default Types:
- GeometricLayer
- GeometricVertex
- GeometricEdge
- GeometricEdgeLoop
- GeometricFace
- GeometricVolume
Tips and tricks:
get all instances of a type
The TemplateParser
keeps track of all classes and instances. So it's easy to find all instances of
a certain type in the data-model. TemplateParser.template_classes
returns a dictionary with all generated python classes.
These classes have an attribute cls_instances
which returns a list with all instances of this type. ValueField
, List
and
all classes which inherit from these do not have cls_instances
.
After loading the data-model:
template_parser = TemplateParser(template_filepath=template_file)
data_model = DataModel(project_path=project_file)
typed_data = data_model.get_typed_data(template_parser=template_parser, create_all=True)
for cls in template_parser.template_classes.values():
if hasattr(cls, 'cls_instances'):
print(f'{cls.__name__}: {cls.cls_instances}')
Extend packages with PySimultan
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file PySimultan-0.1.5.tar.gz
.
File metadata
- Download URL: PySimultan-0.1.5.tar.gz
- Upload date:
- Size: 29.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.7.0 requests/2.24.0 setuptools/57.4.0 requests-toolbelt/0.9.1 tqdm/4.60.0 CPython/3.8.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ecc2fe33badc96c3f8cbebc6e025052d5523bb92fb7ae1f03f04b6ac619cc7f0 |
|
MD5 | 13fdd4b5d72226d1525fa901fb6f7e9c |
|
BLAKE2b-256 | 6571fdeccc340db999ed8a0afa9acfaaeff338236ae2b556678fb6d7dd585731 |
File details
Details for the file PySimultan-0.1.5-py3-none-any.whl
.
File metadata
- Download URL: PySimultan-0.1.5-py3-none-any.whl
- Upload date:
- Size: 21.3 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.2.0 pkginfo/1.7.0 requests/2.24.0 setuptools/57.4.0 requests-toolbelt/0.9.1 tqdm/4.60.0 CPython/3.8.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | a329c201c33103449335851f1546ec9d26d70b7ca72b68887cf8e05f46390db3 |
|
MD5 | fbaa6b1c8fde8c8a58e047ba4fd5311f |
|
BLAKE2b-256 | 72407fbd9a1e3d59a8dd483f6661a93777dadc68aa3c71414114bda54441b1c7 |