• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

LCMPartition.cc

Go to the documentation of this file.
00001 //*****************************************************************//
00002 //    Albany 2.0:  Copyright 2012 Sandia Corporation               //
00003 //    This Software is released under the BSD license detailed     //
00004 //    in the file "license.txt" in the top-level Albany directory  //
00005 //*****************************************************************//
00006 
00007 // Define only if Zoltan is enabled
00008 #if defined (ALBANY_LCM) && defined(ALBANY_ZOLTAN)
00009 
00010 #include <algorithm>
00011 #include <cassert>
00012 #include <cstdlib>
00013 #include <fstream>
00014 #include <iomanip>
00015 #include <iterator>
00016 #include <sstream>
00017 #include <string>
00018 
00019 #include <boost/graph/adjacency_list.hpp>
00020 #include <boost/graph/connected_components.hpp>
00021 
00022 #include "LCMPartition.h"
00023 
00024 using Intrepid::Index;
00025 using Intrepid::Vector;
00026 using Teuchos::ArrayRCP;
00027 
00028 namespace LCM {
00029 
00030 //
00031 // Anonymous namespace for helper functions
00032 //
00033 namespace {
00034 
00035 //
00036 // Print parameters and partitions computed by Zoltan.
00037 // Used for debugging.
00038 //
00039 void PrintPartitionInfo(
00040     std::ostream & output_stream,
00041     int &changes,
00042     int &num_gid_entries,
00043     int &num_lid_entries,
00044     int &num_import,
00045     ZOLTAN_ID_PTR &import_global_ids,
00046     ZOLTAN_ID_PTR &import_local_ids,
00047     int * &import_procs,
00048     int * &import_to_part,
00049     int &num_export,
00050     ZOLTAN_ID_PTR &export_global_ids,
00051     ZOLTAN_ID_PTR &export_local_ids,
00052     int * &export_procs,
00053     int * &export_to_part )
00054 {
00055 
00056   output_stream << "Changes           : " << changes << '\n';
00057   output_stream << "Number GID entries: " << num_gid_entries << '\n';
00058   output_stream << "Number LID entries: " << num_lid_entries << '\n';
00059   output_stream << "Number to import  : " << num_import << '\n';
00060   output_stream << "Number to export  : " << num_export << '\n';
00061 
00062   output_stream << "Import GIDs:" << '\n';
00063   for (int i = 0; i < num_import; ++i) {
00064     output_stream << import_global_ids[i] << '\n';
00065   }
00066 
00067   output_stream << "Import LIDs:" << '\n';
00068   for (int i = 0; i < num_import; ++i) {
00069     output_stream << import_local_ids[i] << '\n';
00070   }
00071 
00072   output_stream << "Import procs:" << '\n';
00073   for (int i = 0; i < num_import; ++i) {
00074     output_stream << import_procs[i] << '\n';
00075   }
00076 
00077   output_stream << "Import parts:" << '\n';
00078   for (int i = 0; i < num_import; ++i) {
00079     output_stream << import_to_part[i] << '\n';
00080   }
00081 
00082   output_stream << "Export GIDs:" << '\n';
00083   for (int i = 0; i < num_export; ++i) {
00084     output_stream << export_global_ids[i] << '\n';
00085   }
00086 
00087   output_stream << "Export LIDs:" << '\n';
00088   for (int i = 0; i < num_export; ++i) {
00089     output_stream << export_local_ids[i] << '\n';
00090   }
00091 
00092   output_stream << "Export procs:" << '\n';
00093   for (int i = 0; i < num_export; ++i) {
00094     output_stream << export_procs[i] << '\n';
00095   }
00096 
00097   output_stream << "Export parts:" << '\n';
00098   for (int i = 0; i < num_export; ++i) {
00099     output_stream << export_to_part[i] << '\n';
00100   }
00101 
00102 }
00103 
00104 //
00105 // Given a vector of points and a set of indices to this vector:
00106 // 1) Find the bounding box of the indexed points.
00107 // 2) Compute the vector sum of the indexed points.
00108 //
00109 boost::tuple< Vector<double>, Vector<double>, Vector<double> >
00110 bounds_and_sum_subset(
00111     std::vector< Vector<double> > const & points,
00112     std::set<Index> const & indices)
00113 {
00114   assert(points.size() > 0);
00115   assert(indices.size() > 0);
00116 
00117   Index const
00118   first = *indices.begin();
00119 
00120   Vector<double>
00121   sum = points[first];
00122 
00123   Vector<double>
00124   lower_corner = sum;
00125 
00126   Vector<double>
00127   upper_corner = sum;
00128 
00129   Index const
00130   N = sum.get_dimension();
00131 
00132   for (std::set<Index>::const_iterator it = ++indices.begin();
00133       it != indices.end();
00134       ++it) {
00135 
00136     Index const
00137     index = *it;
00138 
00139     Vector<double> const &
00140     p = points[index];
00141 
00142     sum += p;
00143 
00144     for (Index i = 0; i < N; ++i) {
00145       lower_corner(i) = std::min(lower_corner(i), p(i));
00146       upper_corner(i) = std::max(upper_corner(i), p(i));
00147     }
00148 
00149   }
00150 
00151   return boost::make_tuple(lower_corner, upper_corner, sum);
00152 }
00153 
00154 //
00155 // Given point, a vector of centers and a set of indices into this vector:
00156 // Return the index of the center closest to the point among the
00157 // indexed centers.
00158 //
00159 Index
00160 closest_subset(
00161     Vector<double> const & point,
00162     std::vector< ClusterCenter > const & centers,
00163     std::set<Index> const & indices)
00164 {
00165   assert(centers.size() > 0);
00166   assert(indices.size() > 0);
00167 
00168   Index const
00169   first = *indices.begin();
00170 
00171   double
00172   minimum = norm_square(centers[first].position - point);
00173 
00174   Index
00175   index_minimum = first;
00176 
00177   for (std::set<Index>::const_iterator it = ++indices.begin();
00178       it != indices.end();
00179       ++it) {
00180 
00181     Index const
00182     index = *it;
00183 
00184     Vector<double> const &
00185     p = centers[index].position;
00186 
00187     double const
00188     s = norm_square(p - point);
00189 
00190     if (s < minimum) {
00191       minimum = s;
00192       index_minimum = index;
00193     }
00194 
00195   }
00196 
00197   return index_minimum;
00198 }
00199 
00200 //
00201 // Given a vector of points and a set of indices:
00202 // 1) Find the bounding box of the indexed points.
00203 // 2) Divide the bounding box along its largest dimension, using median.
00204 // 3) Assign points to one side or the other, and return index sets.
00205 //
00206 std::pair< std::set<Index>, std::set<Index> >
00207 split_box(
00208     std::vector< Vector<double> > const & points,
00209     std::set<Index> const & indices)
00210 {
00211   assert(points.size() > 0);
00212   assert(indices.size() > 0);
00213 
00214   //
00215   // Compute bounding box
00216   //
00217   Index const
00218   first = *indices.begin();
00219 
00220   Vector<double>
00221   lower_corner = points[first];
00222 
00223   Vector<double>
00224   upper_corner = lower_corner;
00225 
00226   Index const
00227   N = lower_corner.get_dimension();
00228 
00229   for (std::set<Index>::const_iterator it = ++indices.begin();
00230       it != indices.end();
00231       ++it) {
00232 
00233     Index const
00234     index = *it;
00235 
00236     Vector<double> const &
00237     p = points[index];
00238 
00239     for (Index i = 0; i < N; ++i) {
00240       lower_corner(i) = std::min(lower_corner(i), p(i));
00241       upper_corner(i) = std::max(upper_corner(i), p(i));
00242     }
00243 
00244   }
00245 
00246   //
00247   // Find largest dimension
00248   //
00249   Vector<double> const
00250   span = upper_corner - lower_corner;
00251 
00252   assert(norm_square(span) > 0.0);
00253 
00254   double
00255   maximum_span = span(0);
00256 
00257   Index
00258   largest_dimension = 0;
00259 
00260   for (Index i = 1; i < N; ++i) {
00261 
00262     double const
00263     s = span(i);
00264 
00265     if (s > maximum_span) {
00266       maximum_span = s;
00267       largest_dimension = i;
00268     }
00269 
00270   }
00271 
00272   //
00273   // Find median coordinate along largest dimension
00274   //
00275   std::vector<double>
00276   coordinates;
00277 
00278   for (std::set<Index>::const_iterator it = indices.begin();
00279       it != indices.end();
00280       ++it) {
00281 
00282     Index const
00283     index = *it;
00284 
00285     Vector<double> const &
00286     p = points[index];
00287 
00288     coordinates.push_back(p(largest_dimension));
00289 
00290   }
00291 
00292   std::sort(coordinates.begin(), coordinates.end());
00293 
00294   double
00295   split_coordinate =
00296       Intrepid::median<double>(coordinates.begin(), coordinates.end());
00297 
00298   //
00299   // Check whether splitting the box will result in one box of
00300   // the same volume as the original and another one of zero volume.
00301   // If so, split the original box into two of equal volume.
00302   //
00303   bool const
00304   box_unchanged =
00305       split_coordinate == lower_corner(largest_dimension) ||
00306       split_coordinate == upper_corner(largest_dimension);
00307 
00308   if (box_unchanged == true) {
00309 
00310     std::sort(coordinates.begin(), coordinates.end());
00311 
00312     split_coordinate =
00313         0.5 * (coordinates[0] + coordinates[coordinates.size() - 1]);
00314 
00315   }
00316 
00317   //
00318   // Assign points to lower or upper half.
00319   //
00320   std::set<Index>
00321   indices_lower;
00322 
00323   std::set<Index>
00324   indices_upper;
00325 
00326   Vector<double>
00327   split_limit = upper_corner;
00328 
00329   split_limit(largest_dimension) = split_coordinate;
00330 
00331   for (std::set<Index>::const_iterator it = indices.begin();
00332       it != indices.end();
00333       ++it) {
00334 
00335     Index const
00336     index = *it;
00337 
00338     Vector<double> const &
00339     p = points[index];
00340 
00341     if (in_box(p, lower_corner, split_limit) == true) {
00342       indices_lower.insert(index);
00343     } else {
00344       indices_upper.insert(index);
00345     }
00346 
00347   }
00348 
00349   return std::make_pair(indices_lower, indices_upper);
00350 }
00351 
00352 } // anonymous namespace
00353 
00354 //
00355 // Build KD tree of list of points.
00356 // \param point list
00357 // \return Boost shared pointer to root node of tree.
00358 //
00359 template<typename Node>
00360 boost::shared_ptr<Node>
00361 BuildKDTree(std::vector< Vector<double> > const & points)
00362 {
00363 
00364   //
00365   // Initially all points are in the index set.
00366   //
00367   Index const
00368   number_points = points.size();
00369 
00370   std::set<Index>
00371   points_indices;
00372 
00373   for (Index i = 0; i < number_points; ++i) {
00374     points_indices.insert(i);
00375   }
00376 
00377   boost::shared_ptr<Node>
00378   dummy;
00379 
00380   std::string
00381   name = "0";
00382 
00383   boost::shared_ptr<Node>
00384   root = CreateKDTreeNode(name, dummy, points, points_indices);
00385 
00386   return root;
00387 }
00388 
00389 //
00390 // Create KD tree node.
00391 // \param point list
00392 // \return Boost shared pointer to node of tree if created, 0 otherwise.
00393 //
00394 template<typename Node>
00395 boost::shared_ptr<Node>
00396 CreateKDTreeNode(
00397     std::string const & name,
00398     boost::shared_ptr<Node> parent,
00399     std::vector< Vector<double> > const & points,
00400     std::set<Index> const & points_indices)
00401 {
00402   if (name.length() >=64) {
00403     std::cout << "Name is too long: " << name << '\n';
00404   }
00405 
00406   //
00407   // Create and fill in node.
00408   //
00409   boost::shared_ptr<Node>
00410   node(new Node);
00411 
00412   node->name = name;
00413 
00414   node->parent = parent;
00415 
00416   Index const
00417   count = points_indices.size();
00418 
00419   node->count = count;
00420   node->cell_points = points_indices;
00421 
00422   switch (count) {
00423 
00424   // Empty node
00425   case 0:
00426     break;
00427 
00428     // Leaf node
00429   case 1:
00430   {
00431     Vector<double> const &
00432     p = points[*points_indices.begin()];
00433     node->lower_corner = p;
00434     node->upper_corner = p;
00435     node->weighted_centroid = p;
00436   }
00437   break;
00438 
00439   default:
00440   {
00441     boost::tie(
00442         node->lower_corner,
00443         node->upper_corner,
00444         node->weighted_centroid) =
00445             bounds_and_sum_subset(points, points_indices);
00446 
00447     std::set<Index>
00448     indices_left;
00449 
00450     std::set<Index>
00451     indices_right;
00452 
00453     boost::tie(indices_left, indices_right) =
00454         split_box(points, points_indices);
00455 
00456     std::string
00457     name_left = name + "0";
00458 
00459     std::string
00460     name_right = name + "1";
00461 
00462     node->left =
00463         CreateKDTreeNode(name_left, node, points, indices_left);
00464 
00465     node->right =
00466         CreateKDTreeNode(name_right, node, points, indices_right);
00467   }
00468   break;
00469 
00470   }
00471 
00472   return node;
00473 }
00474 
00475 //
00476 // KdTree constructor with list of points.
00477 //
00478 template<typename Node>
00479 KDTree<Node>::KDTree(
00480     std::vector<Vector<double> > const & points,
00481     Index const number_centers)
00482     {
00483   root_ = BuildKDTree<Node>(points);
00484 
00485   // Set candidate centers to all
00486   std::set<Index>
00487   candidate_centers;
00488 
00489   for (Index i = 0; i < number_centers; ++i) {
00490     candidate_centers.insert(i);
00491   }
00492 
00493   root_->candidate_centers = candidate_centers;
00494 
00495   return;
00496     }
00497 
00498 //
00499 // Visit Tree nodes recursively and
00500 // perform the action defined by the Visitor object.
00501 //
00502 template<typename Node, typename Visitor>
00503 void
00504 VisitTreeNode(Node & node, Visitor const & visitor)
00505 {
00506   if (visitor.pre_stop(node) == true) return;
00507 
00508   visitor(node);
00509 
00510   if (visitor.post_stop(node) == true) return;
00511 
00512   VisitTreeNode(node->left, visitor);
00513   VisitTreeNode(node->right, visitor);
00514 
00515   return;
00516 }
00517 
00518 //
00519 // Traverse a Tree and perform the action defined by the Visitor object.
00520 //
00521 template<typename Tree, typename Visitor>
00522 void
00523 TraverseTree(Tree & tree, Visitor const & visitor)
00524 {
00525   VisitTreeNode(tree.get_root(), visitor);
00526   return;
00527 }
00528 
00529 //
00530 // Output visitor for KDTree node.
00531 //
00532 template<typename Node>
00533 void
00534 OutputVisitor<Node>::operator()(Node const & node) const
00535 {
00536   std::cout << "Node        : " << node->name << '\n';
00537   std::cout << "Count       : " << node->count << '\n';
00538   std::cout << "Lower corner: " << node->lower_corner << '\n';
00539   std::cout << "Upper corner: " << node->upper_corner << '\n';
00540 
00541   Vector<double>
00542   centroid = node->weighted_centroid / node->count;
00543 
00544   std::cout << "Centroid    : " << centroid << '\n';
00545 
00546   return;
00547 }
00548 
00549 //
00550 // Pre-visit stopping criterion for traversing the tree.
00551 //
00552 template<typename Node>
00553 bool
00554 OutputVisitor<Node>::pre_stop(Node const & node) const
00555 {
00556   return node.get() == NULL;
00557 }
00558 
00559 //
00560 // Post-visit stopping criterion for traversing the tree.
00561 //
00562 template<typename Node>
00563 bool
00564 OutputVisitor<Node>::post_stop(Node const & node) const
00565 {
00566   return false;
00567 }
00568 
00569 //
00570 // Constructor for filtering visitor
00571 //
00572 template<typename Node, typename Center>
00573 FilterVisitor<Node, Center>::FilterVisitor(
00574     std::vector<Vector<double> > & p,
00575     std::vector<Center> & c) :
00576     points(p),
00577     centers(c)
00578 {
00579 }
00580 
00581 namespace {
00582 
00583 template<typename Center, typename Iterator>
00584 Index
00585 closest_center_from_subset(
00586     Vector<double> const & point,
00587     std::vector<Center> const & centers,
00588     Iterator begin,
00589     Iterator end)
00590 {
00591   assert(std::distance(begin, end) > 0);
00592 
00593   Index
00594   closest_index = *begin;
00595 
00596   double
00597   minimum_distance = norm_square(point - centers[closest_index].position);
00598 
00599   for (Iterator it = ++begin; it != end; ++it) {
00600 
00601     Index const
00602     i = *it;
00603 
00604     double const
00605     s = norm_square(point - centers[i].position);
00606 
00607     if (s < minimum_distance) {
00608       closest_index = i;
00609       minimum_distance = s;
00610     }
00611 
00612   }
00613 
00614   return closest_index;
00615 
00616 }
00617 
00618 //
00619 // Given the corners of a box, a vector of centers and
00620 // a subset of indices to the centers:
00621 // Determine the closest center among the subset to the midcell.
00622 // For the remaining centers, define hyperplanes that are
00623 // equidistant to them and the closest center to the midcell.
00624 // Determine whether the box lies entirely on the side of the hyperplane
00625 // where the closest center to the midcell lies as well.
00626 //
00627 template<typename Center>
00628 std::pair<Index, std::set<Index> >
00629 box_proximity_to_centers(
00630     Vector<double> const & lower_corner,
00631     Vector<double> const & upper_corner,
00632     std::vector<Center> const & centers,
00633     std::set<Index> const & index_subset)
00634 {
00635   assert(centers.size() > 0);
00636   assert(index_subset.size() > 0);
00637 
00638   Vector<double> const
00639   midcell = 0.5 * (lower_corner + upper_corner);
00640 
00641   // Determine the closest point to box center only among those
00642   // listed in the index subset.
00643   Index
00644   index_closest = *index_subset.begin();
00645 
00646   double
00647   minimum = norm_square(midcell - centers[index_closest].position);
00648 
00649   for (std::set<Index>::const_iterator
00650       index_iterator = ++index_subset.begin();
00651       index_iterator != index_subset.end();
00652       ++index_iterator) {
00653 
00654     Index const
00655     i = *index_iterator;
00656 
00657     double const
00658     s = norm_square(midcell - centers[i].position);
00659 
00660     if (s < minimum) {
00661       index_closest = i;
00662       minimum = s;
00663     }
00664 
00665   }
00666 
00667   Vector<double> const &
00668   closest_to_midcell = centers[index_closest].position;
00669 
00670   std::set<Index>
00671   indices_candidates;
00672 
00673   // Determine where the box lies
00674   for (std::set<Index>::const_iterator index_iterator = index_subset.begin();
00675       index_iterator != index_subset.end();
00676       ++index_iterator) {
00677 
00678     Index const
00679     i = *index_iterator;
00680 
00681     if (i == index_closest) {
00682       indices_candidates.insert(i);
00683       continue;
00684     }
00685 
00686     Vector<double> const &
00687     p = centers[i].position;
00688 
00689     Vector<double> const
00690     u = p - closest_to_midcell;
00691 
00692     Index const
00693     N = u.get_dimension();
00694 
00695     Vector<double>
00696     v(N);
00697 
00698     for (Index j = 0; j < N; ++j) {
00699 
00700       v(j) = u(j) >= 0.0 ? upper_corner(j) : lower_corner(j);
00701 
00702     }
00703 
00704     if (norm_square(p - v) < norm_square(closest_to_midcell - v)) {
00705       indices_candidates.insert(i);
00706     }
00707 
00708   }
00709 
00710   return std::make_pair(index_closest, indices_candidates);
00711 }
00712 
00713 } // anonymous namespace
00714 
00715 //
00716 // Filtering visitor for KDTree node
00717 //
00718 template<typename Node, typename Center>
00719 void
00720 FilterVisitor<Node, Center>::operator()(Node const & node) const
00721 {
00722   bool const
00723   node_is_empty = node->count == 0;
00724 
00725   if (node_is_empty == true) {
00726     return;
00727   }
00728 
00729   bool const
00730   node_is_leaf = node->count == 1;
00731 
00732   if (node_is_leaf == true) {
00733 
00734     // Get point
00735     Index const
00736     point_index = *(node->cell_points.begin());
00737 
00738     Vector<double> const &
00739     point = points[point_index];
00740 
00741     // Find closest center to it
00742     Index
00743     index_closest =
00744         closest_center_from_subset(
00745             point,
00746             centers,
00747             node->candidate_centers.begin(),
00748             node->candidate_centers.end());
00749 
00750     // Update closest center
00751     Center &
00752     closest_center = centers[index_closest];
00753 
00754     closest_center.weighted_centroid += point;
00755     ++closest_center.count;
00756 
00757     node->closest_center_to_midcell = index_closest;
00758 
00759   } else { // node_is_leaf == false
00760 
00761     // Get midpoint of cell
00762     Index
00763     index_closest_midcell = 0;
00764 
00765     std::set<Index>
00766     candidate_indices;
00767 
00768     boost::tie(index_closest_midcell, candidate_indices) =
00769         box_proximity_to_centers(
00770             node->lower_corner,
00771             node->upper_corner,
00772             centers,
00773             node->candidate_centers);
00774 
00775     node->candidate_centers = candidate_indices;
00776 
00777     if (candidate_indices.size() == 1) {
00778 
00779       Center &
00780       center = centers[index_closest_midcell];
00781 
00782       center.weighted_centroid += node->weighted_centroid;
00783       center.count += node->count;
00784     } else {
00785 
00786       // Update children
00787       node->left->candidate_centers = candidate_indices;
00788       node->right->candidate_centers = candidate_indices;
00789     }
00790 
00791     node->closest_center_to_midcell = index_closest_midcell;
00792 
00793   }
00794 
00795   return;
00796 }
00797 
00798 //
00799 // Pre-visit stopping criterion for traversing the tree.
00800 //
00801 template<typename Node, typename Center>
00802 bool
00803 FilterVisitor<Node, Center>::pre_stop(Node const & node) const
00804 {
00805   bool const
00806   has_no_centers = node->candidate_centers.size() == 0;
00807 
00808   return has_no_centers == true;
00809 }
00810 
00811 //
00812 // Post-visit stopping criterion for traversing the tree.
00813 //
00814 template<typename Node, typename Center>
00815 bool
00816 FilterVisitor<Node, Center>::post_stop(Node const & node) const
00817 {
00818   bool const
00819   node_is_leaf = node->count <= 1;
00820 
00821   bool const
00822   has_single_center = node->candidate_centers.size() == 1;
00823 
00824   bool const
00825   stop_traversal = node_is_leaf || has_single_center;
00826 
00827   return stop_traversal == true;
00828 }
00829 
00830 //
00831 // Default constructor for Connectivity Array
00832 //
00833 ConnectivityArray::ConnectivityArray() :
00834         type_(Intrepid::ELEMENT::UNKNOWN),
00835         dimension_(0),
00836         discretization_ptr_(Teuchos::null),
00837         tolerance_(0.0),
00838         requested_cell_size_(0.0),
00839         maximum_iterations_(0),
00840         initializer_scheme_(PARTITION::HYPERGRAPH)
00841 {
00842   return;
00843 }
00844 
00845 //
00846 // Build array specifying input and output
00847 // \param input_file Exodus II input fine name
00848 // \param output_file Exodus II output fine name
00849 //
00850 ConnectivityArray::ConnectivityArray(
00851     std::string const & input_file,
00852     std::string const & output_file) :
00853           type_(Intrepid::ELEMENT::UNKNOWN),
00854           dimension_(0),
00855           discretization_ptr_(Teuchos::null),
00856           tolerance_(0.0),
00857           requested_cell_size_(0.0),
00858           maximum_iterations_(0),
00859           initializer_scheme_(PARTITION::HYPERGRAPH)
00860 {
00861 
00862   using Albany::StateStruct;
00863 
00864   //Teuchos::GlobalMPISession mpiSession(&argc,&argv);
00865 
00866   Teuchos::RCP<Teuchos::ParameterList> params =
00867       rcp(new Teuchos::ParameterList("params"));
00868 
00869   // Create discretization object
00870   Teuchos::RCP<Teuchos::ParameterList> disc_params =
00871       Teuchos::sublist(params, "Discretization");
00872 
00873   //set Method to Exodus and set input file name
00874   disc_params->set<std::string>("Method", "Exodus");
00875   disc_params->set<std::string>("Exodus Input File Name", input_file);
00876   disc_params->set<std::string>("Exodus Output File Name", output_file);
00877   // Max of 10000 workset size -- automatically resized down
00878   disc_params->set<int>("Workset Size", 10000);
00879 
00880   Teuchos::RCP<Epetra_Comm>
00881   communicator = Albany::createEpetraCommFromMpiComm(Albany_MPI_COMM_WORLD);
00882 
00883   Albany::DiscretizationFactory
00884   disc_factory(params, communicator);
00885 
00886   ArrayRCP<Teuchos::RCP<Albany::MeshSpecsStruct> >
00887   mesh_specs = disc_factory.createMeshSpecs();
00888 
00889   int
00890   workset_size = mesh_specs[0]->worksetSize;
00891 
00892   // Create a state field in stick named Partition on elements
00893   // 1 DOF per node
00894   // 1 internal variable (partition number)
00895   Teuchos::RCP<Albany::StateInfoStruct>
00896   state_info = Teuchos::rcp(new Albany::StateInfoStruct());
00897 
00898   StateStruct::FieldDims dims;
00899   // State has 1 quad point (i.e. element variable)
00900   dims.push_back(workset_size); dims.push_back(1);
00901 
00902   state_info->push_back(Teuchos::rcp(
00903       new StateStruct("Partition", StateStruct::QuadPoint, dims, "scalar")));
00904 
00905   // The default fields
00906   Albany::AbstractFieldContainer::FieldContainerRequirements
00907   req;
00908 
00909   discretization_ptr_ = disc_factory.createDiscretization(1, state_info, req);
00910 
00911   dimension_ = mesh_specs[0]->numDim;
00912 
00913   // Dimensioned: Workset, Cell, Local Node
00914   Albany::WorksetArray<ArrayRCP<ArrayRCP<ArrayRCP<int> > > >::type const &
00915   element_connectivity = discretization_ptr_->getWsElNodeEqID();
00916 
00917   ArrayRCP<double>
00918   coordinates = discretization_ptr_->getCoordinates();
00919 
00920   // For higher-order elements, mid-nodes are ignored and only
00921   // the nodes at the corners of the element are considered
00922   // to define the topology.
00923   const CellTopologyData
00924   cell_topology = mesh_specs[0]->ctd;
00925 
00926   Index const
00927   dimension = cell_topology.dimension;
00928 
00929   assert(dimension == dimension_);
00930 
00931   int const
00932   vertices_per_element = cell_topology.vertex_count;
00933 
00934   type_ = Intrepid::find_type(dimension, vertices_per_element);
00935 
00936   // Assume all the elements have the same number of nodes and eqs
00937   ArrayRCP<int>::size_type
00938   nodes_per_element = element_connectivity[0][0].size();
00939 
00940   // Do some logic so we can get from unknown ID to node ID
00941   int const number_equations = element_connectivity[0][0][0].size();
00942   int stride = 1;
00943   if (number_equations > 1) {
00944     if (element_connectivity[0][0][0][0] + 1 ==
00945         element_connectivity[0][0][0][1]) {
00946       // usual interleaved unknowns case
00947       stride = number_equations;
00948     }
00949   }
00950 
00951 
00952   // Build coordinate array.
00953   // Assume that local numbering of nodes is contiguous.
00954   ArrayRCP<double>::size_type
00955   number_nodes = coordinates.size() / dimension;
00956 
00957   for (ArrayRCP<double>::size_type
00958       node = 0;
00959       node < number_nodes;
00960       ++node) {
00961 
00962     Vector<double> point(0.0, 0.0, 0.0);
00963 
00964     for (Index j = 0; j < dimension; ++j) {
00965       point(j) = coordinates[node * dimension + j];
00966     }
00967 
00968     nodes_.insert(std::make_pair(node, point));
00969   }
00970 
00971   // Build connectivity array.
00972   // Assume that local numbering of elements is contiguous.
00973   // Ignore extra nodes in higher-order elements
00974   ArrayRCP<ArrayRCP<int> >::size_type
00975   element_number = 0;
00976 
00977   ArrayRCP<ArrayRCP<ArrayRCP<int> > >::size_type
00978   workset = 0;
00979 
00980   for (workset = 0; workset < element_connectivity.size(); ++workset) {
00981 
00982     for (ArrayRCP<ArrayRCP<int> >::size_type
00983         cell = 0;
00984         cell < element_connectivity[workset].size();
00985         ++cell, ++element_number) {
00986 
00987       IDList
00988       nodes_element(nodes_per_element);
00989 
00990       for (ArrayRCP<int>::size_type
00991           node = 0;
00992           node < vertices_per_element;
00993           ++node) {
00994 
00995         // Get node ID from first unknown ID by dividing by stride
00996         nodes_element[node] =
00997             element_connectivity[workset][cell][node][0] / stride;
00998 
00999       }
01000 
01001       connectivity_.insert(std::make_pair(element_number, nodes_element));
01002 
01003     }
01004 
01005   }
01006 
01007   return;
01008 }
01009 
01010 
01011 //
01012 // \return Number of nodes on the array
01013 //
01014 Index
01015 ConnectivityArray::GetNumberNodes() const
01016 {
01017   return nodes_.size();
01018 }
01019 
01020 //
01021 // \return Number of elements in the array
01022 //
01023 Index
01024 ConnectivityArray::GetNumberElements() const
01025 {
01026   return connectivity_.size();
01027 }
01028 
01029 //
01030 // \return Space dimension
01031 //
01032 Index
01033 ConnectivityArray::GetDimension() const
01034 {
01035   return dimension_;
01036 }
01037 
01038 //
01039 // \return K-means tolerance
01040 //
01041 double
01042 ConnectivityArray::GetTolerance() const
01043 {
01044   return tolerance_;
01045 }
01046 
01047 //
01048 // \return requested cell size for voxelization
01049 //
01050 double
01051 ConnectivityArray::GetCellSize() const
01052 {
01053   return requested_cell_size_;
01054 }
01055 
01056 //
01057 // \return maximum iterations for K-means
01058 //
01059 Index
01060 ConnectivityArray::GetMaximumIterations() const
01061 {
01062   return maximum_iterations_;
01063 }
01064 
01065 //
01066 // \param K-means tolerance
01067 //
01068 void
01069 ConnectivityArray::SetTolerance(double tolerance)
01070 {
01071   tolerance_ = tolerance;
01072 }
01073 
01074 //
01075 // \return requested cell size for voxelization
01076 //
01077 void
01078 ConnectivityArray::SetCellSize(double requested_cell_size)
01079 {
01080   requested_cell_size_ = requested_cell_size;
01081 }
01082 
01083 //
01084 // \param maximum itearions for K-means
01085 //
01086 void
01087 ConnectivityArray::SetMaximumIterations(Index maximum_iterarions)
01088 {
01089   maximum_iterations_ = maximum_iterarions;
01090 }
01091 
01092 //
01093 // \param Initializer scheme
01094 //
01095 void
01096 ConnectivityArray::SetInitializerScheme(PARTITION::Scheme initializer_scheme)
01097 {
01098   initializer_scheme_ = initializer_scheme;
01099 }
01100 
01101 //
01102 // \return Initializer scheme
01103 //
01104 PARTITION::Scheme
01105 ConnectivityArray::GetInitializerScheme() const
01106 {
01107   return initializer_scheme_;
01108 }
01109 
01110 //
01111 // \return Type of finite element in the array
01112 // (assume same type for all elements)
01113 //
01114 Intrepid::ELEMENT::Type
01115 ConnectivityArray::GetType() const
01116 {
01117   return type_;
01118 }
01119 
01120 //
01121 // \return Node ID and associated point in space
01122 //
01123 PointMap
01124 ConnectivityArray::GetNodeList() const
01125 {
01126   return nodes_;
01127 }
01128 
01129 //
01130 // \return Element - nodes connectivity
01131 //
01132 AdjacencyMap
01133 ConnectivityArray::GetConnectivity() const
01134 {
01135   return connectivity_;
01136 }
01137 
01138 //
01139 // \return Albany abstract discretization corresponding to array
01140 //
01141 Albany::AbstractDiscretization &
01142 ConnectivityArray::GetDiscretization()
01143 {
01144   return (*discretization_ptr_.get());
01145 }
01146 
01147 //
01148 // \return Number of nodes that define element topology
01149 // (assume same type for all elements)
01150 //
01151 Index
01152 ConnectivityArray::GetNodesPerElement() const
01153 {
01154   Index
01155   nodes_per_element;
01156 
01157   switch (GetType()) {
01158 
01159   default:
01160     std::cerr << "ERROR: Unknown element type in GetNodesPerElement()";
01161     std::cerr << '\n';
01162     exit(1);
01163     break;
01164 
01165   case Intrepid::ELEMENT::SEGMENTAL:
01166     nodes_per_element = 2;
01167     break;
01168 
01169   case Intrepid::ELEMENT::TRIANGULAR:
01170     nodes_per_element = 3;
01171     break;
01172 
01173   case Intrepid::ELEMENT::QUADRILATERAL:
01174     nodes_per_element = 4;
01175     break;
01176 
01177   case Intrepid::ELEMENT::TETRAHEDRAL:
01178     nodes_per_element = 4;
01179     break;
01180 
01181   case Intrepid::ELEMENT::HEXAHEDRAL:
01182     nodes_per_element = 8;
01183     break;
01184 
01185   }
01186 
01187   return nodes_per_element;
01188 }
01189 
01190 
01191 //
01192 // \return Volume for each element
01193 //
01194 ScalarMap
01195 ConnectivityArray::GetVolumes() const
01196 {
01197   ScalarMap volumes;
01198   for (AdjacencyMap::const_iterator
01199       elements_iter = connectivity_.begin();
01200       elements_iter != connectivity_.end();
01201       ++elements_iter) {
01202 
01203     int const &
01204     element = (*elements_iter).first;
01205 
01206     IDList const &
01207     node_list = (*elements_iter).second;
01208 
01209     std::vector< Vector<double> >
01210     points;
01211 
01212     for (IDList::size_type
01213         i = 0;
01214         i < node_list.size();
01215         ++i) {
01216 
01217       PointMap::const_iterator
01218       nodes_iter = nodes_.find(node_list[i]);
01219 
01220       assert(nodes_iter != nodes_.end());
01221       points.push_back((*nodes_iter).second);
01222 
01223     }
01224 
01225     double volume = 0.0;
01226 
01227     switch (type_) {
01228 
01229     case Intrepid::ELEMENT::SEGMENTAL:
01230       volume = Intrepid::length(points[0], points[1]);
01231       break;
01232 
01233     case Intrepid::ELEMENT::TRIANGULAR:
01234       volume = Intrepid::area(points[0], points[1], points[2]);
01235       break;
01236 
01237     case Intrepid::ELEMENT::QUADRILATERAL:
01238       volume = Intrepid::area(points[0], points[1], points[2], points[3]);
01239       break;
01240 
01241     case Intrepid::ELEMENT::TETRAHEDRAL:
01242       volume = Intrepid::volume(points[0], points[1], points[2], points[3]);
01243       break;
01244 
01245     case Intrepid::ELEMENT::HEXAHEDRAL:
01246       volume = Intrepid::volume(points[0], points[1], points[2], points[3],
01247           points[4], points[5], points[6], points[7]);
01248       break;
01249 
01250     default:
01251       std::cerr << "Unknown element type in calculating volume." << '\n';
01252       exit(1);
01253       break;
01254 
01255     }
01256 
01257     volumes.insert(std::make_pair(element, volume));
01258 
01259   }
01260 
01261   return volumes;
01262 }
01263 
01264 //
01265 // \return Total volume of the array
01266 //
01267 double
01268 ConnectivityArray::GetVolume() const
01269 {
01270   double volume = 0.0;
01271 
01272   const ScalarMap
01273   volumes = GetVolumes();
01274 
01275   for (ScalarMap::const_iterator
01276       volumes_iter = volumes.begin();
01277       volumes_iter != volumes.end();
01278       ++volumes_iter) {
01279 
01280     volume += (*volumes_iter).second;
01281 
01282   }
01283 
01284   return volume;
01285 }
01286 
01287 //
01288 // \return Partitions when partitioned
01289 //
01290 std::map<int, int>
01291 ConnectivityArray::GetPartitions() const
01292 {
01293   return partitions_;
01294 }
01295 
01296 //
01297 // \return Volume for each partition when partitioned
01298 //
01299 ScalarMap
01300 ConnectivityArray::GetPartitionVolumes() const
01301 {
01302   std::map<int, int>
01303   partitions = GetPartitions();
01304 
01305   ScalarMap
01306   volumes = GetVolumes();
01307 
01308   ScalarMap
01309   partition_volumes;
01310 
01311   for (std::map<int, int>::const_iterator part_iter = partitions.begin();
01312       part_iter != partitions.end();
01313       ++part_iter) {
01314 
01315     int element = (*part_iter).first;
01316     int partition = (*part_iter).second;
01317 
01318     ScalarMap::const_iterator
01319     volumes_iterator = volumes.find(element);
01320 
01321     if (volumes_iterator == volumes.end()) {
01322       std::cerr << "Cannot find volume for element " << element << '\n';
01323       exit(1);
01324     }
01325 
01326     double volume = (*volumes_iterator).second;
01327 
01328     ScalarMap::const_iterator
01329     partition_volumes_iter = partition_volumes.find(partition);
01330 
01331     if (partition_volumes_iter == partition_volumes.end()) {
01332       partition_volumes[partition] = volume;
01333     } else {
01334       partition_volumes[partition] += volume;
01335     }
01336 
01337   }
01338 
01339   return partition_volumes;
01340 }
01341 
01342 //
01343 // \return Partition centroids
01344 //
01345 std::vector< Vector<double> >
01346 ConnectivityArray::GetPartitionCentroids() const
01347 {
01348   std::map<int, int>
01349   partitions = GetPartitions();
01350 
01351   ScalarMap
01352   element_volumes = GetVolumes();
01353 
01354   ScalarMap
01355   partition_volumes = GetPartitionVolumes();
01356 
01357   Index const
01358   number_partitions = partition_volumes.size();
01359 
01360   std::vector< Vector<double> >
01361   partition_centroids(number_partitions);
01362 
01363   for (Index i = 0; i < number_partitions; ++i) {
01364     partition_centroids[i].set_dimension(GetDimension());
01365     partition_centroids[i].clear();
01366   }
01367 
01368   // Determine number of nodes that define element topology
01369   Index const
01370   nodes_per_element = GetNodesPerElement();
01371 
01372   for (std::map<int, int>::const_iterator partitions_iterator =
01373       partitions.begin();
01374       partitions_iterator != partitions.end();
01375       ++partitions_iterator) {
01376 
01377     int
01378     element = (*partitions_iterator).first;
01379 
01380     int
01381     partition = (*partitions_iterator).second;
01382 
01383     AdjacencyMap::const_iterator
01384     elements_iterator = connectivity_.find(element);
01385 
01386     if (elements_iterator == connectivity_.end()) {
01387       std::cerr << "Cannot find element in partition centroids." << element;
01388       std::cerr << '\n';
01389       exit(1);
01390     }
01391 
01392     IDList const &
01393     node_list = (*elements_iterator).second;
01394 
01395     std::vector< Vector<double> >
01396     element_nodes;
01397 
01398     for (IDList::size_type i = 0; i < nodes_per_element; ++i) {
01399 
01400       PointMap::const_iterator
01401       nodes_iterator = nodes_.find(node_list[i]);
01402 
01403       assert(nodes_iterator != nodes_.end());
01404 
01405       element_nodes.push_back((*nodes_iterator).second);
01406 
01407     }
01408 
01409     Vector<double> const
01410     element_centroid = centroid(element_nodes);
01411 
01412     ScalarMap::const_iterator
01413     volumes_iterator = element_volumes.find(element);
01414 
01415     if (volumes_iterator == element_volumes.end()) {
01416       std::cerr << "Cannot find volume for element " << element;
01417       std::cerr << '\n';
01418       exit(1);
01419     }
01420 
01421     double
01422     element_volume = (*volumes_iterator).second;
01423 
01424     partition_centroids[partition] += element_volume * element_centroid;
01425 
01426   }
01427 
01428   for (Index i = 0; i < number_partitions; ++i) {
01429     partition_centroids[i] = partition_centroids[i] / partition_volumes[i];
01430   }
01431 
01432   return partition_centroids;
01433 }
01434 
01435 //
01436 // \return Centroids for each element
01437 //
01438 PointMap
01439 ConnectivityArray::GetCentroids() const
01440 {
01441   PointMap
01442   centroids;
01443 
01444   for (AdjacencyMap::const_iterator
01445       elements_iter = connectivity_.begin();
01446       elements_iter != connectivity_.end();
01447       ++elements_iter) {
01448 
01449     // Get an element
01450     int const &
01451     element = (*elements_iter).first;
01452 
01453     IDList const &
01454     node_list = (*elements_iter).second;
01455 
01456     std::vector< Vector<double> >
01457     points;
01458 
01459     // Collect element nodes
01460     for (IDList::size_type
01461         i = 0;
01462         i < node_list.size();
01463         ++i) {
01464 
01465       int const
01466       node = node_list[i];
01467 
01468       PointMap::const_iterator
01469       nodes_iter = nodes_.find(node);
01470 
01471       assert(nodes_iter != nodes_.end());
01472 
01473       Vector<double> const
01474       point = (*nodes_iter).second;
01475 
01476       points.push_back(point);
01477 
01478     }
01479 
01480     Vector<double> const
01481     centroid = Intrepid::centroid(points);
01482 
01483     centroids.insert(std::make_pair(element, centroid));
01484 
01485   }
01486 
01487   return centroids;
01488 
01489 }
01490 
01494 std::pair<Vector<double>, Vector<double> >
01495 ConnectivityArray::BoundingBox() const
01496 {
01497   PointMap::const_iterator
01498   it = nodes_.begin();
01499 
01500   Vector<double>
01501   min = (*it).second;
01502 
01503   Vector<double>
01504   max = min;
01505 
01506   Index const
01507   N = min.get_dimension();
01508 
01509   ++it;
01510 
01511   for (; it != nodes_.end(); ++it) {
01512 
01513     Vector<double> const &
01514     node = (*it).second;
01515 
01516     for (Index i = 0; i < N; ++i) {
01517       min(i) = std::min(min(i), node(i));
01518       max(i) = std::max(max(i), node(i));
01519     }
01520 
01521   }
01522 
01523   return std::make_pair(min, max);
01524 }
01525 
01526 namespace {
01527 
01528 boost::tuple<Index, double, double>
01529 parametric_limits(Intrepid::ELEMENT::Type const element_type)
01530 {
01531   Index
01532   parametric_dimension = 3;
01533 
01534   double
01535   parametric_size = 1.0;
01536 
01537   double
01538   lower_limit = 0.0;
01539 
01540   switch (element_type) {
01541 
01542   default:
01543     std::cerr << "ERROR: Unknown element type in paramtetric_limits";
01544     std::cerr << '\n';
01545     exit(1);
01546     break;
01547 
01548   case Intrepid::ELEMENT::TRIANGULAR:
01549     lower_limit = 0.0;
01550     parametric_size = 1.0;
01551     parametric_dimension = 3;
01552     break;
01553 
01554   case Intrepid::ELEMENT::QUADRILATERAL:
01555     lower_limit = -1.0;
01556     parametric_size = 2.0;
01557     parametric_dimension = 2;
01558     break;
01559 
01560   case Intrepid::ELEMENT::TETRAHEDRAL:
01561     lower_limit = 0.0;
01562     parametric_size = 1.0;
01563     parametric_dimension = 4;
01564     break;
01565 
01566   case Intrepid::ELEMENT::HEXAHEDRAL:
01567     lower_limit = -1.0;
01568     parametric_size = 2.0;
01569     parametric_dimension = 3;
01570     break;
01571 
01572   }
01573 
01574   return boost::make_tuple(
01575       parametric_dimension,
01576       parametric_size,
01577       lower_limit);
01578 }
01579 
01580 } // namespace anonymous
01581 
01582 //
01583 // Background of the domain for fast determination
01584 // of points being inside or outside the domain.
01585 // \return points inside the domain.
01586 //
01587 std::vector< Vector<double> >
01588 ConnectivityArray::CreateGrid()
01589 {
01590   std::cout << '\n';
01591   std::cout << "Creating background mesh ..." << '\n';
01592 
01593   //
01594   // First determine the maximum dimension of the bounding box.
01595   //
01596   Vector<double>
01597   lower_corner;
01598 
01599   Vector<double>
01600   upper_corner;
01601 
01602   boost::tie(lower_corner, upper_corner) = BoundingBox();
01603 
01604   Vector<double> const
01605   bounding_box_span = upper_corner - lower_corner;
01606 
01607   Index const
01608   dimension = lower_corner.get_dimension();
01609 
01610   double
01611   maximum_dimension = 0.0;
01612 
01613   for (Index i = 0; i < dimension; ++i) {
01614     maximum_dimension = std::max(maximum_dimension, bounding_box_span(i));
01615   }
01616 
01617   double const
01618   delta = GetCellSize();
01619 
01620   //
01621   // Determine number of cells for each dimension.
01622   //
01623   Vector<Index>
01624   cells_per_dimension(dimension);
01625 
01626   cell_size_.set_dimension(dimension);
01627 
01628   for (Index i = 0; i < dimension; ++i) {
01629 
01630     Index const
01631     number_cells = std::ceil((bounding_box_span(i)) / delta);
01632 
01633     cells_per_dimension(i) = number_cells;
01634     cell_size_(i) = bounding_box_span(i) / number_cells;
01635 
01636   }
01637 
01638   //
01639   // Set up the cell array.
01640   // Generalization to N dimensions fails here.
01641   // This is specific to 3D.
01642   //
01643   cells_.resize(cells_per_dimension(0));
01644   for (Index i = 0; i < cells_per_dimension(0); ++i) {
01645     cells_[i].resize(cells_per_dimension(1));
01646     for (Index j = 0; j < cells_per_dimension(1); ++j) {
01647       cells_[i][j].resize(cells_per_dimension(2));
01648       for (Index k = 0; k < cells_per_dimension(2); ++k) {
01649         cells_[i][j][k] = false;
01650       }
01651     }
01652   }
01653 
01654   // Iterate through elements to set array.
01655   Index const
01656   nodes_per_element = GetNodesPerElement();
01657 
01658   Index const
01659   number_of_elements = connectivity_.size();
01660 
01661   for (AdjacencyMap::const_iterator
01662       elements_iter = connectivity_.begin();
01663       elements_iter != connectivity_.end();
01664       ++elements_iter) {
01665 
01666     int const
01667     element = (*elements_iter).first;
01668 
01669     if ((element + 1) % 10000 == 0) {
01670       std::cout << "Processing element: " << element + 1;
01671       std::cout << "/" << number_of_elements << '\n';
01672     }
01673 
01674     IDList const &
01675     node_list = (*elements_iter).second;
01676 
01677     std::vector< Vector<double> >
01678     element_nodes;
01679 
01680     for (IDList::size_type i = 0;
01681         i < nodes_per_element;
01682         ++i) {
01683 
01684       PointMap::const_iterator
01685       nodes_iter = nodes_.find(node_list[i]);
01686 
01687       assert(nodes_iter != nodes_.end());
01688 
01689       element_nodes.push_back((*nodes_iter).second);
01690 
01691     }
01692 
01693     Vector<double>
01694     min;
01695 
01696     Vector<double>
01697     max;
01698 
01699     boost::tie(min, max) =
01700         Intrepid::bounding_box<double>(element_nodes.begin(),
01701             element_nodes.end());
01702 
01703     Vector<double> const
01704     element_span = max - min;
01705 
01706     Vector<Index>
01707     divisions(dimension);
01708 
01709     // Determine number of divisions on each dimension.
01710     // One division if voxel is large.
01711     for (Index i = 0; i < dimension; ++i) {
01712       divisions(i) =
01713           cell_size_(i) > element_span(i) ?
01714               1 :
01715               2.0 * element_span(i) / cell_size_(i) + 0.5;
01716     }
01717 
01718     // Generate points inside the element according to
01719     // the divisions and mark the corresponding voxel
01720     // as being inside the domain.
01721     Intrepid::ELEMENT::Type
01722     element_type = GetType();
01723 
01724     Index
01725     parametric_dimension = 3;
01726 
01727     double
01728     parametric_size = 1.0;
01729 
01730     double
01731     lower_limit = 0.0;
01732 
01733     boost::tie(parametric_dimension, parametric_size, lower_limit) =
01734         parametric_limits(element_type);
01735 
01736     Vector<double>
01737     origin(parametric_dimension);
01738 
01739     for (Index i = 0; i < dimension; ++i) {
01740       origin(i) = lower_limit;
01741     }
01742 
01743     Vector<double>
01744     xi(parametric_dimension);
01745 
01746     for (Index i = 0; i <= divisions(0); ++i) {
01747       xi(0) = origin(0) + double(i) / divisions(0) * parametric_size;
01748       for (Index j = 0; j <= divisions(1); ++j) {
01749         xi(1) = origin(1) + double(j) / divisions(1) * parametric_size;
01750         for (Index k = 0; k <= divisions(2); ++k) {
01751           xi(2) = origin(2) + double(k) / divisions(2) * parametric_size;
01752           Vector<double>
01753           p = interpolate_element(element_type, xi, element_nodes);
01754           for (Index l = 0; l < dimension; ++l) {
01755             p(l) = std::max(p(l), lower_corner(l));
01756             p(l) = std::min(p(l), upper_corner(l));
01757           }
01758 
01759           Vector<int>
01760           index = PointToIndex(p);
01761 
01762           for (Index l = 0; l < dimension; ++l) {
01763             assert(index(l) >= 0);
01764             assert(index(l) <= int(cells_per_dimension(l)));
01765 
01766             if (index(l) == int(cells_per_dimension(l))) {
01767               --index(l);
01768             }
01769           }
01770 
01771           cells_[index(0)][index(1)][index(2)] = true;
01772         }
01773       }
01774     }
01775   }
01776 
01777   std::cout << connectivity_.size() << " elements processed." << '\n';
01778 
01779   // Create points and output voxelization for debugging
01780   std::vector< Vector<double> >
01781   domain_points;
01782 
01783   std::ofstream ofs("cells.csv");
01784   ofs << "X, Y, Z, I" << '\n';
01785   Vector<double> p(dimension);
01786 
01787   for (Index i = 0; i < cells_per_dimension(0); ++i) {
01788     p(0) = (i + 0.5) * bounding_box_span(0) / cells_per_dimension(0) +
01789         lower_corner(0);
01790     for (Index j = 0; j < cells_per_dimension(1); ++j) {
01791       p(1) = (j + 0.5) * bounding_box_span(1) / cells_per_dimension(1) +
01792           lower_corner(1);
01793       for (Index k = 0; k < cells_per_dimension(2); ++k) {
01794         p(2) = (k + 0.5) * bounding_box_span(2) / cells_per_dimension(2) +
01795             lower_corner(2);
01796 
01797         if (cells_[i][j][k] == true) {
01798           domain_points.push_back(p);
01799         }
01800 
01801         ofs << p << "," << cells_[i][j][k] << '\n';
01802       }
01803     }
01804   }
01805 
01806   Index const
01807   number_generated_points =
01808       cells_per_dimension(0) *
01809       cells_per_dimension(1) *
01810       cells_per_dimension(2);
01811 
01812   Index const
01813   number_points_in_domain = domain_points.size();
01814 
01815   double const
01816   ratio = double(number_points_in_domain) / double(number_generated_points);
01817 
01818   std::cout << "Number of cells inside domain: ";
01819   std::cout << number_points_in_domain;
01820   std::cout << '\n';
01821   std::cout << "Number of generated cells    : ";
01822   std::cout << number_generated_points;
01823   std::cout << '\n';
01824   std::cout << "Ratio                        : ";
01825   std::cout << ratio;
01826   std::cout << '\n';
01827 
01828   return domain_points;
01829 }
01830 
01831 //
01832 // Convert point to index into voxel array
01833 //
01834 Vector<int>
01835 ConnectivityArray::PointToIndex(Vector<double> const & point) const
01836 {
01837   int const
01838   i = (point(0) - lower_corner_(0)) / cell_size_(0);
01839 
01840   int const
01841   j = (point(1) - lower_corner_(1)) / cell_size_(1);
01842 
01843   int const
01844   k = (point(2) - lower_corner_(2)) / cell_size_(2);
01845 
01846   return Vector<int>(i, j, k);
01847 }
01848 
01849 //
01850 // Determine if a given point is inside the mesh.
01851 // 3D only for now.
01852 //
01853 bool
01854 ConnectivityArray::IsInsideMesh(Vector<double> const & point) const
01855 {
01856   int
01857   i = (point(0) - lower_corner_(0)) / cell_size_(0);
01858 
01859   int
01860   j = (point(1) - lower_corner_(1)) / cell_size_(1);
01861 
01862   int
01863   k = (point(2) - lower_corner_(2)) / cell_size_(2);
01864 
01865 
01866   int const
01867   x_size = cells_.size();
01868 
01869   int const
01870   y_size = cells_[0].size();
01871 
01872   int const
01873   z_size = cells_[0][0].size();
01874 
01875 
01876   if (i < 0 || i > x_size) {
01877     return false;
01878   }
01879 
01880   if (j < 0 || j > y_size) {
01881     return false;
01882   }
01883 
01884   if (k < 0 || k > z_size) {
01885     return false;
01886   }
01887 
01888 
01889   if (i == x_size) --i;
01890   if (j == y_size) --j;
01891   if (k == z_size) --k;
01892 
01893   return cells_[i][j][k];
01894 }
01895 
01896 //
01897 // Determine is a given point is inside the mesh
01898 // doing it element by element. Slow but useful
01899 // to set up an initial data structure that will
01900 // be used on a faster method.
01901 //
01902 bool
01903 ConnectivityArray::IsInsideMeshByElement(Vector<double> const & point) const
01904 {
01905 
01906   // Check bounding box first
01907   if (in_box(point, lower_corner_, upper_corner_) == false) {
01908     return false;
01909   }
01910 
01911   // Now check element by element
01912   for (AdjacencyMap::const_iterator
01913       elements_iter = connectivity_.begin();
01914       elements_iter != connectivity_.end();
01915       ++elements_iter) {
01916 
01917     IDList const &
01918     node_list = (*elements_iter).second;
01919 
01920     std::vector< Vector<double> >
01921     node;
01922 
01923     for (IDList::size_type
01924         i = 0;
01925         i < node_list.size();
01926         ++i) {
01927 
01928       PointMap::const_iterator
01929       nodes_iter = nodes_.find(node_list[i]);
01930 
01931       assert(nodes_iter != nodes_.end());
01932       node.push_back((*nodes_iter).second);
01933 
01934     }
01935 
01936     switch (type_) {
01937 
01938     case Intrepid::ELEMENT::TETRAHEDRAL:
01939       if (in_tetrahedron(point, node[0], node[1], node[2], node[3]) == true) {
01940         return true;
01941       }
01942       break;
01943 
01944     case Intrepid::ELEMENT::HEXAHEDRAL:
01945       if (in_hexahedron(point, node[0], node[1], node[2], node[3],
01946           node[4], node[5], node[6], node[7])) {
01947         return true;
01948       }
01949       break;
01950 
01951     default:
01952       std::cerr << "Unknown element type in K-means partition." << '\n';
01953       exit(1);
01954       break;
01955 
01956     }
01957 
01958   }
01959 
01960   return false;
01961 }
01962 
01963 //
01964 // \param length_scale Length scale for partitioning for
01965 // variational non-local regularization
01966 // \return Number of partitions defined as total volume
01967 // of the array divided by the cube of the length scale
01968 //
01969 Index
01970 ConnectivityArray::GetNumberPartitions(double const length_scale) const
01971 {
01972   double const
01973   ball_volume = length_scale * length_scale * length_scale;
01974 
01975   Index const
01976   number_partitions =
01977       static_cast<Index>(round(GetVolume() / ball_volume));
01978 
01979   return number_partitions;
01980 }
01981 
01982 //
01983 // Anonymous namespace for helper functions
01984 //
01985 namespace {
01986 
01987 //
01988 // Helper function that return a deterministic pseudo random
01989 // sequence 0,..,N-1 for visualization purposes.
01990 //
01991 std::vector<int>
01992 shuffled_sequence(int number_elements)
01993 {
01994   std::vector<int>
01995   shuffled;
01996 
01997   std::vector<int>
01998   unshuffled;
01999 
02000   for (int i = 0; i < number_elements; ++i) {
02001     unshuffled.push_back(i);
02002   }
02003 
02004   // Happens to be a Mersenne prime for int_32
02005   const int
02006   prime = std::numeric_limits<int>::max();
02007 
02008   for (int i = 0; i < number_elements; ++i) {
02009     const int
02010     remainder = number_elements - i;
02011 
02012     const int
02013     index = prime % remainder;
02014 
02015     const int
02016     selection = unshuffled[index];
02017 
02018     shuffled.push_back(selection);
02019 
02020     std::vector<int>::iterator
02021     delete_position = unshuffled.begin();
02022 
02023     std::advance(delete_position, index);
02024 
02025     unshuffled.erase(delete_position);
02026   }
02027 
02028   return shuffled;
02029 }
02030 
02031 //
02032 // Helper function to renumber partitions to avoid gaps in numbering.
02033 // Also for better color contrast in visualization programs, shuffle
02034 // the partition number so that it is less likely that partitions
02035 // with very close numbers are next to each other, leading to almost
02036 // the same color in output.
02037 //
02038 std::map<int, int>
02039 RenumberPartitions(std::map<int, int> const & old_partitions) {
02040 
02041   std::set<int>
02042   partitions_set;
02043 
02044   for (std::map<int, int>::const_iterator it = old_partitions.begin();
02045       it != old_partitions.end();
02046       ++it) {
02047 
02048     int const
02049     partition = (*it).second;
02050 
02051     partitions_set.insert(partition);
02052   }
02053 
02054   std::set<int>::size_type
02055   number_partitions = partitions_set.size();
02056 
02057   std::vector<int>
02058   partition_shuffle = shuffled_sequence(number_partitions);
02059 
02060   std::map<int, int>
02061   partition_map;
02062 
02063   int
02064   partition_index = 0;
02065 
02066   for (std::set<int>::const_iterator it = partitions_set.begin();
02067       it != partitions_set.end();
02068       ++it) {
02069 
02070     int const
02071     partition = (*it);
02072 
02073     partition_map[partition] = partition_index;
02074 
02075     ++partition_index;
02076 
02077   }
02078 
02079   std::map<int, int>
02080   new_partitions;
02081 
02082   for (std::map<int, int>::const_iterator it = old_partitions.begin();
02083       it != old_partitions.end();
02084       ++it) {
02085 
02086     int const
02087     element = (*it).first;
02088 
02089     int const
02090     old_partition = (*it).second;
02091 
02092     int const
02093     partition_index = partition_map[old_partition];
02094 
02095     int const
02096     new_partition = partition_shuffle[partition_index];
02097 
02098     new_partitions[element] = new_partition;
02099 
02100   }
02101 
02102   return new_partitions;
02103 }
02104 
02105 } // anonymous namespace
02106 
02107 void
02108 ConnectivityArray::CheckNullVolume() const
02109 {
02110   ScalarMap const
02111   partition_volumes = GetPartitionVolumes();
02112 
02113   std::vector<Index>
02114   zero_volume;
02115 
02116   for (ScalarMap::const_iterator it = partition_volumes.begin();
02117       it != partition_volumes.end();
02118       ++it) {
02119 
02120     Index const
02121     partition = (*it).first;
02122 
02123     double const
02124     volume = (*it).second;
02125 
02126     if (volume == 0.0) {
02127       zero_volume.push_back(partition);
02128     }
02129 
02130   }
02131 
02132   Index const
02133   number_null_partitions = zero_volume.size();
02134 
02135   if (number_null_partitions > 0) {
02136     std::cerr << "ERROR: The following partitions have zero volume.";
02137     std::cerr << '\n';
02138     std::cerr << "Length scale may be too small:";
02139     std::cerr << '\n';
02140 
02141     for (Index i = 0; i < number_null_partitions; ++i) {
02142       std::cerr << " " << zero_volume[i];
02143     }
02144 
02145     std::cerr << '\n';
02146 
02147     exit(1);
02148   }
02149 
02150   return;
02151 }
02152 
02153 //
02154 // Partition mesh according to the specified algorithm and length scale
02155 // \param partition_scheme The partition algorithm to use
02156 // \param length_scale The length scale for variational nonlocal
02157 // regularization
02158 // \return Partition number for each element
02159 //
02160 std::map<int, int>
02161 ConnectivityArray::Partition(
02162     const PARTITION::Scheme partition_scheme,
02163     double const length_scale)
02164 {
02165 
02166   std::map<int, int>
02167   partitions;
02168 
02169   switch (partition_scheme) {
02170 
02171   case PARTITION::RANDOM:
02172     partitions = PartitionRandom(length_scale);
02173     break;
02174 
02175   case PARTITION::HYPERGRAPH:
02176     partitions = PartitionHyperGraph(length_scale);
02177     break;
02178 
02179   case PARTITION::GEOMETRIC:
02180     partitions = PartitionGeometric(length_scale);
02181     break;
02182 
02183   case PARTITION::KMEANS:
02184     partitions = PartitionKMeans(length_scale);
02185     break;
02186 
02187   case PARTITION::SEQUENTIAL:
02188     partitions = PartitionSequential(length_scale);
02189     break;
02190 
02191   case PARTITION::KDTREE:
02192     partitions = PartitionKDTree(length_scale);
02193     break;
02194 
02195   default:
02196     std::cerr << "Unknown partitioning scheme." << '\n';
02197     exit(1);
02198     break;
02199 
02200   }
02201 
02202   CheckNullVolume();
02203 
02204   // Store for use by other methods
02205   partitions_ = RenumberPartitions(partitions);
02206 
02207   return partitions_;
02208 
02209 }
02210 
02211 //
02212 // \param Collection of centers
02213 // \return Partition map that assigns each element to the
02214 // closest center to its centroid
02215 //
02216 std::map<int, int>
02217 ConnectivityArray::PartitionByCenters(
02218     std::vector< Vector<double> > const & centers)
02219 {
02220   Index const
02221   number_partitions = centers.size();
02222 
02223   // Partition map.
02224   std::map<int, int>
02225   partitions;
02226 
02227   // Keep track of which partitions have been assigned elements.
02228   std::set<Index>
02229   unassigned_partitions;
02230 
02231   for (Index partition = 0; partition < number_partitions; ++partition) {
02232     unassigned_partitions.insert(partition);
02233   }
02234 
02235   // Determine number of nodes that define element topology
02236   Index const
02237   nodes_per_element = GetNodesPerElement();
02238 
02239   std::ofstream centroids_ofs("centroids.csv");
02240 
02241   centroids_ofs << "X,Y,Z" << '\n';
02242   for (AdjacencyMap::const_iterator
02243       elements_iter = connectivity_.begin();
02244       elements_iter != connectivity_.end();
02245       ++elements_iter) {
02246 
02247     int const &
02248     element = (*elements_iter).first;
02249 
02250     IDList const &
02251     node_list = (*elements_iter).second;
02252 
02253     std::vector< Vector<double> >
02254     element_nodes;
02255 
02256     for (IDList::size_type i = 0; i < nodes_per_element; ++i) {
02257 
02258       PointMap::const_iterator
02259       nodes_iter = nodes_.find(node_list[i]);
02260 
02261       assert(nodes_iter != nodes_.end());
02262 
02263       element_nodes.push_back((*nodes_iter).second);
02264 
02265     }
02266 
02267     Vector<double> const
02268     element_centroid = centroid(element_nodes);
02269 
02270     centroids_ofs << element_centroid << '\n';
02271 
02272     Index const
02273     partition = closest_point(element_centroid, centers);
02274 
02275     partitions[element] = partition;
02276 
02277     std::set<Index>::const_iterator
02278     it = unassigned_partitions.find(partition);
02279 
02280     if (it != unassigned_partitions.end()) {
02281       unassigned_partitions.erase(it);
02282     }
02283 
02284   }
02285 
02286   if (unassigned_partitions.size() > 0) {
02287     std::cout << "WARNING: The following partitions were not" << '\n';
02288     std::cout << "assigned any elements (mesh too coarse?):" << '\n';
02289 
02290     for (std::set<Index>::const_iterator it = unassigned_partitions.begin();
02291         it != unassigned_partitions.end();
02292         ++it) {
02293       std::cout << (*it) << '\n';
02294     }
02295 
02296   }
02297 
02298   std::ofstream generators_ofs("centers.csv");
02299   generators_ofs << "X,Y,Z" << '\n';
02300   for (Index i = 0; i < centers.size(); ++i) {
02301     generators_ofs << centers[i] << '\n';
02302   }
02303 
02304   return partitions;
02305 
02306 }
02307 
02308 //
02309 // Partition mesh with Zoltan Hypergraph algortithm
02310 // \param length_scale The length scale for variational nonlocal
02311 // regularization
02312 // \return Partition number for each element
02313 //
02314 std::map<int, int>
02315 ConnectivityArray::PartitionHyperGraph(double const length_scale)
02316 {
02317   // Zoltan setup
02318   int const
02319   number_partitions = GetNumberPartitions(length_scale);
02320 
02321   std::stringstream
02322   ioss;
02323 
02324   ioss << number_partitions;
02325 
02326   std::string
02327   zoltan_number_parts;
02328 
02329   ioss >> zoltan_number_parts;
02330 
02331   Zoltan
02332   zoltan(MPI_COMM_SELF);
02333 
02334   zoltan.Set_Param("LB_METHOD", "HYPERGRAPH");
02335   zoltan.Set_Param("LB_APPROACH", "PARTITION");
02336   zoltan.Set_Param("DEBUG_LEVEL", "0");
02337   zoltan.Set_Param("OBJ_WEIGHT_DIM", "1");
02338   zoltan.Set_Param("NUM_GLOBAL_PARTS", zoltan_number_parts.c_str());
02339   zoltan.Set_Param("REMAP", "0");
02340   zoltan.Set_Param("HYPERGRAPH_PACKAGE", "PHG");
02341   zoltan.Set_Param("PHG_MULTILEVEL", "1");
02342   zoltan.Set_Param("PHG_EDGE_WEIGHT_OPERATION", "ERROR");
02343   zoltan.Set_Param("IMBALANCE_TOL", "1.01");
02344   zoltan.Set_Param("PHG_CUT_OBJECTIVE", "HYPEREDGES");
02345 
02346   //
02347   // Partition
02348   //
02349   DualGraph
02350   dual_graph(*this);
02351 
02352   ZoltanHyperGraph
02353   zoltan_hypergraph(dual_graph);
02354 
02355   // Set up hypergraph
02356   zoltan.Set_Num_Obj_Fn(
02357       LCM::ZoltanHyperGraph::GetNumberOfObjects,
02358       &zoltan_hypergraph);
02359 
02360   zoltan.Set_Obj_List_Fn(
02361       LCM::ZoltanHyperGraph::GetObjectList,
02362       &zoltan_hypergraph);
02363 
02364   zoltan.Set_HG_Size_CS_Fn(
02365       LCM::ZoltanHyperGraph::GetHyperGraphSize,
02366       &zoltan_hypergraph);
02367 
02368   zoltan.Set_HG_CS_Fn(
02369       LCM::ZoltanHyperGraph::GetHyperGraph,
02370       &zoltan_hypergraph);
02371 
02372   int changes;
02373   int num_gid_entries;
02374   int num_lid_entries;
02375   int num_import;
02376   ZOLTAN_ID_PTR import_global_ids;
02377   ZOLTAN_ID_PTR import_local_ids;
02378   int* import_procs;
02379   int* import_to_part;
02380   int num_export;
02381   ZOLTAN_ID_PTR export_global_ids;
02382   ZOLTAN_ID_PTR export_local_ids;
02383   int* export_procs;
02384   int* export_to_part;
02385 
02386   int rc =
02387       zoltan.LB_Partition(
02388           changes,
02389           num_gid_entries,
02390           num_lid_entries,
02391           num_import,
02392           import_global_ids,
02393           import_local_ids,
02394           import_procs,
02395           import_to_part,
02396           num_export,
02397           export_global_ids,
02398           export_local_ids,
02399           export_procs,
02400           export_to_part);
02401 
02402   if (rc != ZOLTAN_OK) {
02403     std::cerr << "Partitioning failed" << '\n';
02404     exit(1);
02405   }
02406 
02407   // Set up partition map initializing all partitions to zero
02408   std::map<int, int> partitions;
02409 
02410   // Initialize with zeros the partition map for all elements.
02411   const ScalarMap
02412   vertex_weights = zoltan_hypergraph.GetVertexWeights();
02413 
02414   // Fill up with results from Zoltan, which returns partitions for all
02415   // elements that belong to a partition > 0
02416   for (ScalarMap::const_iterator
02417       weights_iter = vertex_weights.begin();
02418       weights_iter != vertex_weights.end();
02419       ++weights_iter) {
02420     int const vertex = (*weights_iter).first;
02421     partitions[vertex] = 0;
02422   }
02423 
02424   // Fill up with results from Zoltan
02425   for (int i = 0; i < num_import; ++i) {
02426     int const vertex = static_cast<int>(import_local_ids[i]);
02427     partitions[vertex] = import_to_part[i];
02428   }
02429 
02430   // cleanup zoltan pointers
02431   // this will free all memory associated with the in and output data
02432   // to zoltan
02433   zoltan.LB_Free_Part(
02434       &import_global_ids,
02435       &import_local_ids,
02436       &import_procs,
02437       &import_to_part );
02438 
02439   zoltan.LB_Free_Part(
02440       &export_global_ids,
02441       &export_local_ids,
02442       &export_procs,
02443       &export_to_part );
02444 
02445   return partitions;
02446 
02447 }
02448 
02449 //
02451 // \param length_scale The length scale for variational nonlocal
02452 // regularization
02453 // \return Partition number for each element
02454 //
02455 std::map<int, int>
02456 ConnectivityArray::PartitionGeometric(double const length_scale)
02457 {
02458   // Zoltan setup
02459   int const
02460   number_partitions = GetNumberPartitions(length_scale);
02461 
02462   std::stringstream
02463   ioss;
02464 
02465   ioss << number_partitions;
02466 
02467   std::string
02468   zoltan_number_parts;
02469 
02470   ioss >> zoltan_number_parts;
02471 
02472   Zoltan
02473   zoltan(MPI_COMM_SELF);
02474 
02475   zoltan.Set_Param("LB_METHOD", "RCB");
02476   zoltan.Set_Param("RCB_RECOMPUTE_BOX", "1");
02477   zoltan.Set_Param("LB_APPROACH", "PARTITION");
02478   zoltan.Set_Param("DEBUG_LEVEL", "0");
02479   zoltan.Set_Param("OBJ_WEIGHT_DIM", "1");
02480   zoltan.Set_Param("NUM_GLOBAL_PARTS", zoltan_number_parts.c_str());
02481   zoltan.Set_Param("REMAP", "0");
02482   zoltan.Set_Param("IMBALANCE_TOL", "1.10");
02483   zoltan.Set_Param("CHECK_GEOM", "1");
02484   zoltan.Set_Param("AVERAGE_CUTS", "1");
02485   zoltan.Set_Param("REDUCE_DIMENSIONS", "1");
02486   zoltan.Set_Param("DEGENERATE_RATIO", "10");
02487 
02488   //
02489   // Partition
02490   //
02491 
02492   // Set up recursive inertial bisection (RIB)
02493   zoltan.Set_Num_Obj_Fn(LCM::ConnectivityArray::GetNumberOfObjects, this);
02494   zoltan.Set_Obj_List_Fn(LCM::ConnectivityArray::GetObjectList, this);
02495   zoltan.Set_Num_Geom_Fn(LCM::ConnectivityArray::GetNumberGeometry, this);
02496   zoltan.Set_Geom_Multi_Fn(LCM::ConnectivityArray::GetGeometry, this);
02497 
02498   int changes;
02499   int num_gid_entries;
02500   int num_lid_entries;
02501   int num_import;
02502   ZOLTAN_ID_PTR import_global_ids;
02503   ZOLTAN_ID_PTR import_local_ids;
02504   int* import_procs;
02505   int* import_to_part;
02506   int num_export;
02507   ZOLTAN_ID_PTR export_global_ids;
02508   ZOLTAN_ID_PTR export_local_ids;
02509   int* export_procs;
02510   int* export_to_part;
02511 
02512   int rc =
02513       zoltan.LB_Partition(
02514           changes,
02515           num_gid_entries,
02516           num_lid_entries,
02517           num_import,
02518           import_global_ids,
02519           import_local_ids,
02520           import_procs,
02521           import_to_part,
02522           num_export,
02523           export_global_ids,
02524           export_local_ids,
02525           export_procs,
02526           export_to_part);
02527 
02528   if (rc != ZOLTAN_OK) {
02529     std::cerr << "Partitioning failed" << '\n';
02530     exit(1);
02531   }
02532 
02533   // Set up partition map initializing all partitions to zero
02534   std::map<int, int> partitions;
02535 
02536   const ScalarMap
02537   element_volumes = GetVolumes();
02538 
02539   // Initialize with zeros the partition map for all elements.
02540   for (ScalarMap::const_iterator
02541       volumes_iter = element_volumes.begin();
02542       volumes_iter != element_volumes.end();
02543       ++volumes_iter) {
02544     int const element = (*volumes_iter).first;
02545     partitions[element] = 0;
02546   }
02547 
02548   // Fill up with results from Zoltan, which returns partitions for all
02549   // elements that belong to a partition > 0
02550   for (int i = 0; i < num_import; ++i) {
02551     int const element = static_cast<int>(import_local_ids[i]);
02552     partitions[element] = import_to_part[i];
02553   }
02554 
02555   return partitions;
02556 
02557 }
02558 
02559 //
02561 // \param length_scale The length scale for variational nonlocal
02562 // regularization
02563 // \return Partition number for each element
02564 //
02565 std::map<int, int>
02566 ConnectivityArray::PartitionKMeans(double const length_scale)
02567 {
02568   //
02569   // Create initial centers
02570   //
02571   std::cout << '\n';
02572   std::cout << "Partition with initializer ..." << '\n';
02573 
02574   // Partition with initializer
02575   PARTITION::Scheme const
02576   initializer_scheme = GetInitializerScheme();
02577 
02578   Partition(initializer_scheme, length_scale);
02579 
02580   // Compute partition centroids and use those as initial centers
02581 
02582   std::vector< Vector<double> >
02583   centers = GetPartitionCentroids();
02584 
02585   Index const
02586   number_partitions = centers.size();
02587 
02588   Vector<double>
02589   lower_corner;
02590 
02591   Vector<double>
02592   upper_corner;
02593 
02594   boost::tie(lower_corner, upper_corner) = BoundingBox();
02595 
02596   lower_corner_ = lower_corner;
02597   upper_corner_ = upper_corner;
02598 
02599   std::vector< Vector<double> >
02600   domain_points = CreateGrid();
02601 
02602   //
02603   // K-means iteration
02604   //
02605   std::cout << "Main K-means Iteration." << '\n';
02606 
02607   Index const
02608   max_iterations = GetMaximumIterations();
02609 
02610   Index
02611   number_iterations = 0;
02612 
02613   double const
02614   diagonal_distance = norm(upper_corner - lower_corner);
02615 
02616   double const
02617   tolerance = GetTolerance() * diagonal_distance;
02618 
02619   double
02620   step_norm = diagonal_distance;
02621 
02622   std::vector<double>
02623   steps(number_partitions);
02624 
02625   for (Index i = 0; i < number_partitions; ++i) {
02626     steps[i] = diagonal_distance;
02627   }
02628 
02629   Index const
02630   number_points = domain_points.size();
02631 
02632   while (step_norm >= tolerance && number_iterations < max_iterations) {
02633 
02634     // Assign points to closest generators
02635     std::vector<double>
02636     point_to_generator(number_points);
02637 
02638     for (Index i = 0; i < domain_points.size(); ++i) {
02639       point_to_generator[i] = closest_point(domain_points[i], centers);
02640     }
02641 
02642     // Determine cluster of points for each generator
02643     std::vector<std::vector<Vector<double> > >
02644     clusters;
02645 
02646     clusters.resize(number_partitions);
02647 
02648     for (Index p = 0; p < point_to_generator.size(); ++p) {
02649 
02650       Index const
02651       c = point_to_generator[p];
02652 
02653       clusters[c].push_back(domain_points[p]);
02654 
02655     }
02656 
02657     // Compute centroids of each cluster and set generators to
02658     // these centroids.
02659     for (Index i = 0; i < clusters.size(); ++i) {
02660 
02661       // If center is empty then generator does not move.
02662       if (clusters[i].size() == 0) {
02663         steps[i] = 0.0;
02664         std::cout << "Iteration: " << number_iterations;
02665         std::cout << ", center " << i << " has zero points." << '\n';
02666         continue;
02667       }
02668 
02669       Vector<double> const
02670       cluster_centroid = centroid(clusters[i]);
02671 
02672       // Update the generator
02673       Vector<double> const
02674       old_generator = centers[i];
02675 
02676       centers[i] = cluster_centroid;
02677 
02678       steps[i] = norm(centers[i] - old_generator);
02679     }
02680 
02681     step_norm = norm(Vector<double>(number_partitions, &steps[0]));
02682 
02683     std::cout << "Iteration: " << number_iterations;
02684     std::cout << ". Step: " << step_norm << ". Tol: " << tolerance;
02685     std::cout << '\n';
02686 
02687     ++number_iterations;
02688 
02689   }
02690 
02691   // Partition map.
02692   std::map<int, int>
02693   partitions = PartitionByCenters(centers);
02694 
02695   return partitions;
02696 }
02697 
02698 //
02700 // \param length_scale The length scale for variational nonlocal
02701 // regularization
02702 // \return Partition number for each element
02703 //
02704 std::map<int, int>
02705 ConnectivityArray::PartitionKDTree(double const length_scale)
02706 {
02707   //
02708   // Create initial centers
02709   //
02710   std::cout << '\n';
02711   std::cout << "Partition with initializer ..." << '\n';
02712 
02713   // Partition with initializer
02714   PARTITION::Scheme const
02715   initializer_scheme = GetInitializerScheme();
02716 
02717   Partition(initializer_scheme, length_scale);
02718 
02719   // Compute partition centroids and use those as initial centers
02720 
02721   std::vector< Vector<double> >
02722   center_positions = GetPartitionCentroids();
02723 
02724   Index const
02725   number_partitions = center_positions.size();
02726 
02727   // Initialize centers
02728   std::cout << "Main K-means Iteration." << '\n';
02729 
02730   std::vector<ClusterCenter>
02731   centers(number_partitions);
02732 
02733   for (Index i = 0; i < number_partitions; ++i) {
02734     centers[i].position = center_positions[i];
02735     centers[i].weighted_centroid = 0.0 * center_positions[i];
02736   }
02737 
02738   Vector<double>
02739   lower_corner;
02740 
02741   Vector<double>
02742   upper_corner;
02743 
02744   boost::tie(lower_corner, upper_corner) = BoundingBox();
02745 
02746   lower_corner_ = lower_corner;
02747   upper_corner_ = upper_corner;
02748 
02749   std::vector< Vector<double> >
02750   domain_points = CreateGrid();
02751 
02752   //
02753   // Create KDTree
02754   //
02755   KDTree<KDTreeNode>
02756   kdtree(domain_points, number_partitions);
02757 
02758   //TraverseTree(kdtree, OutputVisitor<boost::shared_ptr<KDTreeNode> >());
02759 
02760   FilterVisitor<boost::shared_ptr<KDTreeNode>, ClusterCenter>
02761   filter_visitor(domain_points, centers);
02762 
02763   //
02764   // K-means iteration
02765   //
02766   Index const
02767   max_iterations = GetMaximumIterations();
02768 
02769   Index
02770   number_iterations = 0;
02771 
02772   double const
02773   diagonal_distance = norm(upper_corner - lower_corner);
02774 
02775   double const
02776   tolerance = GetTolerance() * GetCellSize();
02777 
02778   double
02779   step_norm = diagonal_distance;
02780 
02781   std::vector<double>
02782   steps(number_partitions);
02783 
02784   for (Index i = 0; i < number_partitions; ++i) {
02785     steps[i] = diagonal_distance;
02786   }
02787 
02788   while (step_norm >= tolerance && number_iterations < max_iterations) {
02789 
02790     // Initialize centers
02791     for (Index i = 0; i < number_partitions; ++i) {
02792       ClusterCenter &
02793       center = centers[i];
02794 
02795       center.weighted_centroid.clear();
02796       center.count = 0;
02797     }
02798 
02799     TraverseTree(kdtree, filter_visitor);
02800 
02801     // Update centers
02802     for (Index i = 0; i < centers.size(); ++i) {
02803 
02804       ClusterCenter &
02805       center = centers[i];
02806 
02807       // If cluster is empty then center does not move.
02808       if (center.count == 0) {
02809         steps[i] = 0.0;
02810         std::cout << "Iteration: " << number_iterations;
02811         std::cout << ", center " << i << " has zero points." << '\n';
02812         continue;
02813       }
02814 
02815       Vector<double> const
02816       new_position = center.weighted_centroid / center.count;
02817 
02818       steps[i] = norm(new_position - center.position);
02819 
02820       center.position = new_position;
02821 
02822     }
02823 
02824     step_norm = norm(Vector<double>(number_partitions, &steps[0]));
02825 
02826     std::cout << "Iteration: " << number_iterations;
02827     std::cout << ". Step: " << step_norm << ". Tol: " << tolerance;
02828     std::cout << '\n';
02829 
02830     ++number_iterations;
02831 
02832   }
02833 
02834   for (Index i = 0; i < number_partitions; i++) {
02835     center_positions[i] = centers[i].position;
02836   }
02837 
02838   // Partition map.
02839   std::map<int, int>
02840   partitions = PartitionByCenters(center_positions);
02841 
02842   return partitions;
02843 
02844 }
02845 
02846 //
02847 // Partition mesh with sequential K-means algortithm
02848 // \param length_scale The length scale for variational nonlocal
02849 // regularization
02850 // \return Partition number for each element
02851 //
02852 std::map<int, int>
02853 ConnectivityArray::PartitionSequential(double const length_scale)
02854 {
02855   int const
02856   number_partitions = GetNumberPartitions(length_scale);
02857 
02858   Vector<double>
02859   lower_corner;
02860 
02861   Vector<double>
02862   upper_corner;
02863 
02864   boost::tie(lower_corner, upper_corner) = BoundingBox();
02865 
02866   lower_corner_ = lower_corner;
02867   upper_corner_ = upper_corner;
02868 
02869   //
02870   // Create initial centers
02871   //
02872 
02873   // Partition with initializer
02874   const PARTITION::Scheme
02875   initializer_scheme = GetInitializerScheme();
02876 
02877   Partition(initializer_scheme, length_scale);
02878 
02879   // Compute partition centroids and use those as initial centers
02880 
02881   std::vector< Vector<double> >
02882   centers = GetPartitionCentroids();
02883 
02884   std::vector<Index>
02885   weights(number_partitions);
02886 
02887   for (int i = 0; i < number_partitions; ++i) {
02888     weights[i] = 1;
02889   }
02890 
02891   // K-means sequential iteration
02892   Index const
02893   number_random_points = GetMaximumIterations() * number_partitions;
02894 
02895   Index const
02896   max_iterations = number_random_points;
02897 
02898   Index
02899   number_iterations = 0;
02900 
02901   double const
02902   diagonal_distance = norm(upper_corner - lower_corner);
02903 
02904   double const
02905   tolerance = GetTolerance() * diagonal_distance;
02906 
02907   std::vector<double>
02908   steps(number_partitions);
02909 
02910   for (int i = 0; i < number_partitions; ++i) {
02911     steps[i] = diagonal_distance;
02912   }
02913 
02914   double
02915   step_norm = diagonal_distance;
02916 
02917   std::cout << "K-means Sequential." << '\n';
02918 
02919   while (step_norm >= tolerance && number_iterations < max_iterations) {
02920 
02921     // Create a random point, find closest generator
02922     bool
02923     is_point_in_domain = false;
02924 
02925     Vector<double>
02926     random_point(lower_corner.get_dimension());
02927 
02928     while (is_point_in_domain == false) {
02929       random_point = random_in_box(lower_corner, upper_corner);
02930       is_point_in_domain = IsInsideMesh(random_point);
02931     }
02932 
02933     // Determine index to closest generator
02934     Index const
02935     i = closest_point(random_point, centers);
02936 
02937     // Update the generator and the weight
02938     Vector<double> const
02939     old_generator = centers[i];
02940 
02941     centers[i] =
02942         (weights[i] * centers[i] + random_point) / (weights[i] + 1);
02943 
02944     weights[i] += 1;
02945 
02946     steps[i] = norm(centers[i] - old_generator);
02947     step_norm = norm(Vector<double>(number_partitions, &steps[0]));
02948 
02949     if (number_iterations % 10000 == 0) {
02950       std::cout << "Random point: " << number_iterations;
02951       std::cout << ". Step: " << step_norm << ". ";
02952       std::cout << "Tol: " << tolerance << '\n';
02953     }
02954 
02955     ++number_iterations;
02956 
02957   }
02958 
02959   std::cout << "Random point: " << number_iterations;
02960   std::cout << ". Step: " << step_norm << ". ";
02961   std::cout << "Tol: " << tolerance << '\n';
02962 
02963   // Partition map.
02964   std::map<int, int>
02965   partitions = PartitionByCenters(centers);
02966 
02967   return partitions;
02968 }
02969 
02970 //
02971 // Partition mesh with randomly generated centers.
02972 // Mostly used to initialize other schemes.
02973 // \param length_scale The length scale for variational nonlocal
02974 // regularization
02975 // \return Partition number for each element
02976 //
02977 std::map<int, int>
02978 ConnectivityArray::PartitionRandom(double const length_scale)
02979 {
02980   int const
02981   number_partitions = GetNumberPartitions(length_scale);
02982 
02983   Vector<double>
02984   lower_corner;
02985 
02986   Vector<double>
02987   upper_corner;
02988 
02989   boost::tie(lower_corner, upper_corner) = BoundingBox();
02990 
02991   lower_corner_ = lower_corner;
02992   upper_corner_ = upper_corner;
02993 
02994   //
02995   // Create initial centers
02996   //
02997   int
02998   number_generators = 0;
02999 
03000   std::vector< Vector<double> >
03001   centers;
03002 
03003   while (number_generators < number_partitions) {
03004 
03005     Vector<double>
03006     p = random_in_box(lower_corner, upper_corner);
03007 
03008     if (IsInsideMesh(p) == true) {
03009       centers.push_back(p);
03010       ++number_generators;
03011     }
03012 
03013   }
03014 
03015   // Partition map.
03016   std::map<int, int>
03017   partitions = PartitionByCenters(centers);
03018 
03019   return partitions;
03020 }
03021 
03022 //
03023 // Zoltan interface query function that returns the number of values
03024 // needed to express the geometry of an object.
03025 // For a three-dimensional object, the return value should be three.
03026 //
03027 // \param   data  Pointer to user-defined data.
03028 //
03029 // \param   ierr  Error code to be set by function.
03030 //
03031 // \return  The number of values needed to express the
03032 // geometry of an object.
03033 //
03034 int
03035 ConnectivityArray::GetNumberGeometry(
03036     void* data,
03037     int* ierr)
03038 {
03039 
03040   ConnectivityArray &
03041   connectivity_array = *(static_cast<ConnectivityArray*>(data));
03042 
03043   *ierr = ZOLTAN_OK;
03044 
03045   int dimension = connectivity_array.GetDimension();
03046 
03047   return dimension;
03048 }
03049 
03050 //
03051 // Zoltan interface, return number of objects
03052 //
03053 int
03054 ConnectivityArray::GetNumberOfObjects(void* data, int* ierr)
03055 {
03056 
03057   ConnectivityArray &
03058   connectivity_array = *(static_cast<ConnectivityArray*>(data));
03059 
03060   *ierr = ZOLTAN_OK;
03061 
03062   int num_objects = connectivity_array.GetConnectivity().size();
03063 
03064   return num_objects;
03065 }
03066 
03067 //
03068 // Zoltan interface, return relevant object properties
03069 //
03070 void
03071 ConnectivityArray::GetObjectList(
03072     void* data,
03073     int sizeGID,
03074     int sizeLID,
03075     ZOLTAN_ID_PTR globalID,
03076     ZOLTAN_ID_PTR localID,
03077     int wgt_dim,
03078     float* obj_wgts,
03079     int* ierr)
03080 {
03081 
03082   ConnectivityArray &
03083   connectivity_array = *(static_cast<ConnectivityArray*>(data));
03084 
03085   *ierr = ZOLTAN_OK;
03086 
03087   ScalarMap
03088   element_volumes = connectivity_array.GetVolumes();
03089 
03090   ZOLTAN_ID_PTR
03091   global_id_ptr = globalID;
03092 
03093   ZOLTAN_ID_PTR
03094   local_id_ptr = localID;
03095 
03096   float*
03097   weight_ptr = obj_wgts;
03098 
03099   for (ScalarMap::const_iterator
03100       volumes_iter = element_volumes.begin();
03101       volumes_iter != element_volumes.end();
03102       ++volumes_iter) {
03103 
03104     int element = (*volumes_iter).first;
03105     double volume = (*volumes_iter).second;
03106 
03107     // Beware of this evil pointer manipulation
03108     (*global_id_ptr) = element;
03109     (*local_id_ptr) = element;
03110     (*weight_ptr) = volume;
03111     global_id_ptr++;
03112     local_id_ptr++;
03113     weight_ptr++;
03114 
03115   }
03116 
03117   return;
03118 }
03119 
03120 //
03121 // Zoltan interface query function that returns a vector of geometry
03122 // values for a list of given objects. The geometry vector is allocated
03123 // by Zoltan to be of size num_obj * num_dim;
03124 // its format is described below.
03125 //
03126 // \param data Pointer to user-defined data.
03127 //
03128 // \param sizeGID The number of array entries used to describe a
03129 // single global ID.  This value is the maximum value over all processors
03130 // of the parameter NUM_GID_ENTRIES.
03131 //
03132 // \param sizeLID The number of array entries used to describe a
03133 // single local ID.  This value is the maximum value over all processors
03134 // of the parameter NUM_LID_ENTRIES. (It should be zero if local ids
03135 // are not used.)
03136 //
03137 // \param num_obj The number of object IDs in arrays
03138 // globalID and localID
03139 //
03140 // \param globalID  Upon return, an array of unique global IDs for
03141 // all objects assigned to the processor.
03142 //
03143 // \param localID Upon return, an array of local IDs, the meaning
03144 // of which can be determined by the application, for all objects
03145 // assigned to the processor. (Optional.)
03146 //
03147 // \param num_dim Number of coordinate entries per object
03148 // (typically 1, 2, or 3).
03149 //
03150 // \param geom_vec  Upon return, an array containing geometry values.
03151 // For object i (specified by globalID[i*sizeGID] and
03152 // localID[i*sizeLID], i=0,1,...,num_obj-1),
03153 // coordinate values should be stored in
03154 // geom_vec[i*num_dim:(i+1)*num_dim-1].
03155 //
03156 // \param ierr Error code to be set by function.
03157 //
03158 void
03159 ConnectivityArray::GetGeometry(
03160     void* data,
03161     int sizeGID,
03162     int sizeLID,
03163     int num_obj,
03164     ZOLTAN_ID_PTR globalID,
03165     ZOLTAN_ID_PTR localID,
03166     int num_dim,
03167     double* geom_vec,
03168     int* ierr)
03169 {
03170 
03171   ConnectivityArray &
03172   connectivity_array = *(static_cast<ConnectivityArray*>(data));
03173 
03174   *ierr = ZOLTAN_OK;
03175 
03176   PointMap
03177   centroids = connectivity_array.GetCentroids();
03178 
03179   // Transfer the centroid coordinates to the Zoltan array
03180   int
03181   index_geom_vec = 0;
03182 
03183   for (PointMap::const_iterator
03184       centroids_iter = centroids.begin();
03185       centroids_iter != centroids.end();
03186       ++centroids_iter) {
03187 
03188     Vector<double> const
03189     centroid = (*centroids_iter).second;
03190 
03191     for (Index i = 0; i < 3; ++i) {
03192 
03193       geom_vec[index_geom_vec] = centroid(i);
03194       ++index_geom_vec;
03195 
03196     }
03197 
03198   }
03199 
03200   return;
03201 }
03202 
03203 //
03204 // Write a Connectivity Array to an output stream
03205 //
03206 std::ostream &
03207 operator<<(
03208     std::ostream & output_stream,
03209     ConnectivityArray const & connectivity_array)
03210 {
03211   output_stream << std::setw(12) << connectivity_array.GetNumberNodes();
03212   output_stream << std::setw(12) << connectivity_array.GetNumberElements();
03213   output_stream << std::setw(12) << connectivity_array.GetType();
03214   output_stream << '\n';
03215 
03216   // Node list
03217   const PointMap
03218   nodes = connectivity_array.GetNodeList();
03219 
03220   int const
03221   dimension = connectivity_array.GetDimension();
03222 
03223   for (PointMap::const_iterator
03224       nodes_iter = nodes.begin();
03225       nodes_iter != nodes.end();
03226       ++nodes_iter) {
03227 
03228     int const
03229     node = (*nodes_iter).first;
03230 
03231     output_stream << std::setw(12) << node;
03232 
03233     Vector<double> const &
03234     point = (*nodes_iter).second;
03235 
03236     for (int j = 0; j < dimension; ++j) {
03237       output_stream << std::scientific;
03238       output_stream << std::setw(16) << std::setprecision(8);
03239       output_stream << point(j);
03240     }
03241 
03242     output_stream << '\n';
03243 
03244   }
03245 
03246   // Output element volumes as well
03247   const ScalarMap
03248   volumes = connectivity_array.GetVolumes();
03249 
03250   // Element connectivity
03251   const AdjacencyMap
03252   connectivity = connectivity_array.GetConnectivity();
03253 
03254   for (AdjacencyMap::const_iterator
03255       connectivity_iter = connectivity.begin();
03256       connectivity_iter != connectivity.end();
03257       ++connectivity_iter) {
03258 
03259     int const element = (*connectivity_iter).first;
03260 
03261     output_stream << std::setw(12) << element;
03262 
03263     IDList const &
03264     node_list = (*connectivity_iter).second;
03265 
03266     for (IDList::size_type j = 0; j < node_list.size(); ++j) {
03267       output_stream << std::setw(12) << node_list[j];
03268     }
03269 
03270     // Element volume
03271     ScalarMap::const_iterator
03272     volumes_iter = volumes.find(element);
03273 
03274     assert(volumes_iter != volumes.end());
03275 
03276     double const
03277     volume = (*volumes_iter).second;
03278 
03279     output_stream << std::scientific << std::setw(16) << std::setprecision(8);
03280     output_stream << volume;
03281 
03282     output_stream << '\n';
03283   }
03284 
03285   return output_stream;
03286 }
03287 
03288 //
03289 // Default constructor for dual graph
03290 //
03291 DualGraph::DualGraph() : number_edges_(0)
03292 {
03293   return;
03294 }
03295 
03296 //
03297 // Build dual graph from connectivity array
03298 // The term face is used as in "proper face" in algebraic topology
03299 //
03300 DualGraph::DualGraph(ConnectivityArray const & connectivity_array)
03301 {
03302 
03303   const std::vector< std::vector<int> >
03304   face_connectivity = GetFaceConnectivity(connectivity_array.GetType());
03305 
03306   const AdjacencyMap
03307   connectivity = connectivity_array.GetConnectivity();
03308 
03309   std::map<std::set<int>, int>
03310   face_nodes_faceID_map;
03311 
03312   int
03313   face_count = 0;
03314 
03315   graph_.clear();
03316 
03317   AdjacencyMap
03318   faceID_element_map;
03319 
03320   // Go element by element
03321   for (AdjacencyMap::const_iterator
03322       connectivity_iter = connectivity.begin();
03323       connectivity_iter != connectivity.end();
03324       ++connectivity_iter) {
03325 
03326     int const
03327     element = (*connectivity_iter).first;
03328 
03329     const std::vector<int>
03330     element_nodes = (*connectivity_iter).second;
03331 
03332     // All elements go into graph, regardless of number of internal faces
03333     // attached to them. This clearing will allocate space for all of them.
03334     graph_[element].clear();
03335 
03336     // Determine the (generalized) faces for each element
03337     for (std::vector< std::vector<int> >::size_type
03338         i = 0;
03339         i < face_connectivity.size();
03340         ++i) {
03341 
03342       std::set<int>
03343       face_nodes;
03344 
03345       for (std::vector<int>::size_type
03346           j = 0;
03347           j < face_connectivity[i].size();
03348           ++j) {
03349         face_nodes.insert(element_nodes[face_connectivity[i][j]]);
03350       }
03351 
03352       // Determine whether this face is new (not found in face map)
03353       std::map<std::set<int>, int>::const_iterator
03354       face_map_iter = face_nodes_faceID_map.find(face_nodes);
03355 
03356       const bool
03357       face_is_new = face_map_iter == face_nodes_faceID_map.end();
03358 
03359       // If face is new then assign new ID to it and add to face map
03360       int
03361       faceID = -1;
03362 
03363       if (face_is_new == true) {
03364         faceID = face_count;
03365         face_nodes_faceID_map.insert(std::make_pair(face_nodes, faceID));
03366         ++face_count;
03367       } else {
03368         faceID = (*face_map_iter).second;
03369       }
03370 
03371       // List this element as attached to this face
03372       faceID_element_map[faceID].push_back(element);
03373 
03374     }
03375 
03376   }
03377 
03378   // Identify internal faces
03379   IDList
03380   internal_faces;
03381 
03382   for (AdjacencyMap::const_iterator
03383       face_element_iter = faceID_element_map.begin();
03384       face_element_iter != faceID_element_map.end();
03385       ++face_element_iter) {
03386 
03387     int const
03388     faceID = (*face_element_iter).first;
03389 
03390     int const
03391     number_elements_per_face = ((*face_element_iter).second).size();
03392 
03393     switch (number_elements_per_face) {
03394 
03395     case 1:
03396       // Do nothing
03397       break;
03398 
03399     case 2:
03400       internal_faces.push_back(faceID);
03401       break;
03402 
03403     default:
03404       std::cerr << "Bad number of faces adjacent to element." << '\n';
03405       exit(1);
03406       break;
03407 
03408     }
03409 
03410   }
03411 
03412   // Build dual graph
03413   for (IDList::size_type
03414       i = 0;
03415       i < internal_faces.size();
03416       ++i) {
03417 
03418     int const
03419     faceID = internal_faces[i];
03420 
03421     const IDList
03422     elements_face = faceID_element_map[faceID];
03423 
03424     assert(elements_face.size() == 2);
03425 
03426     for (IDList::size_type
03427         j = 0;
03428         j < elements_face.size();
03429         ++j) {
03430 
03431       int const
03432       element = elements_face[j];
03433 
03434       graph_[element].push_back(faceID);
03435 
03436     }
03437 
03438   }
03439 
03440   number_edges_ = internal_faces.size();
03441   vertex_weights_ = connectivity_array.GetVolumes();
03442 
03443   return;
03444 }
03445 
03446 int
03447 DualGraph::GetNumberVertices() const
03448 {
03449   return graph_.size();
03450 }
03451 
03452 int
03453 DualGraph::GetNumberEdges() const
03454 {
03455   return number_edges_;
03456 }
03457 
03458 void
03459 DualGraph::SetGraph(AdjacencyMap & graph)
03460 {
03461   graph_ = graph;
03462   return;
03463 }
03464 
03465 AdjacencyMap
03466 DualGraph::GetGraph() const
03467 {
03468   return graph_;
03469 }
03470 
03471 //
03472 // \return Edge list to create boost graph
03473 //
03474 AdjacencyMap
03475 DualGraph::GetEdgeList() const
03476 {
03477   AdjacencyMap edge_list;
03478 
03479   for (AdjacencyMap::const_iterator graph_iter = graph_.begin();
03480       graph_iter != graph_.end();
03481       ++graph_iter) {
03482     int const vertex = (*graph_iter).first;
03483     const IDList edges = (*graph_iter).second;
03484 
03485     for (IDList::const_iterator edges_iter = edges.begin();
03486         edges_iter != edges.end();
03487         ++edges_iter) {
03488 
03489       int const edge = (*edges_iter);
03490 
03491       IDList & vertices = edge_list[edge];
03492 
03493       vertices.push_back(vertex);
03494 
03495     }
03496 
03497   }
03498 
03499   return edge_list;
03500 }
03501 
03502 void
03503 DualGraph::SetVertexWeights(ScalarMap & vertex_weights)
03504 {
03505   vertex_weights_ = vertex_weights;
03506   return;
03507 }
03508 
03509 ScalarMap
03510 DualGraph::GetVertexWeights() const
03511 {
03512   return vertex_weights_;
03513 }
03514 
03515 //
03516 // \return Connected components in the dual graph
03517 //
03518 int
03519 DualGraph::GetConnectedComponents(std::vector<int> & components) const
03520 {
03521   // Create boost graph from edge list
03522   typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS>
03523   UndirectedGraph;
03524 
03525   typedef boost::graph_traits<UndirectedGraph>::vertex_descriptor Vertex;
03526   typedef boost::graph_traits<UndirectedGraph>::edge_descriptor Edge;
03527 
03528   UndirectedGraph graph;
03529 
03530   // Add vertices
03531   std::map<int, Vertex> dual_2_boost;
03532   AdjacencyMap dual_graph = GetGraph();
03533 
03534   for (AdjacencyMap::const_iterator graph_iter = dual_graph.begin();
03535       graph_iter != dual_graph.end();
03536       ++graph_iter) {
03537 
03538     Vertex boost_vertex = boost::add_vertex(graph);
03539     int dual_vertex = (*graph_iter).first;
03540 
03541     dual_2_boost.insert(std::make_pair(dual_vertex, boost_vertex));
03542 
03543   }
03544 
03545   // Add edges
03546   AdjacencyMap
03547   edge_list = GetEdgeList();
03548 
03549   for (AdjacencyMap::const_iterator edges_iter = edge_list.begin();
03550       edges_iter != edge_list.end();
03551       ++edges_iter) {
03552 
03553     const IDList vertices = (*edges_iter).second;
03554 
03555     int source_vertex = vertices[0];
03556     int target_vertex = vertices[1];
03557 
03558     Vertex source_boost_vertex = dual_2_boost[source_vertex];
03559     Vertex target_boost_vertex = dual_2_boost[target_vertex];
03560 
03561     boost::add_edge(source_boost_vertex, target_boost_vertex, graph);
03562 
03563   }
03564 
03565   int const number_vertices = GetNumberVertices();
03566   components.resize(number_vertices);
03567 
03568   int number_components =
03569       boost::connected_components(graph, &components[0]);
03570 
03571   return number_components;
03572 }
03573 
03574 //
03575 // Print graph for debugging
03576 //
03577 void
03578 DualGraph::Print() const
03579 {
03580 
03581   ScalarMap
03582   vertex_weights = GetVertexWeights();
03583 
03584   AdjacencyMap
03585   graph = GetGraph();
03586 
03587   int const
03588   number_vertices = GetNumberVertices();
03589 
03590   int const
03591   number_edges = GetNumberEdges();
03592 
03593   std::cout << '\n';
03594   std::cout << "Vertex - Edge Format:" << '\n';
03595   std::cout << '\n';
03596   std::cout << "============================================================";
03597   std::cout << '\n';
03598   std::cout << "Number of Vertices : " << number_vertices << '\n';
03599   std::cout << "Number of Edges    : " << number_edges << '\n';
03600   std::cout << "------------------------------------------------------------";
03601   std::cout << '\n';
03602   std::cout << "Vertex  Weight          Edges" << '\n';
03603   std::cout << "------------------------------------------------------------";
03604   std::cout << '\n';
03605 
03606   for (ScalarMap::const_iterator vw_iter = vertex_weights.begin();
03607       vw_iter != vertex_weights.end();
03608       ++vw_iter) {
03609 
03610     int const vertex = (*vw_iter).first;
03611     double const weight = (*vw_iter).second;
03612 
03613     std::cout << std::setw(8) << vertex;
03614     std::cout << std::scientific << std::setw(16) << std::setprecision(8);
03615     std::cout << weight;
03616 
03617     AdjacencyMap::const_iterator
03618     graph_iter = graph.find(vertex);
03619 
03620     if (graph_iter == graph.end()) {
03621       std::cerr << "Cannot find vertex " << vertex << '\n';
03622       exit(1);
03623     }
03624 
03625     IDList
03626     edges = graph[vertex];
03627 
03628     for (IDList::const_iterator edges_iter = edges.begin();
03629         edges_iter != edges.end();
03630         ++edges_iter) {
03631       int const edge = *edges_iter;
03632       std::cout << std::setw(8) << edge;
03633     }
03634 
03635     std::cout << '\n';
03636 
03637   }
03638 
03639   std::cout << "============================================================";
03640   std::cout << '\n';
03641 
03642   std::cout << '\n';
03643   std::cout << "Edge - Vertex Format:" << '\n';
03644   std::cout << '\n';
03645 
03646   AdjacencyMap
03647   edge_list = GetEdgeList();
03648 
03649   std::cout << "------------------------------------------------------------";
03650   std::cout << '\n';
03651   std::cout << "Edge    Vertices" << '\n';
03652   std::cout << "------------------------------------------------------------";
03653   std::cout << '\n';
03654 
03655   for (AdjacencyMap::const_iterator edges_iter = edge_list.begin();
03656       edges_iter != edge_list.end();
03657       ++edges_iter) {
03658 
03659     int const edge = (*edges_iter).first;
03660     std::cout << std::setw(8) << edge;
03661     const IDList vertices = (*edges_iter).second;
03662 
03663     for (IDList::const_iterator vertices_iter = vertices.begin();
03664         vertices_iter != vertices.end();
03665         ++vertices_iter) {
03666       int const vertex = (*vertices_iter);
03667       std::cout << std::setw(8) << vertex;
03668     }
03669 
03670     std::cout << '\n';
03671 
03672   }
03673 
03674   std::cout << "============================================================";
03675   std::cout << '\n';
03676 
03677   return;
03678 }
03679 
03680 //
03681 //
03682 //
03683 std::vector< std::vector<int> >
03684 DualGraph::GetFaceConnectivity(Intrepid::ELEMENT::Type const type) const
03685 {
03686 
03687   std::vector< std::vector<int> >
03688   face_connectivity;
03689 
03690   // Ugly initialization, but cannot rely on compilers
03691   // supporting #include <initializer_list> for the time being.
03692   int
03693   number_faces = 0;
03694 
03695   int
03696   nodes_per_face = 0;
03697 
03698   switch (type) {
03699 
03700   case Intrepid::ELEMENT::SEGMENTAL:
03701     number_faces = 2;
03702     nodes_per_face = 1;
03703     break;
03704 
03705   case Intrepid::ELEMENT::TRIANGULAR:
03706     number_faces = 3;
03707     nodes_per_face = 2;
03708     break;
03709 
03710   case Intrepid::ELEMENT::QUADRILATERAL:
03711     number_faces = 4;
03712     nodes_per_face = 2;
03713     break;
03714 
03715   case Intrepid::ELEMENT::TETRAHEDRAL:
03716     number_faces = 4;
03717     nodes_per_face = 3;
03718     break;
03719 
03720   case Intrepid::ELEMENT::HEXAHEDRAL:
03721     number_faces = 6;
03722     nodes_per_face = 4;
03723     break;
03724 
03725   default:
03726     std::cerr << "Unknown element type in face connectivity." << '\n';
03727     exit(1);
03728     break;
03729 
03730   }
03731 
03732   face_connectivity.resize(number_faces);
03733   for (int i = 0; i < number_faces; ++i) {
03734     face_connectivity[i].resize(nodes_per_face);
03735   }
03736 
03737   // Just for abbreviation
03738   std::vector< std::vector<int> > &
03739   f = face_connectivity;
03740 
03741   switch (type) {
03742 
03743   case Intrepid::ELEMENT::SEGMENTAL:
03744     f[0][0] = 0;
03745     f[1][0] = 1;
03746     break;
03747 
03748   case Intrepid::ELEMENT::TRIANGULAR:
03749     f[0][0] = 0; f[0][1] = 1;
03750     f[1][0] = 1; f[1][1] = 2;
03751     f[2][0] = 2; f[2][1] = 0;
03752     break;
03753 
03754   case Intrepid::ELEMENT::QUADRILATERAL:
03755     f[0][0] = 0; f[0][1] = 1;
03756     f[1][0] = 1; f[1][1] = 2;
03757     f[2][0] = 2; f[2][1] = 3;
03758     f[3][0] = 3; f[3][1] = 0;
03759     break;
03760 
03761   case Intrepid::ELEMENT::TETRAHEDRAL:
03762     f[0][0] = 0; f[0][1] = 1; f[0][2] = 2;
03763     f[1][0] = 0; f[1][1] = 3; f[1][2] = 1;
03764     f[2][0] = 1; f[2][1] = 3; f[2][2] = 2;
03765     f[3][0] = 2; f[3][1] = 3; f[3][2] = 0;
03766     break;
03767 
03768   case Intrepid::ELEMENT::HEXAHEDRAL:
03769     f[0][0] = 0; f[0][1] = 1; f[0][2] = 2; f[0][3] = 3;
03770     f[1][0] = 0; f[1][1] = 4; f[1][2] = 5; f[1][3] = 1;
03771     f[2][0] = 1; f[2][1] = 5; f[2][2] = 6; f[2][3] = 2;
03772     f[3][0] = 2; f[3][1] = 6; f[3][2] = 7; f[3][3] = 3;
03773     f[4][0] = 3; f[4][1] = 7; f[4][2] = 4; f[4][3] = 0;
03774     f[5][0] = 4; f[5][1] = 7; f[5][2] = 6; f[5][3] = 5;
03775     break;
03776 
03777   default:
03778     std::cerr << "Unknown element type in face connectivity." << '\n';
03779     exit(1);
03780     break;
03781 
03782   }
03783 
03784   return face_connectivity;
03785 }
03786 
03787 //
03788 // Default constructor for Zoltan hyperedge graph (or hypergraph)
03789 //
03790 ZoltanHyperGraph::ZoltanHyperGraph() :
03791           number_vertices_(0),
03792           number_hyperedges_(0)
03793 {
03794   return;
03795 }
03796 
03797 //
03798 // Build Zoltan Hypergraph from FE mesh Dual Graph
03799 //
03800 ZoltanHyperGraph::ZoltanHyperGraph(DualGraph const & dual_graph)
03801 {
03802   graph_ = dual_graph.GetGraph();
03803   vertex_weights_ = dual_graph.GetVertexWeights();
03804   number_vertices_ = dual_graph.GetNumberVertices();
03805   number_hyperedges_ = dual_graph.GetNumberEdges();
03806   return;
03807 }
03808 
03809 int
03810 ZoltanHyperGraph::GetNumberVertices() const
03811 {
03812   return graph_.size();
03813 }
03814 
03815 void
03816 ZoltanHyperGraph::SetNumberHyperedges(int number_hyperedges)
03817 {
03818   number_hyperedges_ = number_hyperedges;
03819   return;
03820 }
03821 
03822 int
03823 ZoltanHyperGraph::GetNumberHyperedges() const
03824 {
03825   return number_hyperedges_;
03826 }
03827 
03828 void
03829 ZoltanHyperGraph::SetGraph(AdjacencyMap & graph)
03830 {
03831   graph_ = graph;
03832   return;
03833 }
03834 
03835 AdjacencyMap
03836 ZoltanHyperGraph::GetGraph() const
03837 {
03838   return graph_;
03839 }
03840 
03841 void
03842 ZoltanHyperGraph::SetVertexWeights(ScalarMap & vertex_weights)
03843 {
03844   vertex_weights_ = vertex_weights;
03845   return;
03846 }
03847 
03848 ScalarMap
03849 ZoltanHyperGraph::GetVertexWeights() const
03850 {
03851   return vertex_weights_;
03852 }
03853 
03854 //
03855 // Vector with edge IDs
03856 //
03857 std::vector<ZOLTAN_ID_TYPE>
03858 ZoltanHyperGraph::GetEdgeIDs() const
03859 {
03860 
03861   std::vector<ZOLTAN_ID_TYPE>
03862   edges;
03863 
03864   for (AdjacencyMap::const_iterator
03865       graph_iter = graph_.begin();
03866       graph_iter != graph_.end();
03867       ++graph_iter) {
03868 
03869     IDList
03870     hyperedges = (*graph_iter).second;
03871 
03872 
03873     for (IDList::const_iterator
03874         hyperedges_iter = hyperedges.begin();
03875         hyperedges_iter != hyperedges.end();
03876         ++hyperedges_iter) {
03877 
03878       int const hyperedge = (*hyperedges_iter);
03879       edges.push_back(hyperedge);
03880 
03881     }
03882   }
03883 
03884   return edges;
03885 }
03886 
03887 //
03888 // Vector with edge pointers
03889 //
03890 std::vector<int>
03891 ZoltanHyperGraph::GetEdgePointers() const
03892 {
03893 
03894   std::vector<int>
03895   pointers;
03896 
03897   int
03898   pointer = 0;
03899 
03900   for (AdjacencyMap::const_iterator
03901       graph_iter = graph_.begin();
03902       graph_iter != graph_.end();
03903       ++graph_iter) {
03904 
03905     pointers.push_back(pointer);
03906 
03907     IDList
03908     hyperedges = (*graph_iter).second;
03909 
03910 
03911     for (IDList::const_iterator
03912         hyperedges_iter = hyperedges.begin();
03913         hyperedges_iter != hyperedges.end();
03914         ++hyperedges_iter) {
03915 
03916       ++pointer;
03917 
03918     }
03919 
03920   }
03921 
03922   return pointers;
03923 }
03924 
03925 //
03926 // Vector with vertex IDs
03927 //
03928 std::vector<ZOLTAN_ID_TYPE>
03929 ZoltanHyperGraph::GetVertexIDs() const
03930 {
03931 
03932   std::vector<ZOLTAN_ID_TYPE>
03933   vertices;
03934 
03935   for (AdjacencyMap::const_iterator
03936       graph_iter = graph_.begin();
03937       graph_iter != graph_.end();
03938       ++graph_iter) {
03939 
03940     int vertex = (*graph_iter).first;
03941     vertices.push_back(vertex);
03942 
03943   }
03944 
03945   return vertices;
03946 }
03947 
03948 //
03949 // Zoltan interface, return number of objects
03950 //
03951 int
03952 ZoltanHyperGraph::GetNumberOfObjects(void* data, int* ierr)
03953 {
03954 
03955   ZoltanHyperGraph &
03956   zoltan_hypergraph = *(static_cast<ZoltanHyperGraph*>(data));
03957 
03958   *ierr = ZOLTAN_OK;
03959 
03960   int
03961   num_objects = zoltan_hypergraph.GetGraph().size();
03962 
03963   return num_objects;
03964 }
03965 
03966 //
03967 // Zoltan interface, return relevant object properties
03968 //
03969 void
03970 ZoltanHyperGraph::GetObjectList(
03971     void* data,
03972     int sizeGID,
03973     int sizeLID,
03974     ZOLTAN_ID_PTR globalID,
03975     ZOLTAN_ID_PTR localID,
03976     int wgt_dim,
03977     float* obj_wgts,
03978     int* ierr)
03979 {
03980 
03981   ZoltanHyperGraph &
03982   zoltan_hypergraph = *(static_cast<ZoltanHyperGraph*>(data));
03983 
03984   *ierr = ZOLTAN_OK;
03985 
03986   ScalarMap
03987   vertex_weights = zoltan_hypergraph.GetVertexWeights();
03988 
03989   ZOLTAN_ID_PTR
03990   global_id_ptr = globalID;
03991 
03992   ZOLTAN_ID_PTR
03993   local_id_ptr = localID;
03994 
03995   float*
03996   weight_ptr = obj_wgts;
03997 
03998   for (ScalarMap::const_iterator
03999       weights_iter = vertex_weights.begin();
04000       weights_iter != vertex_weights.end();
04001       ++weights_iter) {
04002 
04003     int vertex = (*weights_iter).first;
04004     double vertex_weight = (*weights_iter).second;
04005 
04006     // Beware of this evil pointer manipulation
04007     (*global_id_ptr) = vertex;
04008     (*local_id_ptr) = vertex;
04009     (*weight_ptr) = vertex_weight;
04010     global_id_ptr++;
04011     local_id_ptr++;
04012     weight_ptr++;
04013 
04014   }
04015 
04016   return;
04017 }
04018 
04019 //
04020 // Zoltan interface, get size of hypergraph
04021 //
04022 void
04023 ZoltanHyperGraph::GetHyperGraphSize(
04024     void* data,
04025     int* num_lists,
04026     int* num_pins,
04027     int* format,
04028     int* ierr)
04029 {
04030 
04031   ZoltanHyperGraph &
04032   zoltan_hypergraph = *(static_cast<ZoltanHyperGraph*>(data));
04033 
04034   *ierr = ZOLTAN_OK;
04035 
04036   // Number of vertices
04037   *num_lists = zoltan_hypergraph.GetVertexIDs().size();
04038 
04039   // Numbers of pins, i.e. size of list of hyperedges attached to vertices
04040   *num_pins = zoltan_hypergraph.GetEdgeIDs().size();
04041 
04042   *format = ZOLTAN_COMPRESSED_VERTEX;
04043 
04044   return;
04045 }
04046 
04047 //
04048 // Zoltan interface, get the hypergraph itself
04049 //
04050 void
04051 ZoltanHyperGraph::GetHyperGraph(
04052     void* data,
04053     int num_gid_entries,
04054     int num_vtx_edge,
04055     int num_pins,
04056     int format,
04057     ZOLTAN_ID_PTR vtxedge_GID,
04058     int* vtxedge_ptr,
04059     ZOLTAN_ID_PTR pin_GID,
04060     int* ierr)
04061 {
04062 
04063   ZoltanHyperGraph &
04064   zoltan_hypergraph = *(static_cast<ZoltanHyperGraph*>(data));
04065 
04066   *ierr = ZOLTAN_OK;
04067 
04068   // Validate
04069   assert(num_vtx_edge ==
04070       static_cast<int>(zoltan_hypergraph.GetVertexIDs().size()));
04071 
04072   assert(num_pins ==
04073       static_cast<int>(zoltan_hypergraph.GetEdgeIDs().size()));
04074 
04075   assert(format == ZOLTAN_COMPRESSED_VERTEX);
04076 
04077   // Copy hypergraph data
04078   std::vector<ZOLTAN_ID_TYPE>
04079   vertex_IDs = zoltan_hypergraph.GetVertexIDs();
04080 
04081   std::vector<ZOLTAN_ID_TYPE>
04082   edge_IDs = zoltan_hypergraph.GetEdgeIDs();
04083 
04084   std::vector<int>
04085   edge_pointers = zoltan_hypergraph.GetEdgePointers();
04086 
04087   for (std::vector<ZOLTAN_ID_TYPE>::size_type
04088       i = 0;
04089       i < vertex_IDs.size();
04090       ++i) {
04091 
04092     vtxedge_GID[i] = vertex_IDs[i];
04093 
04094   }
04095 
04096   for (std::vector<ZOLTAN_ID_TYPE>::size_type
04097       i = 0;
04098       i < edge_IDs.size();
04099       ++i) {
04100 
04101     pin_GID[i] = edge_IDs[i];
04102 
04103   }
04104 
04105   for (std::vector<int>::size_type
04106       i = 0;
04107       i < edge_pointers.size();
04108       ++i) {
04109 
04110     vtxedge_ptr[i] = edge_pointers[i];
04111 
04112   }
04113 
04114   return;
04115 }
04116 
04117 //
04118 // Read a Zoltan Hyperedge Graph from an input stream
04119 //
04120 std::istream &
04121 operator>>(std::istream & input_stream, ZoltanHyperGraph & zoltan_hypergraph)
04122 {
04123   //
04124   // First line must contain the number of vertices and hyperedges
04125   //
04126   const std::vector<char>::size_type
04127   MaxChar = 256;
04128 
04129   char line[MaxChar];
04130   input_stream.getline(line, MaxChar);
04131 
04132   std::stringstream header(line);
04133   std::string token;
04134 
04135   // Number of vertices
04136   header >> token;
04137   int number_vertices = atoi(token.c_str());
04138 
04139   // Number of hyperegdes
04140   header >> token;
04141   int number_hyperedges = atoi(token.c_str());
04142 
04143   AdjacencyMap
04144   graph;
04145 
04146   ScalarMap
04147   vertex_weights;
04148 
04149   // Read list of hyperedge IDs adjacent to given vertex
04150   for (int i = 0; i < number_vertices; ++i) {
04151 
04152     input_stream.getline(line, MaxChar);
04153     std::stringstream input_line(line);
04154 
04155     // First entry should be vertex ID
04156     input_line >> token;
04157     int vertex = atoi(token.c_str());
04158 
04159     // Second entry should be vertex weight
04160     input_line >> token;
04161     double vw = atof(token.c_str());
04162     vertex_weights[vertex] = vw;
04163 
04164     // Read the hyperedges
04165     IDList hyperedges;
04166     while (input_line >> token) {
04167       int hyperedge = atoi(token.c_str());
04168       hyperedges.push_back(hyperedge);
04169     }
04170 
04171     graph[vertex] = hyperedges;
04172 
04173   }
04174 
04175   zoltan_hypergraph.SetGraph(graph);
04176   zoltan_hypergraph.SetVertexWeights(vertex_weights);
04177   zoltan_hypergraph.SetNumberHyperedges(number_hyperedges);
04178 
04179   return input_stream;
04180 }
04181 
04182 //
04183 // Write a Zoltan Hyperedge Graph to an output stream
04184 //
04185 std::ostream &
04186 operator<<(
04187     std::ostream & output_stream,
04188     ZoltanHyperGraph const & zoltan_hypergraph)
04189 {
04190 
04191   output_stream << std::setw(12) << zoltan_hypergraph.GetNumberVertices();
04192   output_stream << std::setw(12) << zoltan_hypergraph.GetNumberHyperedges();
04193   output_stream << '\n';
04194 
04195   AdjacencyMap const &
04196   graph = zoltan_hypergraph.GetGraph();
04197 
04198   ScalarMap
04199   vertex_weights = zoltan_hypergraph.GetVertexWeights();
04200 
04201   for (AdjacencyMap::const_iterator
04202       graph_iter = graph.begin();
04203       graph_iter != graph.end();
04204       ++graph_iter) {
04205 
04206     // Vertex ID
04207     int const
04208     vertex = (*graph_iter).first;
04209 
04210     double const
04211     vertex_weight = vertex_weights[vertex];
04212 
04213     output_stream << std::setw(12) << vertex;
04214     output_stream << std::scientific;
04215     output_stream << std::setw(16) << std::setprecision(8);
04216     output_stream << vertex_weight;
04217 
04218     const IDList
04219     hyperedges = (*graph_iter).second;
04220 
04221     for (IDList::const_iterator
04222         hyperedges_iter = hyperedges.begin();
04223         hyperedges_iter != hyperedges.end();
04224         ++hyperedges_iter) {
04225 
04226       int const
04227       hyperedge = (*hyperedges_iter);
04228 
04229       output_stream << std::setw(12) << hyperedge;
04230 
04231     }
04232 
04233     output_stream << '\n';
04234 
04235   }
04236 
04237   return output_stream;
04238 }
04239 
04240 } // namespace LCM
04241 
04242 #endif // #if defined (ALBANY_LCM) && defined(ALBANY_ZOLTAN)

Generated on Wed Mar 26 2014 18:36:39 for Albany: a Trilinos-based PDE code by  doxygen 1.7.1