Working with Edges¶
In this tutorial, we use edges with properties. We notice that the connection between WindTurbine
and Metmast
goes 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'