Skip to content

Commit

Permalink
Rebased and updated: use GR API, port various functions and docstring…
Browse files Browse the repository at this point in the history
… updates from DSS-Python, more enum usage.
  • Loading branch information
PMeira committed Apr 2, 2023
1 parent 029ef08 commit 5969c5f
Show file tree
Hide file tree
Showing 45 changed files with 1,022 additions and 375 deletions.
8 changes: 8 additions & 0 deletions docs/opendssdirect.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ opendssdirect.Generators module
:undoc-members:
:show-inheritance:

opendssdirect.GICSources module
-------------------------------

.. automodule:: opendssdirect.GICSources
:members:
:undoc-members:
:show-inheritance:

opendssdirect.Isource module
----------------------------

Expand Down
2 changes: 1 addition & 1 deletion opendssdirect/ActiveClass.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from ._utils import api_util, Base
from ._utils import api_util, Base


class IActiveClass(Base):
Expand Down
157 changes: 122 additions & 35 deletions opendssdirect/Basic.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
import warnings
from ._utils import api_util, Base
from dss import DSSCompatFlags


class IBasic(Base):
__name__ = "Basic"
_api_prefix = "DSS"
__slots__ = [
"ActiveCircuit",
"Circuits",
"Error",
"Text",
"DSSProgress",
"ActiveClass",
"Executive",
"Events",
"CmathLib",
"Parser",
"DSSim_Coms",
"YMatrix",
"ZIP",
"Obj",
]
_columns = [
"Version",
"Classes",
Expand All @@ -30,6 +16,7 @@ class IBasic(Base):
"UserClasses",
"DefaultEditor",
]
__slots__ = []

def ClearAll(self):
self.CheckForError(self._lib.DSS_ClearAll())
Expand Down Expand Up @@ -94,15 +81,6 @@ def AllowForms(self, *args):
# Setter
value, = args
self.CheckForError(self._lib.DSS_Set_AllowForms(value))
def ShowPanel(self):
# warnings.warn('ShowPanel is not implemented.')
return 0

def NewCircuit(self, name):
if type(name) is not bytes:
name = name.encode(self._api_util.codec)
self.CheckForError(self._lib.DSS_NewCircuit(name))
return "New Circuit" # self.ActiveCircuit

def AllowEditor(self, *args):
"""
Expand All @@ -111,6 +89,8 @@ def AllowEditor(self, *args):
AllowEditor controls whether the external editor is used in commands like "Show".
If you set to 0 (false), the editor is not executed. Note that other side effects,
such as the creation of files, are not affected.
(API Extension)
"""
# Getter
if len(args) == 0:
Expand All @@ -120,19 +100,24 @@ def AllowEditor(self, *args):
value, = args
self.CheckForError(self._lib.DSS_Set_AllowEditor(value))

