Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- name: select python version
uses: actions/setup-python@v2
with:
python-version: 3.9
python-version: '3.12'
- name: install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull_request_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
matrix:
os: [ubuntu-latest]
#os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.9", "3.10", "3.11"]
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v2
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ docs/build/*
tags
cscope.files
tests/data/*/Exports/*
!tests/data/*/Exports/.gitkeep
tests/data/*/Logs/*
!tests/data/*/Logs/.gitkeep
.idea/*
.vscode/*
store.h5
Expand Down
73 changes: 70 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,73 @@
# Welcome to the pydss Repository!
[![Pytest](https://github.com/NatLabRockies/PyDSS/actions/workflows/pull_request_tests.yml/badge.svg)](https://github.com/NatLabRockies/PyDSS/actions/workflows/pull_request_tests.yml) • [![Upload to PyPi](https://github.com/NatLabRockies/PyDSS/actions/workflows/python-publish.yml/badge.svg)](https://github.com/NatLabRockies/PyDSS/actions/workflows/python-publish.yml) • [![deploy-docs](https://github.com/NatLabRockies/PyDSS/actions/workflows/gh-pages.yml/badge.svg)](https://github.com/NatLabRockies/PyDSS/actions/workflows/gh-pages.yml) • ![PyPI - Downloads](https://img.shields.io/pypi/dm/NREL-pydss) • [![GitHub issues](https://img.shields.io/github/issues/NatLabRockies/PyDSS)](https://github.com/NatLabRockies/PyDSS/issues) • [![License](https://img.shields.io/github/license/NatLabRockies/PyDSS)](https://github.com/NatLabRockies/PyDSS/blob/master/LICENSE) • [![PyPI Downloads](https://static.pepy.tech/personalized-badge/nrel-pydss?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/nrel-pydss)

**PyDSS** is a high level python interface for **OpenDSS** and provides the following functionalities
# PyDSS

Documentation on installation, setup and examples can be found here https://natlabrockies.github.io/PyDSS/index.html
**PyDSS** is a high-level Python interface for [OpenDSS](https://www.epri.com/pages/sa/opendss) that extends its organizational, analytical, and co-simulation capabilities. It is built on top of [OpenDSSDirect.py](https://pypi.org/project/OpenDSSDirect.py/).

**Documentation:** [https://natlabrockies.github.io/PyDSS/](https://natlabrockies.github.io/PyDSS/index.html)

## Key Features

- **Custom Control Algorithms** — Define Python-based controllers for any circuit element, executed at each simulation time step. 13 built-in controllers are included (PV, storage, motor stall, fault, transformer, thermostat, and more).
- **HELICS Co-simulation** — Integrate with external simulators via the [HELICS](https://github.com/GMLC-TDC/HELICS) framework for cyber-physical co-simulation studies.
- **Scenario Management** — Run multiple scenarios on a shared OpenDSS model with independent controllers, exports, and post-processing.
- **Flexible Data Export** — Export results to HDF5 or CSV with per-element filtering, regex-based selection, moving averages, and group aggregation.
- **Automated Reports** — Generate reports for voltage metrics, thermal metrics, PV clipping/curtailment, capacitor switching, tap changes, and feeder losses.
- **Monte Carlo Studies** — Built-in support for running Monte Carlo simulations with profile management.
- **Extension Architecture** — Plugin system for custom controllers, post-processing scripts, and report types.

## Installation

Install in a conda virtual environment (recommended):

```bash
conda create -n pydss python=3.11
conda activate pydss
pip install NREL-pydss
```

## Quick Start

```bash
# Create a project with two scenarios
pydss create-project --project=my-project --scenarios="scenario1,scenario2" --path=./projects

# Copy your OpenDSS files into projects/my-project/DSSfiles/
# Set dss_file in projects/my-project/simulation.toml

# Run all scenarios
pydss run ./projects/my-project
```

## Python API

```python
from pydss.pydss_project import PyDssProject

# Run a project
PyDssProject.run_project("./projects/my-project")

# Access results
from pydss.pydss_results import PyDssResults
results = PyDssResults("./projects/my-project")
scenario = results.scenarios[0]
df = scenario.get_dataframe("Lines", "Currents", "Line.pvl_112")
```

## CLI Commands

| Command | Description |
|---------|-------------|
| `pydss create-project` | Create a new project with scenarios |
| `pydss run` | Run all scenarios in a project |
| `pydss export` | Convert HDF5 results to CSV |
| `pydss controllers` | Manage the controller registry |
| `pydss edit-scenario` | Modify scenario configuration |
| `pydss reports` | Generate analysis reports |

Run `pydss --help` for full usage details.

## License

BSD 3-Clause. See [LICENSE](LICENSE) for details.

11 changes: 5 additions & 6 deletions docs/make_model_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
"HelicsModel",
"LoggingModel",
"MonteCarloModel",
"PlotsModel",
"ProfilesModel",
"ReportsModel",
"SimulationRangeModel",
Expand Down Expand Up @@ -60,7 +59,7 @@ def make_tables(output):
property_types = parse_property_types(ordered_names, classes)
for name in ordered_names:
cls = classes[name]
schema = cls.schema()
schema = cls.model_json_schema()
if name in ABSTRACT_TYPES:
continue
f_rst.write(f".. _{name}:\n\n")
Expand Down Expand Up @@ -174,15 +173,15 @@ def parse_property_types(ordered_names, classes):
Two-level dict: {class_name: {property_name: class}}

"""
regex_definition = re.compile(r"^#\/definitions\/(\w+)")
regex_definition = re.compile(r"^#\/(?:definitions|\$defs)\/(\w+)")
property_types = defaultdict(dict)
for name in ordered_names:
if name in ABSTRACT_TYPES:
continue
cls = classes[name]
schema = cls.schema()
for prop, vals in schema["properties"].items():
title = vals["title"]
schema = cls.model_json_schema()
for prop, vals in schema.get("properties", {}).items():
title = vals.get("title", prop)
if "allOf" in vals:
if len(vals["allOf"]) == 1:
match = regex_definition.search(vals["allOf"][0]["$ref"])
Expand Down
124 changes: 68 additions & 56 deletions docs/source/Co-simulation Interfaces.rst
Original file line number Diff line number Diff line change
@@ -1,36 +1,46 @@


The HELICS interface
^^^^^^^^^^^^^^^^^^^^
Co-simulation Interfaces
========================

The HELICS Interface
--------------------

Hierarchical Engine for Large-scale Infrastructure Co-Simulation (HELICS) provides an open-source, general-purpose, modular, highly-scalable co-simulation framework that runs cross-platform (Linux, Windows, and Mac OS X). It is not a modeling tool by itself, but rather an integration tool that enables multiple existing simulation tools (and/or multiple instances of the same tool), known as "federates," to exchange data during runtime and stay synchronized in time such that together they act as one large simulation, or "federation". This enables bringing together established (or new/emerging) off-the-shelf tools from multiple domains to form a complex software-simulation without having to change the individual tools (known as "black-box" modeling). All that is required is for someone to write a thin interface layer for each tool that interfaces with existing simulation time control and data value updating, such as through an existing scripting interface. Moreover, the HELICS community has a growing ecosystem of established interfaces for popular tools, such that many users can simply mix and match existing tools with their own data and run complex co-simulations with minimal coding. More information on HELICS can be found here (https://github.com/GMLC-TDC/HELICS).
`Hierarchical Engine for Large-scale Infrastructure Co-Simulation (HELICS) <https://github.com/GMLC-TDC/HELICS>`_
provides an open-source, general-purpose, modular, highly-scalable co-simulation framework that
runs cross-platform (Linux, Windows, and Mac OS X). It is not a modeling tool by itself, but
rather an integration tool that enables multiple existing simulation tools (known as "federates")
to exchange data during runtime and stay synchronized in time such that together they act as one
large simulation, or "federation".

The HELICS interface for pydss is built to reduce complexity of setting up large scale cosimulation scenarios. The user is required to publications and suscriptions.
The HELICS interface for PyDSS is built to reduce the complexity of setting up large-scale
co-simulation scenarios. The user defines publications and subscriptions to exchange data
with external federates.

A minimal HELICS example is availble in the ``examples`` folder (top directory of the repository). Enabling the HELICS interface requires user to define additional parammeters in the scenario TOML file.


Interface overview
---------------------------
Interface Overview
^^^^^^^^^^^^^^^^^^

The HELICS interface can be enabled and setup using the simultion.toml file.

Following attributes can be configured for the HELICS interface.
The HELICS interface can be enabled and configured using the ``simulation.toml`` file.
The following attributes can be configured:

.. autopydantic_model:: pydss.simulation_input_models.HelicsModel


- "co_simulation_mode" : Set to 'true' to enable the HELICS interface. By default it is set to 'false'
- "federate_name" : Required to identify a federate in a cosimulation with a large number of federates.
- Additional attribution pertaining to convergence, timing and iteration can be configured here
- ``co_simulation_mode``: Set to ``true`` to enable the HELICS interface (default: ``false``).
- ``federate_name``: Required to identify a federate in a co-simulation with many federates.
- Additional settings for convergence, timing, and iteration can be configured here.

Default values for additional simulation settings are as follows. For more information on how to appropriately set these values please look at HELICS documentaion
For more information on these values, refer to the
`HELICS documentation <https://docs.helics.org/>`_.

Once the HELICS co-simulation interface has been enabled, the next step is to set up ``publications`` and ``subscriptions`` to set up information exchange with external federates.
PyDSS enables zero code setup of these modules. Each scenario can have its publlcation and subscription defination and is managed by two file in the ``ExportLists`` directory for a given scenario.
Once the HELICS co-simulation interface has been enabled, the next step is to set up
``publications`` and ``subscriptions`` for data exchange with external federates.
PyDSS enables zero-code setup of these modules. Each scenario can have its own publication
and subscription definitions, managed by files in the ``ExportLists`` directory.

publication tags (names) follow the following convertion
Publication tags (names) follow this convention:

.. code-block::

Expand All @@ -41,19 +51,21 @@ publication tags (names) follow the following convertion
federate1.Circuit.70008.TotalPower
federate1.Load.load_1.VoltageMagAng

where ``federate name`` is defined in the project's ``settings.toml`` file
where ``federate name`` is defined in the project's ``simulation.toml`` file.

Setting up Publications
^^^^^^^^^^^^^^^^^^^^^^^

Setting up publications
---------------------------
Publications (information communicated to external federates) can be set up by using the ``Exports.toml``. This file is also used to define export varibles
for a simulation scenario. By setting the ``publish`` attribute to ``true``, enable automated setup of a HELICS publication.
The file enables users to use multiple filtering options such as regex operation etc. to only pushlish what is reuired for a given use case.
Publications (data sent to external federates) can be configured using ``Exports.toml``.
This file is also used to define export variables for a simulation scenario. By setting the
``publish`` attribute to ``true``, PyDSS automatically sets up a HELICS publication.
The file supports multiple filtering options including regex to publish only what is needed.

examples:

The following code block will setup publications for all PV systems powers in a given model.
Setting the ``publish`` attribute to ``false`` will allow the data to be writtin to the h5 store,
but the data will not be published on the helics interface.
The following example sets up publications for all PV system powers in the model.
Setting ``publish`` to ``false`` will still write the data to the HDF5 store, but
will not publish it on the HELICS interface.

.. code-block:: toml

Expand All @@ -63,11 +75,11 @@ but the data will not be published on the helics interface.
publish = true
store_values_type = "all"

Users tave two options to filter and setup publication for a subset of object type (in this case PV systems).
User are able to use tag attribute ``name_regexes`` to filter PV systems matching a given list of regex expressions.
Alternately, users can use ``names`` attribute to explicitly define objects whos property they want publiched on the HELICS interface.
There are two options to filter and publish a subset of elements. You can use the
``name_regexes`` attribute to filter elements matching regex expressions, or use the
``names`` attribute to explicitly list elements.

Filtering using regex expressions
Filtering using regex expressions:

.. code-block:: toml

Expand All @@ -78,7 +90,7 @@ Filtering using regex expressions
publish = true
store_values_type = "all"

Filtering using explicitly list model names
Filtering using explicit element names:

.. code-block:: toml

Expand All @@ -91,19 +103,19 @@ Filtering using explicitly list model names



Setting up subscriptions
---------------------------
Setting up Subscriptions
^^^^^^^^^^^^^^^^^^^^^^^^

Subscriptions (information ingested from external federates) can be set up
using the ``Subscriptions.toml`` in the ``ExportLists`` directory for a given scenario.
Valis subscriptions should confine to teh following model
Subscriptions (data received from external federates) are configured using
``Subscriptions.toml`` in the ``ExportLists`` directory for a given scenario.
Valid subscriptions should conform to the following model:

.. autopydantic_model:: pydss.helics_interface.Subscription

When setting up subscriptions it is important to understand that the subscription tag is generated by
the external federate and should be known before setting up the subscriptions. In the example below, values recieved from
subscription tag ``test.load1.power`` are used to update the ``kw`` property of load ``Load.mpx000635970``. ``multiplier`` property can be used to
scale values before they are used to update the coupled model.
When setting up subscriptions, note that the subscription tag is generated by the external
federate and must be known before configuration. In the example below, values received from
subscription tag ``test.load1.power`` are used to update the ``kw`` property of load
``Load.mpx000635970``. The ``multiplier`` property can scale values before they update the model.

example

Expand All @@ -119,25 +131,25 @@ example
multiplier = 1


Within the example folder the project named external interfaces provides an example usage of all three interafces.
A complete example is available in ``examples/external_interfaces/``.

The socket interface
^^^^^^^^^^^^^^^^^^^^
The Socket Interface
--------------------

The socket interface is implemented as a pydss pyController. Implmentation details and expected inputs are detailed here: :py:class:`pydss.pyControllers.Controllers.SocketController.SocketController`.
The socket controller is well suited in situatons where an existing controller needs to be integrated to the simulation environment.
An exmaple of this would be integrating a controller for thermostatically controlled loads implemeted in say Modelica or Python.
This allows user to integrate controller, without making changes to the implemented controller. With a little effort,
the same controller can be implemented as a pyController object in pydss.
The socket interface is implemented as a PyDSS controller
(:py:class:`pydss.pyControllers.Controllers.SocketController.SocketController`).
It is well suited for situations where an existing external controller needs to be integrated
into the simulation environment — for example, integrating a controller for thermostatically
controlled loads implemented in Modelica or Python. This allows integration without modifying
the external controller.

The socket interface in pydss also come in handy, when setting up a hardware-in-loop type simulations and integrating the simulation
engine with actual hardware. Interfaces similar to raw socket implementations have been developed (to be open-sourced at a later time)
for Modbus-TCP and DNP3 communcations have developed and tested with pydss with sucess. A minimal socket interfacing example has
been provided as a pydss project in ~PyDSS/examples/external_interfaces. Within the folder,
~/PyDSS/examples/external_interfaces/pydss_project a scenario called 'socket' has been defined. Socket
controller definations have been detailed with the 'pyControllerList' folder. An example of input requirements can be studied below.
This example will publish ``voltage magnitude`` (see Even set in Index) and ``real power`` for load ``Load.mpx000635970`` in the model. Subscribed
values will be used to update the ``kW`` property of the coupled load (Load.mpx000635970 in this case)
The socket interface is also useful for hardware-in-the-loop simulations, integrating the
simulation engine with actual hardware. Interfaces for Modbus-TCP and DNP3 communications
have been developed and tested with PyDSS.
A minimal socket example is provided in ``examples/external_interfaces/pydss_project``.
The ``socket`` scenario defines the socket controller in its ``pyControllerList`` folder.
The controller configuration specifies the element to control, the socket connection details,
and the data to exchange:

.. code-block:: toml

Expand Down
9 changes: 5 additions & 4 deletions docs/source/Python API interface.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
Python API interface
=========================
Python API Interface
====================

These sources provide details into Python API and the associated data models
PyDSS exposes a Python API for programmatic control of simulations and access to results.
The following pages provide API reference documentation and data model schemas.

.. toctree::
:maxdepth: 3

Respository documentaion
Models
4 changes: 2 additions & 2 deletions docs/source/Respository documentaion.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

Python API interface
------------------
API Reference
-------------

.. autosummary::
:toctree: _autosummary
Expand Down
19 changes: 1 addition & 18 deletions docs/source/_autosummary/PyDSS.Extensions.MonteCarlo.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,9 @@ pydss.Extensions.MonteCarlo
.. automodule:: pydss.Extensions.MonteCarlo











.. rubric:: Classes

.. autosummary::

MonteCarloSim










Loading
Loading