Skip to content

Commit 3b553d1

Browse files
committed
Fix Monitors.AsMatrix, add utils.monitor_to_dataframe and related test.
Closes #12
1 parent a30f40e commit 3b553d1

File tree

3 files changed

+79
-2
lines changed

3 files changed

+79
-2
lines changed

opendssdirect/Monitors.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import absolute_import
33
import numpy as np
44
from ._utils import (
5+
api_util,
56
lib,
67
codec,
78
CheckForError,
@@ -201,7 +202,7 @@ def AsMatrix():
201202
Matrix of the active monitor, containing the hour vector, seconds vector, and all channels (index 2 = channel 1).
202203
If you need multiple channels, prefer using this function as it processes the monitor byte-stream once.
203204
"""
204-
buffer = get_int8_array(lib.Monitors_Get_ByteStream)
205+
buffer = api_util.get_int8_array(lib.Monitors_Get_ByteStream)
205206
CheckForError()
206207
if len(buffer) <= 1:
207208
return None

opendssdirect/utils.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import inspect
44
import warnings
55

6-
from ._utils import get_string
6+
from ._utils import get_string, dss_py
77

88
is_pandas_installed = True
99

@@ -235,6 +235,32 @@ def meters_to_dataframe(dss=None):
235235
return to_dataframe(dss.Meters)
236236

237237

238+
def monitor_to_dataframe(dss=None):
239+
"""
240+
Return the data from current active monitor as a Pandas DataFrame
241+
"""
242+
if dss is None:
243+
import opendssdirect as dss
244+
245+
if dss.Solution.Mode() in (dss_py.enums.SolveModes.Harmonic, 17):
246+
# Note: Mode 17 is HarmonicT but it was not exposed in the enum
247+
# ported from COM as of 2021-01-03
248+
columns = ['frequency', 'harmonic']
249+
else:
250+
columns = ['hour', 'second']
251+
252+
columns.extend(col.strip() for col in dss.Monitors.Header())
253+
data = dss.Monitors.AsMatrix()
254+
255+
if is_pandas_installed:
256+
return pd.DataFrame(data, columns=columns)
257+
else:
258+
warnings.warn(
259+
"Pandas is not installed. Please see documentation for how to install extra dependencies."
260+
)
261+
return dict(zip(columns, data.T))
262+
263+
238264
def monitors_to_dataframe(dss=None):
239265
if dss is None:
240266
import opendssdirect as dss

tests/test_opendssdirect.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1963,6 +1963,56 @@ def test_13Node_Monitors(dss):
19631963
assert dss.Monitors.ResetAll() is None
19641964
assert dss.Monitors.SaveAll() is None
19651965
assert dss.Monitors.SampleAll() is None
1966+
1967+
dss.Text.Command("new monitor.test_monitor element=Transformer.Reg3 terminal=2 mode=2")
1968+
dss.Text.Command("solve mode=daily step=15m number=10")
1969+
1970+
assert dss.Monitors.Count() == 1
1971+
assert dss.Monitors.First() == 1
1972+
1973+
expected_dict = pd.DataFrame(
1974+
{
1975+
"Tap (pu)": {
1976+
0: 1.056249976158142,
1977+
1: 1.056249976158142,
1978+
2: 1.056249976158142,
1979+
3: 1.056249976158142,
1980+
4: 1.056249976158142,
1981+
5: 1.056249976158142,
1982+
6: 1.056249976158142,
1983+
7: 1.056249976158142,
1984+
8: 1.056249976158142,
1985+
9: 1.056249976158142
1986+
},
1987+
"hour": {
1988+
0: 0.0,
1989+
1: 0.0,
1990+
2: 0.0,
1991+
3: 1.0,
1992+
4: 1.0,
1993+
5: 1.0,
1994+
6: 1.0,
1995+
7: 2.0,
1996+
8: 2.0,
1997+
9: 2.0
1998+
},
1999+
"second": {
2000+
0: 900.0,
2001+
1: 1800.0,
2002+
2: 2700.0,
2003+
3: 0.0,
2004+
4: 900.0,
2005+
5: 1800.0,
2006+
6: 2700.0,
2007+
7: 0.0,
2008+
8: 900.0,
2009+
9: 1800.0
2010+
}
2011+
}
2012+
).to_dict()
2013+
2014+
actual_dict = dss.utils.monitor_to_dataframe().to_dict()
2015+
assert_dict_equal(actual_dict, expected_dict)
19662016

19672017

19682018
def test_13Node_PDElements(dss):

0 commit comments

Comments
 (0)