def LegacyModels(self, *args):
"""
If enabled, the legacy/deprecated models for PVSystem, InvControl, Storage and StorageControl are used.
In the official OpenDSS version 9.0, the old models where removed. They are temporarily present here
but may be removed in the near future. If they are important to you, please open an issue on GitHub
or contact the authors from DSS Extensions: https://github.com/dss-extensions/
def ShowPanel(self):
# warnings.warn("ShowPanel is not implemented.")
return 0

After toggling LegacyModels, run a "clear" command and the models will be loaded accordingly.
Defaults to False.
def NewCircuit(self, name):
if type(name) is not bytes:
name = name.encode(self._api_util.codec)
self.CheckForError(self._lib.DSS_NewCircuit(name))
return "New Circuit" # self.ActiveCircuit

This can also be enabled by setting the environment variable DSS_CAPI_LEGACY_MODELS to 1.
def LegacyModels(self, *args):
"""
LegacyModels was a flag used to toggle legacy (pre-2019) models for PVSystem, InvControl, Storage and
StorageControl.
In the official OpenDSS version 9.0, the old models were removed. They were temporarily present here
but were also removed in DSS C-API v0.13.0.
NOTE: this option will be removed in a future release.
**NOTE**: this property will be removed for v1.0. It is left to avoid breaking the current API too soon.
(API Extension)
"""
Expand Down Expand Up @@ -167,6 +152,100 @@ def AllowChangeDir(self, *args):
Value, = args
self.CheckForError(self._lib.DSS_Set_AllowChangeDir(Value))

def AllowDOScmd(self, *args):
"""
If enabled, the `DOScmd` command is allowed. Otherwise, an error is reported if the user tries to use it.
Defaults to False/0 (disabled state). Users should consider DOScmd deprecated on DSS Extensions.
This can also be set through the environment variable DSS_CAPI_ALLOW_DOSCMD. Setting it to 1 enables
the command.
(API Extension)
"""
# Getter
if len(args) == 0:
return self.CheckForError(self._lib.DSS_Get_AllowDOScmd()) != 0

# Setter
Value, = args
self.CheckForError(self._lib.DSS_Set_AllowDOScmd(Value))

# def NewContext(self):
# """
# Creates a new DSS engine context.
# A DSS Context encapsulates most of the global state of the original OpenDSS engine,
# allowing the user to create multiple instances in the same process. By creating contexts
# manually, the management of threads and potential issues should be handled by the user.

# (API Extension)
# """
# ffi = self._api_util.ffi
# lib = self._api_util.lib_unpatched
# new_ctx = ffi.gc(lib.ctx_New(), lib.ctx_Dispose)
# new_api_util = CffiApiUtil(ffi, lib, new_ctx)
# new_api_util._allow_complex = self._api_util._allow_complex
# return IDSS(new_api_util)

# def Plotting(self):
# """
# Shortcut for the plotting module. This property is equivalent to:

# ```
# from dss import plot
# return plot
# ```

# Gives access to the `enable()` and `disable()` functions.
# Requires matplotlib and SciPy to be installed, hence it is an
# optional feature.

# (API Extension)
# """
# from dss import plot

# return plot

def CompatFlags(self, *args):
"""
Controls some compatibility flags introduced to toggle some behavior from the official OpenDSS.
**THESE FLAGS ARE GLOBAL, affecting all DSS engines in the process.**
The current bit flags are:
- 0x1 (bit 0): If enabled, don't check for NaNs in the inner solution loop. This can lead to various errors.
This flag is useful for legacy applications that don't handle OpenDSS API errors properly. Through the
development of DSS Extensions, we noticed this is actually a quite common issue.
- 0x2 (bit 1): Toggle worse precision for certain aspects of the engine. For example, the sequence-to-phase
(`As2p`) and sequence-to-phase (`Ap2s`) transform matrices. On DSS C-API, we fill the matrix explicitly
using higher precision, while numerical inversion of an initially worse precision matrix is used in the
official OpenDSS. We will introduce better precision for other aspects of the engine in the future,
so this flag can be used to toggle the old/bad values where feasible.
- 0x4 (bit 2): Toggle some InvControl behavior introduced in OpenDSS 9.6.1.1. It could be a regression
but needs further investigation, so we added this flag in the time being.
These flags may change for each version of DSS C-API, but the same value will not be reused. That is,
when we remove a compatibility flag, it will have no effect but will also not affect anything else
besides raising an error if the user tries to toggle a flag that was available in a previous version.
We expect to keep a very limited number of flags. Since the flags are more transient than the other
options/flags, it was preferred to add this generic function instead of a separate function per
flag.
Related enumeration: DSSCompatFlags
(API Extension)
"""
# Getter
if len(args) == 0:
return self.CheckForError(self._lib.DSS_Get_CompatFlags())

# Setter
Value, = args
self.CheckForError(self._lib.DSS_Set_CompatFlags(Value))


_Basic = IBasic(api_util)

