Building a Pyre component

From DANSE

Table of contents

Introduction

This tutorial should help you create a Pyre application from regular python code. For a discussion of what Pyre applications and components are see What is Pyre?.

Structure of A Pyre Application

Through the Pyre framework, other applications will be able to utilize your program by creating an instance of the "primary class" and invoking methods from that class. Since you will be creating a Pyre Application from your python file, the class should inherit from the Pyre Application module. Additionally, the primary class's name should be similar to the name of your python file or module. For instance, the multiphonon module with the file PyreMultiphonon.py contains the primary class MultiPhonon. Here is an example from PyreMultiphonon.py of how to start the primary class:

from pyre.applications.Application import Application

class MultiPhonon(Application):
    '''pyre adaptation of B. Fultz's Multiphonon code'''

The rest of the class contains the following:

Inventory Class

The Inventory class in a Pyre application inherits from Application.Inventory, and contains variables that the user (or pyre component from which your application was called) can modify. The variables are declared as types defined in pyre.inventory (e.g. int, float, str, etc.), and each variable is given a name and a default value.

The various types of factories, property types, and built-in validators allowd by the inventory are listed in ~/dv/pythia-0.6/packages/pyre/pyre/inventory/__init__.py as:

  • Factories
    • facility
    • curator
    • registry
  • Persistence
    • renderer
    • parser
  • Built-In Property Types
    • property (generic property)
    • str (string)
    • bool (boolean)
    • int (integer)
    • float (floating point)
    • list
    • slice
    • dimensional (handles numbers and units)
  • Built-In Validators
    • less
    • greater
    • range
    • choice

Here is an example of the Inventory class from PyreMultiphonon.py:

    class Inventory(Application.Inventory):
        '''Inventory declares and stores user modifiable variables'''

        import pyre.inventory    #for pythia0.6

        T = pyre.inventory.float('T', default=300.0)
        M = pyre.inventory.float('M', default=58.17)
        E_inc = pyre.inventory.float('E_inc', default=70.0)
        phi = pyre.inventory.float('phi', default=90.0)
        constQ = pyre.inventory.str('constQ', default=None)
        N_phonon = pyre.inventory.int('N_phonon', default=1)
        M_phonon = pyre.inventory.int('M_phonon', default=4)

Note that pyre.inventory must be imported, and that this format of storing variables for accessibility within the pyre framework is specific to pythia-0.6 (there is different syntax for pythia-0.5 and earlier versions).

Config Method

The config method is where variables declared in the Inventory class can be given different values. Each entry in the dictionary kwds contains a 'key' equal to one of the inventory variables, and a corresponding 'value' to which config sets that inventory variable. Here is the config method that would correspond to the Inventory from PyreMultiphonon.py:

    def config(self, **kwds):
        '''config modifies the variables used in the inventory by accepting
a dictionary of keywords and values; this dictionary can be passed directly
as a function call, or indirectly using the commandline parser'''
        for key,value in kwds.items():
            if key == 'T':
                self.inventory.T = value
            elif key == 'M':
                self.inventory.M = value
            elif key == 'E_inc':
                self.inventory.E_inc = value
            elif key == 'phi':
                self.inventory.phi = value
            elif key == 'constQ':
               self.inventory.constQ = value
            elif key == 'N_phonon':
                self.inventory.N_phonon = value
            elif key == 'M_phonon':
                self.inventory.M_phonon = value
         return

Entries can be created in the kwds dictionary in several ways.

  • When an instance of the primary class is created:
    mp = MultiPhonon('mptest', E_inc=75.0, phi=95.0)
  • After the instance of the primary class is created:
    mp.config(phi=85.5)
If an inventory variable is not specifically set through kwds, it retains the default value given in the Inventory class. It is important to note that when launching the application from the commandline, i.e.
python PyreSpinStructure.py -T_kind=fixedT
config is not used. Handling of keywords and values are done by Pyre's commandline parser, and passed directly to the inventory.


Run Method

The run method contains the main code block from the original python program. By putting the main code block here, the program will execute when an instance of the primary class is created and the method main is called (see the 'Main Function' section). In order for the main code block to remain relatively unedited, the run method should first do the following:

  • Declare a local variable for each variable in the Inventory. For instance, run in PyreMultiphonon.py might contain the local variable:
            T = self.inventory.T
    This prevents you from having to replace T with self.inventory.T throughout the main code block.
  • Make sure your main code is not interactive. Remove lines that prompt the user for data, settings, or variable values, and instead incorporate those user-defined variables into the Inventory.

Here is an example of the run method adapted from PyreMultiphonon.py:

    def run(self):
        '''the main code block; adapted from multiphonon/Multiphonon.py'''
        # pass inventory into non-global variables (function calls are tidy)
        T = self.inventory.T
        M = self.inventory.M
        E_inc = self.inventory.E_inc
        phi = self.inventory.phi
        Q = self.inventory.constQ
        if Q not in [None,'None']:      # To make sure Q is a string (?)
            exec "Q = %s" % Q
        N_phonon = self.inventory.N_phonon
        M_phonon = self.inventory.M_phonon

        ### BEGIN MAIN CODE BLOCK ###
        #  ... cut-N-paste the 'Multiphonon.py' run() code here...
        ### END MAIN CODE BLOCK ###
        return

Init Method

The init method is the constructor for the primary class. When an object of the primary class is created, init calls the constructor for Application (since the primary class inherits from Application). It also calls config and passes it the kwds dictionary. Here is the init method from PyreMultiphonon.py:

    def __init__(self, name, **kwds):
        '''instantiate the application, and pass any keywords to config'''
        Application.__init__(self, name)
        self.config(**kwds)
        return

Accessing the Main Code Block Functionality

As described above, the functionality of a Pyre component or application is accessed by creating an object and calling the run method. This can be done in the same file that contains the class definition, or through a separate file that imports the first. In either case, this involves several steps:

  • Create an instance of the primary class.
  • Use Pyre's 'Journal' with the class instance for debugging purposes. (optional)
  • Modify user-definable variables in the Inventory. (optional)
  • Call 'main' on the class instance to run the main code block.

Within the Same File

If the Pyre application is called from the command line, a 'main' can execute for debugging or demonstration purposes. For example, if PyreMultiphonon.py is called from the command line:

python PyreMultiphonon.py

then 'main' in PyreMultiphonon.py will execute:

if __name__ == '__main__':
    '''begin journaling services to log input/output/errors for Multiphonon instance, 
and then run the main code block'''

    import journal
    mp = MultiPhonon('mptest')             #instance of class MultiPhonon (named 'mptest')
    journal.debug('mptest').activate()     #activate journal for 'mptest'

    mp.main()                              #launch the main code block ('MultiPhonon.run')

However, if PyreMultiphonon is imported as a module, __name__ will not be set to '__main__' and therefore nothing will automatically execute.

From a Separate File

Here is an example of a separate file importing PyreMultiphonon.py and accessing the main code block:

'''a simple example demonstrating use of PyreMultiphonon.py'''

# import from the multiphonon package (namespace)
from multiphonon.PyreMultiphonon import *

#instantiate a MultiPhonon instance
mp = MultiPhonon('mptest')
#run the main code block
mp.main()

#use the previous configuration, but with a different 'temperature'
mp.config(T=500.0)
#run the main code block
mp.main()

Examples of Pyre Applications

The multiphonon example referenced throughout this tutorial is available through cvs at arcs.cacr.caltech.edu:/home/arcs/cvs/phonon_calcs/multiphonon/.

Personal tools
Document Uploads/Links