PartitionedDomain.cpp

Go to the documentation of this file.
00001 /* ****************************************************************** **
00002 **    OpenSees - Open System for Earthquake Engineering Simulation    **
00003 **          Pacific Earthquake Engineering Research Center            **
00004 **                                                                    **
00005 **                                                                    **
00006 ** (C) Copyright 1999, The Regents of the University of California    **
00007 ** All Rights Reserved.                                               **
00008 **                                                                    **
00009 ** Commercial use of this program without express permission of the   **
00010 ** University of California, Berkeley, is strictly prohibited.  See   **
00011 ** file 'COPYRIGHT'  in main directory for information on usage and   **
00012 ** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.           **
00013 **                                                                    **
00014 ** Developed by:                                                      **
00015 **   Frank McKenna (fmckenna@ce.berkeley.edu)                         **
00016 **   Gregory L. Fenves (fenves@ce.berkeley.edu)                       **
00017 **   Filip C. Filippou (filippou@ce.berkeley.edu)                     **
00018 **                                                                    **
00019 ** ****************************************************************** */
00020                                                                         
00021 // $Revision: 1.5 $
00022 // $Date: 2006/01/10 00:33:09 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/domain/domain/partitioned/PartitionedDomain.cpp,v $
00024                                                                         
00025                                                                         
00026 // Written: fmk 
00027 // Revision: A
00028 //
00029 // Description: This file contains the class definition for PartitionedDomain.
00030 // PartitionedDomain is an abstract class. The class is responsible for holding
00031 // and providing access to the Elements, Nodes, LoadCases, SP_Constraints 
00032 // and MP_Constraints just like a normal domain. In addition the domain provides
00033 // a method to partition the domain into Subdomains.
00034 //
00035 // ModelBuilder. There are no partitions in a PartitionedDomain.
00036 //
00037 // What: "@(#) PartitionedDomain.C, revA"
00038 
00039 #include <PartitionedDomain.h>
00040 #include <stdlib.h>
00041 
00042 #include <DomainPartitioner.h>
00043 #include <Element.h>
00044 #include <Node.h>
00045 #include <SP_Constraint.h>
00046 #include <MP_Constraint.h>
00047 #include <ArrayOfTaggedObjects.h>
00048 #include <ArrayOfTaggedObjectsIter.h>
00049 #include <Subdomain.h>
00050 #include <DomainPartitioner.h>
00051 #include <PartitionedDomain.h>
00052 #include <PartitionedDomainEleIter.h>
00053 #include <PartitionedDomainSubIter.h>
00054 #include <SingleDomEleIter.h>
00055 #include <Vertex.h>
00056 #include <Graph.h>
00057 #include <LoadPattern.h>
00058 #include <NodalLoad.h>
00059 #include <ElementalLoad.h>
00060 #include <SP_Constraint.h>
00061 #include <Recorder.h>
00062 
00063 PartitionedDomain::PartitionedDomain()
00064 :Domain(),
00065  theSubdomains(0),theDomainPartitioner(0),
00066  theSubdomainIter(0), mySubdomainGraph(0)
00067 {
00068     elements = new ArrayOfTaggedObjects(1024);    
00069     theSubdomains = new ArrayOfTaggedObjects(32);
00070     theSubdomainIter = new PartitionedDomainSubIter(theSubdomains);
00071 
00072     mainEleIter = new SingleDomEleIter(elements);    
00073     theEleIter = new PartitionedDomainEleIter(this);
00074     
00075     if (theSubdomains == 0 || elements == 0 ||
00076         theSubdomainIter == 0 || 
00077         theEleIter == 0 || mainEleIter == 0) {
00078         
00079         opserr << "FATAL: PartitionedDomain::PartitionedDomain ";
00080         opserr << "  - ran out of memory\n";
00081         exit(-1);
00082     }
00083 }
00084 
00085 
00086 PartitionedDomain::PartitionedDomain(DomainPartitioner &thePartitioner)
00087 :Domain(),
00088  theSubdomains(0),theDomainPartitioner(&thePartitioner),
00089  theSubdomainIter(0), mySubdomainGraph(0)
00090 {
00091     elements = new ArrayOfTaggedObjects(1024);    
00092     theSubdomains = new ArrayOfTaggedObjects(32);
00093     theSubdomainIter = new PartitionedDomainSubIter(theSubdomains);
00094 
00095     mainEleIter = new SingleDomEleIter(elements);    
00096     theEleIter = new PartitionedDomainEleIter(this);
00097     
00098     if (theSubdomains == 0 || elements == 0 ||
00099         theSubdomainIter == 0 || theDomainPartitioner == 0 ||
00100         theEleIter == 0 || mainEleIter == 0) {
00101         
00102         opserr << "FATAL: PartitionedDomain::PartitionedDomain ";
00103         opserr << "  - ran out of memory\n";
00104         exit(-1);
00105     }
00106 }
00107 
00108 
00109 PartitionedDomain::PartitionedDomain(int numNodes, int numElements,
00110                                      int numSPs, int numMPs, int numLoadPatterns,
00111                                      int numSubdomains,
00112                                      DomainPartitioner &thePartitioner)
00113 
00114 :Domain(numNodes,0,numSPs,numMPs,numLoadPatterns),
00115  theSubdomains(0),theDomainPartitioner(&thePartitioner),
00116  theSubdomainIter(0), mySubdomainGraph(0)
00117 {
00118     elements = new ArrayOfTaggedObjects(numElements);    
00119     theSubdomains = new ArrayOfTaggedObjects(numSubdomains);
00120     theSubdomainIter = new PartitionedDomainSubIter(theSubdomains);
00121 
00122     mainEleIter = new SingleDomEleIter(elements);    
00123     theEleIter = new PartitionedDomainEleIter(this);
00124     
00125     if (theSubdomains == 0 || elements == 0 ||
00126         theSubdomainIter == 0 || 
00127         theEleIter == 0 || mainEleIter == 0) {
00128         
00129         opserr << "FATAL: PartitionedDomain::PartitionedDomain(int ..) ";
00130         opserr << "  - ran out of memory\n";
00131         exit(-1);
00132     }
00133 }
00134 
00135 
00136 
00137 
00138 PartitionedDomain::~PartitionedDomain()
00139 {
00140   this->clearAll();
00141 
00142   if (elements != 0)
00143     delete elements;
00144   
00145   if (theSubdomains != 0)
00146     delete theSubdomains;
00147   
00148   if (theSubdomainIter != 0)
00149     delete theSubdomainIter;
00150   
00151   if (theEleIter != 0)
00152     delete theEleIter;
00153 }
00154 
00155 void
00156 PartitionedDomain::clearAll(void)
00157 {
00158   this->Domain::clearAll();
00159   elements->clearAll();
00160 
00161   SubdomainIter &mySubdomains = this->getSubdomains();
00162   Subdomain *theSub;
00163   while ((theSub = mySubdomains()) != 0) 
00164     theSub->clearAll();
00165 
00166   theSubdomains->clearAll();
00167 }
00168     
00169 
00170 
00171 bool 
00172 PartitionedDomain::addElement(Element *elePtr)
00173 {
00174   if (elePtr->isSubdomain() == true)
00175     return this->addSubdomain((Subdomain *)elePtr);
00176 
00177   int eleTag = elePtr->getTag();
00178 #ifdef _DEBUG      
00179     if (check == true) {
00180 
00181         // check ele Tag >= 0
00182         if (eleTag < 0) {
00183             opserr << "PartitionedDomain::addElement - Element " << eleTag;
00184             opserr << " tag must be >= 0\n";
00185             return false;
00186         }      
00187         
00188         // check its not in this or any of the subdomains
00189         // MISSING CODE 
00190         
00191         // check all the elements nodes exist in the domain
00192         const ID &nodes = elePtr->getExternalNodes();
00193         for (int i=0; i<nodes.Size(); i++) {
00194             int nodeTag = nodes(i);
00195             Node *nodePtr = this->getNode(nodeTag);
00196             if (nodePtr == 0) {
00197                 opserr << "PartitionedDomain::addElement - In element " << eleTag;
00198                 opserr << " no node " << nodeTag << " exists in the domain\n";
00199                 return false;
00200             }           
00201         }
00202         
00203     }
00204 #endif
00205     
00206     TaggedObject *other = elements->getComponentPtr(eleTag);
00207     if (other != 0)
00208         return false;
00209     
00210     bool result = elements->addComponent(elePtr);
00211     if (result == true) {
00212         elePtr->setDomain(this);
00213         this->domainChange();
00214     }
00215     
00216     return result;
00217 }    
00218 
00219 
00220 
00221 bool 
00222 PartitionedDomain::addNode(Node *nodePtr)
00223 {
00224 #ifdef _DEBUG    
00225     if (check == true) {
00226         // check its not in this or any of the subdomains
00227 
00228         // MISSING CODE 
00229     }
00230 #endif
00231     return (this->Domain::addNode(nodePtr));    
00232 }
00233 
00234 
00235 
00236 bool
00237 PartitionedDomain::addSP_Constraint(SP_Constraint *load)
00238 {
00239   int nodeTag = load->getNodeTag();
00240   
00241   // check the Node exists in the Domain or one of Subdomains
00242 
00243   // if in Domain add it as external .. ignore Subdomains
00244   Node *nodePtr = this->getNode(nodeTag);
00245   if (nodePtr != 0) {
00246     return (this->Domain::addSP_Constraint(load));    
00247   }
00248 
00249   // find subdomain with node and add it .. break if find as internal node
00250   SubdomainIter &theSubdomains = this->getSubdomains();
00251   Subdomain *theSub;
00252   while ((theSub = theSubdomains()) != 0) {
00253     bool res = theSub->hasNode(nodeTag);
00254     if (res == true) 
00255       return theSub->addSP_Constraint(load);
00256   }
00257 
00258     
00259   // if no subdomain .. node not in model .. error message and return failure
00260   opserr << "PartitionedDomain::addSP_Constraint - cannot add as node with tag" <<
00261     nodeTag << "does not exist in model\n"; 
00262 
00263   return false;
00264 
00265 }
00266 
00267 bool
00268 PartitionedDomain::addSP_Constraint(SP_Constraint *load, int pattern)
00269 {
00270   int nodeTag = load->getNodeTag();
00271   
00272   // check the Node exists in the Domain or one of Subdomains
00273 
00274   // if in Domain add it as external .. ignore Subdomains
00275   Node *nodePtr = this->getNode(nodeTag);
00276   if (nodePtr != 0) {
00277     return (this->Domain::addSP_Constraint(load, pattern));    
00278   }
00279 
00280   // find subdomain with node and add it .. break if find as internal node
00281   SubdomainIter &theSubdomains = this->getSubdomains();
00282   Subdomain *theSub;
00283   while ((theSub = theSubdomains()) != 0) {
00284     bool res = theSub->hasNode(nodeTag);
00285     if (res == true) 
00286       return theSub->addSP_Constraint(load, pattern);
00287   }
00288 
00289     
00290   // if no subdomain .. node not in model .. error message and return failure
00291   opserr << "PartitionedDomain::addSP_Constraint - cannot add as node with tag" <<
00292     nodeTag << "does not exist in model\n"; 
00293 
00294   return false;
00295 
00296 }
00297 
00298 bool 
00299 PartitionedDomain::addLoadPattern(LoadPattern *loadPattern)
00300 {
00301   bool result = true;
00302 
00303   int tag = loadPattern->getTag();
00304   if (this->getLoadPattern(tag) != 0) {
00305     opserr << "PartitionedDomain::addLoadPattern - cannot add as LoadPattern with tag" <<
00306       tag << "already exists in model\n";             
00307     return false;
00308   }
00309 
00310   SubdomainIter &theSubdomains = this->getSubdomains();
00311   Subdomain *theSub;
00312   while ((theSub = theSubdomains()) != 0) {
00313     bool res = theSub->addLoadPattern(loadPattern);
00314     if (res != true) {
00315       opserr << "PartitionedDomain::addLoadPattern - cannot add as LoadPattern with tag: " <<
00316         tag << " to subdomain\n";             
00317       result = res;
00318     }
00319   }
00320 
00321   this->Domain::addLoadPattern(loadPattern);
00322 
00323   return result;
00324 }    
00325 
00326 
00327 bool 
00328 PartitionedDomain::addNodalLoad(NodalLoad *load, int pattern)
00329 {
00330   int nodeTag = load->getNodeTag();
00331   
00332   // check the Node exists in the Domain or one of Subdomains
00333 
00334   // if in Domain add it as external .. ignore Subdomains
00335   Node *nodePtr = this->getNode(nodeTag);
00336   if (nodePtr != 0) {
00337     return (this->Domain::addNodalLoad(load, pattern));    
00338   }
00339 
00340 
00341   // find subdomain with node and add it .. break if find as internal node
00342   SubdomainIter &theSubdomains = this->getSubdomains();
00343   Subdomain *theSub;
00344   while ((theSub = theSubdomains()) != 0) {
00345     bool res = theSub->hasNode(nodeTag);
00346     if (res == true) {
00347       // opserr << "PartitionedDomain::addLoadPattern(LoadPattern *loadPattern) SUB " << theSub->getTag() << *load;
00348       return theSub->addNodalLoad(load, pattern);
00349     }
00350   }
00351 
00352   // if no subdomain .. node not in model
00353   opserr << "PartitionedDomain::addNodalLoad - cannot add as node with tag" <<
00354     nodeTag << "does not exist in model\n"; 
00355   return false;
00356 }    
00357 
00358 
00359 bool 
00360 PartitionedDomain::addElementalLoad(ElementalLoad *load, int pattern)
00361 {
00362   opserr << "PartitionedDomain::addElementalLoad - not yet implemented\n";
00363   return false;
00364 }
00365 
00366 
00367 Element *
00368 PartitionedDomain::removeElement(int tag)
00369 {
00370     // we first see if its in the original domain
00371     TaggedObject *res = elements->removeComponent(tag);
00372     Element *result = 0;
00373     if (res != 0) {
00374         result = (Element *)res;
00375         this->domainChange();
00376         return result;
00377     }
00378 
00379     // if not there we must check all the other subdomains
00380     if (theSubdomains != 0) {
00381         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
00382         TaggedObject *theObject;
00383         while ((theObject = theSubsIter()) != 0) {
00384             Subdomain *theSub = (Subdomain *)theObject;     
00385             result = theSub->removeElement(tag);
00386             if (result != 0) {
00387                 return result;
00388             }
00389         }
00390     }
00391 
00392     // its not there
00393     return 0;
00394 }    
00395 
00396 
00397 Node *
00398 PartitionedDomain::removeNode(int tag)    
00399 {
00400     // we first remove it form the original domain (in case on boundary)
00401     Node *result = this->Domain::removeNode(tag);
00402 
00403     // we must also try removing from the subdomains
00404     if (theSubdomains != 0) {
00405         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
00406         TaggedObject *theObject;
00407         while ((theObject = theSubsIter()) != 0) {
00408             Subdomain *theSub = (Subdomain *)theObject;     
00409             Node *res = theSub->removeNode(tag);
00410             if (res != 0) 
00411                 result = res;
00412         }
00413     }
00414     
00415     if (result != 0) 
00416         this->domainChange();
00417     
00418     return result;
00419 }    
00420 
00421 SP_Constraint *
00422 PartitionedDomain::removeSP_Constraint(int tag)
00423 {
00424     // we first see if its in the original domain
00425     SP_Constraint *result = this->Domain::removeSP_Constraint(tag);
00426     if (result != 0) {
00427         this->domainChange();
00428         return result;
00429     }
00430         
00431 
00432     // if not there we must check all the other subdomains
00433     if (theSubdomains != 0) {
00434         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);   
00435         TaggedObject *theObject;
00436         while ((theObject = theSubsIter()) != 0) {
00437             Subdomain *theSub = (Subdomain *)theObject;     
00438             result = theSub->removeSP_Constraint(tag);
00439             if (result != 0) {
00440                 return result;
00441             }
00442         }
00443     }
00444 
00445     // its not there
00446     return 0;
00447 }
00448 
00449 
00450 MP_Constraint *
00451 PartitionedDomain::removeMP_Constraint(int tag)
00452 {
00453     // we first see if its in the original domain
00454     MP_Constraint *result = this->Domain::removeMP_Constraint(tag);
00455     if (result != 0) {
00456         this->domainChange();
00457         return result;
00458     }
00459 
00460     // if not there we must check all the other subdomains
00461     if (theSubdomains != 0) {
00462         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);           
00463         TaggedObject *theObject;
00464         while ((theObject = theSubsIter()) != 0) {
00465             Subdomain *theSub = (Subdomain *)theObject;     
00466             result = theSub->removeMP_Constraint(tag);
00467             if (result != 0) {
00468                 return result;
00469             }
00470         }
00471     }    
00472 
00473     // its not there
00474     return 0;
00475 }
00476 
00477 
00478 LoadPattern * 
00479 PartitionedDomain::removeLoadPattern(int tag)
00480 {
00481     // we first see if its in the original domain
00482     LoadPattern *result = this->Domain::removeLoadPattern(tag);
00483 
00484     // we must also try removing from the subdomains
00485     if (theSubdomains != 0) {
00486         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
00487         TaggedObject *theObject;
00488         while ((theObject = theSubsIter()) != 0) {
00489             Subdomain *theSub = (Subdomain *)theObject;     
00490             LoadPattern *res = theSub->removeLoadPattern(tag);
00491             if (res != 0) 
00492                 result = res;
00493         }
00494     }
00495     
00496     if (result != 0) 
00497         this->domainChange();
00498     
00499     return result;
00500 }    
00501 
00502 // public member functions which have to be modified
00503 ElementIter       &
00504 PartitionedDomain::getElements()
00505 {
00506     theEleIter->reset();
00507     return *theEleIter;
00508 }    
00509 
00510 
00511 Element  *
00512 PartitionedDomain::getElement(int tag) 
00513 {
00514     // we first see if its in the original domain
00515     TaggedObject *res = elements->getComponentPtr(tag);
00516     Element *result =0;
00517     if (res != 0) {
00518         result = (Element *)res;
00519         return result;
00520     }
00521 
00522     // go through the other subdomains until we find it or we run out of subdomains
00523     if (theSubdomains != 0) {
00524         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
00525         TaggedObject *theObject;
00526         while ((theObject = theSubsIter()) != 0) {
00527             Subdomain *theSub = (Subdomain *)theObject;     
00528             result = theSub->getElement(tag);
00529             if (result != 0) 
00530                 return result;
00531         }
00532     }
00533     
00534     // its not there
00535     return 0;
00536 }
00537 
00538 
00539 int             
00540 PartitionedDomain::getNumElements(void) const
00541 {
00542     int result = elements->getNumComponents();
00543 
00544     // add the number of subdomains
00545     result +=  theSubdomains->getNumComponents();
00546     return result;
00547 }
00548 
00549 void
00550 PartitionedDomain::applyLoad(double timeStep)
00551 {
00552     this->Domain::applyLoad(timeStep);
00553 
00554     // do the same for all the subdomains
00555     if (theSubdomains != 0) {
00556         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);   
00557         TaggedObject *theObject;
00558         while ((theObject = theSubsIter()) != 0) {
00559             Subdomain *theSub = (Subdomain *)theObject;     
00560             theSub->applyLoad(timeStep);
00561         }
00562     }
00563 }
00564 
00565 
00566 void
00567 PartitionedDomain::setCommitTag(int newTag)
00568 {
00569     this->Domain::setCommitTag(newTag);
00570 
00571     // do the same for all the subdomains
00572     if (theSubdomains != 0) {
00573         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);   
00574         TaggedObject *theObject;
00575         while ((theObject = theSubsIter()) != 0) {
00576             Subdomain *theSub = (Subdomain *)theObject;     
00577             theSub->setCommitTag(newTag);
00578         }
00579     }
00580 }
00581 
00582 
00583 
00584 void
00585 PartitionedDomain::setCurrentTime(double newTime)
00586 {
00587     this->Domain::setCurrentTime(newTime);
00588 
00589     // do the same for all the subdomains
00590     if (theSubdomains != 0) {
00591         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);   
00592         TaggedObject *theObject;
00593         while ((theObject = theSubsIter()) != 0) {
00594             Subdomain *theSub = (Subdomain *)theObject;     
00595             theSub->setCurrentTime(newTime);
00596         }
00597     }
00598 }
00599 
00600 
00601 void
00602 PartitionedDomain::setCommittedTime(double newTime)
00603 {
00604     this->Domain::setCommittedTime(newTime);
00605 
00606     // do the same for all the subdomains
00607     if (theSubdomains != 0) {
00608         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);   
00609         TaggedObject *theObject;
00610         while ((theObject = theSubsIter()) != 0) {
00611             Subdomain *theSub = (Subdomain *)theObject;     
00612             theSub->setCommittedTime(newTime);
00613         }
00614     }
00615 }
00616 
00617 
00618 void
00619 PartitionedDomain::setLoadConstant(void)
00620 {
00621     this->Domain::setLoadConstant();
00622 
00623     // do the same for all the subdomains
00624     if (theSubdomains != 0) {
00625         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);   
00626         TaggedObject *theObject;
00627         while ((theObject = theSubsIter()) != 0) {
00628             Subdomain *theSub = (Subdomain *)theObject;     
00629             theSub->setLoadConstant();
00630         }
00631     }
00632 }
00633 
00634 
00635 int
00636 PartitionedDomain::update(void)
00637 {
00638   int res = this->Domain::update();
00639 
00640   // do the same for all the subdomains
00641   if (theSubdomains != 0) {
00642     ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);       
00643     TaggedObject *theObject;
00644     while ((theObject = theSubsIter()) != 0) {
00645       Subdomain *theSub = (Subdomain *)theObject;           
00646       theSub->computeNodalResponse();
00647       theSub->update();
00648     }
00649   }
00650 
00651 #ifdef _PARALLEL_PROCESSING
00652   return this->barrierCheck(res);
00653 #endif
00654   return 0;
00655 }
00656 
00657 
00658 
00659 
00660 #ifdef _PARALLEL_PROCESSING
00661 int
00662 PartitionedDomain::barrierCheck(int res)
00663 {
00664   int result = res;
00665 
00666   // do the same for all the subdomains
00667   if (theSubdomains != 0) {
00668     ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);       
00669     TaggedObject *theObject;
00670     while ((theObject = theSubsIter()) != 0) {
00671       Subdomain *theSub = (Subdomain *)theObject;           
00672       int subResult = theSub->barrierCheckIN();
00673       if (subResult != 0)
00674         result = subResult;
00675     }
00676 
00677     ArrayOfTaggedObjectsIter theSubsIter1(*theSubdomains);      
00678     while ((theObject = theSubsIter1()) != 0) {
00679       Subdomain *theSub = (Subdomain *)theObject;           
00680       theSub->barrierCheckOUT(result);
00681     }
00682   }
00683 
00684   return result;
00685 }
00686 #endif
00687 
00688 int
00689 PartitionedDomain::update(double newTime, double dT)
00690 {
00691   this->applyLoad(newTime);
00692   int res = this->Domain::update();
00693 
00694   // do the same for all the subdomains
00695   if (theSubdomains != 0) {
00696     ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);       
00697     TaggedObject *theObject;
00698     while ((theObject = theSubsIter()) != 0) {
00699       Subdomain *theSub = (Subdomain *)theObject;           
00700       theSub->computeNodalResponse();
00701       theSub->update(newTime, dT);
00702     }
00703   }
00704 
00705 #ifdef _PARALLEL_PROCESSING
00706   return this->barrierCheck(res);
00707 #endif
00708   return 0;
00709 
00710   /*
00711 
00712   opserr << "PartitionedDomain::update(double newTime, double dT) -1\n";
00713   int result = 0;
00714 
00715 
00716   opserr << "PartitionedDomain::update(double newTime, double dT) -2\n";
00717   this->update();
00718   opserr << "PartitionedDomain::update(double newTime, double dT) -2a\n";
00719 
00720   // do the same for all the subdomains
00721   if (theSubdomains != 0) {
00722     ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);       
00723     TaggedObject *theObject;
00724     while ((theObject = theSubsIter()) != 0) {
00725       Subdomain *theSub = (Subdomain *)theObject;           
00726       theSub->update(newTime, dT);
00727     }
00728     this->barrierCheck(result);
00729   }
00730   opserr << "PartitionedDomain::update(double newTime, double dT) -3\n";
00731   return result;
00732 
00733 */
00734 
00735 }
00736 
00737 
00738 
00739 int
00740 PartitionedDomain::newStep(double dT)
00741 {
00742     this->Domain::newStep(dT);
00743 
00744     int res = 0;
00745     // do the same for all the subdomains
00746     if (theSubdomains != 0) {
00747       ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);     
00748       TaggedObject *theObject;
00749       while ((theObject = theSubsIter()) != 0) {
00750         Subdomain *theSub = (Subdomain *)theObject;         
00751         res += theSub->newStep(dT);
00752         if (res != 0) 
00753           opserr << "PartitionedDomain::step - subdomain " << theSub->getTag() << " failed in step\n";
00754       }
00755     }
00756     return res;
00757 }
00758 
00759 
00760 
00761 
00762 int
00763 PartitionedDomain::commit(void)
00764 {
00765   int result = this->Domain::commit();
00766   if (result < 0) {
00767     opserr << "PartitionedDomain::commit(void) - failed in Domain::commit()\n";
00768     return result;
00769   }
00770 
00771   // do the same for all the subdomains
00772   if (theSubdomains != 0) {
00773     ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);       
00774     TaggedObject *theObject;
00775     while ((theObject = theSubsIter()) != 0) {
00776       Subdomain *theSub = (Subdomain *)theObject;           
00777       int res = theSub->commit();
00778       if (res < 0) {
00779         opserr << "PartitionedDomain::commit(void)";
00780         opserr << " - failed in Subdomain::commit()\n";
00781         return res;
00782       }     
00783     }
00784   }
00785 
00786   // now we load balance if we have subdomains and a partitioner
00787   int numSubdomains = this->getNumSubdomains();
00788   if (numSubdomains != 0 && theDomainPartitioner != 0)  {
00789     Graph &theSubGraphs = this->getSubdomainGraph();
00790     theDomainPartitioner->balance(theSubGraphs);
00791   }
00792 
00793   return 0;
00794 }
00795 
00796 
00797 int
00798 PartitionedDomain::revertToLastCommit(void)
00799 {
00800     int result = this->Domain::revertToLastCommit();
00801     if (result < 0) {
00802         opserr << "PartitionedDomain::revertToLastCommit(void) - failed in Domain::revertToLastCommit()\n";
00803         return result;
00804     }
00805 
00806     // do the same for all the subdomains
00807     if (theSubdomains != 0) {
00808         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);   
00809         TaggedObject *theObject;
00810         while ((theObject = theSubsIter()) != 0) {
00811             Subdomain *theSub = (Subdomain *)theObject;     
00812             int res = theSub->revertToLastCommit();
00813             if (res < 0) {
00814                 opserr << "PartitionedDomain::revertToLastCommit(void)";
00815                 opserr << " - failed in Subdomain::revertToLastCommit()\n";
00816                 return res;
00817             }       
00818         }
00819     }
00820 
00821     return 0;
00822 }
00823 
00824 int
00825 PartitionedDomain::revertToStart(void)
00826 {
00827     int result = this->Domain::revertToStart();
00828     if (result < 0) {
00829         opserr << "PartitionedDomain::revertToLastCommit(void) - failed in Domain::revertToLastCommit()\n";
00830         return result;
00831     }
00832 
00833     // do the same for all the subdomains
00834     if (theSubdomains != 0) {
00835         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);   
00836         TaggedObject *theObject;
00837         while ((theObject = theSubsIter()) != 0) {
00838             Subdomain *theSub = (Subdomain *)theObject;     
00839             int res = theSub->revertToStart();
00840             if (res < 0) {
00841                 opserr << "PartitionedDomain::revertToLastCommit(void)";
00842                 opserr << " - failed in Subdomain::revertToLastCommit()\n";
00843                 return res;
00844             }       
00845         }
00846     }
00847 
00848     return 0;
00849 }
00850 
00851 
00852 int  
00853 PartitionedDomain::addRecorder(Recorder &theRecorder)
00854 {
00855   if (this->Domain::addRecorder(theRecorder) < 0)
00856     return -1;
00857 
00858   // do the same for all the subdomains
00859   if (theSubdomains != 0) {
00860     ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);       
00861     TaggedObject *theObject;
00862     while ((theObject = theSubsIter()) != 0) {
00863       Subdomain *theSub = (Subdomain *)theObject;           
00864       int res = theSub->addRecorder(theRecorder);
00865       if (res < 0) {
00866         opserr << "PartitionedDomain::revertToLastCommit(void)";
00867         opserr << " - failed in Subdomain::revertToLastCommit()\n";
00868         return res;
00869       }     
00870     }
00871   }
00872   return 0;
00873 }
00874 
00875 int  
00876 PartitionedDomain::removeRecorders(void)
00877 {
00878   if (this->Domain::removeRecorders() < 0)
00879     return -1;
00880 
00881   // do the same for all the subdomains
00882   if (theSubdomains != 0) {
00883     ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);       
00884     TaggedObject *theObject;
00885     while ((theObject = theSubsIter()) != 0) {
00886       Subdomain *theSub = (Subdomain *)theObject;           
00887       int res = theSub->removeRecorders();
00888       if (res < 0) {
00889         opserr << "PartitionedDomain::revertToLastCommit(void)";
00890         opserr << " - failed in Subdomain::revertToLastCommit()\n";
00891         return res;
00892       }     
00893     }
00894   }
00895   return 0;
00896 }
00897 
00898 void 
00899 PartitionedDomain::Print(OPS_Stream &s, int flag)
00900 {
00901   this->Domain::Print(s, flag);
00902 
00903   s << "\nELEMENT DATA: NumEle: " << elements->getNumComponents() << "\n";
00904   elements->Print(s);
00905         
00906   // print all the subdomains
00907   if (theSubdomains != 0) {
00908     ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
00909     TaggedObject *theObject;
00910     while ((theObject = theSubsIter()) != 0) {
00911       theObject->Print(s, flag);
00912     }
00913   }
00914 }
00915 
00916 
00917 int 
00918 PartitionedDomain::setPartitioner(DomainPartitioner *thePartitioner)
00919 {
00920   theDomainPartitioner = thePartitioner;
00921   return 0;
00922 }
00923 
00924 
00925 int 
00926 PartitionedDomain::partition(int numPartitions, bool usingMain, int mainPartitionID)
00927 {
00928   int result = 0;
00929     // need to create element graph before create new subdomains
00930     // DO NOT REMOVE THIS LINE __ EVEN IF COMPILER WARNING ABOUT UNUSED VARIABLE
00931     Graph &theEleGraph = this->getElementGraph();
00932     
00933     // now we call partition on the domainPartitioner which does the partitioning
00934     DomainPartitioner *thePartitioner = this->getPartitioner();
00935     if (thePartitioner != 0) {
00936       thePartitioner->setPartitionedDomain(*this);
00937       result =  thePartitioner->partition(numPartitions, usingMain, mainPartitionID);
00938     } else {
00939       opserr << "PartitionedDomain::partition(int numPartitions) - no associated partitioner\n";
00940       return -1;
00941     }
00942 
00943     //
00944     // add recorder objects
00945     //
00946 
00947     // do the same for all the subdomains
00948     if (theSubdomains != 0) {
00949       ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);     
00950       TaggedObject *theObject;
00951       while ((theObject = theSubsIter()) != 0) {
00952         Subdomain *theSub = (Subdomain *)theObject;         
00953         for (int i=0; i<numRecorders; i++) {
00954           int res = theSub->addRecorder(*theRecorders[i]);
00955           if (res != 0) {
00956             opserr << "PartitionedDomain::revertToLastCommit(void)";
00957             opserr << " - failed in Subdomain::revertToLastCommit()\n";
00958             return res;
00959           }       
00960         }  
00961       }
00962     }
00963 
00964     
00965     return result;
00966 }
00967 
00968 
00969 bool 
00970 PartitionedDomain::addSubdomain(Subdomain *theSubdomain)
00971 {
00972     int eleTag = theSubdomain->getTag();
00973     TaggedObject *other = theSubdomains->getComponentPtr(eleTag);
00974     if (other != 0)
00975         return false;
00976   
00977     bool result = theSubdomains->addComponent(theSubdomain);
00978     if (result == true) {
00979         theSubdomain->setDomain(this);
00980         this->domainChange();
00981     }
00982   
00983   return result;
00984 
00985 }
00986 
00987 int 
00988 PartitionedDomain::getNumSubdomains(void)
00989 {
00990     return theSubdomains->getNumComponents();
00991 }
00992     
00993 Subdomain *
00994 PartitionedDomain::getSubdomainPtr(int tag)
00995 {
00996     TaggedObject *mc = theSubdomains->getComponentPtr(tag);
00997     if (mc == 0) return 0;
00998     Subdomain *result = (Subdomain *)mc;
00999     return result;
01000 }    
01001 
01002 SubdomainIter &
01003 PartitionedDomain::getSubdomains(void)
01004 {
01005     theSubdomainIter->reset();
01006     return *theSubdomainIter;
01007 }
01008 
01009 
01010 
01011 DomainPartitioner *
01012 PartitionedDomain::getPartitioner(void) const
01013 {
01014     return theDomainPartitioner;
01015 }
01016         
01017 
01018 
01019 
01020 int 
01021 PartitionedDomain::buildEleGraph(Graph *theEleGraph)
01022 {
01023     int numVertex = elements->getNumComponents();
01024 
01025     // see if quick return
01026 
01027     if (numVertex == 0) 
01028         return 0;
01029     
01030     // create another vertices array which aids in adding edges
01031     
01032     int *theElementTagVertices = 0;
01033     int maxEleNum = 0;
01034     
01035     TaggedObject *tagdObjPtr;
01036     TaggedObjectIter &theEles = elements->getComponents();
01037     while ((tagdObjPtr = theEles()) != 0)
01038         if (tagdObjPtr->getTag() > maxEleNum)
01039             maxEleNum = tagdObjPtr->getTag();
01040 
01041     theElementTagVertices = new int[maxEleNum+1];
01042 
01043     if (theElementTagVertices == 0) {
01044         opserr << "WARNING Domain::buildEleGraph ";
01045         opserr << " - Not Enough Memory for ElementTagVertices\n";
01046         return -1;
01047     }
01048 
01049     for (int j=0; j<=maxEleNum; j++) theElementTagVertices[j] = -1;
01050 
01051     // now create the vertices with a reference equal to the element number.
01052     // and a tag which ranges from 0 through numVertex-1
01053     
01054     TaggedObjectIter &theEles2 = elements->getComponents();
01055     
01056     int count = START_VERTEX_NUM;
01057     while ((tagdObjPtr = theEles2()) != 0) {
01058         int ElementTag = tagdObjPtr->getTag();
01059         Vertex *vertexPtr = new Vertex(count,ElementTag);
01060 
01061         if (vertexPtr == 0) {
01062             opserr << "WARNING Domain::buildEleGraph";
01063             opserr << " - Not Enough Memory to create ";
01064             opserr << count << "th Vertex\n";
01065             delete [] theElementTagVertices;
01066             return -1;
01067         }
01068 
01069         theEleGraph->addVertex(vertexPtr);
01070         theElementTagVertices[ElementTag] = count++;
01071         
01072     }
01073 
01074     // We now need to determine which elements are asssociated with each node.
01075     // As this info is not in the Node interface we must build it; which we
01076     // do using vertices for each node, when we addVertex at thes nodes we
01077     // will not be adding vertices but element tags.
01078 
01079     Vertex **theNodeTagVertices = 0;
01080     int maxNodNum = 0;
01081     Node *nodPtr;
01082     NodeIter &nodeIter = this->getNodes();
01083     while ((nodPtr = nodeIter()) != 0)
01084         if (nodPtr->getTag() > maxNodNum)
01085             maxNodNum = nodPtr->getTag();
01086 
01087     theNodeTagVertices = new Vertex *[maxNodNum+1];
01088 
01089     if (theNodeTagVertices == 0) {
01090         opserr << "WARNING Domain::buildEleGraph ";
01091         opserr << " - Not Enough Memory for NodeTagVertices\n";
01092         return -1;
01093     }
01094 
01095     for (int l=0; l<=maxNodNum; l++) theNodeTagVertices[l] = 0;
01096 
01097     // now create the vertices with a reference equal to the node number.
01098     // and a tag which ranges from 0 through numVertex-1 and placed in
01099     // theNodeTagVertices at a position equal to the node's tag.
01100 
01101     NodeIter &nodeIter2 = this->getNodes();
01102     count = START_VERTEX_NUM;
01103     while ((nodPtr = nodeIter2()) != 0) {
01104         int nodeTag = nodPtr->getTag();
01105         Vertex *vertexPtr = new Vertex(count++,nodeTag);
01106         theNodeTagVertices[nodeTag] = vertexPtr;
01107 
01108         if (vertexPtr == 0) {
01109             opserr << "WARNING Domain::buildEleGraph";
01110             opserr << " - Not Enough Memory to create ";
01111             opserr << count << "th Node Vertex\n";
01112             delete [] theNodeTagVertices;
01113             return -1;
01114         }
01115     }
01116 
01117     // now add the the Elements to the nodes
01118     Element *elePtr;
01119     TaggedObjectIter &theEles3 = elements->getComponents();
01120     
01121     while((tagdObjPtr = theEles3()) != 0) {
01122         elePtr = (Element *)tagdObjPtr;
01123         int eleTag = elePtr->getTag();
01124         const ID &id = elePtr->getExternalNodes();
01125 
01126         int size = id.Size();
01127         for (int i=0; i<size; i++) 
01128             theNodeTagVertices[id(i)]->addEdge(eleTag);
01129     }
01130 
01131     // now add the edges to the vertices of our element graph;
01132     // this is done by looping over the Node vertices, getting their 
01133     // Adjacenecy and adding edges between elements with common nodes
01134 
01135 
01136     Vertex *vertexPtr;
01137     for (int k=0; k<=maxNodNum; k++)
01138         if ((vertexPtr = theNodeTagVertices[k]) != 0) {
01139 
01140             const ID &id = vertexPtr->getAdjacency();
01141 
01142             int size = id.Size();
01143             for (int i=0; i<size; i++) {
01144                 int Element1 = id(i);
01145 
01146                 int vertexTag1 = theElementTagVertices[Element1];
01147 
01148                 for (int j=0; j<size; j++) 
01149                     if (i != j) {
01150 
01151                         int Element2 = id(j);
01152                         int vertexTag2 = theElementTagVertices[Element2];
01153 
01154                         // addEdge() adds for both vertices - do only once
01155                         if (vertexTag1 > vertexTag2) 
01156                             theEleGraph->addEdge(vertexTag1,vertexTag2);
01157                             theEleGraph->addEdge(vertexTag2,vertexTag1);                        
01158                     }
01159             }
01160         }
01161 
01162     // done now delete theElementTagVertices, the node Vertices and
01163     // theNodeTagVertices
01164    
01165     delete [] theElementTagVertices;    
01166     
01167     for (int i=0; i<=maxNodNum; i++)
01168         if ((vertexPtr = theNodeTagVertices[i]) != 0) 
01169             delete vertexPtr;
01170             
01171     delete [] theNodeTagVertices;
01172 
01173     return 0;
01174     
01175 }
01176 
01177 
01178 
01179 // a method which will only remove a node from the partitioned domain
01180 // it does not touch the subdomains .. can be dangerous to use.
01181 Node *
01182 PartitionedDomain::removeExternalNode(int tag)
01183 {
01184     return (this->Domain::removeNode(tag));        
01185 }
01186 
01187 Graph &
01188 PartitionedDomain::getSubdomainGraph(void)
01189 {
01190     // delete the old always - only object that will 
01191     // use this is a DomainBalancer & it is always looking for latest
01192     if (mySubdomainGraph != 0) {
01193         delete mySubdomainGraph;
01194         mySubdomainGraph = 0;
01195     }
01196 
01197     // create a new graph
01198     if (mySubdomainGraph == 0)
01199         mySubdomainGraph = new Graph(this->getNumSubdomains()+START_VERTEX_NUM);
01200 
01201     if (mySubdomainGraph == 0) // if still 0 try a smaller one
01202         mySubdomainGraph = new Graph();    
01203 
01204     int numVertex = theSubdomains->getNumComponents();
01205 
01206     // see if quick return
01207 
01208     if (numVertex == 0) 
01209         return *mySubdomainGraph;
01210     
01211     // create another vertices array which aids in adding edges
01212     
01213     int *theElementTagVertices = 0;
01214     int maxEleNum = 0;
01215 
01216     TaggedObject *tagdObjPtr;
01217     TaggedObjectIter &theEles = theSubdomains->getComponents();
01218     while ((tagdObjPtr = theEles()) != 0)
01219         if (tagdObjPtr->getTag() > maxEleNum)
01220             maxEleNum = tagdObjPtr->getTag();
01221 
01222     theElementTagVertices = new int[maxEleNum+1];
01223 
01224     if (theElementTagVertices == 0) {
01225         opserr << "WARNING PartitionedDomain::buildEleGraph ";
01226         opserr << " - Not Enough Memory for ElementTagVertices\n";
01227         exit(-1);
01228     }
01229 
01230     for (int j=0; j<=maxEleNum; j++) theElementTagVertices[j] = -1;
01231 
01232     // now create the vertices with a reference equal to the subdomain number.
01233     // and a tag equal to the subdomain number and a weighed according to 
01234     // the subdomain cost 
01235     
01236     TaggedObjectIter &theEles2 = theSubdomains->getComponents();
01237 
01238     while ((tagdObjPtr = theEles2()) != 0) {
01239         Subdomain *theSub = (Subdomain *)tagdObjPtr; // upward cast ok as
01240                                              // only subdomais can be added
01241         int ElementTag = tagdObjPtr->getTag();
01242 
01243         Vertex *vertexPtr = new Vertex(ElementTag, ElementTag, theSub->getCost()); 
01244         if (vertexPtr == 0) {
01245             opserr << "WARNING Domain::buildEleGraph";
01246             opserr << " - Not Enough Memory to create ";
01247             opserr << ElementTag << "th Vertex\n";
01248             delete [] theElementTagVertices;
01249             exit(-1);
01250         }
01251 
01252         mySubdomainGraph->addVertex(vertexPtr);
01253 
01254         theElementTagVertices[ElementTag] = ElementTag;
01255     }
01256 
01257     // We now need to determine which theSubdomains are asssociated with each node.
01258     // As this info is not in the Node interface we must build it; which we
01259     // do using vertices for each node, when we addVertex at thes nodes we
01260     // will not be adding vertices but element tags.
01261 
01262     Vertex **theNodeTagVertices = 0;
01263     int maxNodNum = 0;
01264     Node *nodPtr;
01265     NodeIter &nodeIter = this->getNodes();
01266     while ((nodPtr = nodeIter()) != 0)
01267         if (nodPtr->getTag() > maxNodNum)
01268             maxNodNum = nodPtr->getTag();
01269 
01270     theNodeTagVertices = new Vertex *[maxNodNum+1];
01271 
01272     if (theNodeTagVertices == 0) {
01273         opserr << "WARNING Domain::buildEleGraph ";
01274         opserr << " - Not Enough Memory for NodeTagVertices\n";
01275         exit(-1);
01276     }
01277 
01278     for (int l=0; l<=maxNodNum; l++) theNodeTagVertices[l] = 0;
01279 
01280     // now create the vertices with a reference equal to the node number.
01281     // and a tag which ranges from 0 through numVertex-1 and placed in
01282     // theNodeTagVertices at a position equal to the node's tag.
01283 
01284     NodeIter &nodeIter2 = this->getNodes();
01285     int count = START_VERTEX_NUM;
01286     while ((nodPtr = nodeIter2()) != 0) {
01287         int nodeTag = nodPtr->getTag();
01288         Vertex *vertexPtr = new Vertex(count++,nodeTag);
01289         theNodeTagVertices[nodeTag] = vertexPtr;
01290 
01291         if (vertexPtr == 0) {
01292             opserr << "WARNING Domain::buildEleGraph";
01293             opserr << " - Not Enough Memory to create "; opserr << count << "th Node Vertex\n";
01294             delete [] theNodeTagVertices;
01295             exit(-1);
01296         }
01297     }
01298 
01299     // now add the the TheSubdomains to the nodes
01300     Element *elePtr;
01301     TaggedObjectIter &theEles3 = theSubdomains->getComponents();
01302     
01303     while((tagdObjPtr = theEles3()) != 0) {
01304         elePtr = (Element *)tagdObjPtr;
01305         int eleTag = elePtr->getTag();
01306         const ID &id = elePtr->getExternalNodes();
01307 
01308         int size = id.Size();
01309         for (int i=0; i<size; i++) 
01310             theNodeTagVertices[id(i)]->addEdge(eleTag);
01311     }
01312 
01313     // now add the edges to the vertices of our element graph;
01314     // this is done by looping over the Node vertices, getting their 
01315     // Adjacenecy and adding edges between theSubdomains with common nodes
01316 
01317     Vertex *vertexPtr;
01318     for (int k=0; k<=maxNodNum; k++)
01319         if ((vertexPtr = theNodeTagVertices[k]) != 0) {
01320 
01321             const ID &id = vertexPtr->getAdjacency();
01322 
01323             int size = id.Size();
01324             for (int i=0; i<size; i++) {
01325                 int Element1 = id(i);
01326 
01327                 int vertexTag1 = theElementTagVertices[Element1];
01328 
01329                 for (int j=0; j<size; j++) 
01330                     if (i != j) {
01331 
01332                         int Element2 = id(j);
01333                         int vertexTag2 = theElementTagVertices[Element2];
01334 
01335                         // addEdge() adds for both vertices - do only once
01336                         if (vertexTag1 > vertexTag2) 
01337                             mySubdomainGraph->addEdge(vertexTag1,vertexTag2);
01338                             mySubdomainGraph->addEdge(vertexTag2,vertexTag1);                   
01339                     }
01340             }
01341         }
01342 
01343     // done now delete theElementTagVertices, the node Vertices and
01344     // theNodeTagVertices
01345    
01346     delete [] theElementTagVertices;    
01347 
01348     for (int i=0; i<=maxNodNum; i++)
01349         if ((vertexPtr = theNodeTagVertices[i]) != 0) 
01350             delete vertexPtr;
01351 
01352     delete [] theNodeTagVertices;
01353 
01354     return *mySubdomainGraph;
01355 }
01356 
01357 
01358 double
01359 PartitionedDomain::getNodeDisp(int nodeTag, int dof, int &errorFlag)
01360 {
01361   double result = this->Domain::getNodeDisp(nodeTag, dof, errorFlag);
01362 
01363   if (errorFlag != 0) {
01364 
01365     // do the same for all the subdomains
01366     if (theSubdomains != 0) {
01367         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);   
01368         TaggedObject *theObject;
01369         while ((theObject = theSubsIter()) != 0 && errorFlag != 0) {
01370             Subdomain *theSub = (Subdomain *)theObject;     
01371             result = theSub->getNodeDisp(nodeTag, dof, errorFlag);
01372             if (errorFlag == 0)
01373               return result;
01374         }           
01375     }
01376   }
01377   
01378   return result;
01379 }
01380 
01381 
01382 int
01383 PartitionedDomain::setMass(const Matrix &mass, int nodeTag)
01384 {
01385   int result = this->Domain::setMass(mass, nodeTag);
01386 
01387   if (result != 0) {
01388 
01389     // do the same for all the subdomains
01390     if (theSubdomains != 0) {
01391         ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);   
01392         TaggedObject *theObject;
01393         while ((theObject = theSubsIter()) != 0 && result != 0) {
01394             Subdomain *theSub = (Subdomain *)theObject;     
01395             result = theSub->setMass(mass, nodeTag);
01396         }           
01397     }
01398   }
01399   
01400   return result;
01401 }

Generated on Mon Oct 23 15:05:01 2006 for OpenSees by doxygen 1.5.0