grid-data-models 2.3.3__tar.gz → 2.3.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/.gitignore +0 -1
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/PKG-INFO +7 -7
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/README.md +1 -1
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/pyproject.toml +5 -5
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/__init__.py +1 -0
- grid_data_models-2.3.5/src/gdm/distribution/components/geometry_switch.py +122 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/controllers/distribution_regulator_controller.py +11 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/enums.py +40 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/market/__init__.py +9 -3
- grid_data_models-2.3.5/src/gdm/distribution/market/aggregator.py +259 -0
- grid_data_models-2.3.5/src/gdm/distribution/market/tariff.py +321 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/sys_functools.py +186 -167
- grid_data_models-2.3.5/src/gdm/distribution/upgrade_handler/from__2_3_3__to__2_3_4.py +15 -0
- grid_data_models-2.3.5/src/gdm/distribution/upgrade_handler/from__2_3_4__to__2_3_5.py +15 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/upgrade_handler.py +12 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/version.py +1 -1
- grid_data_models-2.3.3/src/gdm/distribution/market/tariff.py +0 -158
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/LICENSE.txt +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/cli/cli.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/cli/reducer.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/constants.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/dataset/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/dataset/cost_model.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/dataset/dataset_system.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/catalog_system.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/common/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/common/curve.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/common/limitset.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/common/sequence_pair.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/base/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/base/distribution_branch_base.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/base/distribution_component_base.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/base/distribution_switch_base.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/base/distribution_transformer_base.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/distribution_battery.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/distribution_bus.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/distribution_capacitor.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/distribution_feeder.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/distribution_load.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/distribution_regulator.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/distribution_solar.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/distribution_substation.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/distribution_transformer.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/distribution_vsource.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/geometry_branch.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/matrix_impedance_branch.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/matrix_impedance_fuse.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/matrix_impedance_recloser.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/matrix_impedance_switch.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/sequence_impedance_branch.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/controllers/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/controllers/base/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/controllers/base/capacitor_controller_base.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/controllers/base/inverter_controller_base.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/controllers/distribution_capacitor_controller.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/controllers/distribution_inverter_controller.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/controllers/distribution_recloser_controller.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/controllers/distribution_switch_controller.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/distribution_graph.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/distribution_system.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/bare_conductor_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/base/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/base/matrix_impedance_branch_equipment_base.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/battery_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/capacitor_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/concentric_cable_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/distribution_transformer_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/geometry_branch_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/inverter_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/load_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/matrix_impedance_branch_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/matrix_impedance_fuse_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/matrix_impedance_recloser_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/matrix_impedance_switch_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/phase_capacitor_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/phase_load_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/phase_voltagesource_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/recloser_controller_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/sequence_impedance_branch_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/solar_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/equipment/voltagesource_equipment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/model_reduction/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/model_reduction/reducer.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/from__2_0_1__to__2_1_2.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/from__2_1_2__to__2_1_3.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/from__2_1_3__to__2_1_4.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/from__2_1_4__to__2_1_5.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/from__2_1_5__to__2_2_0.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/from__2_2_0__to__2_2_1.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/from__2_2_1__to__2_3_0.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/from__2_3_0__to__2_3_1.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/from__2_3_1__to__2_3_2.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/upgrade_handler/from__2_3_2__to__2_3_3.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/exceptions.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/hashing_utils.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/exceptions.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/inspection/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/inspection/inspector.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/inspection/relationships.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/inspection/topology.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/knowledge/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/knowledge/documentation.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/operations/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/operations/merger.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/operations/splitter.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/schemas.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/server.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/utilities/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/utilities/subsystem.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/utilities/timeseries.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/validation/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/validation/auto_fixer.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/validation/diagnostics.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/validation/suggestions.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/mcp/version.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/quantities.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/components/__init__.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/components/base.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/components/building.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/components/overhead_line_segment.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/components/pole.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/components/pvsystem.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/components/transformer.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/components/underground_cable.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/components/underground_junction.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/structural/structural_system.py +0 -0
- {grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/tracked_changes.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: grid-data-models
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.5
|
|
4
4
|
Project-URL: Documentation, https://github.com/NREL-Distribution-Suites/grid-data-models#readme
|
|
5
5
|
Project-URL: Issues, https://github.com/NREL-Distribution-Suites/grid-data-models/issues
|
|
6
6
|
Project-URL: Source, https://github.com/NREL-Distribution-Suites/grid-data-models
|
|
7
|
-
Author-email:
|
|
7
|
+
Author-email: Aadil Latif <Aadil.Latif@nlr.gov>, Kapil Duwadi <Kapil.Duwadi@nrel.gov>, Tarek Elgindy <tarek.elgindy@nrel.gov>
|
|
8
8
|
License-Expression: BSD-3-Clause
|
|
9
9
|
License-File: LICENSE.txt
|
|
10
10
|
Classifier: License :: OSI Approved :: BSD License
|
|
@@ -13,9 +13,9 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
13
13
|
Requires-Python: >=3.11
|
|
14
14
|
Requires-Dist: geopandas
|
|
15
15
|
Requires-Dist: importlib-metadata
|
|
16
|
-
Requires-Dist: infrasys~=1.
|
|
16
|
+
Requires-Dist: infrasys~=1.2
|
|
17
17
|
Requires-Dist: networkx
|
|
18
|
-
Requires-Dist: pandas~=3.0.
|
|
18
|
+
Requires-Dist: pandas~=3.0.3
|
|
19
19
|
Requires-Dist: plotly
|
|
20
20
|
Requires-Dist: pydantic
|
|
21
21
|
Requires-Dist: semver
|
|
@@ -30,18 +30,18 @@ Requires-Dist: pytest-doctestplus; extra == 'dev'
|
|
|
30
30
|
Requires-Dist: ruff; extra == 'dev'
|
|
31
31
|
Provides-Extra: doc
|
|
32
32
|
Requires-Dist: autodoc-pydantic[erdantic]; extra == 'doc'
|
|
33
|
-
Requires-Dist: jupyter-book<3,>=2.1.
|
|
33
|
+
Requires-Dist: jupyter-book<3,>=2.1.5; extra == 'doc'
|
|
34
34
|
Requires-Dist: myst-parser; extra == 'doc'
|
|
35
35
|
Requires-Dist: pydata-sphinx-theme; extra == 'doc'
|
|
36
36
|
Requires-Dist: sphinx; extra == 'doc'
|
|
37
37
|
Requires-Dist: sphinxcontrib-mermaid; extra == 'doc'
|
|
38
38
|
Provides-Extra: mcp
|
|
39
|
-
Requires-Dist: mcp>=1.
|
|
39
|
+
Requires-Dist: mcp>=1.28.0; extra == 'mcp'
|
|
40
40
|
Description-Content-Type: text/markdown
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
[](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/publish_to_pypi.yml) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/pull_request_tests.yml) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/deploy.yml) •  • [](https://codecov.io/github/NLR-Distribution-Suite/grid-data-models) • [](https://www.codefactor.io/repository/github/nlr-distribution-suite/grid-data-models) •  •  • [](https://github.com/NLR-Distribution-Suite/grid-data-models/issues) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/blob/main/LICENSE.txt)
|
|
44
|
+
[](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/publish_to_pypi.yml) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/pull_request_tests.yml) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/deploy.yml) •  • [](https://codecov.io/github/NLR-Distribution-Suite/grid-data-models) • [](https://www.codefactor.io/repository/github/nlr-distribution-suite/grid-data-models) •  •  • [](https://github.com/NLR-Distribution-Suite/grid-data-models/issues) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/blob/main/LICENSE.txt) • [](https://pepy.tech/projects/grid-data-models)
|
|
45
45
|
|
|
46
46
|
# Grid Data Models (GDM)
|
|
47
47
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
-
[](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/publish_to_pypi.yml) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/pull_request_tests.yml) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/deploy.yml) •  • [](https://codecov.io/github/NLR-Distribution-Suite/grid-data-models) • [](https://www.codefactor.io/repository/github/nlr-distribution-suite/grid-data-models) •  •  • [](https://github.com/NLR-Distribution-Suite/grid-data-models/issues) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/blob/main/LICENSE.txt)
|
|
3
|
+
[](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/publish_to_pypi.yml) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/pull_request_tests.yml) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/actions/workflows/deploy.yml) •  • [](https://codecov.io/github/NLR-Distribution-Suite/grid-data-models) • [](https://www.codefactor.io/repository/github/nlr-distribution-suite/grid-data-models) •  •  • [](https://github.com/NLR-Distribution-Suite/grid-data-models/issues) • [](https://github.com/NLR-Distribution-Suite/grid-data-models/blob/main/LICENSE.txt) • [](https://pepy.tech/projects/grid-data-models)
|
|
4
4
|
|
|
5
5
|
# Grid Data Models (GDM)
|
|
6
6
|
|
|
@@ -11,8 +11,8 @@ requires-python = ">=3.11"
|
|
|
11
11
|
license = "BSD-3-Clause"
|
|
12
12
|
keywords = []
|
|
13
13
|
authors = [
|
|
14
|
+
{ name = "Aadil Latif", email = "Aadil.Latif@nlr.gov" },
|
|
14
15
|
{ name = "Kapil Duwadi", email = "Kapil.Duwadi@nrel.gov" },
|
|
15
|
-
{ name = "Aadil Latif", email = "Aadil.Latif@nrel.gov" },
|
|
16
16
|
{ name = "Tarek Elgindy", email = "tarek.elgindy@nrel.gov" },
|
|
17
17
|
]
|
|
18
18
|
classifiers = [
|
|
@@ -24,19 +24,19 @@ dependencies = [
|
|
|
24
24
|
"semver",
|
|
25
25
|
"networkx",
|
|
26
26
|
"pydantic",
|
|
27
|
-
"infrasys~=1.
|
|
27
|
+
"infrasys~=1.2",
|
|
28
28
|
"importlib_metadata",
|
|
29
29
|
"typer",
|
|
30
|
-
"pandas~=3.0.
|
|
30
|
+
"pandas~=3.0.3",
|
|
31
31
|
"geopandas",
|
|
32
32
|
"plotly",
|
|
33
33
|
]
|
|
34
34
|
|
|
35
35
|
[project.optional-dependencies]
|
|
36
|
-
mcp = ["mcp>=1.
|
|
36
|
+
mcp = ["mcp>=1.28.0"]
|
|
37
37
|
dev = ["pre-commit", "pytest", "pytest-cov", "pytest-doctestplus", "pytest-asyncio", "ruff", "docutils"]
|
|
38
38
|
doc = [
|
|
39
|
-
"jupyter-book>=2.1.
|
|
39
|
+
"jupyter-book>=2.1.5,<3",
|
|
40
40
|
"sphinx",
|
|
41
41
|
"pydata-sphinx-theme",
|
|
42
42
|
"myst-parser",
|
{grid_data_models-2.3.3 → grid_data_models-2.3.5}/src/gdm/distribution/components/__init__.py
RENAMED
|
@@ -7,6 +7,7 @@ from gdm.distribution.components.distribution_solar import DistributionSolar
|
|
|
7
7
|
from gdm.distribution.components.distribution_transformer import DistributionTransformer
|
|
8
8
|
from gdm.distribution.components.distribution_vsource import DistributionVoltageSource
|
|
9
9
|
from gdm.distribution.components.geometry_branch import GeometryBranch
|
|
10
|
+
from gdm.distribution.components.geometry_switch import GeometrySwitch
|
|
10
11
|
from gdm.distribution.components.matrix_impedance_branch import MatrixImpedanceBranch
|
|
11
12
|
from gdm.distribution.components.matrix_impedance_fuse import MatrixImpedanceFuse
|
|
12
13
|
from gdm.distribution.components.matrix_impedance_recloser import MatrixImpedanceRecloser
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""This module contains geometry branch."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated
|
|
4
|
+
|
|
5
|
+
from pydantic import Field
|
|
6
|
+
|
|
7
|
+
from gdm.distribution.components.base.distribution_switch_base import (
|
|
8
|
+
DistributionSwitchBase,
|
|
9
|
+
)
|
|
10
|
+
from gdm.distribution.equipment.geometry_branch_equipment import (
|
|
11
|
+
GeometryBranchEquipment,
|
|
12
|
+
)
|
|
13
|
+
from gdm.distribution.components.distribution_feeder import DistributionFeeder
|
|
14
|
+
from gdm.distribution.components.distribution_substation import (
|
|
15
|
+
DistributionSubstation,
|
|
16
|
+
)
|
|
17
|
+
from gdm.distribution.components.distribution_bus import DistributionBus
|
|
18
|
+
from gdm.distribution.enums import Phase
|
|
19
|
+
from gdm.quantities import Voltage, Distance
|
|
20
|
+
|
|
21
|
+
from gdm.distribution.components.matrix_impedance_switch import MatrixImpedanceSwitch
|
|
22
|
+
from gdm.distribution.equipment import (
|
|
23
|
+
ConcentricCableEquipment,
|
|
24
|
+
)
|
|
25
|
+
from gdm.distribution.equipment.matrix_impedance_switch_equipment import (
|
|
26
|
+
MatrixImpedanceSwitchEquipment,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class GeometrySwitch(DistributionSwitchBase):
|
|
31
|
+
"""Data model for distribution branches based on line geometry."""
|
|
32
|
+
|
|
33
|
+
equipment: Annotated[
|
|
34
|
+
GeometryBranchEquipment,
|
|
35
|
+
Field(..., description="Geometry branch equipment."),
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
def validate_fields(self) -> "GeometrySwitch":
|
|
39
|
+
"""Custom validator for geometry branch fields."""
|
|
40
|
+
if len(self.phases) != len(self.equipment.conductors):
|
|
41
|
+
msg = "Number of phases is not equal to number of wires."
|
|
42
|
+
raise ValueError(msg)
|
|
43
|
+
return self
|
|
44
|
+
|
|
45
|
+
def to_matrix_representation(
|
|
46
|
+
self, frequency_hz: float = 60, soil_resistivity_ohm_m: float = 100
|
|
47
|
+
) -> MatrixImpedanceSwitch:
|
|
48
|
+
"""
|
|
49
|
+
Converts the geometry-based branch model to a matrix impedance representation.
|
|
50
|
+
|
|
51
|
+
This method transforms the current `GeometryBranch` instance into a `MatrixImpedanceBranch`
|
|
52
|
+
by calculating the impedance matrix based on the specified frequency and soil resistivity.
|
|
53
|
+
The conversion process involves using the equipment's matrix representation method to obtain
|
|
54
|
+
the necessary impedance data.
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
frequency_hz : float, optional
|
|
59
|
+
The frequency in hertz used for impedance calculations. Defaults to 60 Hz.
|
|
60
|
+
soil_resistivity_ohm_m : float, optional
|
|
61
|
+
The soil resistivity in ohm-meters used for impedance calculations. Defaults to 100 ohm-m.
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
MatrixImpedanceBranch
|
|
66
|
+
A new instance of `MatrixImpedanceBranch` representing the converted geometry branch.
|
|
67
|
+
|
|
68
|
+
Notes
|
|
69
|
+
-----
|
|
70
|
+
- The method uses the number of neutral phases to assist in the impedance calculation.
|
|
71
|
+
- This conversion is essential for systems that require matrix impedance representations
|
|
72
|
+
for detailed electrical analysis.
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
equipment = self.equipment.to_matrix_representation(
|
|
76
|
+
frequency_hz,
|
|
77
|
+
soil_resistivity_ohm_m,
|
|
78
|
+
n_neutrals=len([phs for phs in self.phases if phs == Phase.N]),
|
|
79
|
+
)
|
|
80
|
+
if isinstance(self.equipment.conductors[0], ConcentricCableEquipment):
|
|
81
|
+
phases = self.phases + [Phase.N for _ in self.phases]
|
|
82
|
+
equipment.kron_reduce(phases)
|
|
83
|
+
|
|
84
|
+
switch_equipment = MatrixImpedanceSwitchEquipment(
|
|
85
|
+
**equipment.model_dump(exclude_none=True)
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return MatrixImpedanceSwitch(
|
|
89
|
+
buses=self.buses,
|
|
90
|
+
length=self.length,
|
|
91
|
+
phases=self.phases,
|
|
92
|
+
substation=self.substation,
|
|
93
|
+
feeder=self.feeder,
|
|
94
|
+
name=self.name,
|
|
95
|
+
equipment=switch_equipment,
|
|
96
|
+
is_closed=self.is_closed,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def example(cls) -> "GeometrySwitch":
|
|
101
|
+
"""Example for geometry branch."""
|
|
102
|
+
buses = [
|
|
103
|
+
DistributionBus(
|
|
104
|
+
voltage_type="line-to-ground",
|
|
105
|
+
phases=[Phase.A, Phase.B, Phase.C],
|
|
106
|
+
rated_voltage=Voltage(400, "volt"),
|
|
107
|
+
substation=DistributionSubstation.example(),
|
|
108
|
+
feeder=DistributionFeeder.example(),
|
|
109
|
+
name=bus_name,
|
|
110
|
+
)
|
|
111
|
+
for bus_name in ["Branch-DistBus1", "Branch-DistBus2"]
|
|
112
|
+
]
|
|
113
|
+
return GeometrySwitch(
|
|
114
|
+
buses=buses,
|
|
115
|
+
length=Distance(130.2, "meter"),
|
|
116
|
+
phases=[Phase.A, Phase.B, Phase.C],
|
|
117
|
+
substation=DistributionSubstation.example(),
|
|
118
|
+
feeder=DistributionFeeder.example(),
|
|
119
|
+
name="DistBranch1",
|
|
120
|
+
is_closed=[True, True, True],
|
|
121
|
+
equipment=GeometryBranchEquipment.example(),
|
|
122
|
+
)
|
|
@@ -20,6 +20,17 @@ class RegulatorController(Component):
|
|
|
20
20
|
"""Data model for a Regulator Controller."""
|
|
21
21
|
|
|
22
22
|
name: Annotated[str, Field("", description="Name of the regulator controller.")]
|
|
23
|
+
|
|
24
|
+
tapped_winding: Annotated[
|
|
25
|
+
Optional[int],
|
|
26
|
+
Field(
|
|
27
|
+
2,
|
|
28
|
+
ge=1,
|
|
29
|
+
le=3,
|
|
30
|
+
description="The index of the winding on the transformer that this controller is controlling.",
|
|
31
|
+
),
|
|
32
|
+
]
|
|
33
|
+
|
|
23
34
|
delay: Annotated[
|
|
24
35
|
Optional[Time],
|
|
25
36
|
PINT_SCHEMA,
|
|
@@ -150,3 +150,43 @@ class BillingDemandBasis(str, Enum):
|
|
|
150
150
|
PEAK_15MIN = "peak_15min"
|
|
151
151
|
PEAK_HOUR = "peak_hour"
|
|
152
152
|
CONTRACT_DEMAND = "contract_demand"
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class WholesaleMarketType(str, Enum):
|
|
156
|
+
DAY_AHEAD = "day_ahead"
|
|
157
|
+
REAL_TIME = "real_time"
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class AncillaryServiceType(str, Enum):
|
|
161
|
+
REGULATION_UP = "regulation_up"
|
|
162
|
+
REGULATION_DOWN = "regulation_down"
|
|
163
|
+
SPINNING_RESERVE = "spinning_reserve"
|
|
164
|
+
NON_SPINNING_RESERVE = "non_spinning_reserve"
|
|
165
|
+
FREQUENCY_RESPONSE = "frequency_response"
|
|
166
|
+
REACTIVE_SUPPLY = "reactive_supply"
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
class CapacityMarketType(str, Enum):
|
|
170
|
+
FORWARD_CAPACITY = "forward_capacity"
|
|
171
|
+
RELIABILITY_MUST_RUN = "reliability_must_run"
|
|
172
|
+
RESOURCE_ADEQUACY = "resource_adequacy"
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class PricingNodeType(str, Enum):
|
|
176
|
+
LOAD_ZONE = "load_zone"
|
|
177
|
+
GENERATOR_NODE = "generator_node"
|
|
178
|
+
HUB = "hub"
|
|
179
|
+
INTERFACE = "interface"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class AggregatorType(str, Enum):
|
|
183
|
+
DER = "der"
|
|
184
|
+
LOAD = "load"
|
|
185
|
+
GENERIC = "generic"
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class DemandResponseType(str, Enum):
|
|
189
|
+
ECONOMIC = "economic"
|
|
190
|
+
EMERGENCY = "emergency"
|
|
191
|
+
DIRECT_LOAD_CONTROL = "direct_load_control"
|
|
192
|
+
INTERRUPTIBLE = "interruptible"
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
from gdm.distribution.market.tariff import (
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
TOURatePeriod,
|
|
2
|
+
AncillaryServiceRate,
|
|
3
|
+
CapacityPayment,
|
|
5
4
|
DemandCharge,
|
|
5
|
+
DistributionTariff,
|
|
6
6
|
FixedCharge,
|
|
7
|
+
LMPRate,
|
|
8
|
+
PricingNode,
|
|
9
|
+
SeasonalTOURates,
|
|
7
10
|
TieredRate,
|
|
11
|
+
TOURatePeriod,
|
|
12
|
+
TransmissionServiceCharge,
|
|
13
|
+
WholesaleMarketTariff,
|
|
8
14
|
)
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"""Data models for resource aggregation in wholesale and demand response markets."""
|
|
2
|
+
|
|
3
|
+
from typing import Annotated, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import Field, model_validator
|
|
6
|
+
from infrasys import Component
|
|
7
|
+
|
|
8
|
+
from gdm.distribution.components.distribution_battery import DistributionBattery
|
|
9
|
+
from gdm.distribution.components.distribution_solar import DistributionSolar
|
|
10
|
+
from gdm.distribution.components.distribution_load import DistributionLoad
|
|
11
|
+
from gdm.distribution.enums import (
|
|
12
|
+
AggregatorType,
|
|
13
|
+
AncillaryServiceType,
|
|
14
|
+
DemandResponseType,
|
|
15
|
+
)
|
|
16
|
+
from gdm.distribution.market.tariff import DistributionTariff, WholesaleMarketTariff
|
|
17
|
+
from gdm.quantities import ActivePower
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AggregatedDER(Component):
|
|
21
|
+
"""A DER resource committed to an aggregation portfolio."""
|
|
22
|
+
|
|
23
|
+
name: str = ""
|
|
24
|
+
resource: Annotated[
|
|
25
|
+
DistributionBattery | DistributionSolar,
|
|
26
|
+
Field(..., description="The DER component being aggregated."),
|
|
27
|
+
]
|
|
28
|
+
committed_capacity: Annotated[
|
|
29
|
+
ActivePower,
|
|
30
|
+
Field(
|
|
31
|
+
...,
|
|
32
|
+
description="Active power capacity committed to the aggregation in kW.",
|
|
33
|
+
ge=0,
|
|
34
|
+
),
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def example(cls) -> "AggregatedDER":
|
|
39
|
+
return AggregatedDER(
|
|
40
|
+
resource=DistributionBattery.example(),
|
|
41
|
+
committed_capacity=ActivePower(50, "kilowatt"),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AggregatedLoad(Component):
|
|
46
|
+
"""A load resource committed to demand response aggregation."""
|
|
47
|
+
|
|
48
|
+
name: str = ""
|
|
49
|
+
resource: Annotated[
|
|
50
|
+
DistributionLoad,
|
|
51
|
+
Field(..., description="The load component being aggregated."),
|
|
52
|
+
]
|
|
53
|
+
curtailable_capacity: Annotated[
|
|
54
|
+
ActivePower,
|
|
55
|
+
Field(
|
|
56
|
+
...,
|
|
57
|
+
description="Active power capacity available for curtailment in kW.",
|
|
58
|
+
ge=0,
|
|
59
|
+
),
|
|
60
|
+
]
|
|
61
|
+
response_type: Annotated[
|
|
62
|
+
DemandResponseType,
|
|
63
|
+
Field(..., description="Type of demand response program."),
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def example(cls) -> "AggregatedLoad":
|
|
68
|
+
return AggregatedLoad(
|
|
69
|
+
resource=DistributionLoad.example(),
|
|
70
|
+
curtailable_capacity=ActivePower(25, "kilowatt"),
|
|
71
|
+
response_type=DemandResponseType.ECONOMIC,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class DERAggregator(Component):
|
|
76
|
+
"""Aggregates distributed energy resources for wholesale market participation."""
|
|
77
|
+
|
|
78
|
+
name: str = Field(..., description="Name of the DER aggregator")
|
|
79
|
+
aggregator_type: AggregatorType = Field(
|
|
80
|
+
default=AggregatorType.DER,
|
|
81
|
+
description="Type of aggregator.",
|
|
82
|
+
)
|
|
83
|
+
resources: Annotated[
|
|
84
|
+
list[AggregatedDER],
|
|
85
|
+
Field(..., min_length=1, description="DER resources in the aggregation portfolio."),
|
|
86
|
+
]
|
|
87
|
+
offered_services: Annotated[
|
|
88
|
+
list[AncillaryServiceType],
|
|
89
|
+
Field(
|
|
90
|
+
default_factory=list,
|
|
91
|
+
description="Ancillary services the aggregator can provide.",
|
|
92
|
+
),
|
|
93
|
+
]
|
|
94
|
+
min_dispatch: Annotated[
|
|
95
|
+
ActivePower,
|
|
96
|
+
Field(
|
|
97
|
+
...,
|
|
98
|
+
description="Minimum dispatchable capacity in kW.",
|
|
99
|
+
ge=0,
|
|
100
|
+
),
|
|
101
|
+
]
|
|
102
|
+
max_dispatch: Annotated[
|
|
103
|
+
ActivePower,
|
|
104
|
+
Field(
|
|
105
|
+
...,
|
|
106
|
+
description="Maximum dispatchable capacity in kW.",
|
|
107
|
+
ge=0,
|
|
108
|
+
),
|
|
109
|
+
]
|
|
110
|
+
wholesale_tariff: Annotated[
|
|
111
|
+
Optional[WholesaleMarketTariff],
|
|
112
|
+
Field(None, description="Wholesale market tariff under which the aggregator settles."),
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
@model_validator(mode="after")
|
|
116
|
+
def validate_dispatch_limits(self) -> "DERAggregator":
|
|
117
|
+
if self.max_dispatch < self.min_dispatch:
|
|
118
|
+
raise ValueError("max_dispatch must be >= min_dispatch")
|
|
119
|
+
return self
|
|
120
|
+
|
|
121
|
+
@classmethod
|
|
122
|
+
def example(cls) -> "DERAggregator":
|
|
123
|
+
return DERAggregator(
|
|
124
|
+
name="DER Portfolio Alpha",
|
|
125
|
+
resources=[AggregatedDER.example()],
|
|
126
|
+
offered_services=[
|
|
127
|
+
AncillaryServiceType.REGULATION_UP,
|
|
128
|
+
AncillaryServiceType.SPINNING_RESERVE,
|
|
129
|
+
],
|
|
130
|
+
min_dispatch=ActivePower(10, "kilowatt"),
|
|
131
|
+
max_dispatch=ActivePower(100, "kilowatt"),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class LoadAggregator(Component):
|
|
136
|
+
"""Aggregates controllable loads for demand response programs."""
|
|
137
|
+
|
|
138
|
+
name: str = Field(..., description="Name of the load aggregator")
|
|
139
|
+
aggregator_type: AggregatorType = Field(
|
|
140
|
+
default=AggregatorType.LOAD,
|
|
141
|
+
description="Type of aggregator.",
|
|
142
|
+
)
|
|
143
|
+
resources: Annotated[
|
|
144
|
+
list[AggregatedLoad],
|
|
145
|
+
Field(..., min_length=1, description="Load resources in the aggregation portfolio."),
|
|
146
|
+
]
|
|
147
|
+
total_curtailable_capacity: Annotated[
|
|
148
|
+
ActivePower,
|
|
149
|
+
Field(
|
|
150
|
+
...,
|
|
151
|
+
description="Total curtailable capacity across all loads in kW.",
|
|
152
|
+
ge=0,
|
|
153
|
+
),
|
|
154
|
+
]
|
|
155
|
+
notification_lead_time_minutes: Annotated[
|
|
156
|
+
int,
|
|
157
|
+
Field(
|
|
158
|
+
...,
|
|
159
|
+
description="Minimum advance notice required before curtailment in minutes.",
|
|
160
|
+
ge=0,
|
|
161
|
+
),
|
|
162
|
+
]
|
|
163
|
+
max_curtailment_duration_hours: Annotated[
|
|
164
|
+
float,
|
|
165
|
+
Field(
|
|
166
|
+
...,
|
|
167
|
+
description="Maximum duration of a single curtailment event in hours.",
|
|
168
|
+
gt=0,
|
|
169
|
+
),
|
|
170
|
+
]
|
|
171
|
+
retail_tariff: Annotated[
|
|
172
|
+
Optional[DistributionTariff],
|
|
173
|
+
Field(None, description="Retail distribution tariff defining avoided cost for DR."),
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
@classmethod
|
|
177
|
+
def example(cls) -> "LoadAggregator":
|
|
178
|
+
return LoadAggregator(
|
|
179
|
+
name="DR Program Beta",
|
|
180
|
+
resources=[AggregatedLoad.example()],
|
|
181
|
+
total_curtailable_capacity=ActivePower(500, "kilowatt"),
|
|
182
|
+
notification_lead_time_minutes=30,
|
|
183
|
+
max_curtailment_duration_hours=4.0,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class Aggregator(Component):
|
|
188
|
+
"""General-purpose aggregator that can bundle both DERs and loads."""
|
|
189
|
+
|
|
190
|
+
name: str = Field(..., description="Name of the aggregator")
|
|
191
|
+
aggregator_type: AggregatorType = Field(
|
|
192
|
+
default=AggregatorType.GENERIC,
|
|
193
|
+
description="Type of aggregator.",
|
|
194
|
+
)
|
|
195
|
+
der_resources: Annotated[
|
|
196
|
+
Optional[list[AggregatedDER]],
|
|
197
|
+
Field(None, description="DER resources in the portfolio."),
|
|
198
|
+
]
|
|
199
|
+
load_resources: Annotated[
|
|
200
|
+
Optional[list[AggregatedLoad]],
|
|
201
|
+
Field(None, description="Load resources in the portfolio."),
|
|
202
|
+
]
|
|
203
|
+
offered_services: Annotated[
|
|
204
|
+
list[AncillaryServiceType],
|
|
205
|
+
Field(
|
|
206
|
+
default_factory=list,
|
|
207
|
+
description="Ancillary services the aggregator can provide.",
|
|
208
|
+
),
|
|
209
|
+
]
|
|
210
|
+
min_dispatch: Annotated[
|
|
211
|
+
ActivePower,
|
|
212
|
+
Field(
|
|
213
|
+
...,
|
|
214
|
+
description="Minimum dispatchable capacity in kW.",
|
|
215
|
+
ge=0,
|
|
216
|
+
),
|
|
217
|
+
]
|
|
218
|
+
max_dispatch: Annotated[
|
|
219
|
+
ActivePower,
|
|
220
|
+
Field(
|
|
221
|
+
...,
|
|
222
|
+
description="Maximum dispatchable capacity in kW.",
|
|
223
|
+
ge=0,
|
|
224
|
+
),
|
|
225
|
+
]
|
|
226
|
+
wholesale_tariff: Annotated[
|
|
227
|
+
Optional[WholesaleMarketTariff],
|
|
228
|
+
Field(None, description="Wholesale market tariff under which DER resources settle."),
|
|
229
|
+
]
|
|
230
|
+
retail_tariff: Annotated[
|
|
231
|
+
Optional[DistributionTariff],
|
|
232
|
+
Field(None, description="Retail distribution tariff defining avoided cost for DR."),
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
@model_validator(mode="after")
|
|
236
|
+
def validate_has_resources(self) -> "Aggregator":
|
|
237
|
+
if not self.der_resources and not self.load_resources:
|
|
238
|
+
raise ValueError("Aggregator must have at least one DER or load resource")
|
|
239
|
+
return self
|
|
240
|
+
|
|
241
|
+
@model_validator(mode="after")
|
|
242
|
+
def validate_dispatch_limits(self) -> "Aggregator":
|
|
243
|
+
if self.max_dispatch < self.min_dispatch:
|
|
244
|
+
raise ValueError("max_dispatch must be >= min_dispatch")
|
|
245
|
+
return self
|
|
246
|
+
|
|
247
|
+
@classmethod
|
|
248
|
+
def example(cls) -> "Aggregator":
|
|
249
|
+
return Aggregator(
|
|
250
|
+
name="Mixed Portfolio Gamma",
|
|
251
|
+
der_resources=[AggregatedDER.example()],
|
|
252
|
+
load_resources=[AggregatedLoad.example()],
|
|
253
|
+
offered_services=[
|
|
254
|
+
AncillaryServiceType.REGULATION_UP,
|
|
255
|
+
AncillaryServiceType.FREQUENCY_RESPONSE,
|
|
256
|
+
],
|
|
257
|
+
min_dispatch=ActivePower(10, "kilowatt"),
|
|
258
|
+
max_dispatch=ActivePower(200, "kilowatt"),
|
|
259
|
+
)
|