Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
ACS
Public
Power System Simulation and Optimization
DPsim
DPsim
Commits
52a33d1e
Commit
52a33d1e
authored
Sep 21, 2017
by
Georg Martin Reinke
Browse files
implement RT simulation with Python interface
Former-commit-id:
1cb9d178
parent
d09d1b55
Changes
3
Hide whitespace changes
Inline
Side-by-side
Source/PySimulation.cpp
View file @
52a33d1e
...
...
@@ -5,6 +5,12 @@
#include <cfloat>
#include <iostream>
#ifdef __linux__
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#endif
using
namespace
DPsim
;
static
PyMethodDef
PySimulation_methods
[]
=
{
...
...
@@ -64,12 +70,77 @@ PyTypeObject DPsim::PySimulationType = {
void
PySimulation
::
simThreadFunction
(
PySimulation
*
pySim
)
{
bool
notDone
=
true
;
#ifdef __linux__
if
(
pySim
->
rt
)
{
simThreadFunctionRT
(
pySim
);
return
;
}
#endif
std
::
unique_lock
<
std
::
mutex
>
lk
(
*
pySim
->
mut
,
std
::
defer_lock
);
pySim
->
numStep
=
0
;
while
(
pySim
->
running
&&
notDone
)
{
notDone
=
pySim
->
sim
->
step
(
*
pySim
->
log
,
*
pySim
->
llog
,
*
pySim
->
rlog
);
pySim
->
numStep
++
;
pySim
->
sim
->
increaseByTimeStep
();
if
(
pySim
->
sigPause
)
{
lk
.
lock
();
pySim
->
state
=
StatePaused
;
pySim
->
cond
->
notify_one
();
pySim
->
cond
->
wait
(
lk
);
pySim
->
state
=
StateRunning
;
lk
.
unlock
();
}
}
lk
.
lock
();
pySim
->
state
=
StateDone
;
pySim
->
cond
->
notify_one
();
}
#ifdef __linux__
void
PySimulation
::
simThreadFunctionRT
(
PySimulation
*
pySim
)
{
bool
notDone
=
true
;
char
timebuf
[
8
];
int
timerfd
;
struct
itimerspec
ts
;
uint64_t
overrun
;
std
::
unique_lock
<
std
::
mutex
>
lk
(
*
pySim
->
mut
,
std
::
defer_lock
);
pySim
->
numStep
=
0
;
// RT method is limited to timerfd right now; to implement it with Exceptions,
// look at Simulation::runRT
timerfd
=
timerfd_create
(
CLOCK_REALTIME
,
0
);
// TODO: better error mechanism (somehow pass an Exception to the Python thread?)
if
(
timerfd
<
0
)
{
std
::
perror
(
"Failed to create timerfd"
);
std
::
exit
(
1
);
}
ts
.
it_value
.
tv_sec
=
(
time_t
)
pySim
->
sim
->
getTimeStep
();
ts
.
it_value
.
tv_nsec
=
(
long
)
(
pySim
->
sim
->
getTimeStep
()
*
1e9
);
ts
.
it_interval
=
ts
.
it_value
;
// optional start synchronization
if
(
pySim
->
startSync
)
{
pySim
->
sim
->
step
(
*
pySim
->
log
,
*
pySim
->
llog
,
*
pySim
->
rlog
,
false
);
// first step, sending the initial values
pySim
->
sim
->
step
(
*
pySim
->
log
,
*
pySim
->
llog
,
*
pySim
->
rlog
,
true
);
// blocking step for synchronization + receiving the initial state of the other network
pySim
->
sim
->
increaseByTimeStep
();
}
if
(
timerfd_settime
(
timerfd
,
0
,
&
ts
,
0
)
<
0
)
{
std
::
perror
(
"Failed to arm timerfd"
);
std
::
exit
(
1
);
}
while
(
pySim
->
running
&&
notDone
)
{
notDone
=
pySim
->
sim
->
step
(
*
pySim
->
log
,
*
pySim
->
llog
,
*
pySim
->
rlog
);
if
(
read
(
timerfd
,
timebuf
,
8
)
<
0
)
{
std
::
perror
(
"Read from timerfd failed"
);
std
::
exit
(
1
);
}
overrun
=
*
((
uint64_t
*
)
timebuf
);
if
(
overrun
>
1
)
{
std
::
cerr
<<
"timerfd overrun of "
<<
overrun
-
1
<<
" at "
<<
pySim
->
sim
->
getTime
()
<<
std
::
endl
;
}
pySim
->
numStep
++
;
pySim
->
sim
->
increaseByTimeStep
();
// in case it wasn't obvious, pausing a RT simulation is a bad idea
// as it will most likely lead to overruns, but it's possible nonetheless
if
(
pySim
->
sigPause
)
{
lk
.
lock
();
pySim
->
state
=
StatePaused
;
...
...
@@ -79,10 +150,12 @@ void PySimulation::simThreadFunction(PySimulation* pySim) {
lk
.
unlock
();
}
}
close
(
timerfd
);
lk
.
lock
();
pySim
->
state
=
StateDone
;
pySim
->
cond
->
notify_one
();
}
#endif
PyObject
*
PySimulation
::
newfunc
(
PyTypeObject
*
type
,
PyObject
*
args
,
PyObject
*
kwds
)
{
PySimulation
*
self
;
...
...
@@ -100,17 +173,27 @@ PyObject* PySimulation::newfunc(PyTypeObject* type, PyObject *args, PyObject *kw
}
int
PySimulation
::
init
(
PySimulation
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
{
static
char
*
kwlist
[]
=
{
"components"
,
"frequency"
,
"timestep"
,
"duration"
,
"log"
,
"llog"
,
"rlog"
,
NULL
};
static
char
*
kwlist
[]
=
{
"components"
,
"frequency"
,
"timestep"
,
"duration"
,
"log"
,
"llog"
,
"rlog"
,
"rt"
,
"start_sync"
,
NULL
};
double
frequency
=
50
,
timestep
=
1e-3
,
duration
=
DBL_MAX
;
const
char
*
log
=
nullptr
,
*
llog
=
nullptr
,
*
rlog
=
nullptr
;
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"O|dddsss"
,
kwlist
,
&
self
->
pyComps
,
&
frequency
,
&
timestep
,
&
duration
,
&
log
,
&
llog
,
&
rlog
))
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"O|dddsss
bb
"
,
kwlist
,
&
self
->
pyComps
,
&
frequency
,
&
timestep
,
&
duration
,
&
log
,
&
llog
,
&
rlog
,
&
self
->
rt
,
&
self
->
startSync
))
return
-
1
;
if
(
!
compsFromPython
(
self
->
pyComps
,
self
->
comps
))
{
PyErr_SetString
(
PyExc_TypeError
,
"Invalid components argument (must by list of dpsim.Component)"
);
return
-
1
;
}
#ifndef __linux__
if
(
self
->
rt
)
{
PyErr_SetString
(
PyExc_SystemError
,
"RT mode not available on this platform"
);
return
-
1
;
}
#endif
if
(
self
->
startSync
&&
!
self
->
rt
)
{
PyErr_Format
(
PyExc_ValueError
,
"start_sync only valid in rt mode"
);
return
-
1
;
}
Py_INCREF
(
self
->
pyComps
);
if
(
log
)
self
->
log
=
new
Logger
(
log
);
...
...
Source/PySimulation.h
View file @
52a33d1e
...
...
@@ -33,6 +33,9 @@ namespace DPsim {
std
::
thread
*
simThread
;
SimState
state
;
bool
rt
;
bool
startSync
;
PyObject
*
pyComps
;
// Components as a (Python) list of PyComponents
std
::
vector
<
BaseComponent
*>
comps
;
int
numSwitch
;
...
...
@@ -44,6 +47,9 @@ namespace DPsim {
// Function executed by the simulation thread
static
void
simThreadFunction
(
PySimulation
*
pySim
);
#ifdef __linux__
static
void
simThreadFunctionRT
(
PySimulation
*
pySim
);
#endif
// The Python API has no notion of C++ classes and methods, so the methods
// that can be called from Python are static.
...
...
Source/Simulation.h
View file @
52a33d1e
...
...
@@ -77,6 +77,7 @@ namespace DPsim {
double
getTime
()
{
return
mTime
;
}
double
getFinalTime
()
{
return
mFinalTime
;
}
double
getTimeStep
()
{
return
mSystemModel
.
getTimeStep
();
}
Matrix
&
getLeftSideVector
()
{
return
mSystemModel
.
getLeftSideVector
();
}
Matrix
&
getRightSideVector
()
{
return
mSystemModel
.
getRightSideVector
();
}
Matrix
&
getSystemMatrix
()
{
return
mSystemModel
.
getCurrentSystemMatrix
();
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment