Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
APFMeshAdapterTest.cpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Zoltan2: A package of combinatorial algorithms for scientific computing
4 //
5 // Copyright 2012 NTESS and the Zoltan2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
17 /**************************************************************/
18 /* Includes */
19 /**************************************************************/
20 
22 #include <Zoltan2_Environment.hpp>
26 
27 // Teuchos includes
28 #include "Teuchos_RCP.hpp"
29 #include "Teuchos_XMLParameterListHelpers.hpp"
30 #include "Teuchos_Hashtable.hpp"
31 
32 // SCOREC includes
33 #ifdef HAVE_ZOLTAN2_PARMA
34 #include <parma.h>
35 #include <apf.h>
36 #include <apfMesh.h>
37 #include <apfMDS.h>
38 #include <apfMesh2.h>
39 #include <PCU.h>
40 #include <gmi_mesh.h>
41 #endif
42 
43 #include <set>
44 
45 using Teuchos::ParameterList;
46 using Teuchos::RCP;
47 using Teuchos::ArrayView;
48 
49 // Computes and prints ghost metrics (takes in a Hyper graph model)
50 template <typename Adapter>
52  typedef typename Adapter::gno_t gno_t;
53  typedef typename Adapter::lno_t lno_t;
54  typedef typename Adapter::scalar_t scalar_t;
55  typedef typename Adapter::offset_t offset_t;
57 
58  ArrayView<const gno_t> Ids;
59  ArrayView<input_t> wgts;
60  mdl.getEdgeList(Ids,wgts);
61  ArrayView<bool> isOwner;
62  mdl.getOwnedList(isOwner);
63  size_t numOwned = mdl.getLocalNumOwnedVertices();
64  ArrayView<const gno_t> pins;
65  ArrayView<const offset_t> offsets;
66  mdl.getPinList(pins,offsets,wgts);
67 
68  std::set<gno_t> gids;
69  for (size_t i=0;i<mdl.getLocalNumVertices();i++) {
70  if (isOwner[i])
71  gids.insert(Ids[i]);
72  }
73  std::set<gno_t> ghosts;
74  gno_t num_ghosts=0;
75  for (size_t i=0;i<mdl.getLocalNumPins();i++) {
76  gno_t pin = pins[i];
77  if (gids.find(pin)==gids.end()) {
78  num_ghosts++;
79  if (ghosts.find(pin)==ghosts.end())
80  ghosts.insert(pin);
81  }
82  }
83  std::cout<< "[METRIC] " << PCU_Comm_Self() << " Total number of ghosts in the hypergraph: " << num_ghosts << "\n"
84  << "[METRIC] " << PCU_Comm_Self() << " Number of unique ghosts: " << ghosts.size() << "\n";
85  gno_t unique_ghosts =ghosts.size();
86  gno_t owned_and_ghosts =unique_ghosts+numOwned;
87  gno_t max_o_and_g,min_o_and_g;
88  gno_t max_ghosts,max_u_ghosts;
89  gno_t min_ghosts,min_u_ghosts;
90  max_ghosts = min_ghosts = num_ghosts;
91  max_u_ghosts = min_u_ghosts = unique_ghosts;
92  max_o_and_g = min_o_and_g = owned_and_ghosts;
93  double avg_ghosts,avg_u_ghosts,avg_o_and_g;
94  PCU_Add_Ints(&num_ghosts,1);
95  PCU_Add_Ints(&unique_ghosts,1);
96  PCU_Add_Ints(&owned_and_ghosts,1);
97  PCU_Max_Ints(&max_ghosts,1);
98  PCU_Max_Ints(&max_u_ghosts,1);
99  PCU_Max_Ints(&max_o_and_g,1);
100  PCU_Min_Ints(&min_ghosts,1);
101  PCU_Min_Ints(&min_u_ghosts,1);
102  PCU_Min_Ints(&min_o_and_g,1);
103  avg_ghosts = num_ghosts*1.0/PCU_Comm_Peers();
104  avg_u_ghosts = unique_ghosts*1.0/PCU_Comm_Peers();
105  avg_o_and_g = owned_and_ghosts*1.0/PCU_Comm_Peers();
106  if (!PCU_Comm_Self())
107  std::cout<< "[METRIC] Global ghosts in the hypergraph (tot max min avg imb): "
108  << num_ghosts<<" "<<max_ghosts<<" "<<min_ghosts<<" "<<avg_ghosts<<" "
109  <<max_ghosts/avg_ghosts << "\n"
110  << "[METRIC] Global unique ghosts (tot max min avg imb): "
111  << unique_ghosts<<" "<<max_u_ghosts<<" "<<min_u_ghosts<<" "<<avg_u_ghosts<<" "
112  <<max_u_ghosts/avg_u_ghosts << "\n"
113  << "[METRIC] Global owned and ghosts (tot max min avg imb): "
114  << owned_and_ghosts<<" "<<max_o_and_g<<" "<<min_o_and_g<<" "<<avg_o_and_g<<" "
115  <<max_o_and_g/avg_o_and_g << "\n";
116 
117 }
118 
119 /*****************************************************************************/
120 /******************************** MAIN ***************************************/
121 /*****************************************************************************/
122 
123 int main(int narg, char *arg[]) {
124 
125  Tpetra::ScopeGuard tscope(&narg, &arg);
126  Teuchos::RCP<const Teuchos::Comm<int> > CommT = Tpetra::getDefaultComm();
127 
128  int me = CommT->getRank();
129  //int numProcs = CommT->getSize();
130 
131  if (me == 0){
132  std::cout
133  << "====================================================================\n"
134  << "| |\n"
135  << "| Example: Partition APF Mesh |\n"
136  << "| |\n"
137  << "| Questions? Contact Karen Devine (kddevin@sandia.gov), |\n"
138  << "| Erik Boman (egboman@sandia.gov), |\n"
139  << "| Siva Rajamanickam (srajama@sandia.gov). |\n"
140  << "| |\n"
141  << "| Zoltan2's website: http://trilinos.sandia.gov/packages/zoltan2 |\n"
142  << "| Trilinos website: http://trilinos.sandia.gov |\n"
143  << "| |\n"
144  << "====================================================================\n";
145  }
146 
147 
148 #ifdef HAVE_MPI
149  if (me == 0) {
150  std::cout << "PARALLEL executable \n";
151  }
152 #else
153  if (me == 0) {
154  std::cout << "SERIAL executable \n";
155  }
156 #endif
157 
158  /***************************************************************************/
159  /******************************* GET INPUTS ********************************/
160  /***************************************************************************/
161 
162  // default values for command-line arguments
163  std::string meshFileName("4/");
164  std::string modelFileName("torus.dmg");
165  std::string action("parma");
166  std::string parma_method("VtxElm");
167  std::string output_loc("");
168  int nParts = CommT->getSize();
169  double imbalance = 1.1;
170  int layers=2;
171  int ghost_metric=false;
172  // Read run-time options.
173  Teuchos::CommandLineProcessor cmdp (false, false);
174  cmdp.setOption("meshfile", &meshFileName,
175  "Mesh file with APF specifications (.smb file(s))");
176  cmdp.setOption("modelfile", &modelFileName,
177  "Model file with APF specifications (.dmg file)");
178  cmdp.setOption("action", &action,
179  "Method to use: mj, scotch, zoltan_rcb, parma or color");
180  cmdp.setOption("parma_method", &parma_method,
181  "Method to use: Vertex, Element, VtxElm, VtxEdgeElm, Ghost, Shape, or Centroid ");
182  cmdp.setOption("nparts", &nParts,
183  "Number of parts to create");
184  cmdp.setOption("imbalance", &imbalance,
185  "Target imbalance for the partitioning method");
186  cmdp.setOption("output", &output_loc,
187  "Location of new partitioned apf mesh. Ex: 4/torus.smb");
188  cmdp.setOption("layers", &layers,
189  "Number of layers for ghosting");
190  cmdp.setOption("ghost_metric", &ghost_metric,
191  "0 does not compute ghost metric otherwise compute both before and after");
192  cmdp.parse(narg, arg);
193 
194  /***************************************************************************/
195  /********************** GET CELL TOPOLOGY **********************************/
196  /***************************************************************************/
197 
198  // Get dimensions
199  //int dim = 3;
200 
201  /***************************************************************************/
202  /***************************** GENERATE MESH *******************************/
203  /***************************************************************************/
204 
205 #ifdef HAVE_ZOLTAN2_PARMA
206 
207  if (me == 0) std::cout << "Generating mesh ... \n\n";
208 
209  //Setup for SCOREC
210  PCU_Comm_Init();
211 
212  // Generate mesh with MDS
213  gmi_register_mesh();
214  apf::Mesh2* m = apf::loadMdsMesh(modelFileName.c_str(),meshFileName.c_str());
215  apf::verify(m);
216 
217  //Data for APF MeshAdapter
218  std::string primary="region";
219  std::string adjacency="face";
220  if (m->getDimension()==2) {
221  primary="face";
222  adjacency="edge";
223  }
224  bool needSecondAdj=false;
225 
226  // Set parameters for partitioning
227  if (me == 0) std::cout << "Creating parameter list ... \n\n";
228 
229  Teuchos::ParameterList params("test params");
230  params.set("timer_output_stream" , "std::cout");
231 
232  bool do_partitioning = false;
233  if (action == "mj") {
234  do_partitioning = true;
235  params.set("debug_level", "basic_status");
236  params.set("imbalance_tolerance", imbalance);
237  params.set("num_global_parts", nParts);
238  params.set("algorithm", "multijagged");
239  params.set("rectilinear", "yes");
240  }
241  else if (action == "scotch") {
242  do_partitioning = true;
243  params.set("debug_level", "no_status");
244  params.set("imbalance_tolerance", imbalance);
245  params.set("num_global_parts", nParts);
246  params.set("partitioning_approach", "partition");
247  params.set("objects_to_partition","mesh_elements");
248  params.set("algorithm", "scotch");
249  needSecondAdj=true;
250  }
251  else if (action == "zoltan_rcb") {
252  do_partitioning = true;
253  params.set("debug_level", "verbose_detailed_status");
254  params.set("imbalance_tolerance", imbalance);
255  params.set("num_global_parts", nParts);
256  params.set("partitioning_approach", "partition");
257  params.set("algorithm", "zoltan");
258  }
259  else if (action == "parma") {
260  do_partitioning = true;
261  params.set("debug_level", "no_status");
262  params.set("imbalance_tolerance", imbalance);
263  params.set("algorithm", "parma");
264  Teuchos::ParameterList &pparams = params.sublist("parma_parameters",false);
265  pparams.set("parma_method",parma_method);
266  pparams.set("step_size",1.1);
267  if (parma_method=="Ghost") {
268  pparams.set("ghost_layers",layers);
269  pparams.set("ghost_bridge",m->getDimension()-1);
270  }
271  adjacency="vertex";
272  }
273  else if (action=="zoltan_hg") {
274  do_partitioning = true;
275  params.set("debug_level", "no_status");
276  params.set("imbalance_tolerance", imbalance);
277  params.set("algorithm", "zoltan");
278  params.set("num_global_parts", nParts);
279  Teuchos::ParameterList &zparams = params.sublist("zoltan_parameters",false);
280  zparams.set("LB_METHOD","HYPERGRAPH");
281  zparams.set("LB_APPROACH","PARTITION");
282  //params.set("compute_metrics","yes");
283  adjacency="vertex";
284  }
285  else if (action=="hg_ghost") {
286  do_partitioning = true;
287  params.set("debug_level", "no_status");
288  params.set("imbalance_tolerance", imbalance);
289  params.set("algorithm", "zoltan");
290  params.set("num_global_parts", nParts);
291  params.set("hypergraph_model_type","ghosting");
292  params.set("ghost_layers",layers);
293  Teuchos::ParameterList &zparams = params.sublist("zoltan_parameters",false);
294  zparams.set("LB_METHOD","HYPERGRAPH");
295  zparams.set("LB_APPROACH","PARTITION");
296  zparams.set("PHG_EDGE_SIZE_THRESHOLD", "1.0");
297  primary="vertex";
298  adjacency="edge";
299  needSecondAdj=true;
300  }
301  else if (action == "color") {
302  params.set("debug_level", "verbose_detailed_status");
303  params.set("debug_output_file", "kdd");
304  params.set("debug_procs", "all");
305  }
306  Parma_PrintPtnStats(m,"before");
307 
308  // Creating mesh adapter
309  if (me == 0) std::cout << "Creating mesh adapter ... \n\n";
310  typedef Zoltan2::APFMeshAdapter<apf::Mesh2*> inputAdapter_t;
312  typedef Zoltan2::MeshAdapter<apf::Mesh2*> baseMeshAdapter_t;
313 
314  double time_1=PCU_Time();
315  inputAdapter_t *ia =
316  new inputAdapter_t(*CommT, m,primary,adjacency,needSecondAdj);
317  double time_2=PCU_Time();
318 
319 
320  inputAdapter_t::scalar_t* arr =
321  new inputAdapter_t::scalar_t[ia->getLocalNumOf(ia->getPrimaryEntityType())];
322  for (size_t i=0;i<ia->getLocalNumOf(ia->getPrimaryEntityType());i++) {
323  arr[i]=PCU_Comm_Self()+1;
324  }
325 
326  const inputAdapter_t::scalar_t* weights=arr;
327  ia->setWeights(ia->getPrimaryEntityType(),weights,1);
328 
329 
330  if (ghost_metric) {
331  const baseMeshAdapter_t *base_ia = dynamic_cast<const baseMeshAdapter_t*>(ia);
332  Zoltan2::modelFlag_t graphFlags_;
333  RCP<Zoltan2::Environment> env;
334  try{
335  env = rcp(new Zoltan2::Environment(params, Tpetra::getDefaultComm()));
336  }
338 
339  RCP<const Zoltan2::Environment> envConst = Teuchos::rcp_const_cast<const Zoltan2::Environment>(env);
340 
341  RCP<const baseMeshAdapter_t> baseInputAdapter_(base_ia,false);
342  Zoltan2::HyperGraphModel<inputAdapter_t> model(baseInputAdapter_,envConst,CommT,
343  graphFlags_,Zoltan2::HYPEREDGE_CENTRIC);
344  PrintGhostMetrics(model);
345  }
346 
347  // create Partitioning problem
348  double time_3 = PCU_Time();
349  if (do_partitioning) {
350  if (me == 0) std::cout << "Creating partitioning problem ... \n\n";
351 
352  Zoltan2::PartitioningProblem<inputAdapter_t> problem(ia, &params, CommT);
353 
354  // call the partitioner
355  if (me == 0) std::cout << "Calling the partitioner ... \n\n";
356 
357  problem.solve();
358 
359 
360 
361  if (me==0) std::cout << "Applying Solution to Mesh\n\n";
362  apf::Mesh2** new_mesh = &m;
363  ia->applyPartitioningSolution(m,new_mesh,problem.getSolution());
364 
365  // create metric object
366  RCP<quality_t> metricObject =
367  rcp(new quality_t(ia, &params, CommT, &problem.getSolution()));
368 
369  if (!me) {
370  metricObject->printMetrics(std::cout);
371  }
372  }
373  else {
374  if (me == 0) std::cout << "Creating coloring problem ... \n\n";
375 
376  Zoltan2::ColoringProblem<inputAdapter_t> problem(ia, &params);
377 
378  // call the partitioner
379  if (me == 0) std::cout << "Calling the coloring algorithm ... \n\n";
380 
381  problem.solve();
382 
383  problem.printTimers();
384 
385 
386  }
387 
388  double time_4=PCU_Time();
389 
390  //Destroy the adapter
391  ia->destroy();
392  delete [] arr;
393  //Parma_PrintPtnStats(m,"after");
394 
395  if (ghost_metric) {
396  inputAdapter_t ia2(*CommT, m,primary,adjacency,true);
397  const baseMeshAdapter_t *base_ia = dynamic_cast<const baseMeshAdapter_t*>(&ia2);
398 
399  Zoltan2::modelFlag_t graphFlags_;
400  RCP<Zoltan2::Environment> env;
401  try{
402  env = rcp(new Zoltan2::Environment(params, Tpetra::getDefaultComm()));
403  }
405  RCP<const Zoltan2::Environment> envConst = Teuchos::rcp_const_cast<const Zoltan2::Environment>(env);
406  RCP<const baseMeshAdapter_t> baseInputAdapter_(base_ia,false);
407  Zoltan2::HyperGraphModel<inputAdapter_t> model(baseInputAdapter_, envConst, CommT,
408  graphFlags_,Zoltan2::HYPEREDGE_CENTRIC);
409 
410  PrintGhostMetrics(model);
411  ia2.destroy();
412  }
413 
414  if (output_loc!="") {
415  m->writeNative(output_loc.c_str());
416  }
417 
418  // delete mesh
419  if (me == 0) std::cout << "Deleting the mesh ... \n\n";
420  time_4-=time_3;
421  time_2-=time_1;
422  PCU_Max_Doubles(&time_2,1);
423  PCU_Max_Doubles(&time_4,1);
424  if (!me) {
425  std::cout<<"\nConstruction time: "<<time_2<<"\n"
426  <<"Problem time: " << time_4<<"\n\n";
427  }
428  //Delete the APF Mesh
429  m->destroyNative();
430  apf::destroyMesh(m);
431  //End communications
432  PCU_Comm_Free();
433 #endif
434 
435  if (me == 0)
436  std::cout << "PASS" << std::endl;
437 
438  return 0;
439 
440 }
441 /*****************************************************************************/
442 /********************************* END MAIN **********************************/
443 /*****************************************************************************/
ColoringProblem sets up coloring problems for the user.
Defines the ColoringProblem class.
#define nParts
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
static ArrayRCP< ArrayRCP< zscalar_t > > weights
void solve(bool updateInputData=true)
Direct the problem to create a solution.
MeshAdapter defines the interface for mesh input.
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:27
Zoltan2::EvaluatePartition< matrixAdapter_t > quality_t
int main(int narg, char **arg)
Definition: coloring1.cpp:164
Defines the APFMeshAdapter class.
size_t getOwnedList(ArrayView< bool > &isOwner) const
Sets pointer to the ownership of this processes vertices.
size_t getEdgeList(ArrayView< const gno_t > &Ids, ArrayView< input_t > &wgts) const
Sets pointers to this process&#39; hyperedge Ids and their weights.
void PrintGhostMetrics(Zoltan2::HyperGraphModel< Adapter > &mdl)
The StridedData class manages lists of weights or coordinates.
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:26
void printTimers() const
Return the communicator passed to the problem.
The user parameters, debug, timing and memory profiling output objects, and error checking methods...
size_t getLocalNumPins() const
Returns the local number of pins.
const PartitioningSolution< Adapter > & getSolution()
Get the solution to the problem.
PartitioningProblem sets up partitioning problems for the user.
Defines the HyperGraphModel interface.
Defines the Environment class.
size_t getPinList(ArrayView< const gno_t > &pinIds, ArrayView< const offset_t > &offsets, ArrayView< input_t > &wgts) const
Sets pointers to this process&#39; pins global Ids based on the centric view given by getCentricView() ...
size_t getLocalNumVertices() const
Returns the number vertices on this process.
Defines the PartitioningProblem class.
A class that computes and returns quality metrics.
HyperGraphModel defines the interface required for hyper graph models.
void solve(bool updateInputData=true)
Direct the problem to create a solution.
size_t getLocalNumOwnedVertices() const
Returns the number vertices on this process that are owned.