©1998-2003, michael aivazis pyre an introduction to the integration framework michael aivazis...
Post on 19-Dec-2015
215 views
TRANSCRIPT
©1998-2003, Michael Aivazis
Pyre
An introduction to the integration framework
Michael Aivazis
California Institute of Technology
DANSE Software Workshop
September 3-8, 2003
2
©1998-2003, Michael Aivazis
Outline
Overview of the framework
Crash course on python
Brief description of key infrastructure
3
©1998-2003, Michael Aivazis
Pyre: the integration framework
A simulation environment thatenables the non-expertdoes not hinder the expert
Target features for “end-users”:complete and intuitive simulation specificationreasonable defaults, consistency checks of input, good diagnosticseasy access to remote facilitiesstatus monitoring
Target features for “developers”:easy access to user inputshorter development cycle, good debugging support
Status as of March 1, 2003:Python scripts: 1300 classes, 70,000 lines of codeC++: 30000 lines of bindings and infrastructure
Largest run to-date:1764 processors, 2.7 mel solid fluid, 256x256x512 fluid~3k timesteps/24hrs~1.5 Tb of data
4
©1998-2003, Michael Aivazis
Distributed services
Workstation Front end Compute nodes
launcher
journal
monitoradlib
arm3d
5
©1998-2003, Michael Aivazis
Pyre Architecture
component
bindings
engine
solver
component
bindings
library
infrastructure
service
framework
service
serviceservice
component
bindings
engine
solver
abstract classabstract class
specializationspecialization
packagepackage
The integration framework is a set of co-operating abstract services
FORTRAN/C/C++FORTRAN/C/C++
pythonpython
6
©1998-2003, Michael Aivazis
Flexibility through the use of scripting
Scripting enables us toOrganize the large number of simulation parameters
Allow the simulation environment to discover new capabilities without the need for recompilation or relinking
The python interpreterThe interpreter
modern object oriented language
robust, portable, mature, well supported, well documented
easily extensible
rapid application development
Support for parallel programmingtrivial embedding of the interpreter in an MPI compliant manner
a python interpreter on each compute node
MPI is fully integrated: bindings + OO layer
No measurable impact on either performance or scalability
7
©1998-2003, Michael Aivazis
Solver integration
custom application driver
properties
geometry
materials
meshing
adv. features viz. support
checkpointsfem
Python bindings
pyadlib.so
MPDb VTFApplication
Controller Application
Mesher Solver StrengthModel
Pyre
8
©1998-2003, Michael Aivazis
Framework services
Problem specificationcomponents and their properties
Solid modelingoverall geometrymodel constructiontopological and geometrical information
Boundary and initial conditionshigh level specificationaccess to the underlying solver data structures in a uniform way
Materials and constitutive modelsmaterials properties databasestrength models and EOSassociation with a region of space
Computational enginesselection and association with geometry
solver specific initializations
coupling mechanism specification
Simulation driverinitialization
appropriate time step computation
orchestration of the data exchange
checkpoints and field dumps
Active monitoringinstrumentation: sensors, actuators
real-time visualization
Full simulation archiving
9
©1998-2003, Michael Aivazis
Writing python bindings
Given a “low level” routine, such as
and a wrapper
double adlib::StableTimeStep();
char pyadlib_stableTimestep__name__[] = "stableTimestep";PyObject * pyaldib_stableTimestep(PyObject *, PyObject * args){ double dt = adlib::StableTimeStep();
return Py_BuildValue("d", dt);}
dt = pyadlib.stableTimestep()
• one can place the result of the routine in a python variable
• The general case is not much more complicated than this
10
©1998-2003, Michael Aivazis
VTFApplication
Integrated applications in Pyre
MaterialModel
arm3d
pyarm3d
GrACE
pygrace
ACIS
pyacis
ARM3d
solid engine
pyadlib
Adlib
options
GUI
script
InterfaceManager
Geometry
Solver
Sensor/Probe
Monitor
Controller
Application
MPI
pympi
11
©1998-2003, Michael Aivazis
Pythia layout
pythia
pyre
journal
mpi
acis
simpleviz
the framework
simulation monitoring
bindings for MPI
solid modelling
integrated visualization
12
©1998-2003, Michael Aivazis
Pythia layout II – under construction
pythia
contact
cpt
elc
contact detection
fast level set generation
an Eulerian-Lagrangian coupler
hdf5 support for reading and writing hdf5 files
pulse
rigid
a trivial Eulerian solver
a trivial Lagrangian solver
plexus scalable meshing
13
©1998-2003, Michael Aivazis
Pyre layout I
pyre
applications
components
facilities
filesystem
geometry
application support
base classes for components
base classes for facilities
support for manipulating file systems
abstract operations on geometrical objects
graph support for building and visualizing graphs
handbook physical constants
ipa authentication daemons
14
©1998-2003, Michael Aivazis
Pyre layout II
pyre
monitors
network
parsing
parsers
properties
timers and other simulation monitors
network server and client support
infrastructure for lexical parsing
some parsers for text files
user settable parameters
units dimensional quantities
util miscellaneous functions
xml framework for parsing XML files
15
©1998-2003, Michael Aivazis
VTF layout II
vtf
io
metis
pulse
rigid
shells
abstract IO layer for checkpoints
graph partitioning
a simple Eulerian solver
a simple Lagrangian solver
shell finite elements
tetra scalable meshing
vtf base classes for VTF simulations
16
©1998-2003, Michael Aivazis
Overview of selected services
Services described hereapplication structure
properties: types and units
parallelism and staging
facilities, components
application monitoring
geometry specification
simulation control: controller, solver
support for integrated visualization
17
©1998-2003, Michael Aivazis
HelloApp
from pyre.application.Application import Application
class HelloApp(Application):
def run(self): print "Hello world!" return
def __init__(self): Application.__init__(self, "hello") return
# mainif __name__ == "__main__": app = HelloApp() app.main()
from pyre.application.Application import Application
class HelloApp(Application):
def run(self): print "Hello world!" return
def __init__(self): Application.__init__(self, "hello") return
# mainif __name__ == "__main__": app = HelloApp() app.main()
access to the base classaccess to the base class
18
©1998-2003, Michael Aivazis
Properties
Named attributes that are under direct user controlautomatic conversions from strings to all supported types
Properties havenamedefault valueoptional validator functions
Accessible from pyre.propertiesfactory methods: string, bool, int, float, sequence, scalar, vectorvalidators: less, greater, range, choice
The user can derive from Property to add new types
import pyre.properties as props
flag = props.bool("flag", True)name = props.string("name", "pyre")scale = props.scalar("scale", 1.0, props.greater(0))
19
©1998-2003, Michael Aivazis
Units
Properties can have units:
framework provides: scalar, vector
Support for units is in pyre.unitsfull support for all SI base and derived units
support for common abbreviations and alternative unit systems
correct handling of all arithmetic operations
addition, multiplication, functions from math
import pyre.properties as propsfrom pyre.units.time import s, hourfrom pyre.units.length import km, mile
speed = props.scalar("speed", 50*mile/hour, pyre.units.velocity)
velocity = props.vector("velocity", (0.0*m/s, 0.0*m/s, 10*km/s), pyre.units.velocity)
20
©1998-2003, Michael Aivazis
HelloApp: adding properties
from pyre.application.Application import Application
class HelloApp(Application): …
class Properties(Application.Properties):
import pyre.properties
__properties__ = Application.Properties.__properties__ + ( pyre.properties.string("name", "world"), )
…
from pyre.application.Application import Application
class HelloApp(Application): …
class Properties(Application.Properties):
import pyre.properties
__properties__ = Application.Properties.__properties__ + ( pyre.properties.string("name", "world"), )
…framework property factoriesframework property factories
21
©1998-2003, Michael Aivazis
from pyre.application.Application import Application
class HelloApp(Application):
def run(self): print "Hello %s!" % self.name return
def __init__(self): Application.__init__(self, "hello") self.name = self.properties.name return
…
from pyre.application.Application import Application
class HelloApp(Application):
def run(self): print "Hello %s!" % self.name return
def __init__(self): Application.__init__(self, "hello") self.name = self.properties.name return
…
HelloApp: using properties
data member tied to propertydata member tied to property
./hello.py --name="Michael"
• Now the name can be set by the user interface
22
©1998-2003, Michael Aivazis
Support for concurrent applications
Python as the driver for concurrent applications thatare embarassingly parallelhave custom communication strategies
sockets, ICE, shared memory
Excellent support for MPImpipython.exe: MPI enabled interpreter (needed only on some platforms)
mpi: package with python bindings for MPIsupport for staging and launchingcommunicator and processor group manipulationsupport for exchanging python objects among processors
mpi.Application: support for launching and staging MPI applicationsdescendant of pyre.application.Applicationauto-detection of parallelismfully configurable at runtimeused as a base class for user defined application classes
23
©1998-2003, Michael Aivazis
Parallel Python
Enabling parallelism in Python is implemented by:embedding the interpreter in an MPI application:
constructing an extension module with bindings for MPI
providing an objected oriented veneer for easy access
int main(int argc, char **argv) { int status = MPI_Init(&argc, &argv); if (status != MPI_SUCCESS) {
std::cerr << argv[0] << ": MPI_Init failed! Exiting ..." << std::endl;
return status; } status = Py_Main(argc, argv); MPI_Finalize(); return status;}
int main(int argc, char **argv) { int status = MPI_Init(&argc, &argv); if (status != MPI_SUCCESS) {
std::cerr << argv[0] << ": MPI_Init failed! Exiting ..." << std::endl;
return status; } status = Py_Main(argc, argv); MPI_Finalize(); return status;}
24
©1998-2003, Michael Aivazis
Python bindings for MPI
// return the communicator rank (MPI_Comm_rank)char pympi_communicatorRank__doc__[] = "";char pympi_communicatorRank__name__[] = "communicatorRank";PyObject * pympi_communicatorRank(PyObject *, PyObject * args){
PyObject * py_comm; int ok = PyArg_ParseTuple(args, "O:communicatorRank", &py_comm);
if (!ok) { return 0; }
// cast the Python object into a Communicator Communicator * comm = (Communicator *) PyCObject_AsVoidPtr(py_comm); int rank = comm->rank();
// return return PyInt_FromLong(rank);}
// return the communicator rank (MPI_Comm_rank)char pympi_communicatorRank__doc__[] = "";char pympi_communicatorRank__name__[] = "communicatorRank";PyObject * pympi_communicatorRank(PyObject *, PyObject * args){
PyObject * py_comm; int ok = PyArg_ParseTuple(args, "O:communicatorRank", &py_comm);
if (!ok) { return 0; }
// cast the Python object into a Communicator Communicator * comm = (Communicator *) PyCObject_AsVoidPtr(py_comm); int rank = comm->rank();
// return return PyInt_FromLong(rank);}
25
©1998-2003, Michael Aivazis
Access to MPI through Pyre
creates a new communicator bymanipulating the communicator group
creates a new communicator bymanipulating the communicator group
import mpi
# get the world communicatorworld = mpi.world()
# compute processor rank in MPI_COMM_WORLDrank = world.rank
# create a new communicatornew = world.include([0])if new: print “world: %d, new: %d” % (rank, new.rank)else: print “world: %d (excluded from new)” % rank
import mpi
# get the world communicatorworld = mpi.world()
# compute processor rank in MPI_COMM_WORLDrank = world.rank
# create a new communicatornew = world.include([0])if new: print “world: %d, new: %d” % (rank, new.rank)else: print “world: %d (excluded from new)” % rank
26
©1998-2003, Michael Aivazis
Parallel HelloApp
from mpi.Application import Application
class HelloApp(Application):
def run(self): import mpi world = mpi.world() print "[%03d/%03d] Hello world" % (world.rank, world.size) return
def __init__(self): Application.__init__(self, "hello") return
# mainif __name__ == "__main__": app = HelloApp() app.main()
from mpi.Application import Application
class HelloApp(Application):
def run(self): import mpi world = mpi.world() print "[%03d/%03d] Hello world" % (world.rank, world.size) return
def __init__(self): Application.__init__(self, "hello") return
# mainif __name__ == "__main__": app = HelloApp() app.main()
new base classnew base class
27
©1998-2003, Michael Aivazis
Staging
from pyre.application.Application import Application as Base
class Application(Base):
… class Facilities(Base.Facilities):
import StagingMPICH import pyre.facilities
__facilities__ = Base.Facilities.__facilities__ + ( pyre.facilities.facility("staging", StagingMPICH()), ) …
from pyre.application.Application import Application as Base
class Application(Base):
… class Facilities(Base.Facilities):
import StagingMPICH import pyre.facilities
__facilities__ = Base.Facilities.__facilities__ + ( pyre.facilities.facility("staging", StagingMPICH()), ) …
The new base class mpi.Applicationoverrides the initialization protocol
gives the user access to the application staging details
excerpt from mpi/Application/Application.pyexcerpt from mpi/Application/Application.py
28
©1998-2003, Michael Aivazis
Facilities and components
A design pattern that enables the assembly of application components at run time under user control
Facilities are named abstract application requirements
Components are concrete named engines that satisfy the requirements
Dynamic control:the application script author provides
a specification of application facilities as part of the Application definition
a component to be used as the default
the user can construct scripts that create alternative components that comply with facility interface
the end user can configure the properties of the component
select which component is to be bound to a given facility
29
©1998-2003, Michael Aivazis
Staging properties
Staging defines the following propertiesnodes: the number of processors (int)
dry: do everything except the actual call to mpirun (bool)
command: specify an alternative to mpirun (string)
extra: additional command line arguments to mpirun (string)
Running the parallel version of HelloApp:./hello.py --staging.nodes=4 –staging.dry=on
./hello.py --staging=asap --staging.nodes=4
Specifying an alternate staging configurationassuming that a script asap.py is in the current directory
or the equivalent
./hello.py --staging=asap --asap.nodes=4
30
©1998-2003, Michael Aivazis
Simulation monitoring
journal: a component for managing application diagnosticserror, warning, infodebug, firewall
Named categories under global dynamic control forpython, C, C++, FORTRAN
import journal
debug = journal.debug("hello")debug.activate()debug.log("this is a diagnostic")
Customizablemessage contentmeta-dataformattingoutput devices
console, files, sockets for remote transport
journal is a component!
31
©1998-2003, Michael Aivazis
Geometry specification
def geometry(): from pyre.units.length import mm side = 50.0*mm diameter = 25.0*mm scale = 5
from pyre.geometry.solids import block,cylinder from pyre.geometry.operations import rotate,subtract,translate
cube = block((side, side, side)) cube = translate(cube, (-side/2, -side/2, -side/2)) hole = cylinder(height=2*side, radius=diameter/2) z_hole = translate(hole, (0*side, 0*side, -side) y_hole = rotate(z_hole, (1,0,0), pi/2) x_hole = rotate(z_hole, (0,1,0), pi/2)
body = subtract(body, x_hole) body = subtract(body, y_hole) body = subtract(body, z_hole)
ils = min(radius, side – diameter)/scale
return pyre.geometry.body(body, ils)
def geometry(): from pyre.units.length import mm side = 50.0*mm diameter = 25.0*mm scale = 5
from pyre.geometry.solids import block,cylinder from pyre.geometry.operations import rotate,subtract,translate
cube = block((side, side, side)) cube = translate(cube, (-side/2, -side/2, -side/2)) hole = cylinder(height=2*side, radius=diameter/2) z_hole = translate(hole, (0*side, 0*side, -side) y_hole = rotate(z_hole, (1,0,0), pi/2) x_hole = rotate(z_hole, (0,1,0), pi/2)
body = subtract(body, x_hole) body = subtract(body, y_hole) body = subtract(body, z_hole)
ils = min(radius, side – diameter)/scale
return pyre.geometry.body(body, ils)
32
©1998-2003, Michael Aivazis
Geometry specification graph
Difference
Rotation
BlockCylinder
Translation
Difference
Difference
Translation
Rotation
body
,
,
33
©1998-2003, Michael Aivazis
def mesh(model): body = createBody(model)
import acis faceter = acis.faceter()
properties = faceter.properties properties.gridAspectRatio = 1.0 properties.maximumEdgeLength = body.ils boundary = faceter.facet(acis.create(body.geometry)) bbox = boundary.boundingBox()
return boundary, bbox
def mesh(model): body = createBody(model)
import acis faceter = acis.faceter()
properties = faceter.properties properties.gridAspectRatio = 1.0 properties.maximumEdgeLength = body.ils boundary = faceter.facet(acis.create(body.geometry)) bbox = boundary.boundingBox()
return boundary, bbox
Creating the model
the Python bindings for the solid modelerthe Python bindings for the solid modeler
convert the abstract geometrical description into an actual instance of the ACIS class BODY
convert the abstract geometrical description into an actual instance of the ACIS class BODY
abstract representation of the modelabstract representation of the model
35
©1998-2003, Michael Aivazis
Simulation control
Achieved through the collaboration of two componentsSimulationController (controller)
Solver (solver)
SimulationController expects Solver to conform to the following interfaceinitialize(), launch()
startTimestep(), endTimestep()
applyBoundaryConditions()
stableTimestep(), advance()
save: publishState(), plotFile(), checkpoint()
Both components provide (trivial but usable) default implementations
The facility/component pattern enables the selection and initialization of solvers by the end user
36
©1998-2003, Michael Aivazis
Advancing the solution in time
from pyre.components.Component import Component
class SimulationController(Component):
def march(self, totalTime=0, steps=0): while 1: solver.startTimestep() solver.applyBoundaryConditions() solver.save() dt = solver.stableTimestep() solver.advance(dt)
self.clock += dt self.step += 1 if totalTime and self.clock >= totalTime: break if steps and self.step >= step: break
solver.endSimulation() return
from pyre.components.Component import Component
class SimulationController(Component):
def march(self, totalTime=0, steps=0): while 1: solver.startTimestep() solver.applyBoundaryConditions() solver.save() dt = solver.stableTimestep() solver.advance(dt)
self.clock += dt self.step += 1 if totalTime and self.clock >= totalTime: break if steps and self.step >= step: break
solver.endSimulation() return
37
©1998-2003, Michael Aivazis
Visualization
Support for integrated remote visualization is provided by simpleviz
It is a default facility for vtf.Application
Three tier system: a data source embedded in the simulation
a data server
a client: visualization tools (such as IRIS Explorer)
The serveris a daemon that listens for socket connections from
data sources (mostly pyre simulations)
visualization tools
The clientis a default facility for vtf.Application
has the hostname and port number of the server
Demonstration later this afternoon