# For backwards compatibility, bind to the default instance
Expand All @@ -188,6 +267,10 @@ def AllowChangeDir(self, *args):
AllowEditor = _Basic.AllowEditor
LegacyModels = _Basic.LegacyModels
AllowChangeDir = _Basic.AllowChangeDir
AllowDOScmd = _Basic.AllowDOScmd
# NewContext = _Basic.NewContext
# Plotting = _Basic.Plotting
CompatFlags = _Basic.CompatFlags
_columns = _Basic._columns
__all__ = [
"ClearAll",
Expand All @@ -208,4 +291,8 @@ def AllowChangeDir(self, *args):
"AllowEditor",
"LegacyModels",
"AllowChangeDir",
"AllowDOScmd",
# "NewContext",
# "Plotting",
"CompatFlags",
]
64 changes: 45 additions & 19 deletions opendssdirect/Bus.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ def Coorddefined(self):

def CplxSeqVoltages(self):
"""(read-only) Complex Double array of Sequence Voltages (0, 1, 2) at this Bus."""
return self._get_float64_array(self._lib.Bus_Get_CplxSeqVoltages)
self.CheckForError(self._lib.Bus_Get_CplxSeqVoltages_GR())
return self._get_complex128_gr_array()

def Cust_Duration(self):
"""(read-only) Accumulated customer outage durations"""
Expand All @@ -73,7 +74,8 @@ def Int_Duration(self):

def Isc(self):
"""(read-only) Short circuit currents at bus; Complex Array."""
return self._get_float64_array(self._lib.Bus_Get_Isc)
self.CheckForError(self._lib.Bus_Get_Isc_GR())
return self._get_complex128_gr_array()

def Lambda(self):
"""(read-only) Accumulated failure rate downstream from this bus; faults per year"""
Expand All @@ -93,7 +95,8 @@ def Name(self):

def Nodes(self):
"""(read-only) Integer Array of Node Numbers defined at the bus in same order as the voltages."""
return self._get_int32_array(self._lib.Bus_Get_Nodes)
self.CheckForError(self._lib.Bus_Get_Nodes_GR())
return self._get_int32_gr_array()

def NumNodes(self):
"""(read-only) Number of Nodes this bus."""
Expand All @@ -104,60 +107,81 @@ def SectionID(self):
return self.CheckForError(self._lib.Bus_Get_SectionID())

def SeqVoltages(self):
"""(read-only) Double Array of sequence voltages at this bus."""
return self._get_float64_array(self._lib.Bus_Get_SeqVoltages)
"""(read-only) Double Array of sequence voltages at this bus. Magnitudes only."""
self.CheckForError(self._lib.Bus_Get_SeqVoltages_GR())
return self._get_float64_gr_array()

def TotalMiles(self):
"""(read-only) Total length of line downline from this bus, in miles. For recloser siting algorithm."""
return self.CheckForError(self._lib.Bus_Get_TotalMiles())

def VLL(self):
"""(read-only) For 2- and 3-phase buses, returns array of complex numbers represetin L-L voltages in volts. Returns -1.0 for 1-phase bus. If more than 3 phases, returns only first 3."""
return self._get_float64_array(self._lib.Bus_Get_VLL)
self.CheckForError(self._lib.Bus_Get_VLL_GR())
return self._get_complex128_gr_array()

def VMagAngle(self):
"""(read-only) Array of doubles containing voltages in Magnitude (VLN), angle (deg)"""
return self._get_float64_array(self._lib.Bus_Get_VMagAngle)
"""(read-only) Array of doubles containing voltages in Magnitude (VLN), angle (degrees)"""
self.CheckForError(self._lib.Bus_Get_VMagAngle_GR())
return self._get_float64_gr_array()

def Voc(self):
"""(read-only) Open circuit voltage; Complex array."""
return self._get_float64_array(self._lib.Bus_Get_Voc)
self.CheckForError(self._lib.Bus_Get_Voc_GR())
return self._get_complex128_gr_array()

