Skip to content

Commit 09c4652

Browse files
committed
Expose GICSources and other DSS C-API features
- Bus: ZSC012Matrix - Circuit: ElementLosses - DSS: AllowDOScmd, COMErrorResults, `__call__` - Fuses: State, NormalState - LineGeometries: Nconds - Loads: Sensor - LoadShapes: UseFloat32, UseFloat64 - PVSystems: Sensor - Reclosers: State, NormalState - Relays: State, NormalState - Sensors: AllocationFactor - Text: Commands - WireData: CapRadius - YMatrix: SetGeneratordQdV, Iteration
1 parent d3bb4c5 commit 09c4652

35 files changed

+607
-17
lines changed

dss/dss_capi_gr/IBus.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,12 @@ def puVoltages(self):
206206
self.CheckForError(self._lib.Bus_Get_puVoltages_GR())
207207
return self._get_float64_gr_array()
208208

209+
@property
210+
def ZSC012Matrix(self):
211+
'''Array of doubles (complex) containing the complete 012 Zsc matrix'''
212+
self.CheckForError(self._lib.Bus_Get_ZSC012Matrix_GR())
213+
return self._get_float64_gr_array()
214+
209215
@property
210216
def x(self):
211217
'''X Coordinate for bus (double)'''

dss/dss_capi_gr/ICircuit.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
from .IParallel import IParallel
4747
from .IReduceCkt import IReduceCkt
4848
from .IStorages import IStorages
49+
from .IGICSources import IGICSources
4950

5051
class ICircuit(Base):
5152
__slots__ = [
@@ -91,7 +92,8 @@ class ICircuit(Base):
9192
'Reactors',
9293
'Parallel',
9394
'ReduceCkt',
94-
'Storages'
95+
'Storages',
96+
'GICSources',
9597
]
9698

9799
_columns = [
@@ -165,6 +167,7 @@ def __init__(self, api_util):
165167
self.Reactors = IReactors(api_util)
166168
self.ReduceCkt = IReduceCkt(api_util) #: Circuit Reduction Interface
167169
self.Storages = IStorages(api_util)
170+
self.GICSources = IGICSources(api_util)
168171

169172
if hasattr(api_util.lib, 'Parallel_CreateActor'):
170173
self.Parallel = IParallel(api_util)
@@ -384,3 +387,14 @@ def YNodeVarray(self):
384387
'''(read-only) Complex array of actual node voltages in same order as SystemY matrix.'''
385388
self.CheckForError(self._lib.Circuit_Get_YNodeVarray_GR())
386389
return self._get_float64_gr_array()
390+
391+
def ElementLosses(self, Value):
392+
'''
393+
Array of total losses (complex) in a selection of elements.
394+
Use the element indices (starting at 1) as parameter.
395+
396+
(API Extension)
397+
'''
398+
Value, ValuePtr, ValueCount = self._prepare_int32_array(Value)
399+
self.CheckForError(self._lib.Circuit_Get_ElementLosses_GR(ValuePtr, ValueCount))
400+
return self._get_float64_gr_array()

dss/dss_capi_gr/ICktElement.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def AllVariableValues(self):
130130
@property
131131
def BusNames(self):
132132
'''
133-
Array of strings. Get Bus definitions to which each terminal is connected. 0-based array.
133+
Array of strings. Get Bus definitions to which each terminal is connected.
134134
'''
135135
return self.CheckForError(self._get_string_array(self._lib.CktElement_Get_BusNames))
136136

dss/dss_capi_gr/IDSS.py

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Copyright (c) 2018-2022 DSS Extensions contributors
66
'''
77
import warnings
8-
from .._cffi_api_util import Base, CffiApiUtil
8+
from .._cffi_api_util import Base, CffiApiUtil, DSSException
99
from .ICircuit import ICircuit
1010
from .IError import IError
1111
from .IText import IText
@@ -216,6 +216,48 @@ def AllowChangeDir(self):
216216
def AllowChangeDir(self, Value):
217217
self.CheckForError(self._lib.DSS_Set_AllowChangeDir(Value))
218218

219+
@property
220+
def AllowDOScmd(self):
221+
'''
222+
If enabled, the `DOScmd` command is allowed. Otherwise, an error is reported if the user tries to use it.
223+
224+
Defaults to False/0 (disabled state). Users should consider DOScmd deprecated on DSS Extensions.
225+
226+
This can also be set through the environment variable DSS_CAPI_ALLOW_DOSCMD. Setting it to 1 enables
227+
the command.
228+
229+
(API Extension)
230+
'''
231+
return self.CheckForError(self._lib.DSS_Get_AllowDOScmd()) != 0
232+
233+
@AllowDOScmd.setter
234+
def AllowDOScmd(self, Value):
235+
self.CheckForError(self._lib.DSS_Set_AllowDOScmd(Value))
236+
237+
@property
238+
def COMErrorResults(self):
239+
'''
240+
If enabled, in case of errors or empty arrays, the API returns arrays with values compatible with the
241+
official OpenDSS COM interface.
242+
243+
For example, consider the function `Loads_Get_ZIPV`. If there is no active circuit or active load element:
244+
- In the disabled state (COMErrorResults=False), the function will return "[]", an array with 0 elements.
245+
- In the enabled state (COMErrorResults=True), the function will return "[0.0]" instead. This should
246+
be compatible with the return value of the official COM interface.
247+
248+
Defaults to True/1 (enabled state) in the v0.12.x series. This will change to false in future series.
249+
250+
This can also be set through the environment variable DSS_CAPI_COM_DEFAULTS. Setting it to 0 disables
251+
the legacy/COM behavior. The value can be toggled through the API at any time.
252+
253+
(API Extension)
254+
'''
255+
return self.CheckForError(self._lib.DSS_Get_COMErrorResults()) != 0
256+
257+
@COMErrorResults.setter
258+
def COMErrorResults(self, Value):
259+
self.CheckForError(self._lib.DSS_Set_COMErrorResults(Value))
260+
219261
def NewContext(self):
220262
'''
221263
Creates a new DSS engine context.
@@ -230,3 +272,43 @@ def NewContext(self):
230272
new_ctx = lib.ctx_New()
231273
new_api_util = CffiApiUtil(ffi, lib, new_ctx)
232274
return IDSS(new_api_util)
275+
276+
def __call__(self, single=None, block=None):
277+
'''
278+
Shortcut to pass text commands.
279+
280+
If `single` is set and is a string, a normal `DSS.Text.Command = single` is called.
281+
Otherwise, the value is passed to `DSS.Text.Commands`.
282+
283+
Examples:
284+
285+
# single command
286+
DSS("new Circuit.test")
287+
DSS(single="new Circuit.test")
288+
289+
# list of commands (either will work)
290+
DSS(["new Circuit.test", "new Line.line1 bus1=a bus2=b"])
291+
DSS(single=["new circuit.test", "new Line.line1 bus1=a bus2=b"])
292+
DSS(block=["new circuit.test", "new Line.line1 bus1=a bus2=b"])
293+
294+
# block of commands in a big string
295+
DSS(block="""
296+
clear
297+
new Circuit.test
298+
new Line.line1 bus1=a bus2=b
299+
new Load.load1 bus1=a bus2=b
300+
""")
301+
302+
(API Extension)
303+
'''
304+
if (single is not None) and (block is not None):
305+
raise DSSException("Only a single argument is accepted.")
306+
307+
if (single is None) and (block is None):
308+
raise DSSException("A value is required.")
309+
310+
if single is not None:
311+
self.Text.Command = single
312+
return
313+
314+
self.Text.Commands(single or block)

dss/dss_capi_gr/IFuses.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,27 @@ class IFuses(Iterable):
2121
'RatedCurrent',
2222
'SwitchedObj',
2323
'SwitchedTerm',
24+
'State',
25+
'NormalState',
2426
]
2527

2628

2729
def Close(self):
30+
'''Close all phases of the fuse.'''
2831
self.CheckForError(self._lib.Fuses_Close())
2932

3033
def IsBlown(self):
34+
'''Current state of the fuses. TRUE if any fuse on any phase is blown. Else FALSE.'''
3135
return self.CheckForError(self._lib.Fuses_IsBlown()) != 0
3236

