Zoltan2
Loading...
Searching...
No Matches
test_driver.cpp
Go to the documentation of this file.
1// @HEADER
2//
3// ***********************************************************************
4//
5// Zoltan2: A package of combinatorial algorithms for scientific computing
6// Copyright 2012 Sandia Corporation
7//
8// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9// the U.S. Government retains certain rights in this software.
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17//
18// 2. Redistributions in binary form must reproduce the above copyright
19// notice, this list of conditions and the following disclaimer in the
20// documentation and/or other materials provided with the distribution.
21//
22// 3. Neither the name of the Corporation nor the names of the
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Questions? Contact Karen Devine (kddevin@sandia.gov)
39// Erik Boman (egboman@sandia.gov)
40// Siva Rajamanickam (srajama@sandia.gov)
41//
42// ***********************************************************************
43//
44// @HEADER
45
46/* \file test_driver.cpp
47 * \brief Test driver for Zoltan2. Facilitates generation of test problem via
48 * a simple .xml input interface
49 */
50
51// taking headers from existing driver template
52// will keep or remove as needed
53#include <UserInputForTests.hpp>
54#include <Zoltan2_Typedefs.hpp>
55#include <AdapterForTests.hpp>
58
61
66
68
69#include <Teuchos_DefaultComm.hpp>
70#include <Teuchos_XMLObject.hpp>
71#include <Teuchos_FileInputSource.hpp>
72
73#include <sstream>
74#include <string>
75#include <map>
76#include <iostream>
77#include <queue>
78
79using Teuchos::ParameterList;
80using Teuchos::Comm;
81using Teuchos::RCP;
82using Teuchos::ArrayRCP;
83using Teuchos::XMLObject;
84using namespace Zoltan2_TestingFramework;
85
86using std::string;
87using std::map;
88using std::pair;
89using std::exception;
90using std::ostringstream;
91using std::queue;
92
93#define ERRMSG(msg) if (rank == 0){ std::cerr << "FAIL: " << msg << std::endl; }
94#define EXC_ERRMSG(msg, e) \
95if (rank==0){ std::cerr << "FAIL: " << msg << std::endl << e.what() << std::endl;}
96
97void xmlToModelPList(const Teuchos::XMLObject &xml,
98 Teuchos::ParameterList & plist)
99{
100 // This method composes a plist for the problem
101 Teuchos::XMLParameterListReader reader;
102 plist = reader.toParameterList(xml);
103
104 // Get list of valid Zoltan2 Parameters
105 // Zoltan 2 parameters appear in the input file
106 // Right now we have default values stored in
107 // the parameter list, we would like to apply
108 // the options specified by the user in their
109 // input file
110 Teuchos::ParameterList zoltan2Parameters;
111 Zoltan2::createAllParameters(zoltan2Parameters);
112
113 if (plist.isSublist("Zoltan2Parameters")) {
114 // Apply user specified zoltan2Parameters
115 ParameterList &sub = plist.sublist("Zoltan2Parameters");
116 zoltan2Parameters.setParameters(sub);
117 }
118}
119
120bool getParameterLists(const string &inputFileName,
121 queue<ParameterList> &problems,
122 queue<ParameterList> &comparisons,
123 const RCP<const Teuchos::Comm<int> > & comm)
124{
125 int rank = comm->getRank();
126 // return a parameter list of problem definitions
127 // and a parameter list for solution comparisons
128 Teuchos::FileInputSource inputSource(inputFileName);
129 if(rank == 0) {
130 std::cout << "Input file source: " << inputFileName << std::endl;
131 }
132 XMLObject xmlInput;
133
134 // Try to get xmlObject from inputfile
135 try
136 {
137 xmlInput = inputSource.getObject();
138 }
139 catch(exception &e)
140 {
141 EXC_ERRMSG("Test Driver error: reading", e); // error reading input
142 return false;
143 }
144
145 // get the parameter lists for each model
146 for(int i = 0; i < xmlInput.numChildren(); i++)
147 {
148 ParameterList plist;
149 xmlToModelPList(xmlInput.getChild(i), plist);
150
151 if(plist.name() == "Comparison") {
152 comparisons.emplace(plist);
153 }
154 else {
155 problems.emplace(plist);
156 }
157 }
158
159 return true;
160}
161
162// Utility function for safe type conversion of adapter
163bool analyzeMetrics(RCP<EvaluateFactory> evaluateFactory,
164 std::ostringstream & msg,
165 const ParameterList &problem_parameters) {
166 #define ANALYZE_METRICS(adapterClass, metricAnalyzerClass) \
167 RCP<EvaluateBaseClass<adapterClass>> pCast = \
168 rcp_dynamic_cast<EvaluateBaseClass<adapterClass>>( \
169 evaluateFactory->getEvaluateClass()); \
170 if(pCast == Teuchos::null) throw std::logic_error( \
171 "Bad evaluate class cast in analyzeMetrics!" ); \
172 metricAnalyzerClass analyzer(pCast); \
173 return analyzer.analyzeMetrics( \
174 problem_parameters.sublist("Metrics"), msg);
175
176 #define ANALYZE_METRICS_PARTITIONING(adapterClass) \
177 ANALYZE_METRICS(adapterClass, \
178 MetricAnalyzerEvaluatePartition<adapterClass>)
179
180 #define ANALYZE_METRICS_ORDERING(adapterClass) \
181 ANALYZE_METRICS(adapterClass, \
182 MetricAnalyzerEvaluateOrdering<adapterClass>)
183
184 if(evaluateFactory->getProblemName() == "partitioning") {
185 Z2_TEST_UPCAST(evaluateFactory->getAdapterType(), ANALYZE_METRICS_PARTITIONING)
186 }
187 else if(evaluateFactory->getProblemName() == "ordering") {
188 Z2_TEST_UPCAST(evaluateFactory->getAdapterType(), ANALYZE_METRICS_ORDERING)
189 }
190 else {
191 throw std::logic_error(
192 "analyzeMetrics not implemented for this problem type!" );
193 }
194}
195
196// Utility function for safe type conversion of adapter
197LocalOrderingSolution<zlno_t> * getLocalOrderingSolution(
198 RCP<ProblemFactory> problemFactory) {
199 #define GET_LOCAL_ORDERING(adapterClass) \
200 return (rcp_dynamic_cast<OrderingProblem<adapterClass>>( \
201 problemFactory->getProblem()))->getLocalOrderingSolution();
202 Z2_TEST_UPCAST(problemFactory->getAdapterType(), GET_LOCAL_ORDERING)
203}
204
205// Utility function for safe type conversion of adapter
206const zpart_t * getPartListView(RCP<ProblemFactory> problemFactory) {
207 #define GET_PROBLEM_PARTS(adapterClass) \
208 return (rcp_dynamic_cast<PartitioningProblem<adapterClass>>( \
209 problemFactory->getProblem()))->getSolution().getPartListView();
210 Z2_TEST_UPCAST(problemFactory->getAdapterType(), GET_PROBLEM_PARTS)
211}
212
213// Utility function for safe type conversion of adapter
214void getIDsView(RCP<AdapterFactory> adapterFactory, const zgno_t *&Ids) {
215 #define GET_IDS_VIEW(adapterClass) \
216 return dynamic_cast<adapterClass*>( \
217 adapterFactory->getMainAdapter())->getIDsView(Ids);
218 Z2_TEST_UPCAST(adapterFactory->getMainAdapterType(), GET_IDS_VIEW);
219 throw std::logic_error( "getIDsView() failed to match adapter name" );
220}
221
222bool run(const UserInputForTests &uinput,
223 const ParameterList &problem_parameters,
224 bool bHasComparisons,
225 RCP<ComparisonHelper> & comparison_helper,
226 const RCP<const Teuchos::Comm<int> > & comm)
227{
228 // Major steps in running a problem in zoltan 2
229 // 1. get an input adapter
230 // 2. construct the problem
231 // 3. solve the problem
232 // 4. analyze metrics
233 // 5. clean up
234
235 int rank = comm->getRank();
236 if(!problem_parameters.isParameter("kind"))
237 {
238 if(rank == 0) {
239 std::cout << "Problem kind not provided" << std::endl;
240 }
241 return false;
242 }
243 if(!problem_parameters.isParameter("InputAdapterParameters"))
244 {
245 if(rank == 0) {
246 std::cout << "Input adapter parameters not provided" << std::endl;
247 }
248 return false;
249 }
250 if(!problem_parameters.isParameter("Zoltan2Parameters"))
251 {
252 if(rank == 0) {
253 std::cout << "Zoltan2 problem parameters not provided" << std::endl;
254 }
255 return false;
256 }
257
258 if(rank == 0) {
259 std::cout << "\n\nRunning test: " << problem_parameters.name() << std::endl;
260 }
261
263 // 0. add comparison source
265 RCP<ComparisonSource> comparison_source = rcp(new ComparisonSource);
266
267 comparison_helper->AddSource(problem_parameters.name(), comparison_source);
268 comparison_source->addTimer("adapter construction time");
269 comparison_source->addTimer("problem construction time");
270 comparison_source->addTimer("solve time");
271
273 // 1. get basic input adapter
275 const ParameterList &adapterPlist =
276 problem_parameters.sublist("InputAdapterParameters");
277 comparison_source->timers["adapter construction time"]->start();
278
279 // a pointer to a basic type
280 RCP<AdapterFactory> adapterFactory = rcp(new AdapterFactory(
281 const_cast<UserInputForTests*>(&uinput), adapterPlist, comm));
282
283 comparison_source->timers["adapter construction time"]->stop();
284
285 comparison_source->adapterFactory = adapterFactory; // saves until done
286
288 // 2. construct a Zoltan2 problem
290 // If we are here we have an input adapter, no need to check for one.
291 string adapter_name = adapterPlist.get<string>("input adapter");
292 // get Zoltan2 Parameters
293 ParameterList zoltan2_parameters =
294 const_cast<ParameterList &>(problem_parameters.sublist("Zoltan2Parameters"));
295 if(rank == 0) {
296 std::cout << std::endl;
297 }
298
299 comparison_source->timers["problem construction time"]->start();
300 std::string problem_kind = problem_parameters.get<std::string>("kind");
301 if (rank == 0) {
302 std::cout << "Creating a new " << problem_kind << " problem." << std::endl;
303 }
304
305 RCP<ProblemFactory> problemFactory = rcp(new ProblemFactory(
306 problem_kind,
307 adapterFactory,
308 &zoltan2_parameters
309 #ifdef HAVE_ZOLTAN2_MPI
310 ,MPI_COMM_WORLD
311 #endif
312 ));
313
314 if(rank == 0) {
315 std::cout << "Using input adapter type: " + adapter_name << std::endl;
316 }
317
318 comparison_source->problemFactory = problemFactory; // saves until done
319
321 // 3. Solve the problem
323 comparison_source->timers["solve time"]->start();
324
325 problemFactory->getProblem()->solve();
326
327 comparison_source->timers["solve time"]->stop();
328 if (rank == 0) {
329 std::cout << problem_kind + " problem solved." << std::endl;
330 }
331
332#undef KDDKDD
333#ifdef KDDKDD
334 if(problem_kind == "partitioning") {
335 const base_adapter_t::gno_t *kddIDs = NULL;
336 getIDsView(adapterFactory, kddIDs);
337 for (size_t i = 0;
338 i < adapterFactory->getMainAdapter()->getLocalNumIDs(); i++) {
339 std::cout << rank << " LID " << i
340 << " GID " << kddIDs[i]
341 << " PART "
342 << getPartListView(problemFactory)[i]
343 << std::endl;
344 }
345 }
346 if (adapter_name == "XpetraCrsGraph") {
347 typedef xCG_xCG_t::lno_t lno_t;
348 typedef xCG_xCG_t::gno_t gno_t;
349 typedef xCG_xCG_t::scalar_t scalar_t;
350 const xCG_xCG_t * xscrsGraphAdapter =
351 dynamic_cast<const xCG_xCG_t *>(adapterFactory->getMainAdapter());
352
353 int ewgtDim = xscrsGraphAdapter->getNumWeightsPerEdge();
354 lno_t localNumObj = xscrsGraphAdapter->getLocalNumVertices();
355 const gno_t *vertexIds;
356 xscrsGraphAdapter->getVertexIDsView(vertexIds);
357 const offset_t *offsets;
358 const gno_t *adjIds;
359 xscrsGraphAdapter->getEdgesView(offsets, adjIds);
360 for (int edim = 0; edim < ewgtDim; edim++) {
361 const scalar_t *weights;
362 int stride=0;
363 xscrsGraphAdapter->getEdgeWeightsView(weights, stride, edim);
364 for (lno_t i=0; i < localNumObj; i++)
365 for (offset_t j=offsets[i]; j < offsets[i+1]; j++)
366 std::cout << edim << " " << vertexIds[i] << " "
367 << adjIds[j] << " " << weights[stride*j] << std::endl;
368 }
369 }
370#endif
371
373 // 4. Print problem metrics
375 bool bSuccess = true;
376 if(problem_parameters.isSublist("Metrics") || bHasComparisons) {
377 RCP<EvaluateFactory> evaluateFactory = rcp(new EvaluateFactory(
378 problem_kind,
379 adapterFactory,
380 &zoltan2_parameters,
381 problemFactory));
382
383 if(rank == 0) {
384 std::cout << "Create evaluate class for: " + problem_kind << std::endl;
385 }
386
387 // must add for proper deletion
388 comparison_source->evaluateFactory = evaluateFactory; // saves until done
389
390 std::ostringstream msgSummary;
391
392 evaluateFactory->getEvaluateClass()->printMetrics(msgSummary);
393 if(rank == 0) {
394 std::cout << msgSummary.str();
395 }
396
397 std::ostringstream msgResults;
398 if (!analyzeMetrics(evaluateFactory, msgResults, problem_parameters)) {
399 bSuccess = false;
400 std::cout << "MetricAnalyzer::analyzeMetrics() "
401 << "returned false and the test is FAILED." << std::endl;
402 }
403 if(rank == 0) {
404 std::cout << msgResults.str();
405 }
406
407//#define BDD
408#ifdef BDD
409 if (problem_kind == "ordering") {
410 std::cout << "\nLet's examine the solution..." << std::endl;
411 LocalOrderingSolution<zlno_t> * localOrderingSolution =
412 getLocalOrderingSolution(problemFactory);
413 if (localOrderingSolution->haveSeparators() ) {
414 std::cout << "Number of column blocks: "
415 << localOrderingSolution->getNumSeparatorBlocks() << std::endl;
416 {
417 if (localOrderingSolution->havePerm()) {
418 std::cout << "permutation: {";
419 for (auto &x : localOrderingSolution->getPermutationRCPConst(false))
420 std::cout << " " << x;
421 std::cout << "}" << std::endl;
422 }
423
424 if (localOrderingSolution->haveInverse()) {
425 std::cout << "inverse permutation: {";
426 for (auto &x : localOrderingSolution->getPermutationRCPConst(true))
427 std::cout << " " << x;
428 std::cout << "}" << std::endl;
429 }
430
431 if (localOrderingSolution->haveSeparatorRange()) {
432 std::cout << "separator range: {";
433 for (auto &x : localOrderingSolution->getSeparatorRangeRCPConst())
434 std::cout << " " << x;
435 std::cout << "}" << std::endl;
436 }
437
438 if (localOrderingSolution->haveSeparatorTree()) {
439 std::cout << "separator tree: {";
440 for (auto &x : localOrderingSolution->getSeparatorTreeRCPConst())
441 std::cout << " " << x;
442 std::cout << "}" << std::endl;
443 }
444 }
445 }
446 }
447#endif
448
449 comparison_source->printTimers();
450
451 // write mesh solution
452 // if(problem_kind == "partitioning") {
453 // auto sol = reinterpret_cast<partitioning_problem_t *>(problem)->getSolution();
454 // MyUtils::writePartionSolution(sol.getPartListView(), ia->getLocalNumIDs(), comm);
455 // }
456 }
457
458 return bSuccess;
459}
460
461bool mainExecute(int narg, char *arg[], RCP<const Comm<int> > &comm)
462{
464 // (0) Set up MPI environment and timer
466 int rank = comm->getRank(); // get rank
467
469 // (1) Get and read the input file
470 // the input file defines tests to be run
472 string inputFileName("");
473 if(narg > 1)
474 inputFileName = arg[1]; // user has provided an input file
475 else{
476 if(rank == 0){
477 std::cout << "\nFAILED to specify xml input file!" << std::endl;
478 std::ostringstream msg;
479 msg << "\nStandard use of test_driver.cpp:\n";
480 msg << "mpiexec -n <procs> ./Zoltan2_test_driver.exe <input_file.xml>\n";
481 std::cout << msg.str() << std::endl;
482 }
483 return false;
484 }
485
487 // (2) Get All Input Parameter Lists
489 queue<ParameterList> problems, comparisons;
490 if( !getParameterLists(inputFileName, problems, comparisons, comm) ) {
491 return false;
492 }
493
495 // (3) Get Input Data Parameters
497
498 // assumes that first block will always be the input block
499 const ParameterList inputParameters = problems.front();
500 if(inputParameters.name() != "InputParameters")
501 {
502 if(rank == 0)
503 std::cout << "InputParameters not defined. Testing FAILED." << std::endl;
504 return false;
505 }
506
507 // get the user input for all tests
508 // UserInputForTests uinput(inputParameters,comm);
509
510 problems.pop();
511 comm->barrier();
512
513 bool bPass = true;
514 if(true)
515 {
517 // (4) Perform all tests
519// pamgen debugging
520// MyUtils::writeMesh(uinput,comm);
521// MyUtils::getConnectivityGraph(uinput, comm);
522
523 RCP<ComparisonHelper> comparison_manager = rcp(new ComparisonHelper);
524 while (!problems.empty()) {
525 UserInputForTests uinput(inputParameters,comm);
526
527 if(uinput.hasInput()) {
528 if (!run(uinput, problems.front(), !comparisons.empty(),
529 comparison_manager, comm)) {
530 std::cout << "Problem run returned false" << std::endl;
531 bPass = false;
532 }
533 }
534 problems.pop();
535 }
536
538 // (5) Compare solutions
540
541 while (!comparisons.empty()) {
542 if (!comparison_manager->Compare(comparisons.front(),comm)) {
543 if (rank == 0) {
544 std::cout << "Comparison manager returned false so the "
545 << "test should fail." << std::endl;
546 }
547 bPass = false;
548 }
549 comparisons.pop();
550 }
551 }
552 else {
553 if(rank == 0) {
554 std::cout << "\nFAILED to load input data source. Skipping "
555 "all tests." << std::endl;
556 return false;
557 }
558 }
559
560 return bPass;
561}
562
563int main(int narg, char *arg[])
564{
565 Tpetra::ScopeGuard tscope(&narg, &arg);
566 Teuchos::RCP<const Teuchos::Comm<int> > comm = Tpetra::getDefaultComm();
567
568 int result = 0;
569 int rank = comm->getRank();
570 try {
571 result = mainExecute(narg, arg, comm) ? 0 : 1; // code 0 is ok,
572 // 1 is a failed test
573 }
574 catch(std::logic_error &e) {
575 // logic_error exceptions can be thrown by EvaluatePartition or
576 // MetricAnalyzer if any problem is detected in the formatting of the
577 // input xml
578 if (rank == 0) {
579 std::cout << "Test driver for rank " << rank
580 << " caught the following exception: " << e.what() << std::endl;
581 }
582 result = 1; // fail for any exception
583 }
584 catch(std::runtime_error &e) {
585 std::cout << "Test driver for rank " << rank
586 << " caught the following exception: " << e.what() << std::endl;
587 result = 1; // fail for any exception
588 }
589 catch(std::exception &e) {
590 std::cout << "Test driver for rank " << rank
591 << " caught the following exception: " << e.what() << std::endl;
592 result = 1; // fail for any exception
593 }
594
595 // clean up - reduce the result codes
596 comm->barrier();
597 int resultReduced;
598
599 // for a passed test all of these values should return 0 -
600 // if any result is 1 this will reduce to 1 and the test will fail
601 reduceAll<int,int>(*comm, Teuchos::EReductionType::REDUCE_MAX, 1,
602 &result, &resultReduced);
603
604 // provide a final message which guarantees that the test will fail
605 // if any of the processes failed
606 if (rank == 0) {
607 std::cout << "Test Driver with " << comm->getSize()
608 << " processes has reduced result code " << resultReduced
609 << " and is exiting in the "
610 << ((resultReduced == 0 ) ? "PASSED" : "FAILED") << " state."
611 << std::endl;
612 }
613
614 return result;
615}
Generate Adapter for testing purposes.
Generate input for testing purposes.
Defines the BasicIdentifierAdapter class.
Store and compare solution sets from different problems.
Returns a pointer to new test classes. Is not responsible for memory management!
Defines Parameter related enumerators, declares functions.
Tpetra::Map ::global_ordinal_type zgno_t
keep typedefs that commonly appear in many places localized
#define Z2_TEST_UPCAST(adptr, TEMPLATE_ACTION)
Defines XpetraCrsGraphAdapter class.
Defines the XpetraCrsMatrixAdapter class.
Defines the XpetraMultiVectorAdapter.
int main()
A class for comparing solutions, metrics, and timing data of Zoltan2 problems.
A class used to save problem solutions and timers.
InputTraits< User >::scalar_t scalar_t
InputTraits< User >::lno_t lno_t
InputTraits< User >::gno_t gno_t
Provides access for Zoltan2 to Xpetra::CrsGraph data.
int getNumWeightsPerEdge() const
Returns the number (0 or greater) of edge weights.
ProblemFactory class contains 1 static factory method.
ProblemFactory class contains 1 static factory method.
map_t::local_ordinal_type lno_t
map_t::global_ordinal_type gno_t
void createAllParameters(Teuchos::ParameterList &pList)
Create a list of all Zoltan2 parameters and validators.
static ArrayRCP< ArrayRCP< zscalar_t > > weights
#define GET_PROBLEM_PARTS(adapterClass)
bool analyzeMetrics(RCP< EvaluateFactory > evaluateFactory, std::ostringstream &msg, const ParameterList &problem_parameters)
const zpart_t * getPartListView(RCP< ProblemFactory > problemFactory)
#define GET_IDS_VIEW(adapterClass)
#define ANALYZE_METRICS_ORDERING(adapterClass)
#define EXC_ERRMSG(msg, e)
LocalOrderingSolution< zlno_t > * getLocalOrderingSolution(RCP< ProblemFactory > problemFactory)
bool getParameterLists(const string &inputFileName, queue< ParameterList > &problems, queue< ParameterList > &comparisons, const RCP< const Teuchos::Comm< int > > &comm)
bool run(const UserInputForTests &uinput, const ParameterList &problem_parameters, bool bHasComparisons, RCP< ComparisonHelper > &comparison_helper, const RCP< const Teuchos::Comm< int > > &comm)
void getIDsView(RCP< AdapterFactory > adapterFactory, const zgno_t *&Ids)
bool mainExecute(int narg, char *arg[], RCP< const Comm< int > > &comm)
void xmlToModelPList(const Teuchos::XMLObject &xml, Teuchos::ParameterList &plist)
#define ANALYZE_METRICS_PARTITIONING(adapterClass)
#define GET_LOCAL_ORDERING(adapterClass)