# pyrun.py ---
#
# Filename: pyrun.py
# Description:
# Author: Subhasis Ray
# Maintainer:
# Created: Wed Oct 15 10:14:15 2014 (+0530)
# Version:
# Last-Updated:
# By:
# Update #: 0
# URL:
# Keywords:
# Compatibility:
#
#
# Commentary:
#
#
#
#
# Change log:
#
#
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street, Fifth
# Floor, Boston, MA 02110-1301, USA.
#
#
# Code:
import numpy as np
from matplotlib import pyplot as plt
import moose
[docs]def run_sequence():
"""In this example we demonstrate the use of PyRun objects to execute
Python statements from MOOSE. Here is a couple of fun things to
indicate the power of MOOSE-Python integration.
First we create a PyRun object called `Hello`. In its `initString`
we put in Python statements that prints the element's string
representation using pymoose-API. When ``moose.reinit()`` is
called, this causes MOOSE to execute these Python statements which
include Python calling a MOOSE function
(Python->MOOSE->Python->MOOSE) - isn't that cool!
We also initialize a counter called `hello_count` to 0.
The statements in initString gets executed once, when we call
``moose.reinit()``.
In the `runString` we put a couple of print statements to indicate
the name fof the object which is running and the current
count. Then we increase the count directly.
When we call ``moose.start()``, the `runString` gets executed at
each time step.
The other PyRun object we create, is `/World`. In its `initString`
apart from ordinary print statements and initialization, we define
a Python function called ``incr_count``. This silly little
function just increments the global `world_count` by 1.
The `runString` for `World` simply calls this function to
increment the count and print it.
We may notice that we assign tick 0 to `Hello` and tick 1 to
`World`. Looking at the output, you will realize that the
sequences of the ticks strictly maintain the sequence of
execution.
"""
model = moose.Neutral('/model')
hello_runner = moose.PyRun('/model/Hello')
hello_runner.initString = """
print 'Init', moose.element('/model/Hello')
hello_count = 0
"""
hello_runner.runString = """
print 'Running Hello'
print 'Hello count =', hello_count
hello_count += 1
"""
hello_runner.run('from datetime import datetime')
hello_runner.run('print "Hello: current time:", datetime.now().isoformat()')
moose.useClock(0, hello_runner.path, 'process')
world_runner = moose.PyRun('World')
world_runner.initString = """
print 'Init World'
world_count = 0
def incr_count():
global world_count
world_count += 1
"""
world_runner.runString = """
print 'Running World'
print 'World count =', world_count
incr_count()
"""
world_runner.run('from datetime import datetime')
world_runner.run('print "World: current time:", datetime.now().isoformat()')
moose.useClock(0, world_runner.path, 'process')
moose.reinit()
moose.start(0.001)
def input_output():
model = moose.Neutral('/model')
input_pulse = moose.PulseGen('/model/pulse')
#: set the baseline output 0
input_pulse.baseLevel = 0.0
#: We make it generate three pulses
input_pulse.count = 3
input_pulse.level[0] = 1.0
input_pulse.level[1] = 2.0
input_pulse.level[2] = 3.0
#: Each pulse will appear 1 s after the previous one
input_pulse.delay[0] = 1.0
input_pulse.delay[1] = 1.0
input_pulse.delay[2] = 1.0
#: Each pulse is 1 s wide
input_pulse.width[0] = 1.0
input_pulse.width[1] = 1.0
input_pulse.width[2] = 1.0
#: Now create the PyRun object
pyrun = moose.PyRun('/model/pyrun')
pyrun.runString = """
output = input_ * input_
print 'input =', input_
print 'output =', output
"""
pyrun.mode = 2 # do not run process method
moose.connect(input_pulse, 'output', pyrun, 'trigger')
output_table = moose.Table('/model/output')
moose.connect(pyrun, 'output', output_table, 'input')
input_table = moose.Table('/model/input')
moose.connect(input_pulse, 'output', input_table, 'input')
moose.setClock(0, 0.25)
moose.setClock(1, 0.25)
moose.setClock(2, 0.25)
moose.useClock(0, input_pulse.path, 'process')
#: this is unnecessary because the mode=2 ensures that `process`
#: does nothing
moose.useClock(1, pyrun.path, 'process')
moose.useClock(2, '/model/#[ISA=Table]', 'process')
moose.reinit()
moose.start(10.0)
#ts =
plt.plot(input_table.vector, label='input')
plt.plot(output_table.vector, label='output')
plt.legend()
plt.show()
[docs]def main():
"""You can use the PyRun class to run Python statements from MOOSE at
runtime. This opens up many possibilities of interleaving computing in
Python and MOOSE. You can also use this for debugging simulations.
The PyRun class can take a double input through `trigger`
field. Whenever another object sends an input to this field, the
`runString` is executed.
The fun part of this is that you can use the input value in your
python statements in `runString`. This is stored in a local
variable called `input_`. You can rename this by setting `inputVar`
field.
Things become even more interesting when you can send out a value
computed using Python. PyRun objects allow you to define a local
variable called `output` and whatever value you assign to this,
will be sent out through the source field `output` on successful
execution of the `runString`.
You can rename the output variable by setting `outputVar` field.
In this example, we send the output of a pulsegen object sending
out the values 1, 2, 3 during each pulse and compute the square of
these numbers in Python and set output to this square.
The calculated value is assigned to the `output` variable and in
turn sent out to a Table object's input and gets recorded.
By default PyRun executes the `runString` whenever a `trigger`
message is received and when its process method is called at each
timestep. In both cases it sends out the `output` value. Since
this may cause inaccuracies depending on what the Python
statements in `runString` do, a `mode` can be specified to disable
one of the above. We set ``mode = 2`` to disable the `process`
method. Note that this could also have been done by setting its
``tick = -1``.
``mode = 1`` will disable `trigger` message and ``mode = 0``, the
default, enables both.
"""
run_sequence()
moose.delete('/model')
input_output()
if __name__ == '__main__':
main()
#
# pyrun.py ends here