3337
def Open(self):
38+
'''Manual opening of all phases of the fuse.'''
3439
self.CheckForError(self._lib.Fuses_Open())
3540

41+
def Reset(self):
42+
'''Reset fuse to normal state.'''
43+
self.CheckForError(self._lib.Fuses_Reset())
44+
3645
@property
3746
def Delay(self):
3847
'''
@@ -120,3 +129,23 @@ def TCCcurve(self, Value):
120129
Value = Value.encode(self._api_util.codec)
121130

122131
self.CheckForError(self._lib.Fuses_Set_TCCcurve(Value))
132+
133+
@property
134+
def State(self):
135+
'''Array of strings indicating the state of each phase of the fuse.'''
136+
return self.CheckForError(self._get_string_array(self._lib.Fuses_Get_State))
137+
138+
@State.setter
139+
def State(self, Value):
140+
Value, ValuePtr, ValueCount = self._prepare_string_array(Value)
141+
self.CheckForError(self._lib.Fuses_Set_State(ValuePtr, ValueCount))
142+
143+
@property
144+
def NormalState(self):
145+
'''Array of strings indicating the normal state of each phase of the fuse.'''
146+
return self.CheckForError(self._get_string_array(self._lib.Fuses_Get_NormalState))
147+
148+
@NormalState.setter
149+
def NormalState(self, Value):
150+
Value, ValuePtr, ValueCount = self._prepare_string_array(Value)
151+
self.CheckForError(self._lib.Fuses_Set_NormalState(ValuePtr, ValueCount))

dss/dss_capi_gr/ILineGeometries.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class ILineGeometries(Iterable):
1414
_columns = [
1515
'Name',
1616
'idx',
17+
'Nconds',
1718
'Phases',
1819
'RhoEarth',
1920
'Reduce',
@@ -128,3 +129,11 @@ def Ycoords(self, Value):
128129
Value, ValuePtr, ValueCount = self._prepare_float64_array(Value)
129130
self.CheckForError(self._lib.LineGeometries_Set_Ycoords(ValuePtr, ValueCount))
130131

132+
@property
133+
def Nconds(self):
134+
'''Number of conductors in this geometry. Default is 3. Triggers memory allocations. Define first!'''
135+
return self.CheckForError(self._lib.LineGeometries_Get_Nconds())
136+
137+
@Nconds.setter
138+
def Nconds(self, Value):
139+
self.CheckForError(self._lib.LineGeometries_Set_Nconds(Value))

dss/dss_capi_gr/ILoadShapes.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,21 @@ def sInterval(self, Value):
133133

134134
Sinterval = sInterval
135135
SInterval = sInterval
136+
137+
def UseFloat32(self):
138+
'''
139+
Converts the current LoadShape data to float32/single precision.
140+
If there is no data or the data is already represented using float32, nothing is done.
141+
142+
(API Extension)
143+
'''
144+
self.CheckForError(self._lib.LoadShapes_UseFloat32())
145+
146+
def UseFloat64(self):
147+
'''
148+
Converts the current LoadShape data to float64/double precision.
149+
If there is no data or the data is already represented using float64, nothing is done.
150+
151+
(API Extension)
152+
'''
153+
self.CheckForError(self._lib.LoadShapes_UseFloat64())

dss/dss_capi_gr/ILoads.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class ILoads(Iterable):
4747
'AllocationFactor',
4848
'xfkVA',
4949
'pctSeriesRL',
50+
'Sensor',
5051
]
5152

5253
@property
@@ -374,6 +375,11 @@ def xfkVA(self):
374375
def xfkVA(self, Value):
375376
self.CheckForError(self._lib.Loads_Set_xfkVA(Value))
376377

378+
@property
379+
def Sensor(self):
380+
'''Name of the sensor monitoring this load.'''
381+
return self._get_string(self.CheckForError(self._lib.Loads_Get_Sensor()))
382+
377383
# API extensions
378384
@property
379385
def Phases(self):

dss/dss_capi_gr/IPVSystems.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class IPVSystems(Iterable):
2929
'Tdaily',
3030
'Tduty',
3131
'Tyearly',
32+
'Sensor',
3233
]
3334

3435
@property
@@ -202,3 +203,8 @@ def Pmpp(self):
202203
@Pmpp.setter
203204
def Pmpp(self, Value):
204205
self.CheckForError(self._lib.PVSystems_Set_Pmpp(Value))
206+
207+
@property
208+
def Sensor(self):
209+
'''Name of the sensor monitoring this element.'''
210+
return self._get_string(self.CheckForError(self._lib.PVSystems_Get_Sensor()))

dss/dss_capi_gr/IReclosers.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class IReclosers(Iterable):
2323
'PhaseTrip',
2424
'RecloseIntervals',
2525
'Shots',
26+
'State',
27+
'NormalState',
2628
]
2729

2830
def Close(self):
@@ -133,3 +135,33 @@ def SwitchedTerm(self):
133135
def SwitchedTerm(self, Value):
134136
self.CheckForError(self._lib.Reclosers_Set_SwitchedTerm(Value))
135137

138+
139+
def Reset(self):
140+
'''
141+
Reset recloser to normal state.
142+
If open, lock out the recloser.
143+
If closed, resets recloser to first operation.
144+
'''
145+
self.CheckForError(self._lib.Reclosers_Reset())
146+
147+
@property
148+
def State(self):
149+
'''
150+
Get/Set present state of recloser.
151+
If set to open (ActionCodes.Open=1), open recloser's controlled element and lock out the recloser.
152+
If set to close (ActionCodes.Close=2), close recloser's controlled element and resets recloser to first operation.
153+
'''
154+
return self.CheckForError(self._lib.Reclosers_Get_State())
155+
156+
@State.setter
157+
def State(self, Value):
158+
self.CheckForError(self._lib.Reclosers_Set_State(Value))
159+
160+
@property
161+
def NormalState(self):
162+
'''Get/set normal state (ActionCodes.Open=1, ActionCodes.Close=2) of the recloser.'''
163+
return self.CheckForError(self._lib.Reclosers_Get_NormalState())
164+
165+
@NormalState.setter
166+
def NormalState(self, Value):
167+
self.CheckForError(self._lib.Reclosers_Set_NormalState(Value))

dss/dss_capi_gr/IRelays.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class IRelays(Iterable):
1616
'MonitoredTerm',
1717
'SwitchedObj',
1818
'SwitchedTerm',
19+
'State',
20+
'NormalState'
1921
]
2022

2123
@property
@@ -59,3 +61,41 @@ def SwitchedTerm(self):
5961
@SwitchedTerm.setter
6062
def SwitchedTerm(self, Value):
6163
self.CheckForError(self._lib.Relays_Set_SwitchedTerm(Value))
64+
65+
def Open(self):
66+
'''Open relay's controlled element and lock out the relay.'''
67+
self.CheckForError(self._lib.Relays_Open())
68+
69+
def Close(self):
70+
'''Close the switched object controlled by the relay. Resets relay to first operation.'''
71+
self.CheckForError(self._lib.Relays_Close())
72+
73+
def Reset(self):
74+
'''
75+
Reset relay to normal state.
76+
If open, lock out the relay.
77+
If closed, resets relay to first operation.
78+
'''
79+
self.CheckForError(self._lib.Relays_Reset())
80+
81+
@property
82+
def State(self):
83+
'''
84+
Get/Set present state of relay.
85+
If set to open, open relay's controlled element and lock out the relay.
86+
If set to close, close relay's controlled element and resets relay to first operation.
87+
'''
88+
return self.CheckForError(self._lib.Relays_Get_State())
89+
90+
@State.setter
91+
def State(self, Value):
92+
self.CheckForError(self._lib.Relays_Set_State(Value))
93+
94+
@property
95+
def NormalState(self):
96+
'''Normal state of relay.'''
97+
return self.CheckForError(self._lib.Relays_Get_NormalState())
98+
99+
@NormalState.setter
100+
def NormalState(self, Value):
101+
self.CheckForError(self._lib.Relays_Set_NormalState(Value))

0 commit comments

Comments
 (0)