THYRA_DEPRECATED
void uninitializePrec(
  const PreconditionerFactoryBase<Scalar> &precFactory,
  PreconditionerBase<Scalar> *prec,
  Teuchos::RCP<const LinearOpBase<Scalar> > *fwdOp = NULL,
  ESupportSolveUse *supportSolveUse = NULL
  )
{
  using Teuchos::ptr;
  uninitializePrec<Scalar>(precFactory, ptr(prec), ptr(fwdOp),
    ptr(supportSolveUse));
}
THYRA_DEPRECATED
SolveStatus<Scalar> solve(
  const LinearOpWithSolveBase<Scalar> &A,
  const EOpTransp A_trans,
  const MultiVectorBase<Scalar> &B,
  MultiVectorBase<Scalar> *X,
  const SolveCriteria<Scalar> *solveCriteria = NULL
  )
{
  using Teuchos::ptr;
  return A.solve(A_trans, B, ptr(X), ptr(solveCriteria));
}
THYRA_DEPRECATED
void uninitializeOp(
  const LinearOpWithSolveFactoryBase<Scalar> &lowsFactory,
  LinearOpWithSolveBase<Scalar> *Op,
  RCP<const LinearOpBase<Scalar> > *fwdOp = NULL,
  RCP<const PreconditionerBase<Scalar> > *prec = NULL,
  RCP<const LinearOpBase<Scalar> > *approxFwdOp = NULL,
  ESupportSolveUse *supportSolveUse = NULL
  )
{
  using Teuchos::ptr;
  uninitializeOp<Scalar>(lowsFactory, ptr(Op), ptr(fwdOp), ptr(prec),
    ptr(approxFwdOp), ptr(supportSolveUse));
}
예제 #4
0
int 
main (int argc, char *argv[]) 
{
  using Teuchos::Array;
  using Teuchos::as;
  using Teuchos::Comm;
  using Teuchos::CommandLineProcessor;
  using Teuchos::ParameterList;
  using Teuchos::ptr;
  using Teuchos::RCP;
  using Teuchos::rcp;
  using Teuchos::REDUCE_MAX;
  using Teuchos::REDUCE_MIN;
  using Teuchos::reduceAll;
  using std::cerr;
  using std::cout;
  using std::endl;

  typedef double scalar_type;
  typedef int local_ordinal_type;
  typedef int global_ordinal_type;
  typedef Kokkos::SerialNode node_type;

  Teuchos::GlobalMPISession mpiSession (&argc, &argv, &cout);
  RCP<const Comm<int> > comm = 
    Tpetra::DefaultPlatform::getDefaultPlatform().getComm();
  const int myRank = comm->getRank();
  const int numProcs = comm->getSize();

  std::string inputFilename;  // Matrix Market file to read
  std::string temporaryFilename; // Matrix Market file to write (if applicable)
  std::string outputFilename; // Matrix Market file to write (if applicable)

  // Number of a specific test to run.  If nonzero, only run that
  // test.  We always run Test #1 since its result is needed for
  // subsequent tests.
  int testToRun = 0;

  // FIXME (mfh 07 Feb 2012) Currently, all tests with a different
  // index base FAIL.  Reading in the multivector appears to be
  // correct, but writing it results in a multivector of all zeros (on
  // _all_ processes).
  bool testDifferentIndexBase = false;
  bool testContiguousInputMap = true;
  bool testNoncontiguousInputMap = false; 

  bool testWrite = true; // Test Matrix Market output?
  bool tolerant = false; // Parse the file tolerantly?
  bool echo = false;     // Echo the read-in matrix back?
  bool verbose = false;  // Verbosity of output
  bool debug = false;    // Print debugging info?
  // If true, stop after a single test failure.  Intended for
  // interactive use, so that you can examine a test's output file.
  // Not intended for batch or ctest use.
  bool stopAfterFailure = false; 

  CommandLineProcessor cmdp (false, true);
  cmdp.setOption ("inputFilename", &inputFilename,
		  "Name of the Matrix Market dense matrix file to read.");
  cmdp.setOption ("temporaryFilename", &temporaryFilename,
		  "If --testWrite is true, then use this file as temporary "
		  "storage on (MPI) Proc 0.  Otherwise, this argument is "
		  "ignored.");
  cmdp.setOption ("outputFilename", &outputFilename,
		  "If --testWrite is true, then write the read-in matrix to "
		  "this file in Matrix Market format on (MPI) Proc 0.  "
		  "Otherwise, this argument is ignored.  Note that the output "
		  "file may not be identical to the input file.");
  cmdp.setOption ("testToRun", &testToRun, "Number of a specific test to run.  "
		  "If nonzero, only run that test.  We always run Test #1 since"
		  " its result is needed for subsequent tests.");
  cmdp.setOption ("testDifferentIndexBase", "dontTestDifferentIndexBase",
		  &testDifferentIndexBase, "Whether to test input and output "
		  "for Maps with different index bases.");
  cmdp.setOption ("testContiguousInputMap", "dontTestContiguousInputMap",
		  &testContiguousInputMap,
		  "Whether to test input and output for nonnull contiguous "
		  "input Maps.");
  cmdp.setOption ("testNoncontiguousInputMap", "dontTestNoncontiguousInputMap",
		  &testNoncontiguousInputMap,
		  "Whether to test input and output for nonnull noncontiguous "
		  "input Maps.");
  cmdp.setOption ("testWrite", "noTestWrite", &testWrite,
		  "Whether to test Matrix Market file output.  Ignored if no "
		  "--outputFilename value is given.");
  cmdp.setOption ("tolerant", "strict", &tolerant, 
		  "Whether to parse the input Matrix Market file tolerantly.");
  cmdp.setOption ("echo", "noecho", &echo,
		  "Whether to echo the read-in matrix back to stdout on Rank 0 "
		  "in Matrix Market format.  Note that the echoed matrix may "
		  "not be identical to the input file.");
  cmdp.setOption ("verbose", "quiet", &verbose, "Print messages and results.");
  cmdp.setOption ("debug", "nodebug", &debug, "Print debugging information.");
  cmdp.setOption ("stopAfterFailure", "dontStopAfterFailure", &stopAfterFailure, 
		  "Whether to stop after a single test failure.");

  // Parse the command-line arguments.
  {
    const CommandLineProcessor::EParseCommandLineReturn parseResult = 
      cmdp.parse (argc,argv);
    // If the caller asks us to print the documentation, or does not
    // explicitly say to run the benchmark, we let this "test" pass
    // trivially.
    if (parseResult == CommandLineProcessor::PARSE_HELP_PRINTED) {
      if (myRank == 0) {
	cout << "End Result: TEST PASSED" << endl;
      }
      return EXIT_SUCCESS;
    }
    TEUCHOS_TEST_FOR_EXCEPTION(parseResult != CommandLineProcessor::PARSE_SUCCESSFUL, 
      std::invalid_argument, "Failed to parse command-line arguments.");
  }

  // Get a Kokkos Node instance for the particular Node type.
  RCP<node_type> node = getNode<node_type>();

  // List of numbers of failed tests.
  std::vector<int> failedTests;
  // Current test number.  Increment before starting each test.  If a
  // test is only run conditionally, increment before evaluating the
  // condition.  This ensures that each test has the same number each
  // time, whether or not a particular test is run.
  int testNum = 0;

  // Run all the tests.  If no input filename was specified, we don't
  // invoke the test and we report a "TEST PASSED" message.
  if (inputFilename != "") {
    // Convenient abbreviations
    typedef scalar_type ST;
    typedef local_ordinal_type LO;
    typedef global_ordinal_type GO;
    typedef node_type NT;
    typedef Tpetra::MultiVector<ST, LO, GO, NT> MV;
    typedef Tpetra::Map<LO, GO, NT> MT;

    // If not testing writes, don't do the sanity check that tests
    // input by comparing against output.
    std::string outFilename = testWrite ? outputFilename : "";
    std::string tmpFilename = testWrite ? temporaryFilename : "";

    // Test 1: null input Map.
    ++testNum;
    if (verbose && myRank == 0) {
      cout << "Test " << testNum << ": Null Map on input to readDenseFile()" << endl;
    }
    RCP<MV> X;
    try {
      X = testReadDenseFile<MV> (inputFilename, tmpFilename, comm,
				 node, tolerant, verbose, debug);
      if (outFilename != "") {
	testWriteDenseFile<MV> (outFilename, X, echo, verbose, debug);
      }
    } catch (std::exception& e) {
      failedTests.push_back (testNum);
      // If Test 1 fails, the other tests shouldn't even run, since
      // they depend on the result of Test 1 (the multivector X).
      throw e;
    }

    // Test 2: nonnull contiguous input Map with the same index base
    // as X's Map.  This Map may or may not necessarily be the same as
    // (in the sense of isSameAs()) or even compatible with X's Map.
    ++testNum;
    if ((testToRun == 0 && testContiguousInputMap) || 
	(testToRun != 0 && testToRun == testNum)) {
      if (verbose && myRank == 0) {
	cout << "Test " << testNum << ": Nonnull contiguous Map (same index "
	  "base) on input to readDenseFile()" << endl;
      }
      const Tpetra::global_size_t globalNumRows = X->getMap()->getGlobalNumElements();
      const GO indexBase = X->getMap()->getIndexBase();
      // Create the Map.
      RCP<const MT> map = 
	rcp (new Tpetra::Map<LO, GO, NT> (globalNumRows, indexBase, comm, 
					  Tpetra::GloballyDistributed, node));
      try {
	RCP<MV> X2 = 
	  testReadDenseFileWithInputMap<MV> (inputFilename, tmpFilename,
					     map, tolerant, verbose, debug);
	if (outFilename != "") {
	  testWriteDenseFile<MV> (outFilename, X2, echo, verbose, debug);
	}
      } catch (std::exception& e) {
	failedTests.push_back (testNum);
	if (myRank == 0) {
	  cerr << "Test " << testNum << " failed: " << e.what() << endl;
	}

	if (stopAfterFailure) {
	  if (failedTests.size() > 0) {
	    if (myRank == 0) {
	      cout << "End Result: TEST FAILED" << endl;
	    }
	    return EXIT_FAILURE;
	  }
	  else {
	    if (myRank == 0) {
	      cout << "End Result: TEST PASSED" << endl;
	    }
	    return EXIT_SUCCESS;
	  }
	} // if stop after failure
      }
    }

    // Test 3: nonnull contiguous input Map, with a different index
    // base than X's Map.  In this case, the index base is X's Map's
    // index base plus a small number (3).  For sufficiently long
    // vectors, this tests the case where the GID sets overlap.
    ++testNum;
    if ((testToRun == 0 && testContiguousInputMap && testDifferentIndexBase) || 
	(testToRun != 0 && testToRun == testNum)) {
      if (verbose && myRank == 0) {
	cout << "Test " << testNum << ": Nonnull contiguous Map (different "
	  "index base) on input to readDenseFile()" << endl;
      }
      const Tpetra::global_size_t globalNumRows = X->getMap()->getGlobalNumElements();
      const GO indexBase = X->getMap()->getIndexBase() + as<GO> (3);

      // Make sure that the index base is the same on all processes.
      // It definitely should be, since the Map's getMaxAllGlobalIndex()
      // method should return the same value on all processes.
      GO minIndexBase = indexBase;
      reduceAll (*comm, REDUCE_MIN, indexBase, ptr (&minIndexBase));
      GO maxIndexBase = indexBase;
      reduceAll (*comm, REDUCE_MAX, indexBase, ptr (&maxIndexBase));
      TEUCHOS_TEST_FOR_EXCEPTION(minIndexBase != maxIndexBase || minIndexBase != indexBase,
        std::logic_error, "Index base values do not match on all processes.  "
        "Min value is " << minIndexBase << " and max value is " << maxIndexBase 
        << ".");

      // Create the Map.
      RCP<const MT> map = 
	rcp (new Tpetra::Map<LO, GO, NT> (globalNumRows, indexBase, comm, 
					  Tpetra::GloballyDistributed, node));
      try {
	RCP<MV> X3 = 
	  testReadDenseFileWithInputMap<MV> (inputFilename, tmpFilename,
					     map, tolerant, verbose, debug);
	if (outFilename != "") {
	  testWriteDenseFile<MV> (outFilename, X3, echo, verbose, debug);
	}
      } catch (std::exception& e) {
	failedTests.push_back (testNum);
	if (myRank == 0) {
	  cerr << "Test " << testNum << " failed: " << e.what() << endl;
	}

	if (stopAfterFailure) {
	  if (failedTests.size() > 0) {
	    if (myRank == 0) {
	      cout << "End Result: TEST FAILED" << endl;
	    }
	    return EXIT_FAILURE;
	  }
	  else {
	    if (myRank == 0) {
	      cout << "End Result: TEST PASSED" << endl;
	    }
	    return EXIT_SUCCESS;
	  }
	} // if stop after failure
      }
    }

    // Test 4: nonnull contiguous input Map, with a different index
    // base than X's Map.  In this case, the new index base is chosen
    // so that the new GID set does not overlap with X's Map's GID
    // set.
    ++testNum;
    if ((testToRun == 0 && testContiguousInputMap && testDifferentIndexBase) || 
	(testToRun != 0 && testToRun == testNum)) {
      if (verbose && myRank == 0) {
	cout << "Test " << testNum << ": Nonnull contiguous Map (different "
	  "index base) on input to readDenseFile()" << endl;
      }
      const Tpetra::global_size_t globalNumRows = X->getMap()->getGlobalNumElements();
      // Choose the Map's index base so that the global ordinal sets
      // of X->getMap() and map don't overlap.  This will ensure that
      // we test something nontrivial.
      const GO indexBase = X->getMap()->getMaxAllGlobalIndex() + 1;

      // Make sure that the index base is the same on all processes.
      // It definitely should be, since the Map's getMaxAllGlobalIndex()
      // method should return the same value on all processes.
      GO minIndexBase = indexBase;
      reduceAll (*comm, REDUCE_MIN, indexBase, ptr (&minIndexBase));
      GO maxIndexBase = indexBase;
      reduceAll (*comm, REDUCE_MAX, indexBase, ptr (&maxIndexBase));
      TEUCHOS_TEST_FOR_EXCEPTION(minIndexBase != maxIndexBase || minIndexBase != indexBase,
        std::logic_error, "Index base values do not match on all processes.  "
        "Min value is " << minIndexBase << " and max value is " << maxIndexBase 
        << ".");

      // Create the Map.
      RCP<const MT> map = 
	rcp (new Tpetra::Map<LO, GO, NT> (globalNumRows, indexBase, comm, 
					  Tpetra::GloballyDistributed, node));
      try {
	RCP<MV> X3 = 
	  testReadDenseFileWithInputMap<MV> (inputFilename, tmpFilename,
					     map, tolerant, verbose, debug);
	if (outFilename != "") {
	  testWriteDenseFile<MV> (outFilename, X3, echo, verbose, debug);
	}
      } catch (std::exception& e) {
	failedTests.push_back (testNum);
	if (myRank == 0) {
	  cerr << "Test " << testNum << " failed: " << e.what() << endl;
	}

	if (stopAfterFailure) {
	  if (failedTests.size() > 0) {
	    if (myRank == 0) {
	      cout << "End Result: TEST FAILED" << endl;
	    }
	    return EXIT_FAILURE;
	  }
	  else {
	    if (myRank == 0) {
	      cout << "End Result: TEST PASSED" << endl;
	    }
	    return EXIT_SUCCESS;
	  }
	} // if stop after failure
      }
    }

    ++testNum;
    if ((testToRun == 0 && testNoncontiguousInputMap) || 
	(testToRun != 0 && testToRun == testNum)) {
      // Test 5: nonnull input Map with the same index base as X's
      // Map, and a "noncontiguous" distribution (in the sense that
      // the Map is constructed using the constructor that takes an
      // arbitrary list of GIDs; that doesn't necessarily mean that
      // the GIDs themselves are noncontiguous).
      if (verbose && myRank == 0) {
	cout << "Test " << testNum << ": Nonnull noncontiguous Map (same index "
	  "base) on input to readDenseFile()" << endl;
      }
      const GO indexBase = X->getMap()->getIndexBase();
      const Tpetra::global_size_t globalNumRows = X->getMap()->getGlobalNumElements();

      // Compute number of GIDs owned by each process.  We're
      // replicating Tpetra functionality here because we want to
      // trick Tpetra into thinking we have a noncontiguous
      // distribution.  This is the most general case and the most
      // likely to uncover bugs.
      const size_t quotient = globalNumRows / numProcs;
      const size_t remainder = globalNumRows - quotient * numProcs;
      const size_t localNumRows = (as<size_t> (myRank) < remainder) ? 
	(quotient + 1) : quotient;

      // Build the list of GIDs owned by this process.
      Array<GO> elementList (localNumRows);
      GO myStartGID;
      if (as<size_t> (myRank) < remainder) {
	myStartGID = indexBase + as<GO> (myRank) * as<GO> (quotient + 1);
      } 
      else {
	// This branch does _not_ assume that GO is a signed type.
	myStartGID = indexBase + as<GO> (remainder) * as<GO> (quotient + 1) +
	  (as<GO> (myRank) - as<GO> (remainder)) * as<GO> (quotient);
      }
      for (GO i = 0; i < as<GO> (localNumRows); ++i) {
	elementList[i] = myStartGID + i;
      }

      if (debug) {
	for (int p = 0; p < numProcs; ++p) {
	  if (p == myRank) {
	    if (elementList.size() > 0) {
	      const GO minGID = *std::min_element (elementList.begin(), elementList.end());
	      const GO maxGID = *std::max_element (elementList.begin(), elementList.end());
	      cerr << "On Proc " << p << ": min,max GID = " << minGID << "," << maxGID << endl;
	    }
	    else {
	      cerr << "On Proc " << p << ": elementList is empty" << endl;
	    }
	    cerr << std::flush;
	  } 
	  comm->barrier ();
	  comm->barrier ();
	  comm->barrier ();
	}
      }

      // Create the Map.
      using Tpetra::createNonContigMapWithNode;
      RCP<const MT> map = 
	createNonContigMapWithNode<LO, GO, NT> (elementList(), comm, node);
      try {
	RCP<MV> X4 = testReadDenseFileWithInputMap<MV> (inputFilename, tmpFilename,
							map, tolerant, verbose, debug);
	if (outFilename != "") {
	  testWriteDenseFile<MV> (outFilename, X4, echo, verbose, debug);
	}
      } catch (std::exception& e) {
	failedTests.push_back (testNum);
	if (myRank == 0) {
	  cerr << "Test " << testNum << " failed: " << e.what() << endl;
	}

	if (stopAfterFailure) {
	  if (failedTests.size() > 0) {
	    if (myRank == 0) {
	      cout << "End Result: TEST FAILED" << endl;
	    }
	    return EXIT_FAILURE;
	  }
	  else {
	    if (myRank == 0) {
	      cout << "End Result: TEST PASSED" << endl;
	    }
	    return EXIT_SUCCESS;
	  }
	} // if stop after failure
      }
    } // if test noncontiguous input Map

    ++testNum;
    if ((testToRun == 0 && testNoncontiguousInputMap && testDifferentIndexBase) ||
	(testToRun != 0 && testToRun == testNum)) {
      // Test 6: nonnull input Map with a different index base than
      // X's Map, and a "noncontiguous" distribution (in the sense
      // that the Map is constructed using the constructor that takes
      // an arbitrary list of GIDs; that doesn't necessarily mean that
      // the GIDs themselves are noncontiguous).
      if (verbose && myRank == 0) {
	cout << "Test " << testNum << ": Nonnull noncontiguous Map (different "
	  "index base) on input to readDenseFile()" << endl;
      }
      // Make sure that the global ordinal sets of X->getMap() and
      // map don't overlap.
      GO indexBase = X->getMap()->getMaxAllGlobalIndex() + 1;
      const Tpetra::global_size_t globalNumRows = X->getMap()->getGlobalNumElements();

      // Compute number of GIDs owned by each process.  We're
      // replicating Tpetra functionality here because we want to
      // trick Tpetra into thinking we have a noncontiguous
      // distribution.  This is the most general case and the most
      // likely to uncover bugs.
      const size_t quotient = globalNumRows / numProcs;
      const size_t remainder = globalNumRows - quotient * numProcs;
      const size_t localNumRows = (as<size_t> (myRank) < remainder) ? 
	(quotient + 1) : quotient;

      // Build the list of GIDs owned by this process.
      Array<GO> elementList (localNumRows);
      GO myStartGID;
      if (as<size_t> (myRank) < remainder) {
	myStartGID = indexBase + as<GO> (myRank) * as<GO> (quotient + 1);
      } 
      else {
	// This branch does _not_ assume that GO is a signed type.
	myStartGID = indexBase + as<GO> (remainder) * as<GO> (quotient + 1) +
	  (as<GO> (remainder) - as<GO> (myRank)) * as<GO> (quotient);
      }
      for (GO i = 0; i < as<GO> (localNumRows); ++i) {
	elementList[i] = myStartGID + i;
      }

      // Create the Map.
      using Tpetra::createNonContigMapWithNode;
      RCP<const MT> map = 
	createNonContigMapWithNode<LO, GO, NT> (elementList(), comm, node);
      try {
	RCP<MV> X5 = testReadDenseFileWithInputMap<MV> (inputFilename, tmpFilename,
							map, tolerant, verbose, debug);
	if (outFilename != "") {
	  testWriteDenseFile<MV> (outFilename, X5, echo, verbose, debug);
	}
      } catch (std::exception& e) {
	failedTests.push_back (testNum);
	if (myRank == 0) {
	  cerr << "Test " << testNum << " failed: " << e.what() << endl;
	}

	if (stopAfterFailure) {
	  if (failedTests.size() > 0) {
	    if (myRank == 0) {
	      cout << "End Result: TEST FAILED" << endl;
	    }
	    return EXIT_FAILURE;
	  }
	  else {
	    if (myRank == 0) {
	      cout << "End Result: TEST PASSED" << endl;
	    }
	    return EXIT_SUCCESS;
	  }
	} // if stop after failure
      }
    } // if test noncontiguous input Map

    ++testNum;
    if ((testToRun == 0 && testNoncontiguousInputMap) || 
	(testToRun != 0 && testToRun == testNum)) {
      // Test 7: nonnull input Map with the same index base as X's
      // Map, and a "noncontiguous" distribution with GIDs that start
      // at 3.  This lets us easily observe any missing entries after
      // writing X and reading it back in again.
      if (verbose && myRank == 0) {
	cout << "Test " << testNum << ": Nonnull noncontiguous Map (same index "
	  "base, GIDs not in 0 .. N-1) on input to readDenseFile()" << endl;
      }
      const Tpetra::global_size_t globalNumRows = X->getMap()->getGlobalNumElements();
      const GO globalStartGID = as<GO> (3);

      // Compute number of GIDs owned by each process.  We're
      // replicating Tpetra functionality here because we want to
      // trick Tpetra into thinking we have a noncontiguous
      // distribution.  This is the most general case and the most
      // likely to uncover bugs.
      const size_t quotient = globalNumRows / numProcs;
      const size_t remainder = globalNumRows - quotient * numProcs;
      const size_t localNumRows = (as<size_t> (myRank) < remainder) ? 
	(quotient + 1) : quotient;

      // Build the list of GIDs owned by this process.
      Array<GO> elementList (localNumRows);
      GO myStartGID;
      if (as<size_t> (myRank) < remainder) {
	myStartGID = globalStartGID + as<GO> (myRank) * as<GO> (quotient + 1);
      } 
      else {
	// This branch does _not_ assume that GO is a signed type.
	myStartGID = globalStartGID + as<GO> (remainder) * as<GO> (quotient + 1) +
	  (as<GO> (myRank) - as<GO> (remainder)) * as<GO> (quotient);
      }
      for (GO i = 0; i < as<GO> (localNumRows); ++i) {
	elementList[i] = myStartGID + i;
      }

      if (debug) {
	for (int p = 0; p < numProcs; ++p) {
	  if (p == myRank) {
	    if (elementList.size() > 0) {
	      const GO minGID = *std::min_element (elementList.begin(), elementList.end());
	      const GO maxGID = *std::max_element (elementList.begin(), elementList.end());
	      cerr << "On Proc " << p << ": min,max GID = " << minGID << "," << maxGID << endl;
	    }
	    else {
	      cerr << "On Proc " << p << ": elementList is empty" << endl;
	    }
	    cerr << std::flush;
	  } 
	  comm->barrier ();
	  comm->barrier ();
	  comm->barrier ();
	}
      }

      // Create the Map.
      using Tpetra::createNonContigMapWithNode;
      RCP<const MT> map = 
	createNonContigMapWithNode<LO, GO, NT> (elementList(), comm, node);
      try {
	RCP<MV> X7 = testReadDenseFileWithInputMap<MV> (inputFilename, tmpFilename,
							map, tolerant, verbose, debug);
	if (outFilename != "") {
	  testWriteDenseFile<MV> (outFilename, X7, echo, verbose, debug);
	}
      } catch (std::exception& e) {
	failedTests.push_back (testNum);
	if (myRank == 0) {
	  cerr << "Test " << testNum << " failed: " << e.what() << endl;
	}

	if (stopAfterFailure) {
	  if (failedTests.size() > 0) {
	    if (myRank == 0) {
	      cout << "End Result: TEST FAILED" << endl;
	    }
	    return EXIT_FAILURE;
	  }
	  else {
	    if (myRank == 0) {
	      cout << "End Result: TEST PASSED" << endl;
	    }
	    return EXIT_SUCCESS;
	  }
	} // if stop after failure
      }
    } // if test noncontiguous input Map
  }

  if (failedTests.size() > 0) {
    if (myRank == 0) {
      cout << "End Result: TEST FAILED" << endl;
    }
    return EXIT_FAILURE;
  }
  else {
    if (myRank == 0) {
      cout << "End Result: TEST PASSED" << endl;
    }
    return EXIT_SUCCESS;
  }
}