Subversion Repositories OpenSees

Rev

Rev 4329 | Rev 4992 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/* ****************************************************************** **
**    OpenSees - Open System for Earthquake Engineering Simulation    **
**          Pacific Earthquake Engineering Research Center            **
**                                                                    **
**                                                                    **
** (C) Copyright 1999, The Regents of the University of California    **
** All Rights Reserved.                                               **
**                                                                    **
** Commercial use of this program without express permission of the   **
** University of California, Berkeley, is strictly prohibited.  See   **
** file 'COPYRIGHT'  in main directory for information on usage and   **
** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.           **
**                                                                    **
** Developed by:                                                      **
**   Frank McKenna (fmckenna@ce.berkeley.edu)                         **
**   Gregory L. Fenves (fenves@ce.berkeley.edu)                       **
**   Filip C. Filippou (filippou@ce.berkeley.edu)                     **
**                                                                    **
** ****************************************************************** */

                                                                       
// $Revision: 1.21 $
// $Date: 2010-09-16 00:07:11 $
// $Source: /usr/local/cvs/OpenSees/SRC/domain/domain/partitioned/PartitionedDomain.cpp,v $
                                                                       
// Written: fmk
// Revision: A
//
// Description: This file contains the class definition for PartitionedDomain.
// PartitionedDomain is an abstract class. The class is responsible for holding
// and providing access to the Elements, Nodes, LoadCases, SP_Constraints
// and MP_Constraints just like a normal domain. In addition the domain provides
// a method to partition the domain into Subdomains.
//
// ModelBuilder. There are no partitions in a PartitionedDomain.
//
// What: "@(#) PartitionedDomain.C, revA"

#include <PartitionedDomain.h>
#include <stdlib.h>

#include <Matrix.h>

#include <DomainPartitioner.h>
#include <Element.h>
#include <Node.h>
#include <SP_Constraint.h>
#include <MP_Constraint.h>
#include <ArrayOfTaggedObjects.h>
#include <ArrayOfTaggedObjectsIter.h>
#include <Subdomain.h>
#include <DomainPartitioner.h>
#include <PartitionedDomain.h>
#include <PartitionedDomainEleIter.h>
#include <PartitionedDomainSubIter.h>
#include <SingleDomEleIter.h>
#include <Vertex.h>
#include <Graph.h>
#include <LoadPattern.h>
#include <NodalLoad.h>
#include <ElementalLoad.h>
#include <SP_Constraint.h>
#include <Recorder.h>
#include <Parameter.h>

#include <MapOfTaggedObjects.h>
#include <MapOfTaggedObjectsIter.h>

typedef map<int, int>         MAP_INT;
typedef MAP_INT::value_type   MAP_INT_TYPE;
typedef MAP_INT::iterator     MAP_INT_ITERATOR;

typedef map<int, ID *> MAP_ID;
typedef MAP_ID::value_type   MAP_ID_TYPE;
typedef MAP_ID::iterator     MAP_ID_ITERATOR;

PartitionedDomain::PartitionedDomain()
:Domain(),
 theSubdomains(0),theDomainPartitioner(0),
 theSubdomainIter(0), mySubdomainGraph(0)
{
    elements = new ArrayOfTaggedObjects(1024);    
    theSubdomains = new ArrayOfTaggedObjects(32);
    theSubdomainIter = new PartitionedDomainSubIter(theSubdomains);

    mainEleIter = new SingleDomEleIter(elements);    
    theEleIter = new PartitionedDomainEleIter(this);
   
    if (theSubdomains == 0 || elements == 0 ||
        theSubdomainIter == 0 ||
        theEleIter == 0 || mainEleIter == 0) {
       
        opserr << "FATAL: PartitionedDomain::PartitionedDomain ";
        opserr << "  - ran out of memory\n";
        exit(-1);
    }
}


PartitionedDomain::PartitionedDomain(DomainPartitioner &thePartitioner)
:Domain(),
 theSubdomains(0),theDomainPartitioner(&thePartitioner),
 theSubdomainIter(0), mySubdomainGraph(0)
{
    elements = new ArrayOfTaggedObjects(1024);    
    theSubdomains = new ArrayOfTaggedObjects(32);
    theSubdomainIter = new PartitionedDomainSubIter(theSubdomains);

    mainEleIter = new SingleDomEleIter(elements);    
    theEleIter = new PartitionedDomainEleIter(this);
   
    if (theSubdomains == 0 || elements == 0 ||
        theSubdomainIter == 0 || theDomainPartitioner == 0 ||
        theEleIter == 0 || mainEleIter == 0) {
       
        opserr << "FATAL: PartitionedDomain::PartitionedDomain ";
        opserr << "  - ran out of memory\n";
        exit(-1);
    }
}


PartitionedDomain::PartitionedDomain(int numNodes, int numElements,
                                     int numSPs, int numMPs, int numLoadPatterns,
                                     int numSubdomains,
                                     DomainPartitioner &thePartitioner)

:Domain(numNodes,0,numSPs,numMPs,numLoadPatterns),
 theSubdomains(0),theDomainPartitioner(&thePartitioner),
 theSubdomainIter(0), mySubdomainGraph(0)
{
    elements = new ArrayOfTaggedObjects(numElements);    
    theSubdomains = new ArrayOfTaggedObjects(numSubdomains);
    theSubdomainIter = new PartitionedDomainSubIter(theSubdomains);

    mainEleIter = new SingleDomEleIter(elements);    
    theEleIter = new PartitionedDomainEleIter(this);
   
    if (theSubdomains == 0 || elements == 0 ||
        theSubdomainIter == 0 ||
        theEleIter == 0 || mainEleIter == 0) {
       
        opserr << "FATAL: PartitionedDomain::PartitionedDomain(int ..) ";
        opserr << "  - ran out of memory\n";
        exit(-1);
    }
}




PartitionedDomain::~PartitionedDomain()
{
  this->PartitionedDomain::clearAll();

  if (elements != 0)
    delete elements;

  if (theSubdomains != 0)
    delete theSubdomains;

  if (theSubdomainIter != 0)
    delete theSubdomainIter;

  if (theEleIter != 0)
    delete theEleIter;

}

