Zoltan2
Zoltan2_PartitioningProblem.hpp
Go to the documentation of this file.
00001 // @HEADER
00002 //
00003 // ***********************************************************************
00004 //
00005 //   Zoltan2: A package of combinatorial algorithms for scientific computing
00006 //                  Copyright 2012 Sandia Corporation
00007 //
00008 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00009 // the U.S. Government retains certain rights in this software.
00010 //
00011 // Redistribution and use in source and binary forms, with or without
00012 // modification, are permitted provided that the following conditions are
00013 // met:
00014 //
00015 // 1. Redistributions of source code must retain the above copyright
00016 // notice, this list of conditions and the following disclaimer.
00017 //
00018 // 2. Redistributions in binary form must reproduce the above copyright
00019 // notice, this list of conditions and the following disclaimer in the
00020 // documentation and/or other materials provided with the distribution.
00021 //
00022 // 3. Neither the name of the Corporation nor the names of the
00023 // contributors may be used to endorse or promote products derived from
00024 // this software without specific prior written permission.
00025 //
00026 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00027 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00029 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00030 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00031 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00032 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00033 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00034 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00035 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00036 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037 //
00038 // Questions? Contact Karen Devine      (kddevin@sandia.gov)
00039 //                    Erik Boman        (egboman@sandia.gov)
00040 //                    Siva Rajamanickam (srajama@sandia.gov)
00041 //
00042 // ***********************************************************************
00043 //
00044 // @HEADER
00045 
00050 #ifndef _ZOLTAN2_PARTITIONINGPROBLEM_HPP_
00051 #define _ZOLTAN2_PARTITIONINGPROBLEM_HPP_
00052 
00053 #include <Zoltan2_Problem.hpp>
00054 #include <Zoltan2_PartitioningAlgorithms.hpp>
00055 #include <Zoltan2_PartitioningSolution.hpp>
00056 #include <Zoltan2_PartitioningSolutionQuality.hpp>
00057 #include <Zoltan2_GraphModel.hpp>
00058 #include <Zoltan2_IdentifierModel.hpp>
00059 #include <Zoltan2_IntegerRangeList.hpp>
00060 #include <Zoltan2_MachineRepresentation.hpp>
00061 #include <Zoltan2_TaskMapping.hpp>
00062 
00063 #ifndef _WIN32
00064 #include <unistd.h>
00065 #else
00066 #include <process.h>
00067 #define NOMINMAX
00068 #include <windows.h>
00069 #endif
00070 
00071 #ifdef HAVE_ZOLTAN2_OVIS
00072 #include <ovis.h>
00073 #endif
00074 
00075 namespace Zoltan2{
00076 
00100 template<typename Adapter>
00101 class PartitioningProblem : public Problem<Adapter>
00102 {
00103 public:
00104 
00105   typedef typename Adapter::scalar_t scalar_t;
00106   typedef typename Adapter::zgid_t zgid_t;
00107   typedef typename Adapter::gno_t gno_t;
00108   typedef typename Adapter::lno_t lno_t;
00109   typedef typename Adapter::part_t part_t;
00110   typedef typename Adapter::user_t user_t;
00111   typedef typename Adapter::base_adapter_t base_adapter_t;
00112 
00113 #ifdef HAVE_ZOLTAN2_MPI
00114   typedef Teuchos::OpaqueWrapper<MPI_Comm> mpiWrapper_t;
00117   PartitioningProblem(Adapter *A, ParameterList *p, MPI_Comm comm):
00118       Problem<Adapter>(A,p,comm), solution_(),
00119       problemComm_(), problemCommConst_(),
00120       inputType_(InvalidAdapterType), 
00121       graphFlags_(), idFlags_(), coordFlags_(), algName_(),
00122       numberOfWeights_(), partIds_(), partSizes_(), 
00123       numberOfCriteria_(), levelNumberParts_(), hierarchical_(false), 
00124       timer_(), metricsRequested_(false), metrics_()
00125   {
00126     for(int i=0;i<MAX_NUM_MODEL_TYPES;i++) modelAvail_[i]=false;
00127     initializeProblem();
00128   }
00129 #endif
00130 
00132   PartitioningProblem(Adapter *A, ParameterList *p):
00133       Problem<Adapter>(A,p), solution_(),
00134       problemComm_(), problemCommConst_(),
00135       inputType_(InvalidAdapterType), 
00136       graphFlags_(), idFlags_(), coordFlags_(), algName_(),
00137       numberOfWeights_(), 
00138       partIds_(), partSizes_(), numberOfCriteria_(), 
00139       levelNumberParts_(), hierarchical_(false), timer_(),
00140       metricsRequested_(false), metrics_()
00141   {
00142     for(int i=0;i<MAX_NUM_MODEL_TYPES;i++) modelAvail_[i]=false;
00143     initializeProblem();
00144   }
00145 
00147   PartitioningProblem(Adapter *A, ParameterList *p,
00148                       RCP<const Teuchos::Comm<int> > &comm):
00149       Problem<Adapter>(A,p,comm), solution_(),
00150       problemComm_(), problemCommConst_(),
00151       inputType_(InvalidAdapterType), 
00152       graphFlags_(), idFlags_(), coordFlags_(), algName_(),
00153       numberOfWeights_(), 
00154       partIds_(), partSizes_(), numberOfCriteria_(), 
00155       levelNumberParts_(), hierarchical_(false), timer_(),
00156       metricsRequested_(false), metrics_()
00157   {
00158     for(int i=0;i<MAX_NUM_MODEL_TYPES;i++) modelAvail_[i]=false;
00159     initializeProblem();
00160   }
00161 
00164   ~PartitioningProblem() {};
00165 
00167   //
00168   //    \param updateInputData   If true this indicates that either
00169   //          this is the first attempt at solution, or that we
00170   //          are computing a new solution and the input data has
00171   //          changed since the previous solution was computed.  
00172   //          By input data we mean coordinates, topology, or weights.
00173   //          If false, this indicates that we are computing a
00174   //          new solution using the same input data was used for
00175   //          the previous solution, even though the parameters
00176   //          may have been changed.
00177   //
00178   //  For the sake of performance, we ask the caller to set \c updateInputData
00179   //  to false if he/she is computing a new solution using the same input data,
00180   //  but different problem parameters, than that which was used to compute 
00181   //  the most recent solution.
00182 
00183   void solve(bool updateInputData=true );
00184  
00186   //          when a point lies on a part boundary, the lowest part
00187   //          number on that boundary is returned.
00188   //          Note that not all partitioning algorithms will support
00189   //          this method.
00190   //
00191   //   \param dim : the number of dimensions specified for the point in space
00192   //   \param point : the coordinates of the point in space; array of size dim
00193   //   \return the part number of a part overlapping the given point
00194   //
00195   //   TODO:  This method might be more appropriate in a partitioning solution
00196   //   TODO:  But then the solution would need to know about the algorithm.
00197   //   TODO:  Consider moving the algorithm to the partitioning solution.
00198   part_t pointAssign(int dim, scalar_t *point) 
00199   {
00200     part_t p;
00201     try {
00202       if (this->algorithm_ == Teuchos::null)
00203         throw std::logic_error("no partitioning algorithm has been run yet");
00204 
00205       p = this->algorithm_->pointAssign(dim, point); 
00206     }
00207     Z2_FORWARD_EXCEPTIONS
00208     return p;
00209   }
00210 
00212   //   This method allocates memory for the return argument, but does not
00213   //   control that memory.  The user is responsible for freeing the 
00214   //   memory.
00215   //
00216   //   \param dim : (in) the number of dimensions specified for the box
00217   //   \param lower : (in) the coordinates of the lower corner of the box; 
00218   //                   array of size dim
00219   //   \param upper : (in) the coordinates of the upper corner of the box; 
00220   //                   array of size dim
00221   //   \param nPartsFound : (out) the number of parts overlapping the box
00222   //   \param partsFound :  (out) array of parts overlapping the box
00223   //   TODO:  This method might be more appropriate in a partitioning solution
00224   //   TODO:  But then the solution would need to know about the algorithm.
00225   //   TODO:  Consider moving the algorithm to the partitioning solution.
00226   void boxAssign(int dim, scalar_t *lower, scalar_t *upper,
00227                  size_t &nPartsFound, part_t **partsFound) 
00228   {
00229     try {
00230       if (this->algorithm_ == Teuchos::null)
00231         throw std::logic_error("no partitioning algorithm has been run yet");
00232 
00233       this->algorithm_->boxAssign(dim, lower, upper, nPartsFound, partsFound); 
00234     }
00235     Z2_FORWARD_EXCEPTIONS
00236   }
00237 
00239   //
00240   //   \return  a reference to the solution to the most recent solve().
00241 
00242   const PartitioningSolution<Adapter> &getSolution() {
00243     return *(solution_.getRawPtr());
00244   };
00245 
00254   const scalar_t getWeightImbalance(int idx=0) const {
00255     scalar_t imb = 0;
00256     if (!metrics_.is_null())
00257       metrics_->getWeightImbalance(imb, idx);
00258 
00259     return imb;
00260   }
00261 
00266   ArrayRCP<const MetricValues<scalar_t> > getMetrics() const {
00267    if (metrics_.is_null()){
00268       ArrayRCP<const MetricValues<scalar_t> > emptyMetrics;
00269       return emptyMetrics;
00270     }
00271     else
00272       return metrics_->getMetrics();
00273   }
00274 
00280   void printMetrics(std::ostream &os) const {
00281     if (metrics_.is_null())
00282       os << "No metrics available." << endl;
00283     else
00284       metrics_->printMetrics(os);
00285   };
00286 
00325   void setPartSizes(int len, part_t *partIds, scalar_t *partSizes, 
00326     bool makeCopy=true) 
00327   { 
00328     setPartSizesForCriteria(0, len, partIds, partSizes, makeCopy);
00329   }
00330 
00365   void setPartSizesForCriteria(int criteria, int len, part_t *partIds,
00366     scalar_t *partSizes, bool makeCopy=true) ;
00367 /*
00368   void setMachine(MachineRepresentation<typename Adapter::base_adapter_t::scalar_t> *machine);
00369 */
00372   void resetParameters(ParameterList *params)
00373   {
00374     Problem<Adapter>::resetParameters(params);  // creates new environment
00375     if (timer_.getRawPtr() != NULL)
00376       this->env_->setTimer(timer_);
00377   }
00378 
00383   const RCP<const Environment> & getEnvironment() const 
00384   {
00385     return this->envConst_;
00386   }
00387 
00388 private:
00389   void initializeProblem();
00390 
00391   void createPartitioningProblem(bool newData);
00392 
00393   RCP<PartitioningSolution<Adapter> > solution_;
00394 
00395   RCP<MachineRepresentation <typename Adapter::base_adapter_t::scalar_t>  > machine_;
00396 
00397   RCP<Comm<int> > problemComm_;
00398   RCP<const Comm<int> > problemCommConst_;
00399 
00400   BaseAdapterType inputType_;
00401 
00402   //ModelType modelType_;
00403   bool modelAvail_[MAX_NUM_MODEL_TYPES];
00404 
00405   modelFlag_t graphFlags_;
00406   modelFlag_t idFlags_;
00407   modelFlag_t coordFlags_;
00408   std::string algName_;
00409 
00410   int numberOfWeights_;
00411 
00412   // Suppose Array<part_t> partIds = partIds_[w].  If partIds.size() > 0
00413   // then the user supplied part sizes for weight index "w", and the sizes
00414   // corresponding to the Ids in partIds are partSizes[w].
00415   //
00416   // If numberOfWeights_ >= 0, then there is an Id and Sizes array for
00417   // for each weight.  Otherwise the user did not supply object weights,
00418   // but they can still specify part sizes. 
00419   // So numberOfCriteria_ is numberOfWeights_ or one, whichever is greater.
00420 
00421   ArrayRCP<ArrayRCP<part_t> > partIds_;
00422   ArrayRCP<ArrayRCP<scalar_t> > partSizes_;
00423   int numberOfCriteria_;
00424 
00425   // Number of parts to be computed at each level in hierarchical partitioning.
00426   
00427   ArrayRCP<int> levelNumberParts_;
00428   bool hierarchical_;
00429 
00430   // Create a Timer if the user asked for timing stats.
00431 
00432   RCP<TimerManager> timer_;
00433 
00434   // Did the user request metrics?
00435 
00436   bool metricsRequested_;
00437   RCP<const PartitioningSolutionQuality<Adapter> > metrics_;
00438 };
00440 
00441 /*
00442 template <typename Adapter>
00443 void PartitioningProblem<Adapter>::setMachine(MachineRepresentation<typename Adapter::base_adapter_t::scalar_t> *machine){
00444   this->machine_ = RCP<MachineRepresentation<typename Adapter::base_adapter_t::scalar_t> > (machine, false);
00445 }
00446 */
00447 
00448 
00449 template <typename Adapter>
00450   void PartitioningProblem<Adapter>::initializeProblem()
00451 {
00452   HELLO;
00453 
00454   this->env_->debug(DETAILED_STATUS, "PartitioningProblem::initializeProblem");
00455 
00456   if (getenv("DEBUGME")){
00457 #ifndef _WIN32
00458     std::cout << getpid() << std::endl;
00459     sleep(15);
00460 #else
00461     std::cout << _getpid() << std::endl;
00462     Sleep(15000);
00463 #endif
00464   }
00465 
00466 #ifdef HAVE_ZOLTAN2_OVIS
00467   ovis_enabled(this->comm_->getRank());
00468 #endif
00469 
00470   // Create a copy of the user's communicator.  
00471 
00472   problemComm_ = this->comm_->duplicate();
00473   problemCommConst_ = rcp_const_cast<const Comm<int> > (problemComm_);
00474 
00475   machine_ = RCP <Zoltan2::MachineRepresentation<typename Adapter::scalar_t> >(new Zoltan2::MachineRepresentation<typename Adapter::scalar_t>(problemComm_));
00476 
00477   // Number of criteria is number of user supplied weights if non-zero.
00478   // Otherwise it is 1 and uniform weight is implied.
00479 
00480   numberOfWeights_ = this->inputAdapter_->getNumWeightsPerID();
00481 
00482   numberOfCriteria_ = (numberOfWeights_ > 1) ? numberOfWeights_ : 1;
00483 
00484   inputType_ = this->inputAdapter_->adapterType();
00485 
00486   // The Caller can specify part sizes in setPartSizes().  If he/she
00487   // does not, the part size arrays are empty.
00488 
00489   ArrayRCP<part_t> *noIds = new ArrayRCP<part_t> [numberOfCriteria_];
00490   ArrayRCP<scalar_t> *noSizes = new ArrayRCP<scalar_t> [numberOfCriteria_];
00491 
00492   partIds_ = arcp(noIds, 0, numberOfCriteria_, true);
00493   partSizes_ = arcp(noSizes, 0, numberOfCriteria_, true);
00494 
00495   if (this->env_->getDebugLevel() >= DETAILED_STATUS){
00496     std::ostringstream msg;
00497     msg << problemComm_->getSize() << " procs,"
00498       << numberOfWeights_ << " user-defined weights\n";
00499     this->env_->debug(DETAILED_STATUS, msg.str());
00500   }
00501 
00502   this->env_->memory("After initializeProblem");
00503 }
00504 
00505 template <typename Adapter>
00506   void PartitioningProblem<Adapter>::setPartSizesForCriteria(
00507     int criteria, int len, part_t *partIds, scalar_t *partSizes, bool makeCopy) 
00508 {
00509   this->env_->localInputAssertion(__FILE__, __LINE__, "invalid length", 
00510     len>= 0, BASIC_ASSERTION);
00511 
00512   this->env_->localInputAssertion(__FILE__, __LINE__, "invalid criteria", 
00513     criteria >= 0 && criteria < numberOfCriteria_, BASIC_ASSERTION);
00514 
00515   if (len == 0){
00516     partIds_[criteria] = ArrayRCP<part_t>();
00517     partSizes_[criteria] = ArrayRCP<scalar_t>();
00518     return;
00519   }
00520 
00521   this->env_->localInputAssertion(__FILE__, __LINE__, "invalid arrays", 
00522     partIds && partSizes, BASIC_ASSERTION);
00523 
00524   // The global validity of the partIds and partSizes arrays is performed
00525   // by the PartitioningSolution, which computes global part distribution and
00526   // part sizes.
00527 
00528   part_t *z2_partIds = NULL;
00529   scalar_t *z2_partSizes = NULL;
00530   bool own_memory = false;
00531 
00532   if (makeCopy){
00533     z2_partIds = new part_t [len];
00534     z2_partSizes = new scalar_t [len];
00535     this->env_->localMemoryAssertion(__FILE__, __LINE__, len, z2_partSizes);
00536     memcpy(z2_partIds, partIds, len * sizeof(part_t));
00537     memcpy(z2_partSizes, partSizes, len * sizeof(scalar_t));
00538     own_memory=true;
00539   }
00540   else{
00541     z2_partIds = partIds;
00542     z2_partSizes = partSizes;
00543   }
00544 
00545   partIds_[criteria] = arcp(z2_partIds, 0, len, own_memory);
00546   partSizes_[criteria] = arcp(z2_partSizes, 0, len, own_memory);
00547 }
00548 
00549 template <typename Adapter>
00550 void PartitioningProblem<Adapter>::solve(bool updateInputData)
00551 {
00552   HELLO;
00553   this->env_->debug(DETAILED_STATUS, "Entering solve");
00554 
00555   // Create the computational model.
00556 
00557   this->env_->timerStart(MACRO_TIMERS, "create problem");
00558 
00559   createPartitioningProblem(updateInputData);
00560 
00561   this->env_->timerStop(MACRO_TIMERS, "create problem");
00562 
00563   // TODO: If hierarchical_
00564 
00565   // Create the solution. The algorithm will query the Solution
00566   //   for part and weight information. The algorithm will
00567   //   update the solution with part assignments and quality
00568   //   metrics.  The Solution object itself will convert our internal
00569   //   global numbers back to application global Ids if needed.
00570 
00571   RCP<const IdentifierMap<user_t> > idMap = 
00572     this->baseModel_->getIdentifierMap();
00573 
00574   PartitioningSolution<Adapter> *soln = NULL;
00575 
00576   this->env_->timerStart(MACRO_TIMERS, "create solution");
00577 
00578   try{
00579     soln = new PartitioningSolution<Adapter>( 
00580       this->envConst_, problemCommConst_, idMap, numberOfWeights_, 
00581       partIds_.view(0, numberOfCriteria_), 
00582       partSizes_.view(0, numberOfCriteria_));
00583   }
00584   Z2_FORWARD_EXCEPTIONS;
00585 
00586   solution_ = rcp(soln);
00587 
00588   this->env_->timerStop(MACRO_TIMERS, "create solution");
00589 
00590   this->env_->memory("After creating Solution");
00591 
00592   // Call the algorithm
00593 
00594   try {
00595     if (algName_ == std::string("scotch")) {
00596 
00597       this->algorithm_ = rcp(new AlgPTScotch<Adapter>(this->envConst_,
00598                                             problemComm_,
00599                                             this->graphModel_));
00600       this->algorithm_->partition(solution_);
00601     }
00602 
00603     else if (algName_ == std::string("parmetis")) {
00604 
00605       this->algorithm_ = rcp(new AlgParMETIS<Adapter>(this->envConst_,
00606                                             problemComm_,
00607                                             this->graphModel_));
00608       this->algorithm_->partition(solution_);
00609     }
00610 
00611     else if (algName_ == std::string("block")) {
00612 
00613       this->algorithm_ = rcp(new AlgBlock<Adapter>(this->envConst_,
00614                                          problemComm_, this->identifierModel_));
00615       this->algorithm_->partition(solution_);
00616     }
00617 
00618     else if (algName_ == std::string("rcb")) {
00619 
00620       this->algorithm_ = rcp(new AlgRCB<Adapter>(this->envConst_, problemComm_,
00621                                                  this->coordinateModel_));
00622       this->algorithm_->partition(solution_);
00623     }
00624 
00625     else if (algName_ == std::string("multijagged")) {
00626 
00627       this->algorithm_ = rcp(new Zoltan2_AlgMJ<Adapter>(this->envConst_,
00628                                               problemComm_,
00629                                               this->coordinateModel_));
00630       this->algorithm_->partition(solution_);
00631     }
00632 
00633     else if (algName_ == std::string("wolf")) {
00634 
00635       this->algorithm_ = rcp(new AlgWolf<Adapter>(this->envConst_,
00636                                         problemComm_,this->graphModel_,
00637                                         this->coordinateModel_));
00638 
00639       // need to add coordModel, make sure this is built
00640       this->algorithm_->partition(solution_);
00641     }
00642     else {
00643       throw std::logic_error("partitioning algorithm not supported");
00644     }
00645   }
00646   Z2_FORWARD_EXCEPTIONS;
00647 
00648   //if mapping is requested
00649   const Teuchos::ParameterEntry *pe = this->envConst_->getParameters().getEntryPtr("mapping_type");
00650   int mapping_type = -1;
00651   if (pe){
00652     mapping_type = pe->getValue(&mapping_type);
00653   }
00654   //if mapping is 0 -- coordinate mapping
00655 
00656   if (mapping_type == 0){
00657 
00658     //part_t *task_communication_xadj = NULL, *task_communication_adj = NULL;
00659 
00660     Zoltan2::CoordinateTaskMapper <Adapter, part_t> *ctm=
00661                   new Zoltan2::CoordinateTaskMapper<Adapter,part_t>(
00662                           problemComm_.getRawPtr(),
00663                           machine_.getRawPtr(),
00664                           this->coordinateModel_.getRawPtr(),
00665                           solution_.getRawPtr(),
00666                           this->envConst_.getRawPtr()
00667                           //,task_communication_xadj,
00668                           //task_communication_adj
00669                           );
00670     //for now just delete the object.
00671     delete ctm;
00672   }
00673   else if (mapping_type == 1){
00674     //if mapping is 1 -- graph mapping
00675   }
00676 
00677   if (metricsRequested_){
00678     typedef PartitioningSolution<Adapter> ps_t;
00679     typedef PartitioningSolutionQuality<Adapter> psq_t;
00680 
00681     psq_t *quality = NULL;
00682     RCP<const ps_t> solutionConst = rcp_const_cast<const ps_t>(solution_);
00683     RCP<const Adapter> adapter = rcp(this->inputAdapter_, false);
00684 
00685     try{
00686       quality = new psq_t(this->envConst_, problemCommConst_, adapter, 
00687         solutionConst);
00688     }
00689     Z2_FORWARD_EXCEPTIONS
00690 
00691     metrics_ = rcp(quality);
00692   }
00693 
00694   this->env_->debug(DETAILED_STATUS, "Exiting solve");
00695 }
00696 
00697 template <typename Adapter>
00698 void PartitioningProblem<Adapter>::createPartitioningProblem(bool newData)
00699 {
00700   HELLO;
00701   this->env_->debug(DETAILED_STATUS, 
00702     "PartitioningProblem::createPartitioningProblem");
00703 
00704   using std::string;
00705   using Teuchos::ParameterList;
00706 
00707   // A Problem object may be reused.  The input data may have changed and
00708   // new parameters or part sizes may have been set.
00709   //
00710   // Save these values in order to determine if we need to create a new model.
00711 
00712   //ModelType previousModel = modelType_;
00713   bool prevModelAvail[MAX_NUM_MODEL_TYPES];
00714   for(int i=0;i<MAX_NUM_MODEL_TYPES;i++)
00715   {
00716     prevModelAvail[i] = modelAvail_[i];
00717   }
00718 
00719 
00720   modelFlag_t previousGraphModelFlags = graphFlags_;
00721   modelFlag_t previousIdentifierModelFlags = idFlags_;
00722   modelFlag_t previousCoordinateModelFlags = coordFlags_;
00723 
00724   //modelType_ = InvalidModel;
00725   for(int i=0;i<MAX_NUM_MODEL_TYPES;i++)
00726   {
00727     modelAvail_[i] = false;
00728   }
00729 
00730   graphFlags_.reset();
00731   idFlags_.reset();
00732   coordFlags_.reset();
00733 
00735   // It's possible at this point that the Problem may want to
00736   // add problem parameters to the parameter list in the Environment. 
00737   //
00738   // Since the parameters in the Environment have already been
00739   // validated in its constructor, a new Environment must be created:
00741   // Teuchos::RCP<const Teuchos::Comm<int> > oldComm = this->env_->comm_;
00742   // const ParameterList &oldParams = this->env_->getUnvalidatedParameters();
00743   // 
00744   // ParameterList newParams = oldParams;
00745   // newParams.set("new_parameter", "new_value");
00746   // 
00747   // ParameterList &newPartParams = newParams.sublist("partitioning");
00748   // newPartParams.set("new_partitioning_parameter", "its_value");
00749   // 
00750   // this->env_ = rcp(new Environment(newParams, oldComm));
00752 
00753   this->env_->debug(DETAILED_STATUS, "    parameters");
00754   Environment &env = *(this->env_);
00755   ParameterList &pl = env.getParametersNonConst();
00756 
00757   std::string defString("default");
00758 
00759   // Did the user ask for computation of quality metrics?
00760 
00761   int yesNo=0;
00762   const Teuchos::ParameterEntry *pe = pl.getEntryPtr("compute_metrics");
00763   if (pe){
00764     yesNo = pe->getValue<int>(&yesNo);
00765     metricsRequested_ = true;
00766   }
00767 
00768   // Did the user specify a computational model?
00769 
00770   std::string model(defString);
00771   pe = pl.getEntryPtr("model");
00772   if (pe)
00773     model = pe->getValue<std::string>(&model);
00774 
00775   // Did the user specify an algorithm?
00776 
00777   std::string algorithm(defString);
00778   pe = pl.getEntryPtr("algorithm");
00779   if (pe)
00780     algorithm = pe->getValue<std::string>(&algorithm);
00781 
00782   // Possible algorithm requirements that must be conveyed to the model:
00783 
00784   bool needConsecutiveGlobalIds = false;
00785   bool removeSelfEdges= false;
00786 
00788   // Determine algorithm, model, and algorithm requirements.  This
00789   // is a first pass.  Feel free to change this and add to it.
00790 
00791   if (algorithm != defString)
00792   {
00793 
00794     // Figure out the model required by the algorithm
00795     if (algorithm == std::string("block") ||
00796         algorithm == std::string("random") ||
00797         algorithm == std::string("cyclic") ){
00798 
00799       //modelType_ = IdentifierModelType;
00800       modelAvail_[IdentifierModelType] = true;
00801 
00802       algName_ = algorithm;
00803       needConsecutiveGlobalIds = true;
00804     }
00805     else if (algorithm == std::string("rcb") ||
00806              algorithm == std::string("rib") ||
00807              algorithm == std::string("multijagged") ||
00808              algorithm == std::string("hsfc"))
00809     {
00810       //modelType_ = CoordinateModelType;
00811       modelAvail_[CoordinateModelType]=true;
00812     
00813       algName_ = algorithm;
00814     }
00815     else if (algorithm == std::string("metis") ||
00816              algorithm == std::string("parmetis") ||
00817              algorithm == std::string("scotch") ||
00818              algorithm == std::string("ptscotch"))
00819     {
00820 
00821       //modelType_ = GraphModelType;
00822       modelAvail_[GraphModelType]=true;
00823 
00824       algName_ = algorithm;
00825       removeSelfEdges = true;
00826       needConsecutiveGlobalIds = true;
00827     }
00828     else if (algorithm == std::string("patoh") ||
00829              algorithm == std::string("phg"))
00830     {
00831       // if ((modelType_ != GraphModelType) &&
00832       //     (modelType_ != HypergraphModelType) )
00833       if ((modelAvail_[GraphModelType]==false) &&
00834           (modelAvail_[HypergraphModelType]==false) )
00835       {
00836         //modelType_ = HypergraphModelType;
00837         modelAvail_[HypergraphModelType]=true;
00838       }
00839       algName_ = algorithm;
00840       needConsecutiveGlobalIds = true;
00841     }
00842     else if (algorithm == std::string("wolf"))
00843     {
00844       modelAvail_[GraphModelType]=true;
00845       modelAvail_[CoordinateModelType]=true;
00846       algName_ = algorithm;
00847     }
00848     else
00849     {
00850       // Parameter list should ensure this does not happen.
00851       throw std::logic_error("parameter list algorithm is invalid");
00852     }
00853   }
00854   else if (model != defString)
00855   {
00856     // Figure out the algorithm suggested by the model.
00857     if (model == std::string("hypergraph"))
00858     {      
00859       //modelType_ = HypergraphModelType;
00860       modelAvail_[HypergraphModelType]=true;
00861 
00862       if (problemComm_->getSize() > 1)
00863         algName_ = std::string("phg"); 
00864       else
00865         algName_ = std::string("patoh"); 
00866       needConsecutiveGlobalIds = true;
00867     }
00868     else if (model == std::string("graph"))
00869     {
00870       //modelType_ = GraphModelType;
00871       modelAvail_[GraphModelType]=true;
00872 
00873 #ifdef HAVE_ZOLTAN2_SCOTCH
00874       if (problemComm_->getSize() > 1)
00875         algName_ = std::string("ptscotch"); 
00876       else
00877         algName_ = std::string("scotch"); 
00878       removeSelfEdges = true;
00879       needConsecutiveGlobalIds = true;
00880 #else
00881 #ifdef HAVE_ZOLTAN2_PARMETIS
00882       if (problemComm_->getSize() > 1)
00883         algName_ = std::string("parmetis"); 
00884       else
00885         algName_ = std::string("metis"); 
00886       removeSelfEdges = true;
00887       needConsecutiveGlobalIds = true;
00888 #else
00889       if (problemComm_->getSize() > 1)
00890         algName_ = std::string("phg"); 
00891       else
00892         algName_ = std::string("patoh"); 
00893       removeSelfEdges = true;
00894       needConsecutiveGlobalIds = true;
00895 #endif
00896 #endif
00897     }
00898     else if (model == std::string("geometry"))
00899     {
00900       //modelType_ = CoordinateModelType;
00901       modelAvail_[CoordinateModelType]=true;
00902 
00903       algName_ = std::string("rcb");
00904     }
00905     else if (model == std::string("ids"))
00906     {
00907       //modelType_ = IdentifierModelType;
00908       modelAvail_[IdentifierModelType]=true;
00909 
00910       algName_ = std::string("block");
00911       needConsecutiveGlobalIds = true;
00912     }
00913     else
00914     {
00915       // Parameter list should ensure this does not happen.
00916       env.localBugAssertion(__FILE__, __LINE__, 
00917         "parameter list model type is invalid", 1, BASIC_ASSERTION);
00918     }
00919   }
00920   else
00921   {   
00922     // Determine an algorithm and model suggested by the input type.
00923     //   TODO: this is a good time to use the time vs. quality parameter
00924     //     in choosing an algorithm, and setting some parameters
00925 
00926     if (inputType_ == MatrixAdapterType)
00927     {
00928       //modelType_ = HypergraphModelType;
00929       modelAvail_[HypergraphModelType]=true;
00930       
00931       if (problemComm_->getSize() > 1)
00932         algName_ = std::string("phg"); 
00933       else
00934         algName_ = std::string("patoh"); 
00935     }
00936     else if (inputType_ == GraphAdapterType ||
00937         inputType_ == MeshAdapterType)
00938     {
00939       //modelType_ = GraphModelType;
00940       modelAvail_[GraphModelType]=true;
00941 
00942       if (problemComm_->getSize() > 1)
00943         algName_ = std::string("phg"); 
00944       else
00945         algName_ = std::string("patoh"); 
00946     }
00947     else if (inputType_ == CoordinateAdapterType)
00948     {
00949       //modelType_ = CoordinateModelType;
00950       modelAvail_[CoordinateModelType]=true;
00951 
00952       if(algName_ != std::string("multijagged"))
00953       algName_ = std::string("rcb");
00954     }
00955     else if (inputType_ == VectorAdapterType ||
00956              inputType_ == IdentifierAdapterType)
00957     {
00958       //modelType_ = IdentifierModelType;
00959       modelAvail_[IdentifierModelType]=true;
00960 
00961       algName_ = std::string("block");
00962     }
00963     else{
00964       // This should never happen
00965       throw std::logic_error("input type is invalid");
00966     }
00967   }
00968 
00969   // Hierarchical partitioning?
00970 
00971   Array<int> valueList;
00972   pe = pl.getEntryPtr("topology");
00973 
00974   if (pe){
00975     valueList = pe->getValue<Array<int> >(&valueList);
00976 
00977     if (!Zoltan2::noValuesAreInRangeList<int>(valueList)){
00978       int *n = new int [valueList.size() + 1];
00979       levelNumberParts_ = arcp(n, 0, valueList.size() + 1, true);
00980       int procsPerNode = 1;
00981       for (int i=0; i < valueList.size(); i++){
00982         levelNumberParts_[i+1] = valueList[i];
00983         procsPerNode *= valueList[i];
00984       }
00985       // Number of parts in the first level
00986       levelNumberParts_[0] = env.numProcs_ / procsPerNode;
00987 
00988       if (env.numProcs_ % procsPerNode > 0)
00989         levelNumberParts_[0]++;
00990     }
00991   }
00992   else{
00993     levelNumberParts_.clear();
00994   }
00995 
00996   hierarchical_ = levelNumberParts_.size() > 0;
00997 
00998   // Object to be partitioned? (rows, columns, etc)
00999 
01000   std::string objectOfInterest(defString);
01001   pe = pl.getEntryPtr("objects_to_partition");
01002   if (pe)
01003     objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
01004 
01006   // Set model creation flags, if any.
01007 
01008   this->env_->debug(DETAILED_STATUS, "    models");
01009   //  if (modelType_ == GraphModelType)
01010   if (modelAvail_[GraphModelType]==true)
01011   {
01012 
01013     // Any parameters in the graph sublist?
01014 
01015     std::string symParameter(defString);
01016     pe = pl.getEntryPtr("symmetrize_graph");
01017     if (pe){
01018       symParameter = pe->getValue<std::string>(&symParameter);
01019       if (symParameter == std::string("transpose"))
01020         graphFlags_.set(SYMMETRIZE_INPUT_TRANSPOSE);
01021       else if (symParameter == std::string("bipartite"))
01022         graphFlags_.set(SYMMETRIZE_INPUT_BIPARTITE);
01023     } 
01024 
01025     int sgParameter = 0;
01026     pe = pl.getEntryPtr("subset_graph");
01027     if (pe)
01028       sgParameter = pe->getValue<int>(&sgParameter);
01029 
01030     if (sgParameter == 1)
01031         graphFlags_.set(GRAPH_IS_A_SUBSET_GRAPH);
01032 
01033     // Any special behaviors required by the algorithm?
01034     
01035     if (removeSelfEdges)
01036       graphFlags_.set(SELF_EDGES_MUST_BE_REMOVED);
01037 
01038     if (needConsecutiveGlobalIds)
01039       graphFlags_.set(IDS_MUST_BE_GLOBALLY_CONSECUTIVE);
01040 
01041     // How does user input map to vertices and edges?
01042 
01043     if (inputType_ == MatrixAdapterType){
01044       if (objectOfInterest == defString ||
01045           objectOfInterest == std::string("matrix_rows") )
01046         graphFlags_.set(VERTICES_ARE_MATRIX_ROWS);
01047       else if (objectOfInterest == std::string("matrix_columns"))
01048         graphFlags_.set(VERTICES_ARE_MATRIX_COLUMNS);
01049       else if (objectOfInterest == std::string("matrix_nonzeros"))
01050         graphFlags_.set(VERTICES_ARE_MATRIX_NONZEROS);
01051     }
01052 
01053     else if (inputType_ == MeshAdapterType){
01054       if (objectOfInterest == defString ||
01055           objectOfInterest == std::string("mesh_nodes") )
01056         graphFlags_.set(VERTICES_ARE_MESH_NODES);
01057       else if (objectOfInterest == std::string("mesh_elements"))
01058         graphFlags_.set(VERTICES_ARE_MESH_ELEMENTS);
01059     } 
01060   }
01061   //MMW is it ok to remove else?
01062   //  else if (modelType_ == IdentifierModelType)
01063   if (modelAvail_[IdentifierModelType]==true)
01064   {
01065 
01066     // Any special behaviors required by the algorithm?
01067     
01068     if (needConsecutiveGlobalIds)
01069       idFlags_.set(IDS_MUST_BE_GLOBALLY_CONSECUTIVE);
01070   }
01071   //  else if (modelType_ == CoordinateModelType)
01072   if (modelAvail_[CoordinateModelType]==true)
01073   {
01074 
01075     // Any special behaviors required by the algorithm?
01076     
01077     if (needConsecutiveGlobalIds)
01078       coordFlags_.set(IDS_MUST_BE_GLOBALLY_CONSECUTIVE);
01079   }
01080 
01081 
01082   if ( newData ||
01083        (modelAvail_[GraphModelType]!=prevModelAvail[GraphModelType]) ||
01084        (modelAvail_[HypergraphModelType]!=prevModelAvail[HypergraphModelType]) ||
01085        (modelAvail_[CoordinateModelType]!=prevModelAvail[CoordinateModelType]) ||
01086        (modelAvail_[IdentifierModelType]!=prevModelAvail[IdentifierModelType]) ||
01087   //       (modelType_ != previousModel) ||
01088        (graphFlags_ != previousGraphModelFlags) ||
01089        (coordFlags_ != previousCoordinateModelFlags) ||
01090        (idFlags_ != previousIdentifierModelFlags) ) 
01091   {
01092 
01093     // Create the computational model.
01094     // Models are instantiated for base input adapter types (mesh,
01095     // matrix, graph, and so on).  We pass a pointer to the input
01096     // adapter, cast as the base input type.
01097 
01098     //KDD Not sure why this shadow declaration is needed
01099     //KDD Comment out for now; revisit later if problems.
01100     //KDD const Teuchos::ParameterList pl = this->envConst_->getParameters();
01101     //bool exceptionThrow = true;
01102 
01103     if(modelAvail_[GraphModelType]==false && modelAvail_[HypergraphModelType]==false &&
01104        modelAvail_[CoordinateModelType]==false && modelAvail_[IdentifierModelType]==false)
01105     {
01106       cout << __func__zoltan2__ << " Invalid model"  << endl;
01107     }
01108     else
01109     {
01110       if(modelAvail_[GraphModelType]==true)
01111       {
01112         this->env_->debug(DETAILED_STATUS, "    building graph model");
01113         this->graphModel_ = rcp(new GraphModel<base_adapter_t>(
01114           this->baseInputAdapter_, this->envConst_, problemComm_, graphFlags_));
01115 
01116         this->baseModel_ = rcp_implicit_cast<const Model<base_adapter_t> >(this->graphModel_);
01117       }
01118       if(modelAvail_[HypergraphModelType]==true)
01119       {
01120   std::cout << "Hypergraph model not implemented yet..." << std::endl;
01121       }
01122 
01123       if(modelAvail_[CoordinateModelType]==true)
01124       {
01125         this->env_->debug(DETAILED_STATUS, "    building coordinate model");
01126         this->coordinateModel_ = rcp(new CoordinateModel<base_adapter_t>(
01127                    this->baseInputAdapter_, this->envConst_, problemComm_, coordFlags_));
01128 
01129         this->baseModel_ = rcp_implicit_cast<const Model<base_adapter_t> >(this->coordinateModel_);
01130       }
01131 
01132       if(modelAvail_[IdentifierModelType]==true)
01133       {
01134         this->env_->debug(DETAILED_STATUS, "    building identifier model");
01135         this->identifierModel_ = rcp(new IdentifierModel<base_adapter_t>(
01136                                      this->baseInputAdapter_, this->envConst_, problemComm_, idFlags_));
01137 
01138         this->baseModel_ = rcp_implicit_cast<const Model<base_adapter_t> >(this->identifierModel_);
01139       }
01140   
01141 
01142     }
01143 
01144 
01145 
01146     this->env_->memory("After creating Model");
01147     this->env_->debug(DETAILED_STATUS, "createPartitioningProblem done");
01148   }
01149 
01150 }
01151 
01152 }  // namespace Zoltan2
01153 #endif