Tracking changes in GDM#
The grid-data-models
(GDM) package includes comprehensive support for modeling temporal changes within a distribution system. This functionality allows users to effectively manage tracked changes to a base grid model, enabling dynamic analysis and scenario planning. All tracked changes are built upon a single base GDM model, ensuring a consistent foundation for analysis. The system enables edits, additions, and deletions to a base GDM model at specific timestamps. Each modification is tracked and stored, ensuring a clear history of changes over time.
Relevent GMD utility Classed and Functions :
TrackedChange
: A class that represents a tracked change to a system. It includes attributes for the date scenario name, changes are applied, the list of additions, edits, and deletions.apply_updates_to_system
: Takes in a list ofTrackedChange
objects and returns the GDM model updated to include all changes.filter_tracked_changes_by_name_and_date
: Helper function that enables users to filter a list ofTrackedChange
objects base on scenario_name and / or date of interest.
Example: Building a temporal model#
In the following example,
We will Make use of
gdmloader
package to fist download a sample GDM model. The package can be installed usingpip intall gdmloader
.
from gdm import DistributionSystem, DistributionLoad, DistributionSolar, MatrixImpedanceBranch
from gdm.quantities import PositiveDistance
from gdmloader.constants import GDM_CASE_SOURCE
from gdmloader.source import SystemLoader
loader = SystemLoader()
loader.add_source(GDM_CASE_SOURCE)
base_model: DistributionSystem = loader.load_dataset(DistributionSystem, GDM_CASE_SOURCE.name, "three_feeder_switch")
base_model.auto_add_composed_components = True
Next, We will build a catalog of components that will serve as a equipment library for additions to the base model and maps to temporal changes in the base model. In this catalog, we add two examples models with fixed uuids that will later be used for temporal mapping
from uuid import UUID, uuid4
catalog = DistributionSystem(auto_add_composed_components=True)
# Model to edit in 2022
catalog.add_component(
DistributionLoad.example().model_copy(update={'uuid': UUID('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa')})
)
catalog.add_component(
DistributionSolar.example().model_copy(update={'uuid': UUID('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb')})
)
From the model, we get a line model and two load models. These components will be modified to reflect changes in the base model.
line_model_to_edit = base_model.get_component(MatrixImpedanceBranch, "fdr3_3_load_fdr3_3_load_4")
load_model_to_delete_in_2024 = base_model.get_component(DistributionLoad, "fdr2_load12")
load_model_to_delete_in_2025 = base_model.get_component(DistributionLoad, "fdr3_load15")
Each
TrackedChange
object has a scenario name. Additionally, this object may also have a date field that can be used to filter changes based on specific dates. EachTrackedChange
has a list of system additions, edits and deletions to be applied on the date.
additions: This is a list attribute that holds the UUIDs of the components that were added in this modification. These UUIDs should exist in the
catalog
.deletions: This is a list attribute that holds the UUIDs of the components that were deleted in this modification. These UUIDs should exist in the
base system model
edits: This is a list attribute that holds the
PropertyEdit
objects that represent the edits made in this modification.PropertyEdit
requires name of the property to be edited, the new value of the property and the component_uuid that maps to the modified component.
NOTE: When editing property of an existing component, make sure to use the same quantity / component type as defined in the model defination. For example when modifing the length property of a distribution branch, PositiveDistance is used to the define the new value in the example below
from gdm.temporal_models import UpdateScenario, PropertyEdit, TrackedChange
update_scenario = [
TrackedChange(
scenario_name="scenario_1",
update_date="2022-01-01",
edits=[
PropertyEdit(
component_uuid=capacitor.uuid,
name="rated_reactive_power",
value=PositiveReactivePower(200, "kvar"),
)
],
),
TrackedChange(
scenario_name="scenario_1",
update_date="2023-01-01",
additions=["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"],
),
TrackedChange(
scenario_name="scenario_1",
update_date="2024-01-01",
deletions=[load1.uuid],
),
TrackedChange(
scenario_name="scenario_2",
update_date="2025-01-01",
deletions=[load2.uuid],
),
]
Next, we usse
filter_tracked_changes_by_name_and_date
to filter a list of tracked changes based on a specific scenario name and / or update date.
tracked_changes = filter_tracked_changes_by_name_and_date(
tracked_changes,
scenario_name="scenario_1",
update_date=datetime.strptime("2022-1-1", "%Y-%m-%d").date(),
)
Finally, we use functions provided by the GDM library to apply changes to the base distribution system model.
from datetime import date
from gdm.temporal_models import apply_updates_to_system
model_on_date= date(2024, 1, 1)
new_system = apply_updates_to_system(
tracked_changes=tracked_changes, system=system, catalog=catalog
)
Execution of code block above returns the new distribution model with all temporal changes applied unto 2024/01/01. All changes applied to the base model are provided to the use in tabular form.
Updates applied to the system
┏━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Timestamp ┃ Operation ┃ UUID ┃ Component Type ┃ Component Name ┃ Connected bus ┃ Scenario ┃
┡━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ 2022-01-01 │ Edit │ ce5f1242-9e2f-46df-b20c-d6032eababe5 │ PhaseCapacitorEquipment │ phase_capacitor_0_4 │ None │ scenario_1 │
└────────────┴───────────┴──────────────────────────────────────┴─────────────────────────┴─────────────────────┴───────────────┴────────────┘
Note: We can alternately filter tracked changes based on just the scenario name.
tracked_changes = filter_tracked_changes_by_name_and_date(
tracked_changes,
scenario_name="scenario_1",
)
Using the following filtering function above returns
Updates applied to the system
┏━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Timestamp ┃ Operation ┃ UUID ┃ Component Type ┃ Component Name ┃ Connected bus ┃ Scenario ┃
┡━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ 2022-01-01 │ Edit │ 050b6713-8ef9-44d5-b7c2-8ef7ceb5bc0f │ PhaseCapacitorEquipment │ phase_capacitor_0_4 │ None │ scenario_1 │
│ 2023-01-01 │ Addition │ aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa │ LoadEquipment │ added_phase_load_model │ None │ scenario_1 │
│ 2024-01-01 │ Deletion │ a5f728f3-df2a-4581-bd6a-6274b02bf63c │ DistributionLoad │ load_5 │ bus_5 │ scenario_1 │
└────────────┴───────────┴──────────────────────────────────────┴─────────────────────────┴────────────────────────┴───────────────┴────────────┘