void
PartitionedDomain::clearAll(void)
{
  this->removeRecorders();

  SubdomainIter &mySubdomains = this->getSubdomains();
  Subdomain *theSub;
  while ((theSub = mySubdomains()) != 0)
    theSub->clearAll();

  theSubdomains->clearAll();

  this->Domain::clearAll();

  elements->clearAll();
}
   


bool
PartitionedDomain::addElement(Element *elePtr)
{
  if (elePtr->isSubdomain() == true)
    return this->addSubdomain((Subdomain *)elePtr);

  int eleTag = elePtr->getTag();
#ifdef _DEBUG      

        // check ele Tag >= 0
        if (eleTag < 0) {
            opserr << "PartitionedDomain::addElement - Element " << eleTag;
            opserr << " tag must be >= 0\n";
            return false;
        }      
       
        // check its not in this or any of the subdomains
        // MISSING CODE
       
        // check all the elements nodes exist in the domain
        const ID &nodes = elePtr->getExternalNodes();
        for (int i=0; i<nodes.Size(); i++) {
            int nodeTag = nodes(i);
            Node *nodePtr = this->getNode(nodeTag);
            if (nodePtr == 0) {
                opserr << "PartitionedDomain::addElement - In element " << eleTag;
                opserr << " no node " << nodeTag << " exists in the domain\n";
                return false;
            }          
        }
       
#endif
   
    TaggedObject *other = elements->getComponentPtr(eleTag);
    if (other != 0)
        return false;
   
    bool result = elements->addComponent(elePtr);
    if (result == true) {
        elePtr->setDomain(this);
        elePtr->update();
        this->domainChange();
    }
   
    return result;
}    




bool
PartitionedDomain::addNode(Node *nodePtr)
{
#ifdef _DEBUG    
   
#endif
    return (this->Domain::addNode(nodePtr));    
}



bool
PartitionedDomain::addSP_Constraint(SP_Constraint *load)
{
  int nodeTag = load->getNodeTag();
 
  // check the Node exists in the Domain or one of Subdomains

  // if in Domain add it as external .. ignore Subdomains
  Node *nodePtr = this->getNode(nodeTag);
  if (nodePtr != 0) {
    return (this->Domain::addSP_Constraint(load));    
  }

  // find subdomain with node and add it .. break if find as internal node
  SubdomainIter &theSubdomains = this->getSubdomains();
  Subdomain *theSub;
  while ((theSub = theSubdomains()) != 0) {
    bool res = theSub->hasNode(nodeTag);
    if (res == true)
      return theSub->addSP_Constraint(load);
  }

  // if no subdomain .. node not in model .. error message and return failure
  opserr << "PartitionedDomain::addSP_Constraint - cannot add as node with tag" <<
    nodeTag << "does not exist in model\n";

  return false;
}



int
PartitionedDomain::addSP_Constraint(int axisDirn, double axisValue,
                                   const ID &fixityCodes, double tol)
{
  int spTag = 0;

  spTag = this->Domain::addSP_Constraint(axisDirn, axisValue, fixityCodes, tol);

  // find subdomain with node and add it .. break if find as internal node
  SubdomainIter &theSubdomains = this->getSubdomains();
  Subdomain *theSub;
  while ((theSub = theSubdomains()) != 0) {
    theSub->addSP_Constraint(axisDirn, axisValue, fixityCodes, tol);
  }

  return spTag;
}


bool
PartitionedDomain::addSP_Constraint(SP_Constraint *load, int pattern)
{
  int nodeTag = load->getNodeTag();
 
  // check the Node exists in the Domain or one of Subdomains

  // if in Domain add it as external .. ignore Subdomains
  Node *nodePtr = this->getNode(nodeTag);
  if (nodePtr != 0) {
    return (this->Domain::addSP_Constraint(load, pattern));    
  }

  // find subdomain with node and add it .. break if find as internal node
  SubdomainIter &theSubdomains = this->getSubdomains();
  Subdomain *theSub;
  while ((theSub = theSubdomains()) != 0) {
    bool res = theSub->hasNode(nodeTag);
    if (res == true)
      return theSub->addSP_Constraint(load, pattern);
  }

   
  // if no subdomain .. node not in model .. error message and return failure
  opserr << "PartitionedDomain::addSP_Constraint - cannot add as node with tag" <<
    nodeTag << "does not exist in model\n";

  return false;
}


