5.3 A Simple Computational Steering Example
5.3.3 The Steering Python Script
When operating the oscillator code from Python, we want to repeat the following procedure:
– adjust a parameter in Python,
– update the corresponding data structure in the F77 code, – run a number of time steps, and
– plot the solution.
5.3. A Simple Computational Steering Example 219 To this end, we create a functionsetprm()for transferring parameters in the Python script to the F77 code, and a functionrun(nsteps) for running the simulationnstepssteps and plotting the solution.
The physical and numerical parameters are variables in the Python script.
Their values can be set in a GUI or from command-line options, as we demon- strate in the scriptssimvizGUI2.pyandsimviz1.pyfrom Chapters 6.2 and 2.3, respectively. However, scripts used to steer simulations are subject to frequent changes so a useful approach is often to just hardcode a set of approprite de- fault values, for instance,
m = 1.0; b = 0.7; c = 5.0; func = ’y’; A = 5.0; w = 2*math.pi y0 = 0.2; tstop = 30.0; dt = 0.05
and then assign new values when needed, directly in the script file, or in an interactive Python session, as we shall demonstrate.
Thesetprm()function for transferring the physical and numerical param- eters from the Python script to the F77 code is just a short notation for a complete call to thescan2 F77 function:
def setprm():
oscillator.scan2(m, b, c, A, w, y0, tstop, dt, func)
Therun(nsteps)function calls thetimeloop2function in theoscillatormod- ule and plots the solution. We have here chosen to exemplify how theGnuplot module can be used directly to plot array data:
from scitools.numpyutils import seq, zeros maxsteps = 10000
n = 2
y = zeros((n,maxsteps)) step = 0; time = 0.0 import Gnuplot
g1 = Gnuplot.Gnuplot(persist=1) # (y(t),dy/dt) plot g2 = Gnuplot.Gnuplot(persist=1) # y(t) plot
def run(nsteps):
global step, time, y if step+nsteps > maxsteps:
print ’no more memory available in y’; return
y, step, time = oscillator.timeloop2(y, step, time, nsteps) t = seq(0.0, time, dt)
y1 = y[0,0:step+1]
y2 = y[1,0:step+1]
g1.plot(Gnuplot.Data(y1,y2, with=’lines’)) g2.plot(Gnuplot.Data(t, y1, with=’lines’))
In the present case we use 0 as base index foryin the Python script (required) and 1 in the F77 code. Such “inconsistency” is unfortunately a candidate for bugs in numerical codes, but 1 as base index is a common habit in Fortran routines so it might be an idea to illustrate how to deal with this.
-0.4 -0.3 -0.2 -0.1 0 0.1 0.2 0.3
0 2 4 6 8 10 12 14 16 -1.5
-1 -0.5 0 0.5 1 1.5
-0.4 -0.3 -0.2 -0.1 0 0.1 0.2 0.3
Fig. 5.1.Plots produced by an interactive session involving theoscillatormod- ule, as explained in Chapter 5.3.3. To the left is the displacementy(t), and to the right is the trajectory (y(t), y(t)).
The first plot is a phase space curve (y, dy/dt), easily created by extract- ing the steps0up to, but not including,step+1. We can write the extraction compactly asy[:,0:step+1]. To plot they(t) curve, we extract the first com- ponent of the solution for the same number of steps: y[0,0:step+1]. The corresponding t values are stored in an array t (note that we useseq from scitools.numpyutils to ensure that the upper limit,time, is included as last element, cf. Chapter 4.3.7).
A complete steering Python module is found in src/py/mixed/simviz/f2py/simviz_steering.py
This module imports the oscillator extension module, defines physical pa- rameters such asm,b,c, etc., and the previously shownsetprmandrunfunc- tions, plus more to be described later.
Let us demonstrate how we can perform a simulation in several steps.
First, we launch a Python shell (IPython or the IDLE shell) and import the steering interface to theoscillator program:
from simviz_steering import * We can now issue commands like
setprm() # send default values to the oscillator code run(60) # simulate the first 60 time steps
w = math.pi # change the frequency of the applied load setprm() # notify simulator about any parameter change run(120) # simulate for another 120 steps
A = 10 # change the amplitude of the applied load setprm()
run(100)
5.3. A Simple Computational Steering Example 221 The run function updates the solution in a plot on the screen so we can immediately see the effect of changing parameters and running the simulator.
To rewind the simulatornsteps, and perhaps change parameters and re- run some steps, thesimviz_steering module contains the function
def rewind(nsteps=0):
global step, time
if nsteps == 0: # start all over again?
step = 0 time = 0.0
else: # rewind nsteps
step -= nsteps time -= nsteps*dt
Here is an example in the interactive shell:
>>> from simviz_steering import *
>>> run(50)
>>> rewind(50)
>>> A=20
>>> setprm()
>>> run(50) # try again the 50 steps, now with A=20
A session where we check the effect of changing the amplitude and frequency of the load during the simulation can look like this:
>>> rewind()
>>> A=1; setprm(); run(100)
>>> run(300)
>>> rewind(200)
>>> A=10; setprm(); run(200)
>>>> rewind(200)
>>> w=1; setprm(); run(400)
With the following function fromsimviz_steering.py we can generate hard- copies of the plots when desired:
def psplot():
g1.hardcopy(filename=’tmp_phaseplot_%d.ps’ % step, enhanced=1, mode=’eps’, color=0, fontname=’Times-Roman’, fontsize=28) g2.hardcopy(filename=’tmp_y1_%d.ps’ % step,
enhanced=1, mode=’eps’, color=0, fontname=’Times-Roman’, fontsize=28)
Hopefully, the reader has realized how easy it is to create a dynamic working environment where functionality can be added on the fly with the aid of Python scripts.
Remark. You should not changedtduring a simulation without a complete rewind to time zero. The reason is that thetarray used for plottingy1(t) is based on a constant time step during the whole simulation. However, recom- puting the solution with a smaller time step is often necessary if the first try leads to numerical instabilities.