(Post 29/08/2006) In this section, we define
a simple cellular problem and show how we would write the Java code that
uses OptimalGrid to study the problem.
Các phần đã đăng:
Section 5. Writing an OptimalGrid problem solver
Introduction
In this section, we define a simple cellular problem
and show how we would write the Java code that uses OptimalGrid to study
the problem.
As we go along, we'll provide links to the full Java
source code for the Java classes that we describe. If you have downloaded
and installed OptimalGrid, then you can also access the JavaDoc for the
OptimalGrid system. If you installed OptimalGrid
into C:\java , then you can use the following URL address:
file://localhost/C:/java/grid/html/javadoc/index.html
Eden model
For our example, we will use the Eden model for bacterial
growth. In our problem, we have three entities representing three types
of bacteria (A, B, and C) that are growing in a two-dimensional space
(petri Dish). We use Cartesian coordinates so the smallest elements or
cells in this space are squares with sides of unit length. In the Eden
model, each OPC represents a cell that may contain an entity that represents
one of the 3 kinds of bacteria. Each cell also contains the methods or
rules that describe how the entities interact on site and how they spread
or propagate to other sites. The entities contain information about to
interact with other entities. In this example, the interaction method
causes A to eat B, B to eat C, and C to eat A. The propagation method
describes how the bacteria spread. Propagation to adjacent sites or cells
requires that each cell also store pointers to (nearest) neighbors. These
pointers define a graph and, together with the propagation method, add
the communication requirement to the problem. In the example, the propagate
method causes, at every iteration, an entity at site (i,j) to spread to
its nearest neighbors at sites (i+1,j),(i-1,j),(i,j+1),(i,j-1) each with
probability 0.5.
We will study the resulting spread of bacteria visually.
Figure 5 shows the status of the three types of bacteria at four different
points in time.
Define Java class for Eden model cell
The first step is to define a Java class that defines
the contents of and methods used by the OPC.
See the Code listing for OPCEden class.
For this problem, we will implement an OPCEden Java class
that extends the OPCAbstract class. OPCAbstract contains the data and
behavior that is required for any OPC object.
public class OPCEden extends OPCAbstract
implements Serializable, Cloneable {
|
An OPCEden class contains two methods that are run at
each iteration of the problem.
- propagation()
- localInteraction()
The propagation() method describes how the bacteria
spread. Propagation to adjacent sites or cells requires that each cell
also store pointers to (nearest) neighbors. These pointers define a graph
and together with the propagation method add the communication requirement
to the problem. In the example, the propagate method causes, at every
iteration, a bacteria at site (i,j) to spread to its nearest neighbors
at sites (i+1,j),(i-1,j),(i,j+1),(i,j-1) each with probability 0.4 (the
classic Eden model for bacterial growth).
The localInteraction() method causes bacteria
A to eat B, B to eat C, and C to eat A.
When the problem is run with a grid of networked machines,
one or more neighbors of an OPC may reside on a separate machine, but
that is transparent to the OPCEden class.
Define Java class for the Eden entity
An Eden OPC may contain occupants that represent a type
of bacteria of a specified type or species (i.e. A, B or C) that is living
in the cell. It has a foodID attribute that represents the type of food
(another type of bacteria in this predator prey example) that it will
eat. For this example code, bacteria A eats B; B eats C; and C eats A.
In other models, entities might represent a fluid, an electron or electron
density, local stress, bacteria, heat, temperature, etc. For our Eden
model, we will define a Java class, EntityEden, that describes
the bacteria.
See the Code Listing for EntityEden class.
public class EntityEden extends EntityAbstract
implements Serializable, Cloneable {
|
An EntityEden class uses the following instance variables.
- _entityID ID of this bacteria. Inherited from EntityAbstract
- _foodID ID of the bacteria this bacteria will eat.
- _alive true if the bacteria is alive
- _propagationprob Probability that this bacteria will propagate
to its neighbor
- _rgbColor Color assigned to this bacteria. This is inherited
from EntityAbstract and is used for graphical representation of the
problem.
Define Java class for Eden properties
An Eden OPC may contain properties that represent the
properties assigned to this OPC. Properties might be local elastic constants,
local hardness, local conductivity, thermal conductivity, heat capacity,
and so forth. For our Eden model, we will define the PropertyEden which
describes the adjustment to the probability with which bacteria associated
with an OPC will propagate to its neighbors.
See the Code listing for PropertyEden class.
Eden model propagate() method
The important parts of the OPCEden.propagate()
method are shown below.
See the Code listing for OPCEden Propagate().
The propagate() method is passed the following
parameters.
- int collectionIndex_ -- Index to the OPCCollection
- VppAbstract vpp_ -- Reference to the VPP for this OPC element
- int iteration_ -- Iteration number
- Random rnd_ -- Random number generator
public synchronized ArrayList propagate(int collectionIndex_,
VppAbstract vpp_, int iteration_, Random rnd_) {
|
It will now get a list of all the neighboring OPCs.
ArrayList tempArray = this.getAllOPCNeighbors(collectionIndex_, vpp_);
|
It will now iterate through the neighboring OPCs and
for each one call the processNeighbor() method that will handle
propagation between that OPC back to the current OPC.
Iterator iter = tempArray.iterator();
while (iter.hasNext()) {
// get the collection element
OPCEden OPCNeighbor = (OPCEden) iter.next();
// propagate neighbors entities to newOccupants
processNeighbor(OPCNeighbor,newOccupants,vpp_,iteration_,rnd_);
} // while hasNext
|
Now it has in newOccupants a list of competing
entities. We will return this new ArrayList. Note that we do
not store it yet in the current OPC because when we process the next OPC,
it will look at this OPC as a neighbor and we want it to be unchanged.
The ArrayList that we return here will be an input to the localInteraction
method.
Eden model localInteration() method
The following is the important code for the OPCEden localInteraction()
method.
See the Code listing for OPCEden localInteraction().
The localInteraction() method is passed a reference
to the VPP, the iteration number and an ArrayList of competing entity
objects that belong to this OPC as the result of the propagation()
method.
public synchronized void localInteraction(VppAbstract vpp_, \
int iteration_, ArrayList occupants_) {
|
It will now go through the list of competing entities,
and based on the rules of which bacteria (entities) eat which, it will
come up with only one remaining bacteria. Remember! A eats B, B eats C,
and C eats A.
// are there any occupants?
if ((occupants_ != null) && (occupants_.size() > 1)) {
// yes, then loop through them
for (int i = 0; i < occupants_.size(); i++) {
for (int j = 0; j < occupants_.size(); j++) {
if (i == j) continue;
EntityEden obj1 = (EntityEden) occupants_.get(i);
EntityEden obj2 = (EntityEden) occupants_.get(j);
// obj2._foodID contains the type of food that obj2 eats.
// so if it matches the EntityID for obj1, then obj2 eats obj1.
if (obj2.isAlive() && (obj2.getFoodID() == obj1.getEntityID())) {
//yes, then obj1 is dead
obj1.setAlive(false);
}
} // for j
} // for i. First loop checks for predators
|
It will now go through the list of occupants and remove
the dead ones.
for (Iterator iter = occupants_.iterator(); iter.hasNext();) {
EntityEden obj1 = (EntityEden) iter.next();
if ( ! obj1.isAlive() ) {
// no, then log the population change and remove it
vpp_._valueMonitor.accumulateValueData(iteration_, obj1.getEntityID(), -1);
iter.remove();
}
} // iterate. Second loop removed dead occupants
} // end if not null or empty
|
It will now save the list of EntityEden objects to the
OPCEden instance.
super.setOccupants(occupants_);
|
EntityEden class
The following is the important part of the code for the
EntityEden class.
See also Code Listing for EntityEden class.
public class EntityEden extends EntityAbstract {
private boolean _dead = false;
private double _propagationProb;
private int _foodID = 0;
/**
* Types of bacteria are TYPE_A, TYPE_B and TYPE_C
*
* TYPE_A eats TYPE_B; TYPE_B eats TYPE_C and TYPE_C eats TYPE_A
*/
public static final int TYPE_A = 5;
public static final int TYPE_B = 3;
public static final int TYPE_C = 2;
/**
* Predefined entities used by VppEdenInitializer to set up
* initial conditions
*/
public static final EntityEden ENTITY_A = new EntityEden(
TYPE_A,TYPE_B,0.4);
public static final EntityEden ENTITY_B = new EntityEden(
TYPE_B,TYPE_C,0.4);
public static final EntityEden ENTITY_C = new EntityEden(
TYPE_C,TYPE_A,0.4);
/**
*
* Construct and EntityEden with default values.
* This public constructor is required so that the XML support
* can dynamically build from an XML file.
*/
public EntityEden() {
}
/**
* Builds an Eden entity instance which describes a bacteria.
* @param entityID_ The type of bacteria TYPE_A, TYPE_B or TYPE_C
* @param foodID_ Food: The type of bacteria this one eats
* @param double propagationProb_ The propagation probability
*/
public EntityEden(int entityID_, int foodID_, double propagationProb_) {
_propProb = propagationProb_;
_entityID = entityID_;
_alive = true;
_foodID = foodID_;
// define the color based on type
if (_entityID == TYPE_A) {
_rgbColor = Color.RED.getRGB();
} else if (_entityID == TYPE_B) {
_rgbColor = Color.GREEN.getRGB();
} else if (_entityID == TYPE_C) {
_rgbColor = Color.BLUE.getRGB();
} else {
Debug.error("EntityEden:"," Invalid Entity. entityID="+_entityID);
}
}
|
EntityEden Class, continued
The following two sections show the getXML and
initFromXML methods that are part of the code for the EntityEden
class.
Because the entityEden class has added some
new instance variables (_foodID and _propagationProb),
it needs to add these to the generated XML and be able to initialize the
value when the XML is read back in. This is taken care of by the getXML()
and initFromXML() methods which are shown below. These two
methods are required in EntityEden and PropertyEden because
they have added unique instance variables. If OPCEden had added
instance variables, it would require these methods also. If they are not
included, the XML created and read by the problem would not be complete.
Note that the instance variable _dead is not specified. It is
only used to pass state from the propagate() method to the localInteraction()
method and is not needed to show state at the end of an interval.
/**************************************************************************
** getXML() **
*******************/
/**
*
* Generates an XML representation of an entity object
* to be appended to the EntityElement by the XMLOPCCollectionWriter.
* These elements contain any data unique to a class
* extending EntityAbstract (this class).
*
* The XML support will generate something like the following for
* the EntityAbstract object. Note that the code in this method has
* added "food="3" to the attributes.
*
*
*
*
*
*
*
*
* This element must contain all data unique to a class extending
* entityAbstract. The first thing the getXML() method implementation
* should do in any class extending entityAbstract is to call
* the getXmlElement() method from its superclass to get the basic
* XML for an abstract entity.
*
* Uses the libraries defining element defined in org.jdom
*
* @see com.ibm.almaden.smartgrid.EntityAbstract
*
*
* @returns entityElement the XML representation for an EntityEden class
*
*
***************************************************************************
*/
public Element getXML() {
// It must first call the getXMLElement for the entityAbstract
Element entityElement = super.getXmlElement();
// now add the _foodID and _probProb attribute to the XML.
entityElement.setAttribute(PROBABILITY, "" + this._propProb);
entityElement.setAttribute(FOOD_ID, "" + this._foodID);
return entityElement;
}// getXML()
|
More about the EntityEden class
This is the initFromXML() method
/**************************************************************************
** initFromXML() **
*******************/
/**
** Required method. Generates a new EntityEden instance from
* an XML representation of the entity.
*
* This method initializes an EntityEden object based on the
* XML that was created by the getXML() method.
* Using the following line of XML, the EntityEden instance
* will be recreated including the "foodID" value that this class
* defines.
*
*
*
*
*
** Generates a new EntityEden instance from an XML element
* The first thing any entity.initFromXML() method must do
* is call super. initCommonSubsetFromXML() to initialize
* those entities characteristic of any class extending
* entityAbstract.
*
* Uses the libraries
* org.jdom.Element;
*
* @see com.ibm.almaden.smartgrid.EntityAbstract
*
* @param entityElement_ the xml representation of a property object
*
*
*
***************************************************************************
*/
public void initFromXML(Element entityElement_) {
super.initCommonSubsetFromXML(entityElement_);
this._propProb = getDoubleAttribute(entityElement_, PROBABILITY);
this._foodID = getIntAttribute(entityElement_, FOOD_ID);
}// initFromXMLL()
|
PropertyEden class
The Property class defines any properties that
may apply to the OPC or its entities. In this example of the Eden model,
the PropertyEden class is used to modify the propagation of the
EntityEden objects (the bacteria). In other models, properties
might be local elastic constants, local hardness, local conductivity,
thermal conductivity, heat capacity, and so forth.
The adjustment to the probability value is a new instance
variable in the PropertyEden class. If the PropertyId
matches the entity, then the propagation probability is increased
by the PropertyEden probability value. Otherwise, it is decreased
by that value. Think of this class as an abstract property or factor that
makes a specific OPC more or less friendly to a particular type of bacteria.
Because the probability value is an addition to PropertyAbstract
instance variables, it requires getXML() and initFromXML()
methods similar to the EntityEden methods.
See the Code listing for PropertyEden class.
VppEdenInitializer Class
The VppEdenInitializer class extends VppDataInitializerAbstract.
Most applications will need to provide a class to initialize
the state of the application specific OPCs in the original collections
describing a problem at time zero (the beginning of a run). If the OPC
classes have application-specific data they will require application-specific
initializers. These classes are used when a run is started using the ProblemAutoBuilder
which constructs the problem state from scratch. These classes are not
required when launching a problem with the ProblemBuilderXML
as the problem state defined in the XML documents are, presumably, properly
initialized.
The VppEdenInitializer class determines what
bacteria (what entities) are placed in new OPCEden instances
used to populate the initial collections. For now, properties are not
set by VppEdenInitializer. The VppEdenInitializer picks
one collection in each VPP and puts an instance of each of the three EntityEden
bacteria types in different OPCEden objects.
See the Code Listing for VppEdenInitializer class.
AppUtils class
The Eden model does not use a specific application utility
class. All the data and methods required for the Eden model are contained
in the OPC class (so the Eden model, by default, uses the empty
class AppUtilsGeneric). The application programmer can define
a class that implements the AppUtilsAbstract class. It can contain
application-specific utility functions and data that can be initialized
from the application configuration file at startup. Every OPC can share
one instance of an implementation of AppUtilsAbstract. This provides
an efficient place to store data and/or methods common to every OPC in
an application. It is not required that the user implement this utility.
By default, the AppUtilsGeneric class is used.
See the Code listing for AppUtilsGeneric class.
eden.cfg file
Every application can specify an application-specific
config file. If not required, the grid.cfg file sets the necessary
defaults. We suggest that developers always use an application-specific
configuration if for no other reason than to specify in a concise way
the necessary class files used for their application. See the eden.cfg
file file provided in the distributed example. The VppEdenInitializer
code show an example of the simple code needed to access the configuration
data.
An excerpt from both the system configuration file, grid.cfg,
and the problem configuration file, eden.cfg, is shown below:
# grid.cfg
[a]
...
appConfigFile = ./eden.cfg
...
# eden.cfg
# This is the configuration file for the Eden model application
# running on OptimalGrid
#-----------------------------------------------------------
# The [problem] section contains general specifications for
# the Eden model problem
#-----------------------------------------------------------
#
[problem]
OPCClass = com.ibm.almaden.smartgrid.apps.eden.OPCEden
utilClass = com.ibm.almaden.smartgrid.AppUtilsGeneric
vppInitializerClass = com.ibm.almaden.smartgrid.\
apps.eden.VppEdenInitializer
|
The name of the config file to use can be set in the
grid.cfg file as shown above or it can be specified on the command line.
./grid.bat -problemConfig ./eden.cfg
When the problem manager is started, a dialog window
will be displayed so that you can make temporary changes to the OptimalGrid
configuration.
Further problem termination
When the problem terminates, the final status of each
OPC is written as XML. You could use this XML output file to start another
OptimalGrid session or write your own data reduction program to read and
process the XML.
The following is an excerpt of the XML that is written
for the Eden model problem.
<?xml version="1.0" encoding="UTF-8"?> <OptimalGrid> <OPCCollection Name="c0" Number="0" Size="144" VppOwner="VPP_0"
LocalTime="401"> <MinCoord xVal="0" yVal="0" zVal="0" /> <MaxCoord xVal="11" yVal="11" zVal="0" /> <CollectionEdge Index="0" UniqueKey="c0.0"> <RequiredConnection ReqKey="c1.0" VppOwnerName="VPP_1" /> </CollectionEdge> <CollectionEdge Index="1" UniqueKey="c0.1"> <RequiredConnection ReqKey="c4.0" VppOwnerName="VPP_0" /> </CollectionEdge> <CollectionEdge Index="2" UniqueKey="c0.2"> <RequiredConnection ReqKey="c1.2" VppOwnerName="VPP_1" /> <RequiredConnection ReqKey="c4.1" VppOwnerName="VPP_0" /> </CollectionEdge> <collectionArray> <OPC Index="0" parentEdgeID="-1" parentEdgeIndex="-1"> <class name="class com.ibm.almaden.smartgrid.apps.eden.OPCEden" /> <Coords xVal="0" yVal="0" zVal="0" /> <localNeighbor Id="1" /> <localNeighbor Id="12" /> <entityAbstract Id="5" color="16711680" prob="0.4" food="3"> <class name="class com.ibm.almaden.smartgrid.apps.eden.EntityEden" /> </entityAbstract> </OPC> <OPC Index="1" parentEdgeID="-1" parentEdgeIndex="-1"> <class name="class com.ibm.almaden.smartgrid.apps.eden.OPCEden" /> <Coords xVal="1" yVal="0" zVal="0" /> <localNeighbor Id="2" /> <localNeighbor Id="0" /> <localNeighbor Id="13" /> <entityAbstract Id="2" color="255" prob="0.4" food="5"> <class name="class com.ibm.almaden.smartgrid.apps.eden.EntityEden" /> </entityAbstract> </OPC> ... |
(Copyright IBM Corporation) |