def Voltages(self):
"""(read-only) Complex array of voltages at this bus."""
return self._get_float64_array(self._lib.Bus_Get_Voltages)
self.CheckForError(self._lib.Bus_Get_Voltages_GR())
return self._get_complex128_gr_array()

def YscMatrix(self):
"""(read-only) Complex array of Ysc matrix at bus. Column by column."""
return self._get_float64_array(self._lib.Bus_Get_YscMatrix)
self.CheckForError(self._lib.Bus_Get_YscMatrix_GR())
return self._get_complex128_gr_array()

def Zsc0(self):
"""(read-only) Complex Zero-Sequence short circuit impedance at bus."""
return self._get_float64_array(self._lib.Bus_Get_Zsc0)
self.CheckForError(self._lib.Bus_Get_Zsc0_GR())
return self._get_complex128_gr_simple()

def Zsc1(self):
"""(read-only) Complex Positive-Sequence short circuit impedance at bus.."""
return self._get_float64_array(self._lib.Bus_Get_Zsc1)
"""(read-only) Complex Positive-Sequence short circuit impedance at bus."""
self.CheckForError(self._lib.Bus_Get_Zsc1_GR())
return self._get_complex128_gr_simple()

def ZscMatrix(self):
"""(read-only) Complex array of Zsc matrix at bus. Column by column."""
return self._get_float64_array(self._lib.Bus_Get_ZscMatrix)
self.CheckForError(self._lib.Bus_Get_ZscMatrix_GR())
return self._get_complex128_gr_array()

def kVBase(self):
"""(read-only) Base voltage at bus in kV"""
return self.CheckForError(self._lib.Bus_Get_kVBase())

def puVLL(self):
"""(read-only) Returns Complex array of pu L-L voltages for 2- and 3-phase buses. Returns -1.0 for 1-phase bus. If more than 3 phases, returns only 3 phases."""
return self._get_float64_array(self._lib.Bus_Get_puVLL)
self.CheckForError(self._lib.Bus_Get_puVLL_GR())
return self._get_complex128_gr_array()

def puVmagAngle(self):
"""(read-only) Array of doubles containig voltage magnitude, angle pairs in per unit"""
return self._get_float64_array(self._lib.Bus_Get_puVmagAngle)
"""(read-only) Array of doubles containing voltage magnitude, angle (degrees) pairs in per unit"""
self.CheckForError(self._lib.Bus_Get_puVmagAngle_GR())
return self._get_float64_gr_array()

def PuVoltage(self):
"""(read-only) Complex Array of pu voltages at the bus."""
return self._get_float64_array(self._lib.Bus_Get_puVoltages)
self.CheckForError(self._lib.Bus_Get_puVoltages_GR())
return self._get_complex128_gr_array()

def ZSC012Matrix(self):
"""
Array of doubles (complex) containing the complete 012 Zsc matrix.
Only available after Zsc is computed, either through the "ZscRefresh" command, or running a "FaultStudy" solution.
Only available for buses with 3 nodes.
"""
self.CheckForError(self._lib.Bus_Get_ZSC012Matrix_GR())
return self._get_complex128_gr_array()

def X(self, *args):
"""X Coordinate for bus (double)"""
Expand Down Expand Up @@ -241,6 +265,7 @@ def AllPDEatBus(self):
Y = _Bus.Y
LoadList = _Bus.LoadList
LineList = _Bus.LineList
ZSC012Matrix = _Bus.ZSC012Matrix
_columns = _Bus._columns
__all__ = [
"AllPCEatBus",
Expand Down Expand Up @@ -279,4 +304,5 @@ def AllPDEatBus(self):
"Y",
"LoadList",
"LineList",
"ZSC012Matrix",
]
Loading

0 comments on commit 5969c5f

Please sign in to comment.