Working with Edges¶
In this tutorial, we use edges with properties. We notice that the connection between WindTurbine and Metmastgoes through an edge with the property distance.
from wind_turbine import WindTurbineClient
pygen = WindTurbineClient.from_toml("config.toml")
Listing and Filtering Edges¶
The Distance edges are available on the wind_turbine class, and have a list method we can use to list and filter all edges of this type.
pygen.wind_turbine.metmast_edge.list(limit=5)
| space | external_id | edge_type | start_node | end_node | distance | data_record | |
|---|---|---|---|---|---|---|---|
| 0 | sp_wind | turbine1_to_utsira | {'space': 'sp_pygen_power_enterprise', 'extern... | {'space': 'sp_wind', 'external_id': 'hornsea_1... | {'space': 'sp_wind', 'external_id': 'utsira_st... | 1000.0 | {'version': 1, 'last_updated_time': 2024-11-16... |
| 1 | sp_wind | turbine2_to_utsira | {'space': 'sp_pygen_power_enterprise', 'extern... | {'space': 'sp_wind', 'external_id': 'hornsea_1... | {'space': 'sp_wind', 'external_id': 'utsira_st... | 1200.0 | {'version': 1, 'last_updated_time': 2024-11-16... |
| 2 | sp_wind | turbine3_to_utsira | {'space': 'sp_pygen_power_enterprise', 'extern... | {'space': 'sp_wind', 'external_id': 'hornsea_1... | {'space': 'sp_wind', 'external_id': 'utsira_st... | 700.0 | {'version': 1, 'last_updated_time': 2024-11-16... |
| 3 | sp_wind | turbine4_to_utsira | {'space': 'sp_pygen_power_enterprise', 'extern... | {'space': 'sp_wind', 'external_id': 'hornsea_1... | {'space': 'sp_wind', 'external_id': 'utsira_st... | 1500.0 | {'version': 1, 'last_updated_time': 2024-11-16... |
| 4 | sp_wind | turbine5_to_utsira | {'space': 'sp_pygen_power_enterprise', 'extern... | {'space': 'sp_wind', 'external_id': 'hornsea_1... | {'space': 'sp_wind', 'external_id': 'utsira_st... | 2100.0 | {'version': 1, 'last_updated_time': 2024-11-16... |
The Distance edge is also used in the data model from MetMast to WindTurbine so we can list it from the metmast as well.
pygen.metmast.wind_turbines_edge.list(min_distance=1000, limit=5)
| space | external_id | edge_type | start_node | end_node | distance | data_record | |
|---|---|---|---|---|---|---|---|
| 0 | sp_wind | turbine1_to_utsira | {'space': 'sp_pygen_power_enterprise', 'extern... | {'space': 'sp_wind', 'external_id': 'hornsea_1... | {'space': 'sp_wind', 'external_id': 'utsira_st... | 1000.0 | {'version': 1, 'last_updated_time': 2024-11-16... |
| 1 | sp_wind | turbine2_to_utsira | {'space': 'sp_pygen_power_enterprise', 'extern... | {'space': 'sp_wind', 'external_id': 'hornsea_1... | {'space': 'sp_wind', 'external_id': 'utsira_st... | 1200.0 | {'version': 1, 'last_updated_time': 2024-11-16... |
| 2 | sp_wind | turbine4_to_utsira | {'space': 'sp_pygen_power_enterprise', 'extern... | {'space': 'sp_wind', 'external_id': 'hornsea_1... | {'space': 'sp_wind', 'external_id': 'utsira_st... | 1500.0 | {'version': 1, 'last_updated_time': 2024-11-16... |
| 3 | sp_wind | turbine5_to_utsira | {'space': 'sp_pygen_power_enterprise', 'extern... | {'space': 'sp_wind', 'external_id': 'hornsea_1... | {'space': 'sp_wind', 'external_id': 'utsira_st... | 2100.0 | {'version': 1, 'last_updated_time': 2024-11-16... |
| 4 | sp_wind | turbine3_to_hitra | {'space': 'sp_pygen_power_enterprise', 'extern... | {'space': 'sp_wind', 'external_id': 'hornsea_1... | {'space': 'sp_wind', 'external_id': 'hitra_sta... | 1100.0 | {'version': 1, 'last_updated_time': 2024-11-16... |
Note, that we now also are filtering on the edge.
Query/Filterin/Selecting with Edges¶
Edges are seldom used in isolation. However, they can be very powerful when we want to fetch data based on the properties in the edge.
For example, if we want to find all wheather stations within 1000 meter of a given WindTurbine we can write
metmast = (
pygen.wind_turbine.select()
.name.equals("hornsea_1_mill_1")
.metmast.distance.range(0, 1000)
.end_node.list_metmast(limit=-1)
)
metmast
| space | external_id | position | temperature | tilt_angle | wind_speed | data_record | |
|---|---|---|---|---|---|---|---|
| 0 | sp_wind | utsira_station | 62.0 | utsira_station_temperature | utsira_station_tilt_angle | utsira_station_wind_speed | {'version': 1, 'last_updated_time': 2024-11-16... |
| 1 | sp_wind | hitra_station | 63.0 | hitra_station_temperature | hitra_station_tilt_angle | hitra_station_wind_speed | {'version': 1, 'last_updated_time': 2024-11-16... |
turbine = (
pygen.wind_turbine.select()
.name.equals("hornsea_1_mill_1")
.metmast.distance.range(0, 1000)
.end_node.list_full(limit=-1)
)
turbine
| space | external_id | capacity | name | blades | datasheets | metmast | nacelle | rotor | windfarm | data_record | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | sp_wind | hornsea_1_mill_1 | 7.0 | hornsea_1_mill_1 | [hornsea_1_mill_1_blade_A, hornsea_1_mill_1_bl... | [windmill_schematics] | [{'space': 'sp_wind', 'external_id': 'turbine1... | hornsea_1_mill_1_nacelle | hornsea_1_mill_1_rotor | Hornsea 1 | {'version': 4, 'last_updated_time': 2024-11-16... |
turbine[0].metmast[0]
| value | |
|---|---|
| space | sp_wind |
| external_id | turbine1_to_utsira |
| edge_type | {'space': 'sp_pygen_power_enterprise', 'extern... |
| start_node | {'space': 'sp_wind', 'external_id': 'hornsea_1... |
| end_node | {'space': 'sp_wind', 'external_id': 'utsira_st... |
| data_record | {'version': 1, 'last_updated_time': 2024-11-16... |
| distance | 1000.0 |
Create Edges with Properties¶
Creating edges with properties are always done with the nodes these edges belong. This means, you cannot create edges alone, they always have to be connected to nodes.
The creation of edges are done as a step between the nodes when the edges has at least one property:
from wind_turbine import data_classes as data_cls
new_turbine = data_cls.WindTurbineWrite(
external_id="doctriono_b",
name="A new Wind Turbine",
capacity=8.0,
metmast=[
data_cls.DistanceWrite(
distance=500.0,
end_node=data_cls.MetmastWrite(
external_id="doctrino_weather",
position=42.0,
),
)
],
)
We can now create the new turbine with a memast startion
created = pygen.upsert(new_turbine)
created.nodes
| space | instance_type | external_id | version | was_modified | last_updated_time | created_time | |
|---|---|---|---|---|---|---|---|
| 0 | sp_wind | node | doctriono_b | 1 | True | 2024-11-16 21:19:33.212 | 2024-11-16 21:19:33.212 |
| 1 | sp_wind | node | doctrino_weather | 1 | True | 2024-11-16 21:19:33.212 | 2024-11-16 21:19:33.212 |
created.edges
| space | instance_type | external_id | version | was_modified | last_updated_time | created_time | |
|---|---|---|---|---|---|---|---|
| 0 | sp_wind | edge | doctriono_b:doctrino_weather | 1 | True | 2024-11-16 21:19:33.212 | 2024-11-16 21:19:33.212 |
created.time_series
# Clean
pygen.delete(new_turbine)
InstancesDeleteResult(nodes=[NodeId(space='sp_wind', external_id='doctriono_b'), NodeId(space='sp_wind', external_id='doctrino_weather')], edges=[EdgeId(space='sp_wind', external_id='doctriono_b:doctrino_weather')])
(Advanced) External ID Hook¶
pygen sets the external_id for edges automatically for you. This is done with an external_id hook, and if you want to control this behavior you can overwrite this hook to control how external ids are set.
from wind_turbine import data_classes as data_cls
data_cls.DomainRelationWrite.external_id_factory
<function wind_turbine.data_classes._core.base.default_edge_external_id_factory(start_node: 'DomainModelWrite | str | dm.NodeId', end_node: 'DomainModelWrite | str | dm.NodeId', edge_type: 'dm.DirectRelationReference') -> 'str'>
We can for example set this to a uuid
from uuid import uuid4
def my_id_creator(*_, **__) -> str:
return str(uuid4())
data_cls.DomainRelationWrite.external_id_factory = my_id_creator
We now repeat the example above
new_turbine = data_cls.WindTurbineWrite(
external_id="doctriono_b",
name="A new Wind Turbine",
capacity=8.0,
metmast=[
data_cls.DistanceWrite(
distance=500.0,
end_node=data_cls.MetmastWrite(
external_id="doctrino_weather",
position=42.0,
),
)
],
)
resources = new_turbine.to_instances_write()
resources.edges[0].external_id
'4a1c28c7-3296-4742-9d9e-25aa6cf826ea'
We notice that this time the external ID of the edge is set to an UUID
We can reset back to the default external id hook, by calling the following
data_cls.DomainRelationWrite.reset_external_id_factory()
Note If we do not want to use the external id hook, we can pass in the external_id directly
new_turbine = data_cls.WindTurbineWrite(
external_id="doctriono_b",
name="A new Wind Turbine",
capacity=8.0,
metmast=[
data_cls.DistanceWrite(
external_id="distance_from_doctrino_b_to_doctrino_weather",
distance=500.0,
end_node=data_cls.MetmastWrite(
external_id="doctrino_weather",
position=42.0,
),
)
],
)
new_turbine.to_instances_write().edges[0].external_id
'distance_from_doctrino_b_to_doctrino_weather'