bool
PartitionedDomain::addMP_Constraint(MP_Constraint *load)
{
  bool res = true;
  bool getRetained = false;
  bool addedMain = false;

  // to every domain with the constrained node we must
  // 1. add the retained node if not already there & any sp constraints on that node
  // 2. add the constraint.

  int retainedNodeTag = load->getNodeRetained();
  int constrainedNodeTag = load->getNodeConstrained();

  //
  // first we check the main domain
  // if has the constrained but not retained we mark as needing retained
  //

  Node *retainedNodePtr = this->Domain::getNode(retainedNodeTag);
  Node *constrainedNodePtr = this->Domain::getNode(constrainedNodeTag);
  if (constrainedNodePtr != 0) {
    if (retainedNodePtr != 0) {

      res = this->Domain::addMP_Constraint(load);    
      if (res == false) {
        opserr << "PartitionedDomain::addMP_Constraint - problems adding to main domain\n";
        return res;
      }
      addedMain = true;
    } else {
      getRetained = true;
    }
  }

  //
  // now we check all subdomains
  // if a subdomain has both nodes we add the constraint, if only the
  // constrained node we mark as needing retained
  //

  SubdomainIter &theSubdomains = this->getSubdomains();
  Subdomain *theSub;
  while ((theSub = theSubdomains()) != 0) {

    bool hasConstrained = theSub->hasNode(constrainedNodeTag);

    if (hasConstrained == true) {

      bool hasRestrained = theSub->hasNode(retainedNodeTag);

      if (hasRestrained == true) {

        res = theSub->addMP_Constraint(load);

        if (res == false) {
          opserr << "PartitionedDomain::addMP_Constraint - problems adding to subdomain with retained\n";
          return res;
        }
      } else
        getRetained = true;
    }
  }

  //
  // if getRetained is true, a subdomain or main domain has the constrained node
  // but no retained node .. we must go get it && SP constraints as well
  // 1. we first go get it
  // 2. then we add to main domain
  // 3. then we add to any subdomain
  //

  if (getRetained == true) {

    // we get a copy of the retained Node, set mass equal 0 (don't want to double it)
    if (retainedNodePtr == 0) {
      SubdomainIter &theSubdomains2 = this->getSubdomains();
      while ((theSub = theSubdomains2()) != 0 && retainedNodePtr == 0) {
       
        bool hasRestrained = theSub->hasNode(retainedNodeTag);

        if (hasRestrained == true) {
          retainedNodePtr = theSub->getNode(retainedNodeTag);

          Matrix mass(retainedNodePtr->getNumberDOF(), retainedNodePtr->getNumberDOF());
          mass.Zero();
          retainedNodePtr->setMass(mass);
        }
      }
    } else {
      // get a copy & zero the mass
      retainedNodePtr = new Node(*retainedNodePtr, false);
    }

    if (retainedNodePtr == 0) {
      opserr << "partitionedDomain::addMP_Constraint - can't find retained node anywhere!\n";
      return false;
    }

    //
    // if main has it we add the retained to main & constraint
    //

    if (constrainedNodePtr != 0 && addedMain == false) {
      res = this->Domain::addNode(retainedNodePtr);

      if (res == false) {
        opserr << "PartitionedDomain::addMP_Constraint - problems adding retained to main domain\n";
        return res;
      }
      res = this->Domain::addMP_Constraint(load);

      if (res == false) {
        opserr << "PartitionedDomain::addMP_Constraint - problems adding constraint to main domain after adding node\n";
        return res;
      }
    }

    //
    // to subdmains that have the constrained but no retained
    // 1. we add a copy of retained
    // 2. we add the constraint
    //

    SubdomainIter &theSubdomains3 = this->getSubdomains();
    while ((theSub = theSubdomains3()) != 0) {
      bool hasConstrained = theSub->hasNode(constrainedNodeTag);
      if (hasConstrained == true) {

        bool hasRestrained = theSub->hasNode(retainedNodeTag);
        if (hasRestrained == false) {

          res = theSub->addNode(retainedNodePtr);

          if (res == false) {
            opserr << "PartitionedDomain::addMP_Constraint - problems adding retained to subdomain\n";
            return res;
          }

          res = theSub->addMP_Constraint(load);

          if (res == false) {
            opserr << "PartitionedDomain::addMP_Constraint - problems adding constraint to subdomain after adding node\n";
            return res;
          }
        }
      }
    }

    // clean up memory
    if (addedMain == true && getRetained == true)
      delete retainedNodePtr;

  }

  return res;

}


bool
PartitionedDomain::addLoadPattern(LoadPattern *loadPattern)
{
  bool result = true;

  int tag = loadPattern->getTag();
  if (this->getLoadPattern(tag) != 0) {
    opserr << "PartitionedDomain::addLoadPattern - cannot add as LoadPattern with tag" <<
      tag << "already exists in model\n";            
    return false;
  }

  SubdomainIter &theSubdomains = this->getSubdomains();
  Subdomain *theSub;
  while ((theSub = theSubdomains()) != 0) {
    bool res = theSub->addLoadPattern(loadPattern);
    if (res != true) {
      opserr << "PartitionedDomain::addLoadPattern - cannot add as LoadPattern with tag: " <<
        tag << " to subdomain\n";            
      result = res;
    }
  }

  this->Domain::addLoadPattern(loadPattern);

  return result;
}    


bool
PartitionedDomain::addNodalLoad(NodalLoad *load, int pattern)
{
  int nodeTag = load->getNodeTag();
 
  // check the Node exists in the Domain or one of Subdomains

  // if in Domain add it as external .. ignore Subdomains
  Node *nodePtr = this->getNode(nodeTag);
  if (nodePtr != 0) {
    return (this->Domain::addNodalLoad(load, pattern));    
  }


  // find subdomain with node and add it .. break if find as internal node
  SubdomainIter &theSubdomains = this->getSubdomains();
  Subdomain *theSub;
  while ((theSub = theSubdomains()) != 0) {
    bool res = theSub->hasNode(nodeTag);
    if (res == true) {
      // opserr << "PartitionedDomain::addLoadPattern(LoadPattern *loadPattern) SUB " << theSub->getTag() << *load;
      return theSub->addNodalLoad(load, pattern);
    }
  }

  // if no subdomain .. node not in model
  opserr << "PartitionedDomain::addNodalLoad - cannot add as node with tag" <<
    nodeTag << "does not exist in model\n";
  return false;
}    


bool
PartitionedDomain::addElementalLoad(ElementalLoad *load, int pattern)
{
  int eleTag = load->getElementTag();
 
  // check the Node exists in the Domain or one of Subdomains

  // if in Domain add it as external .. ignore Subdomains
  Element *elePtr = this->getElement(eleTag);
  if (elePtr != 0) {
    return (this->Domain::addElementalLoad(load, pattern));    
  }


  // find subdomain with node and add it .. break if find as internal node
  SubdomainIter &theSubdomains = this->getSubdomains();
  Subdomain *theSub;
  while ((theSub = theSubdomains()) != 0) {
    bool res = theSub->hasElement(eleTag);
    if (res == true) {
      // opserr << "PartitionedDomain::addLoadPattern(LoadPattern *loadPattern) SUB " << theSub->getTag() << *load;
      return theSub->addElementalLoad(load, pattern);
    }
  }

  // if no subdomain .. node not in model
  opserr << "PartitionedDomain::addElementalLoad - cannot add as element with tag" <<
    eleTag << "does not exist in model\n";

  return false;
}


Element *
PartitionedDomain::removeElement(int tag)
{
    // we first see if its in the original domain
    TaggedObject *res = elements->removeComponent(tag);
    Element *result = 0;
    if (res != 0) {
        result = (Element *)res;
        this->domainChange();
        return result;
    }

    // if not there we must check all the other subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            result = theSub->removeElement(tag);
            if (result != 0) {
                return result;
            }
        }
    }

    // its not there
    return 0;
}    


Node *
PartitionedDomain::removeNode(int tag)    
{
    // we first remove it form the original domain (in case on boundary)
    Node *result = this->Domain::removeNode(tag);

    // we must also try removing from the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            Node *res = theSub->removeNode(tag);
            if (res != 0)
                result = res;
        }
    }
   
    if (result != 0)
        this->domainChange();
   
    return result;
}    

SP_Constraint *
PartitionedDomain::removeSP_Constraint(int tag)
{
    // we first see if its in the original domain
    SP_Constraint *result = this->Domain::removeSP_Constraint(tag);
    if (result != 0) {
        this->domainChange();
        return result;
    }
       

    // if not there we must check all the other subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            result = theSub->removeSP_Constraint(tag);
            if (result != 0) {
                return result;
            }
        }
    }

    // its not there
    return 0;
}


int
PartitionedDomain::removeSP_Constraint(int nodeTag, int dof, int loadPatternTag)
{
  // we first see if its in the original domain
  int result = this->Domain::removeSP_Constraint(nodeTag, dof, loadPatternTag);

  // if not there we must check all the other subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);              
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      result += theSub->removeSP_Constraint(nodeTag, dof, loadPatternTag);
    }    
  }

  if (result != 0) {
    this->domainChange();
  }

  // its not there
  return result;  
}



MP_Constraint *
PartitionedDomain::removeMP_Constraint(int tag)
{
    // we first see if its in the original domain
    MP_Constraint *result = this->Domain::removeMP_Constraint(tag);
    if (result != 0) {
        this->domainChange();
        return result;
    }

    // if not there we must check all the other subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);          
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            result = theSub->removeMP_Constraint(tag);
            if (result != 0) {
                return result;
            }
        }
    }    

    // its not there
    return 0;
}


int
PartitionedDomain::removeMP_Constraints(int tag)
{
    // we first see if its in the original domain
    int result = this->Domain::removeMP_Constraints(tag);

    // if not there we must check all the other subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);          
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            result += theSub->removeMP_Constraints(tag);
        }
    }    
   
    if (result != 0) {
      this->domainChange();
    }
   
    // its not there
    return result;
}


LoadPattern *
PartitionedDomain::removeLoadPattern(int tag)
{
    // we first see if its in the original domain
    LoadPattern *result = this->Domain::removeLoadPattern(tag);

    // we must also try removing from the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            LoadPattern *res = theSub->removeLoadPattern(tag);
            if (res != 0)
                result = res;
        }
    }
   
    if (result != 0)
        this->domainChange();
   
    return result;
}    

// public member functions which have to be modified
ElementIter       &
PartitionedDomain::getElements()
{
    theEleIter->reset();
    return *theEleIter;
}    


Element  *
PartitionedDomain::getElement(int tag)
{
    // we first see if its in the original domain
    TaggedObject *res = elements->getComponentPtr(tag);
    Element *result =0;
    if (res != 0) {
        result = (Element *)res;
        return result;
    }

    /*
    // go through the other subdomains until we find it or we run out of subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            result = theSub->getElement(tag);
            if (result != 0)
                return result;
        }
    }
    */


    // its not there
    return 0;
}


int            
PartitionedDomain::getNumElements(void) const
{
    int result = elements->getNumComponents();

    // add the number of subdomains
    result +=  theSubdomains->getNumComponents();
    return result;
}

void
PartitionedDomain::applyLoad(double timeStep)
{
    this->Domain::applyLoad(timeStep);

    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            theSub->applyLoad(timeStep);
        }
    }
}


void
PartitionedDomain::setCommitTag(int newTag)
{
    this->Domain::setCommitTag(newTag);

    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            theSub->setCommitTag(newTag);
        }
    }
}



void
PartitionedDomain::setCurrentTime(double newTime)
{
    this->Domain::setCurrentTime(newTime);

    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            theSub->setCurrentTime(newTime);
        }
    }
}


void
PartitionedDomain::setCommittedTime(double newTime)
{
    this->Domain::setCommittedTime(newTime);

    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            theSub->setCommittedTime(newTime);
        }
    }
}


void
PartitionedDomain::setLoadConstant(void)
{
    this->Domain::setLoadConstant();

    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            theSub->setLoadConstant();
        }
    }
}


int
PartitionedDomain::setRayleighDampingFactors(double alphaM, double betaK, double betaK0, double betaKc)
{
    this->Domain::setRayleighDampingFactors(alphaM, betaK, betaK0, betaKc);

    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            theSub->setRayleighDampingFactors(alphaM, betaK, betaK0, betaKc);
        }
    }
    return 0;
}


int
PartitionedDomain::update(void)
{
  int res = this->Domain::update();

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      theSub->computeNodalResponse();
      res += theSub->update();
    }
  }

#ifdef _PARALLEL_PROCESSING
  return this->barrierCheck(res);
#endif
  return res;
}




#ifdef _PARALLEL_PROCESSING
int
PartitionedDomain::barrierCheck(int res)
{
  int result = res;

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      int subResult = theSub->barrierCheckIN();
      if (subResult != 0)
        result = subResult;
    }

    ArrayOfTaggedObjectsIter theSubsIter1(*theSubdomains);     
    while ((theObject = theSubsIter1()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      theSub->barrierCheckOUT(result);
    }
  }

  return result;
}
#endif

int
PartitionedDomain::update(double newTime, double dT)
{
  this->applyLoad(newTime);
  int res = this->Domain::update();

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      theSub->computeNodalResponse();
      res +=theSub->update(newTime, dT);
    }
  }

#ifdef _PARALLEL_PROCESSING
  return this->barrierCheck(res);
#endif
  return res;

  /*

  opserr << "PartitionedDomain::update(double newTime, double dT) -1\n";
  int result = 0;


  opserr << "PartitionedDomain::update(double newTime, double dT) -2\n";
  this->update();
  opserr << "PartitionedDomain::update(double newTime, double dT) -2a\n";

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      theSub->update(newTime, dT);
    }
    this->barrierCheck(result);
  }
  opserr << "PartitionedDomain::update(double newTime, double dT) -3\n";
  return result;

*/


}


