Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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 Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.7.0-slim
FROM python:3.11.0-slim

RUN apt-get update

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Welcome to the pydss Repository!


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

Documentation on installation, setup and examples can be found here https://natlabrockies.github.io/PyDSS/index.html
Expand Down
3 changes: 2 additions & 1 deletion src/pydss/SolveMode.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@


def GetSolver(settings: SimulationSettingsModel, dssInstance):
logger.info('Setting solver to %s mode.', settings.project.simulation_type.value)
# logger.info('Setting solver to %s mode.', settings.project.simulation_type.value)
logger.info(f'Setting solver to {settings.project.simulation_type.value} mode.')
return get_solver_from_simulation_type(settings.project)


Expand Down
9 changes: 8 additions & 1 deletion src/pydss/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from pathlib import Path
import ast
import sys
import os

from loguru import logger
import click
Expand Down Expand Up @@ -80,6 +81,11 @@ def run(project_path, options=None, tar_project=False, zip_project=False, verbos
logger.error("Logs path %s does not exist", logs_path)
sys.exit(1)
filename = logs_path / "pydss.log"
if settings.logging.clear_old_log_file:
logs_path = project_path / "Logs"
filename = logs_path / "pydss.log"
if os.path.exists(filename):
os.remove(filename)
Comment thread
nadiavp marked this conversation as resolved.
Outdated

logger.level(console_level)
if filename:
Expand All @@ -92,8 +98,9 @@ def run(project_path, options=None, tar_project=False, zip_project=False, verbos
if not isinstance(options, dict):
logger.error("options are invalid: %s", options)
sys.exit(1)

# logger.info(f"indicator 1")
Comment thread
nadiavp marked this conversation as resolved.
Outdated
project = PyDssProject.load_project(project_path, options=options, simulation_file=simulations_file)
# logger.info(f"indicator 2")
Comment thread
nadiavp marked this conversation as resolved.
Outdated
project.run(tar_project=tar_project, zip_project=zip_project, dry_run=dry_run)

if dry_run:
Expand Down
1 change: 0 additions & 1 deletion src/pydss/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class ControllerType(enum.Enum):
STORAGE_CONTROLLER = "StorageController"
THERMOSTATIC_LOAD_CONTROLLER = "ThermostaticLoad"
XMFR_CONTROLLER = "xmfrController"
DYNAMIC_VOLTAGE_SUPPORT = "DynamicVoltageSupport"

CONTROLLER_TYPES = tuple(x.value for x in ControllerType)
CONFIG_EXT = ".toml"
Expand Down
1 change: 1 addition & 0 deletions src/pydss/dataset_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def __init__(
max_chunk_bytes=None, attributes=None, names=None,
column_ranges_per_name=None, data=None
):

if max_chunk_bytes is None:
max_chunk_bytes = DEFAULT_MAX_CHUNK_BYTES
self._buf_index = 0
Expand Down
9 changes: 7 additions & 2 deletions src/pydss/dssElement.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ast

from loguru import logger
from opendssdirect import DSSException

from pydss.dssBus import dssBus
Expand Down Expand Up @@ -60,9 +60,10 @@ def __init__(self, dssInstance):
super(dssElement, self).__init__(dssInstance, name, fullName)
self._Enabled = dssInstance.CktElement.Enabled()
if not self._Enabled:
logger.debug(f"Element isn't defined: {fullName}")
return

self._Parameters = {}
logger.debug(fullName)
self._NumTerminals = dssInstance.CktElement.NumTerminals()
self._NumConductors = dssInstance.CktElement.NumConductors()

Expand Down Expand Up @@ -135,8 +136,12 @@ def DataLength(self, VarName):
return 0, None

def GetValue(self, VarName, convert=False):

if self._dssInstance.Element.Name() != self._FullName:
self.SetActiveObject()
fullName = self._dssInstance.Element.Name()
# logger.debug("123456789123456789123456789123456789123456789123456789")
# logger.debug(fullName)
if VarName in self._Variables:
VarValue = self.GetVariable(VarName, convert=convert)
elif VarName in self._Parameters:
Expand Down
51 changes: 43 additions & 8 deletions src/pydss/dssInstance.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,11 @@ def _compile_model(self):
def _CreateControllers(self, ControllerDict):
self._pyControls = {}
self._pyControls_types = {}
# logger.info(f'self._dssObjects -> {self._dssObjects}')
# os.system("PAUSE")
for ControllerType, ElementsDict in ControllerDict.items():
# logger.info(f'ControllerType -> {ControllerType}, ElementsDict -> {ElementsDict}')
# os.system("PAUSE")
for ElmName, SettingsDict in ElementsDict.items():
Controller = pyControllers.pyController.Create(ElmName, ControllerType, SettingsDict, self._dssObjects,
self._dssInstance, self._dssSolver)
Expand Down Expand Up @@ -205,7 +209,8 @@ def CreateDssObjects(dssBuses):
InvalidSelection = ['Settings', 'ActiveClass', 'dss', 'utils', 'PDElements', 'XYCurves', 'Bus', 'Properties']
# TODO: this causes a segmentation fault. Aadil says it may not be needed.
#self._dssObjectsByClass={'LoadShape': self._get_relavent_object_dict('LoadShape')}

# logger.info(f"dss.Circuit.AllElementNames() -> {dss.Circuit.AllElementNames()}")
# os.system("PAUSE")
for ElmName in dss.Circuit.AllElementNames():
Class, Name = ElmName.split('.', 1)
ClassName = Class + 's'
Expand Down Expand Up @@ -246,13 +251,28 @@ def RunStep(self, step, updateObjects=None):
if self._settings.profiles.use_profile_manager:
self.profileStore.update()

if self._settings.helics.co_simulation_mode:
# self._heilcs_interface.updateHelicsPublications()
self._increment_flag, helics_time = self._heilcs_interface.request_time_increment()

if self._settings.helics.co_simulation_mode:
self._heilcs_interface.updateHelicsSubscriptions()
else:
if updateObjects:
for object, params in updateObjects.items():
cl, name = object.split('.')
self._Modifier.Edit_Element(cl, name, params)

# pydss_update_agian = "y"
# while pydss_update_agian == "y":
# if self._settings.helics.co_simulation_mode:
# self._heilcs_interface.updateHelicsSubscriptions()
# else:
# if updateObjects:
# for object, params in updateObjects.items():
# cl, name = object.split('.')
# self._Modifier.Edit_Element(cl, name, params)
# pydss_update_agian = input('enter your pydss update command: ')

# run simulation time step and get results
time_step_has_converged = True
Expand All @@ -263,6 +283,7 @@ def RunStep(self, step, updateObjects=None):
for i in range(self._settings.project.max_control_iterations):
has_converged, error = self._update_controllers(priority, step, i, UpdateResults=False)
logger.debug('Control Loop {} convergence error: {}'.format(priority, error))
logger.debug('Control Loop {} convergence @step {} '.format(priority, step))
if has_converged:
priority_has_converged = True
break
Expand Down Expand Up @@ -297,8 +318,9 @@ def RunStep(self, step, updateObjects=None):

if self._settings.helics.co_simulation_mode:
self._heilcs_interface.updateHelicsPublications()
self._increment_flag, helics_time = self._heilcs_interface.request_time_increment()

# if step < 1:
# self._increment_flag, helics_time = self._heilcs_interface.request_time_increment_2()
# os.system("PAUSE")
return time_step_has_converged

def _HandleConvergenceErrorChecks(self, step, error):
Expand All @@ -316,7 +338,7 @@ def _HandleOpenDSSConvergenceErrorChecks(self, step):
self._convergenceErrorsOpenDSS += 1

if self._maxConvergenceErrorCount is not None and self._convergenceErrorsOpenDSS > self._maxConvergenceErrorCount:
logger.error("Exceeded OpenDSS convergence error count threshold at step %s", step)
logger.error(f"Exceeded OpenDSS convergence error count threshold at step {step}")
raise OpenDssConvergenceErrorCountExceeded(f"{self._convergenceErrorsOpenDSS} errors occurred")

def DryRunSimulation(self, project, scenario):
Expand Down Expand Up @@ -357,7 +379,7 @@ def RunSimulation(self, project, scenario, MC_scenario_number=None):
dss.Solution.Convergence(self._settings.project.error_tolerance)
logger.info('Running simulation from {} till {}.'.format(sTime, eTime))
logger.info('Simulation time step {}.'.format(Steps))
logger.info("Set OpenDSS convergence to %s", dss.Solution.Convergence())
logger.info(f"Set OpenDSS convergence to {dss.Solution.Convergence()}")
logger.info('Max convergence error count {}.'.format(self._maxConvergenceErrorCount))
logger.info("initializing store")
self.ResultContainer.InitializeDataStore(project.hdf_store, Steps, MC_scenario_number)
Expand Down Expand Up @@ -388,19 +410,32 @@ def RunSimulation(self, project, scenario, MC_scenario_number=None):
within_range = self._simulation_range.is_within_range(self._dssSolver.GetDateTime())
if within_range:
pydss_has_converged = self.RunStep(step)
# logger.info(f'Finish simulation: step {step} 1')
# pydss_has_converged = self.RunStep(step)
# logger.info(f'Finish simulation: step {step} 2')
# pydss_has_converged = self.RunStep(step)
# logger.info(f'Finish simulation: step {step} 3')
opendss_has_converged = dss.Solution.Converged()
if not opendss_has_converged:
logger.error("OpenDSS did not converge at step=%s pydss_converged=%s",
step, pydss_has_converged)
logger.error(f"OpenDSS did not converge at step={step} pydss_converged={pydss_has_converged}")
self._HandleOpenDSSConvergenceErrorChecks(step)
has_converged = pydss_has_converged and opendss_has_converged

if pydss_has_converged:
has_converged = True
else:
has_converged = pydss_has_converged and opendss_has_converged

if step == 0 and self.ResultContainer is not None:
size = make_human_readable_size(self.ResultContainer.max_num_bytes())
logger.info('Storage requirement estimation: %s, estimated based on first time step run.', size)
if postprocessors and within_range:
step, has_converged = self._RunPostProcessors(step, Steps, postprocessors)
if self._increment_flag:
step += 1
# if step < 1:
# step += 1
# else:
# step += 2

# In the case of a frequency sweep, the code updates results at each frequency.
# Doing so again would cause a duplicate result.
Expand Down
42 changes: 38 additions & 4 deletions src/pydss/helics_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import helics
import os
import re

import pandas as pd
from loguru import logger

from pydss.simulation_input_models import SimulationSettingsModel
Expand Down Expand Up @@ -208,6 +208,7 @@ def _create_helics_federate(self):
IP = self._settings.helics.broker
Port = self._settings.helics.broker_port
logger.info("Connecting to broker @ {}".format(f"{IP}:{Port}" if Port else IP))
logger.info(f"Connecting to broker @ {self._settings.helics}")
if self._settings.helics.broker:
helics.helicsFederateInfoSetBroker(self.fedinfo, str(self._settings.helics.broker))
if self._settings.helics.broker_port:
Expand Down Expand Up @@ -261,8 +262,9 @@ def updateHelicsSubscriptions(self):
value = helics.helicsInputGetInteger(subscription.sub)

if value and value != 0:
if value > 1e6 or value < -1e6:
value = 1.0
logger.info(f"value is {value}")
if value > 1e6 or value < -1e6 or pd.isna(value):
value = 1.0

value = value * subscription.multiplier
subscription.object.SetParameter(subscription.property, value)
Expand Down Expand Up @@ -337,7 +339,39 @@ def updateHelicsPublications(self):

def request_time_increment(self):
error = sum([abs(sub.states[0] - sub.states[1]) for sub in self.subscriptions.subscriptions])
r_seconds = self._dss_solver.GetTotalSeconds() #- self._dss_solver.GetStepResolutionSeconds()
# r_seconds = self._dss_solver.GetTotalSeconds() # parallel
r_seconds = self._dss_solver.GetTotalSeconds() + self._dss_solver.GetStepResolutionSeconds() # transmission priority
# if r_seconds > 0:
# r_seconds = self._dss_solver.GetTotalSeconds() + self._dss_solver.GetStepResolutionSeconds()
# logger.info(f"self._dss_solver.GetTotalSeconds(): {self._dss_solver.GetTotalSeconds()}, self._dss_solver.GetStepResolutionSeconds(): {self._dss_solver.GetStepResolutionSeconds()}")
# os.system('PAUSE')
if not self._settings.helics.iterative_mode:
while self.c_seconds < r_seconds:
self.c_seconds = helics.helicsFederateRequestTime(self._federate, r_seconds)
logger.info('Time requested: {} - time granted: {} '.format(r_seconds, self.c_seconds))
return True, self.c_seconds
else:

self.c_seconds, iteration_state = helics.helicsFederateRequestTimeIterative(
self._federate,
r_seconds,
helics.helics_iteration_request_iterate_if_needed
)

logger.info('Time requested: {} - time granted: {} error: {} it: {}'.format(
r_seconds, self.c_seconds, error, self.itr))
if error > -1 and self.itr < self._co_convergance_max_iterations - 1:
self.itr += 1
return False, self.c_seconds
else:
self.itr = 0
return True, self.c_seconds

def request_time_increment_2(self):
error = sum([abs(sub.states[0] - sub.states[1]) for sub in self.subscriptions.subscriptions])
r_seconds = self._dss_solver.GetTotalSeconds() + self._dss_solver.GetStepResolutionSeconds()/2
# logger.info('Time requested: {} - self._dss_solver.GetStepResolutionSeconds(): {} '.format(r_seconds, self._dss_solver.GetStepResolutionSeconds()))
# os.system('PAUSE')
if not self._settings.helics.iterative_mode:
while self.c_seconds < r_seconds:
self.c_seconds = helics.helicsFederateRequestTime(self._federate, r_seconds)
Expand Down
2 changes: 1 addition & 1 deletion src/pydss/modes/solver_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def __init__(self, dssInstance, settings: ProjectModel):

#self._dssSolution.DblHour()
self.reSolve()
logger.info("%s solver setup complete", settings.simulation_type)
logger.info(f"{settings.simulation_type} solver setup complete")

def setFrequency(self, frequency):
self._dssSolution.Frequency(frequency)
Expand Down
Loading
Loading