Zoltan2
Loading...
Searching...
No Matches
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
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
45using Teuchos::ParameterList;
46using Teuchos::RCP;
47using Teuchos::ArrayView;
48
49// Computes and prints ghost metrics (takes in a Hyper graph model)
50template <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
123int 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/*****************************************************************************/
void PrintGhostMetrics(Zoltan2::HyperGraphModel< Adapter > &mdl)
#define nParts
Defines the APFMeshAdapter class.
Defines the ColoringProblem class.
Defines the Environment class.
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
Defines the HyperGraphModel interface.
Defines the PartitioningProblem class.
int main()
ColoringProblem sets up coloring problems for the user.
void solve(bool updateInputData=true)
Direct the problem to create a solution.
The user parameters, debug, timing and memory profiling output objects, and error checking methods.
A class that computes and returns quality metrics.
HyperGraphModel defines the interface required for hyper graph models.
size_t getLocalNumPins() const
Returns the local number of pins.
size_t getPinList(ArrayView< const gno_t > &pinIds, ArrayView< const offset_t > &offsets, ArrayView< input_t > &wgts) const
Sets pointers to this process' pins global Ids based on the centric view given by getCentricView()
size_t getOwnedList(ArrayView< bool > &isOwner) const
Sets pointer to the ownership of this processes vertices.
size_t getLocalNumOwnedVertices() const
Returns the number vertices on this process that are owned.
size_t getEdgeList(ArrayView< const gno_t > &Ids, ArrayView< input_t > &wgts) const
Sets pointers to this process' hyperedge Ids and their weights.
size_t getLocalNumVertices() const
Returns the number vertices on this process.
MeshAdapter defines the interface for mesh input.
PartitioningProblem sets up partitioning problems for the user.
const PartitioningSolution< Adapter > & getSolution()
Get the solution to the problem.
void solve(bool updateInputData=true)
Direct the problem to create a solution.
void printTimers() const
Return the communicator passed to the problem.
The StridedData class manages lists of weights or coordinates.
map_t::local_ordinal_type lno_t
map_t::global_ordinal_type gno_t
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
static ArrayRCP< ArrayRCP< zscalar_t > > weights
Zoltan2::EvaluatePartition< matrixAdapter_t > quality_t