int
PartitionedDomain::hasDomainChanged(void)
{
  return this->Domain::hasDomainChanged();
}

int
PartitionedDomain::analysisStep(double dT)
{
  // first we need to see if any subdomain has changed & mark the change in domain
  bool domainChangedAnySubdomain = this->getDomainChangeFlag();
  if (domainChangedAnySubdomain == false) {
    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while (((theObject = theSubsIter()) != 0) && (domainChangedAnySubdomain == false)) {
            Subdomain *theSub = (Subdomain *)theObject;    
            domainChangedAnySubdomain = theSub->getDomainChangeFlag();
        }
    }
  }

  if (domainChangedAnySubdomain == true) {
    this->Domain::domainChange();
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while (((theObject = theSubsIter()) != 0) && (domainChangedAnySubdomain == false)) {
            Subdomain *theSub = (Subdomain *)theObject;    
            theSub->domainChange();
        }
    }
  }

  this->Domain::analysisStep(dT);

    int res = 0;
    // do the same for all the subdomains
    if (theSubdomains != 0) {
      ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);    
      TaggedObject *theObject;
      while ((theObject = theSubsIter()) != 0) {
        Subdomain *theSub = (Subdomain *)theObject;        
        res += theSub->analysisStep(dT);
        if (res != 0)
          opserr << "PartitionedDomain::step - subdomain " << theSub->getTag() << " failed in step\n";
      }
    }
    return res;
}



int
PartitionedDomain::eigenAnalysis(int numModes, bool generalized)
{
  // first we need to see if any subdomain has changed & mark the change in domain
  bool domainChangedAnySubdomain = this->getDomainChangeFlag();
  if (domainChangedAnySubdomain == false) {
    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while (((theObject = theSubsIter()) != 0) && (domainChangedAnySubdomain == false)) {
            Subdomain *theSub = (Subdomain *)theObject;    
            domainChangedAnySubdomain = theSub->getDomainChangeFlag();
        }
    }
  }

  if (domainChangedAnySubdomain == true) {
    this->Domain::domainChange();
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while (((theObject = theSubsIter()) != 0) && (domainChangedAnySubdomain == false)) {
            Subdomain *theSub = (Subdomain *)theObject;    
            theSub->domainChange();
        }
    }
  }

  this->Domain::eigenAnalysis(numModes, generalized);
 
  int res = 0;
  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      res += theSub->eigenAnalysis(numModes, generalized);
      if (res != 0)
        opserr << "PartitionedDomain::step - subdomain " << theSub->getTag() << " failed in step\n";
    }
  }
  return res;
}


int
PartitionedDomain::record(void)
{
  int result = 0;

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      result += theSub->record();
      if (result < 0) {
        opserr << "PartitionedDomain::record(void)";
        opserr << " - failed in Subdomain::record()\n";
      }    
    }
  }

  result += this->Domain::record();

  return result;
}

int
PartitionedDomain::commit(void)
{
  int result = this->Domain::commit();

  if (result < 0) {
    opserr << "PartitionedDomain::commit(void) - failed in Domain::commit()\n";
    return result;
  }

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      int res = theSub->commit();
      if (res < 0) {
        opserr << "PartitionedDomain::commit(void)";
        opserr << " - failed in Subdomain::commit()\n";
        return res;
      }    
    }
  }

  // now we load balance if we have subdomains and a partitioner
  int numSubdomains = this->getNumSubdomains();
  if (numSubdomains != 0 && theDomainPartitioner != 0)  {
    Graph &theSubGraphs = this->getSubdomainGraph();
    theDomainPartitioner->balance(theSubGraphs);
  }

  return 0;
}


int
PartitionedDomain::revertToLastCommit(void)
{
    int result = this->Domain::revertToLastCommit();
    if (result < 0) {
        opserr << "PartitionedDomain::revertToLastCommit(void) - failed in Domain::revertToLastCommit()\n";
        return result;
    }

    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            int res = theSub->revertToLastCommit();
            if (res < 0) {
                opserr << "PartitionedDomain::revertToLastCommit(void)";
                opserr << " - failed in Subdomain::revertToLastCommit()\n";
                return res;
            }      
        }
    }

    return 0;
}

int
PartitionedDomain::revertToStart(void)
{
    int result = this->Domain::revertToStart();
    if (result < 0) {
        opserr << "PartitionedDomain::revertToLastCommit(void) - failed in Domain::revertToLastCommit()\n";
        return result;
    }

    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            int res = theSub->revertToStart();
            if (res < 0) {
                opserr << "PartitionedDomain::revertToLastCommit(void)";
                opserr << " - failed in Subdomain::revertToLastCommit()\n";
                return res;
            }      
        }
    }

    return 0;
}


int  
PartitionedDomain::addRecorder(Recorder &theRecorder)
{
  if (this->Domain::addRecorder(theRecorder) < 0)
    return -1;

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      int res = theSub->addRecorder(theRecorder);
      if (res < 0) {
        opserr << "PartitionedDomain::revertToLastCommit(void)";
        opserr << " - failed in Subdomain::revertToLastCommit()\n";
        return res;
      }    
    }
  }
  return 0;
}

int  
PartitionedDomain::removeRecorders(void)
{
  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      int res = theSub->removeRecorders();
      if (res < 0) {
        opserr << "PartitionedDomain::removeRecorders(void)";
        opserr << " - failed in Subdomain::removeRecorders()\n";
        return res;
      }    
    }
  }

  if (this->Domain::removeRecorders() < 0)
    return -1;

  return 0;
}


int  
PartitionedDomain::removeRecorder(int tag)
{
  if (this->Domain::removeRecorder(tag) < 0)
    return -1;

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      int res = theSub->removeRecorder(tag);
      if (res < 0) {
        opserr << "PartitionedDomain::removeRecorder(void)";
        opserr << " - failed in Subdomain::removeRecorder()\n";
        return res;
      }    
    }
  }
  return 0;
}

void
PartitionedDomain::Print(OPS_Stream &s, int flag)
{
  this->Domain::Print(s, flag);

  s << "\nELEMENT DATA: NumEle: " << elements->getNumComponents() << "\n";
  elements->Print(s);
       
  // print all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      theObject->Print(s, flag);
    }
  }
}


void
PartitionedDomain::Print(OPS_Stream &s, ID *nodeTags, ID *eleTags, int flag)
{
  if (nodeTags != 0)
    this->Domain::Print(s, nodeTags, 0, flag);

  if (eleTags != 0) {
    int numEle = eleTags->Size();
    for (int i=0; i<numEle; i++) {
      int eleTag = (*eleTags)(i);
      TaggedObject *theEle = elements->getComponentPtr(eleTag);
      if (theEle != 0)
        theEle->Print(s, flag);
    }
  }
 

  // print all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      theSub->Print(s, nodeTags, eleTags, flag);
    }
  }
}



int
PartitionedDomain::setPartitioner(DomainPartitioner *thePartitioner)
{
  theDomainPartitioner = thePartitioner;
  return 0;
}


int
PartitionedDomain::partition(int numPartitions, bool usingMain, int mainPartitionID)
{
  int result = 0;
    // need to create element graph before create new subdomains
    // DO NOT REMOVE THIS LINE __ EVEN IF COMPILER WARNING ABOUT UNUSED VARIABLE
    Graph &theEleGraph = this->getElementGraph();
   
    // now we call partition on the domainPartitioner which does the partitioning
    DomainPartitioner *thePartitioner = this->getPartitioner();
    if (thePartitioner != 0) {
      thePartitioner->setPartitionedDomain(*this);
      result =  thePartitioner->partition(numPartitions, usingMain, mainPartitionID);
    } else {
      opserr << "PartitionedDomain::partition(int numPartitions) - no associated partitioner\n";
      return -1;
    }

    //
    // add recorder objects
    //

    // do the same for all the subdomains
    if (theSubdomains != 0) {
      ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);    
      TaggedObject *theObject;
      while ((theObject = theSubsIter()) != 0) {
        Subdomain *theSub = (Subdomain *)theObject;        
        for (int i=0; i<numRecorders; i++) {
          int res = theSub->addRecorder(*theRecorders[i]);
          if (res != 0) {
            opserr << "PartitionedDomain::revertToLastCommit(void)";
            opserr << " - failed in Subdomain::revertToLastCommit()\n";
            return res;
          }      
        }  
      }
    }

    return result;
}


bool
PartitionedDomain::addSubdomain(Subdomain *theSubdomain)
{
    int eleTag = theSubdomain->getTag();
    TaggedObject *other = theSubdomains->getComponentPtr(eleTag);
    if (other != 0)
        return false;
 
    bool result = theSubdomains->addComponent(theSubdomain);
    if (result == true) {
        theSubdomain->setDomain(this);
        this->domainChange();
    }
 
  return result;

}

int
PartitionedDomain::getNumSubdomains(void)
{
    return theSubdomains->getNumComponents();
}
   
Subdomain *
PartitionedDomain::getSubdomainPtr(int tag)
{
    TaggedObject *mc = theSubdomains->getComponentPtr(tag);
    if (mc == 0) return 0;
    Subdomain *result = (Subdomain *)mc;
    return result;
}    

SubdomainIter &
PartitionedDomain::getSubdomains(void)
{
    theSubdomainIter->reset();
    return *theSubdomainIter;
}



DomainPartitioner *
PartitionedDomain::getPartitioner(void) const
{
    return theDomainPartitioner;
}
       


int
PartitionedDomain::buildEleGraph(Graph *theEleGraph)
{
   // see if quick return
    int numVertex = this->getNumElements();
    if (numVertex == 0)
        return 0;

    //
    // iterate over the lements of the domain
    //  create a vertex with a unique tag for each element
    //  also create a map to hold element tag - vertex tag mapping
    //

    MAP_INT theEleToVertexMap;
    MAP_INT_ITERATOR theEleToVertexMapEle;


    TaggedObject *theTagged;
    TaggedObjectIter &theElements = elements->getComponents();
    int count = START_VERTEX_NUM;
    while ((theTagged = theElements()) != 0) {
      int eleTag = theTagged->getTag();
      Vertex *vertexPtr = new Vertex(count, eleTag);

      if (vertexPtr == 0) {
        opserr << "WARNING Domain::buildEleGraph - Not Enough Memory to create the " << count << " vertex\n";
        return -1;
      }

      theEleGraph->addVertex(vertexPtr);
      theEleToVertexMapEle = theEleToVertexMap.find(eleTag);
      if (theEleToVertexMapEle == theEleToVertexMap.end()) {
        theEleToVertexMap.insert(MAP_INT_TYPE(eleTag, count));

        // check if sucessfully added
        theEleToVertexMapEle = theEleToVertexMap.find(eleTag);
        if (theEleToVertexMapEle == theEleToVertexMap.end()) {
          opserr << "Domain::buildEleGraph - map STL failed to add object with tag : " << eleTag << endln;
          return false;
        }

        count++;
      }
    }

    //
    // We now need to determine which elements are asssociated with each node.
    // As this info is not in the Node interface we must build it;
    //
    // again we will use an stl map, index will be nodeTag, object will be Vertex
    // do using vertices for each node, when we addVertex at thes nodes we
    // will not be adding vertices but element tags.
    //

    MAP_ID theNodeToVertexMap;
    MAP_ID_ITERATOR theNodeEle;

    Node *nodPtr;

    // now create the vertices with a reference equal to the node number.
    // and a tag which ranges from 0 through numVertex-1 and placed in
    // theNodeTagVertices at a position equal to the node's tag.

    NodeIter &theNodes = this->getNodes();
    while ((nodPtr = theNodes()) != 0) {
      int nodeTag = nodPtr->getTag();
      ID *eleTags = new ID(0, 4);

      if (eleTags == 0) {
        opserr << "WARNING Domain::buildEleGraph - Not Enough Memory to create the " << count << " vertex\n";
        return -1;
      }

      theNodeEle = theNodeToVertexMap.find(nodeTag);
      if (theNodeEle == theNodeToVertexMap.end()) {
        theNodeToVertexMap.insert(MAP_ID_TYPE(nodeTag, eleTags));

        // check if sucessfully added
        theNodeEle = theNodeToVertexMap.find(nodeTag);
        if (theNodeEle == theNodeToVertexMap.end()) {
          opserr << "Domain::buildEleGraph - map STL failed to add object with tag : " << nodeTag << endln;
          return false;
        }
      }
    }

    // now add the the Elements to the node vertices
    Element *theEle;
    TaggedObjectIter &theEle3 = elements->getComponents();

    while((theTagged = theEle3()) != 0) {
      theEle = (Element *)theTagged;
      int eleTag = theEle->getTag();
      const ID &id = theEle->getExternalNodes();

      int size = id.Size();
      for (int i=0; i<size; i++) {
        int nodeTag = id(i);

        MAP_ID_ITERATOR theNodeEle;
        theNodeEle = theNodeToVertexMap.find(nodeTag);
        if (theNodeEle == theNodeToVertexMap.end()) {
          return -1;
        } else {
          ID *theNodeEleTags = (*theNodeEle).second;
          theNodeEleTags->insert(eleTag);
        }
      }
    }

    //
    // now add the edges to the vertices of our element graph;
    // this is done by looping over the Node vertices, getting their
    // Adjacenecy and adding edges between elements with common nodes
    //

    MAP_ID_ITERATOR currentComponent;
    currentComponent = theNodeToVertexMap.begin();
    while (currentComponent != theNodeToVertexMap.end()) {
      ID *id = (*currentComponent).second;

      int size = id->Size();
      for (int i=0; i<size; i++) {
        int eleTag1 = (*id)(i);

        theEleToVertexMapEle = theEleToVertexMap.find(eleTag1);
        if (theEleToVertexMapEle != theEleToVertexMap.end()) {
          int vertexTag1 = (*theEleToVertexMapEle).second;

          for (int j=0; j<size; j++)
            if (i != j) {
              int eleTag2 = (*id)(j);
              theEleToVertexMapEle = theEleToVertexMap.find(eleTag2);
              if (theEleToVertexMapEle != theEleToVertexMap.end()) {
                int vertexTag2 = (*theEleToVertexMapEle).second;

                // addEdge() adds for both vertices - do only once

                if (vertexTag1 > vertexTag2) {
                  theEleGraph->addEdge(vertexTag1,vertexTag2);
                  theEleGraph->addEdge(vertexTag2,vertexTag1);
                }
              }
            }
        }
      }
      currentComponent++;
    }

    // clean up - delete the ID's associated with the nodes
    currentComponent = theNodeToVertexMap.begin();
    while (currentComponent != theNodeToVertexMap.end()) {
      delete (*currentComponent).second;
      currentComponent++;
    }
           
    return 0;    
}



// a method which will only remove a node from the partitioned domain
// it does not touch the subdomains .. can be dangerous to use.
Node *
PartitionedDomain::removeExternalNode(int tag)
{
    return (this->Domain::removeNode(tag));        
}

Graph &
PartitionedDomain::getSubdomainGraph(void)
{
    // delete the old always - only object that will
    // use this is a DomainBalancer & it is always looking for latest
    if (mySubdomainGraph != 0) {
        delete mySubdomainGraph;
        mySubdomainGraph = 0;
    }

    // create a new graph
    if (mySubdomainGraph == 0)
        mySubdomainGraph = new Graph(this->getNumSubdomains()+START_VERTEX_NUM);

    if (mySubdomainGraph == 0) // if still 0 try a smaller one
        mySubdomainGraph = new Graph();    

    int numVertex = theSubdomains->getNumComponents();

    // see if quick return

    if (numVertex == 0)
        return *mySubdomainGraph;
   
    // create another vertices array which aids in adding edges
   
    int *theElementTagVertices = 0;
    int maxEleNum = 0;

    TaggedObject *tagdObjPtr;
    TaggedObjectIter &theEles = theSubdomains->getComponents();
    while ((tagdObjPtr = theEles()) != 0)
        if (tagdObjPtr->getTag() > maxEleNum)
            maxEleNum = tagdObjPtr->getTag();

    theElementTagVertices = new int[maxEleNum+1];

    if (theElementTagVertices == 0) {
        opserr << "WARNING PartitionedDomain::buildEleGraph ";
        opserr << " - Not Enough Memory for ElementTagVertices\n";
        exit(-1);
    }

    for (int j=0; j<=maxEleNum; j++) theElementTagVertices[j] = -1;

    // now create the vertices with a reference equal to the subdomain number.
    // and a tag equal to the subdomain number and a weighed according to
    // the subdomain cost
   
    TaggedObjectIter &theEles2 = theSubdomains->getComponents();

    while ((tagdObjPtr = theEles2()) != 0) {
        Subdomain *theSub = (Subdomain *)tagdObjPtr; // upward cast ok as
                                             // only subdomais can be added
        int ElementTag = tagdObjPtr->getTag();

        Vertex *vertexPtr = new Vertex(ElementTag, ElementTag, theSub->getCost());
        if (vertexPtr == 0) {
            opserr << "WARNING Domain::buildEleGraph";
            opserr << " - Not Enough Memory to create ";
            opserr << ElementTag << "th Vertex\n";
            delete [] theElementTagVertices;
            exit(-1);
        }

        mySubdomainGraph->addVertex(vertexPtr);

        theElementTagVertices[ElementTag] = ElementTag;
    }

    // We now need to determine which theSubdomains are asssociated with each node.
    // As this info is not in the Node interface we must build it; which we
    // do using vertices for each node, when we addVertex at thes nodes we
    // will not be adding vertices but element tags.

    Vertex **theNodeTagVertices = 0;
    int maxNodNum = 0;
    Node *nodPtr;
    NodeIter &nodeIter = this->getNodes();
    while ((nodPtr = nodeIter()) != 0)
        if (nodPtr->getTag() > maxNodNum)
            maxNodNum = nodPtr->getTag();

    theNodeTagVertices = new Vertex *[maxNodNum+1];

    if (theNodeTagVertices == 0) {
        opserr << "WARNING Domain::buildEleGraph ";
        opserr << " - Not Enough Memory for NodeTagVertices\n";
        exit(-1);
    }

    for (int l=0; l<=maxNodNum; l++) theNodeTagVertices[l] = 0;

    // now create the vertices with a reference equal to the node number.
    // and a tag which ranges from 0 through numVertex-1 and placed in
    // theNodeTagVertices at a position equal to the node's tag.

    NodeIter &nodeIter2 = this->getNodes();
    int count = START_VERTEX_NUM;
    while ((nodPtr = nodeIter2()) != 0) {
        int nodeTag = nodPtr->getTag();
        Vertex *vertexPtr = new Vertex(count++,nodeTag);
        theNodeTagVertices[nodeTag] = vertexPtr;

        if (vertexPtr == 0) {
            opserr << "WARNING Domain::buildEleGraph";
            opserr << " - Not Enough Memory to create "; opserr << count << "th Node Vertex\n";
            delete [] theNodeTagVertices;
            exit(-1);
        }
    }

    // now add the the TheSubdomains to the nodes
    Element *elePtr;
    TaggedObjectIter &theEles3 = theSubdomains->getComponents();
   
    while((tagdObjPtr = theEles3()) != 0) {
        elePtr = (Element *)tagdObjPtr;
        int eleTag = elePtr->getTag();
        const ID &id = elePtr->getExternalNodes();

        int size = id.Size();
        for (int i=0; i<size; i++)
            theNodeTagVertices[id(i)]->addEdge(eleTag);
    }

    // now add the edges to the vertices of our element graph;
    // this is done by looping over the Node vertices, getting their
    // Adjacenecy and adding edges between theSubdomains with common nodes

    Vertex *vertexPtr;
    for (int k=0; k<=maxNodNum; k++)
        if ((vertexPtr = theNodeTagVertices[k]) != 0) {

            const ID &id = vertexPtr->getAdjacency();

            int size = id.Size();
            for (int i=0; i<size; i++) {
                int Element1 = id(i);

                int vertexTag1 = theElementTagVertices[Element1];

                for (int j=0; j<size; j++)
                    if (i != j) {

                        int Element2 = id(j);
                        int vertexTag2 = theElementTagVertices[Element2];

                        // addEdge() adds for both vertices - do only once
                        if (vertexTag1 > vertexTag2)
                            mySubdomainGraph->addEdge(vertexTag1,vertexTag2);
                            mySubdomainGraph->addEdge(vertexTag2,vertexTag1);                  
                    }
            }
        }

    // done now delete theElementTagVertices, the node Vertices and
    // theNodeTagVertices
   
    delete [] theElementTagVertices;    

    for (int i=0; i<=maxNodNum; i++)
        if ((vertexPtr = theNodeTagVertices[i]) != 0)
            delete vertexPtr;

    delete [] theNodeTagVertices;

    return *mySubdomainGraph;
}


double
PartitionedDomain::getNodeDisp(int nodeTag, int dof, int &errorFlag)
{
  double result = this->Domain::getNodeDisp(nodeTag, dof, errorFlag);

  if (errorFlag != 0) {

    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0 && errorFlag != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            result = theSub->getNodeDisp(nodeTag, dof, errorFlag);
            if (errorFlag == 0)
              return result;
        }          
    }
  }
 
  return result;
}


int
PartitionedDomain::setMass(const Matrix &mass, int nodeTag)
{
  int result = this->Domain::setMass(mass, nodeTag);

  if (result != 0) {

    // do the same for all the subdomains
    if (theSubdomains != 0) {
        ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);  
        TaggedObject *theObject;
        while ((theObject = theSubsIter()) != 0 && result != 0) {
            Subdomain *theSub = (Subdomain *)theObject;    
            result = theSub->setMass(mass, nodeTag);
        }          
    }
  }
 
  return result;
}

const Vector *
PartitionedDomain::getNodeResponse(int nodeTag, NodeResponseType response)
{
  const Vector *res = this->Domain::getNodeResponse(nodeTag, response);
  if (res != 0)
    return res;

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      const Vector *result = theSub->getNodeResponse(nodeTag, response);
      if (result != 0)
        return result;
    }      
  }

  return NULL;
}

int
PartitionedDomain::calculateNodalReactions(bool inclInertia)
{
  int res = this->Domain::calculateNodalReactions(inclInertia);

  // do the same for all the subdomains
  /*
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      res += theSub->calculateNodalReactions(inclInertia);
    }
  }
  */

  return res;
}

bool
PartitionedDomain::addParameter(Parameter *param)
{
    bool res = this->Domain::addParameter(param);

    // do the same for all the subdomains
    if (theSubdomains != 0) {
      ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);    
      TaggedObject *theObject;
      while ((theObject = theSubsIter()) != 0) {
        Subdomain *theSub = (Subdomain *)theObject;        
        theSub->addParameter(param);
      }
    }

    return res;
}

Parameter *
PartitionedDomain::removeParameter(int tag)
{
  Parameter *res = this->Domain::removeParameter(tag);

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      theSub->removeParameter(tag);
    }
  }

  return res;
}


int
PartitionedDomain::updateParameter(int tag, int value)
{
  int res = this->Domain::updateParameter(tag, value);

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {

      Subdomain *theSub = (Subdomain *)theObject;          
      theSub->updateParameter(tag, value);
    }
  }

  return res;
}


int
PartitionedDomain::updateParameter(int tag, double value)
{
  int res = this->Domain::updateParameter(tag, value);

  // do the same for all the subdomains
  if (theSubdomains != 0) {
    ArrayOfTaggedObjectsIter theSubsIter(*theSubdomains);      
    TaggedObject *theObject;
    while ((theObject = theSubsIter()) != 0) {
      Subdomain *theSub = (Subdomain *)theObject;          
      theSub->updateParameter(tag, value);
    }
  }

  return res;
}