Tpetra Matrix/Vector Services  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
lesson05_redistribution.cpp
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //          Tpetra: Templated Linear Algebra Services Package
00005 //                 Copyright (2008) Sandia Corporation
00006 //
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ************************************************************************
00040 // @HEADER
00041 
00049 #include <Teuchos_GlobalMPISession.hpp>
00050 #include <Teuchos_oblackholestream.hpp>
00051 #include <Teuchos_TimeMonitor.hpp>
00052 #include <Tpetra_CrsMatrix.hpp>
00053 #include <Tpetra_DefaultPlatform.hpp>
00054 #include <Tpetra_Version.hpp>
00055 #include <iostream>
00056 
00057 
00058 template<class TpetraMatrixType>
00059 class MatrixFactory {
00060 public:
00061   // Fetch typedefs from the Tpetra::CrsMatrix.
00062   typedef typename TpetraMatrixType::scalar_type scalar_type;
00063   typedef typename TpetraMatrixType::local_ordinal_type local_ordinal_type;
00064   typedef typename TpetraMatrixType::global_ordinal_type global_ordinal_type;
00065   typedef typename TpetraMatrixType::node_type node_type;
00066 
00067   // The type of Map objects to use.
00068   typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
00069 
00070   // Create and return a simple example CrsMatrix, with row
00071   // distribution over the given Map.
00072   Teuchos::RCP<const TpetraMatrixType>
00073   create (const Teuchos::RCP<const map_type>& map) const
00074   {
00075     using Teuchos::arcp;
00076     using Teuchos::ArrayRCP;
00077     using Teuchos::ArrayView;
00078     using Teuchos::RCP;
00079     using Teuchos::rcp;
00080     using Teuchos::Time;
00081     using Teuchos::TimeMonitor;
00082     using Teuchos::tuple;
00083     typedef Tpetra::global_size_t GST;
00084 
00085     // Create a timer for sparse matrix creation.
00086     RCP<Time> timer = TimeMonitor::getNewCounter ("Sparse matrix creation");
00087 
00088     // Time the whole scope of this routine, not counting timer lookup.
00089     TimeMonitor monitor (*timer);
00090 
00091     // Create a Tpetra::Matrix using the Map, with dynamic allocation.
00092     RCP<TpetraMatrixType> A = rcp (new TpetraMatrixType (map, 3));
00093 
00094     // Add rows one at a time.  Off diagonal values will always be -1.
00095     const scalar_type two    = static_cast<scalar_type>( 2.0);
00096     const scalar_type negOne = static_cast<scalar_type>(-1.0);
00097 
00098     const GST numGlobalElements = map->getGlobalNumElements ();
00099     //    const size_t numMyElements = map->getNodeNumElements ();
00100 
00101     // The list of global elements owned by this MPI process.
00102     ArrayView<const global_ordinal_type> myGlobalElements =
00103       map->getNodeElementList ();
00104 
00105     typedef typename ArrayView<const global_ordinal_type>::const_iterator iter_type;
00106     for (iter_type it = myGlobalElements.begin(); it != myGlobalElements.end(); ++it) {
00107       const local_ordinal_type i_local = *it;
00108       const global_ordinal_type i_global = map->getGlobalElement (i_local);
00109 
00110       // Can't insert local indices without a column map, so we insert
00111       // global indices here.
00112       if (i_global == 0) {
00113         A->insertGlobalValues (i_global,
00114                               tuple (i_global, i_global+1),
00115                               tuple (two, negOne));
00116       } else if (static_cast<GST> (i_global) == numGlobalElements - 1) {
00117         A->insertGlobalValues (i_global,
00118                               tuple (i_global-1, i_global),
00119                               tuple (negOne, two));
00120       } else {
00121         A->insertGlobalValues (i_global,
00122                               tuple (i_global-1, i_global, i_global+1),
00123                               tuple (negOne, two, negOne));
00124       }
00125     }
00126 
00127     // Finish up the matrix.
00128     A->fillComplete ();
00129     return A;
00130   }
00131 };
00132 
00133 
00134 template<class NodeType>
00135 void
00136 example (const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
00137          const Teuchos::RCP<NodeType>& node,
00138          std::ostream& out,
00139          std::ostream& err)
00140 {
00141   using std::endl;
00142   using Teuchos::ParameterList;
00143   using Teuchos::RCP;
00144   using Teuchos::rcp;
00145   using Teuchos::Time;
00146   using Teuchos::TimeMonitor;
00147   typedef Tpetra::global_size_t GST;
00148 
00149   // Print out the Tpetra software version information.
00150   out << Tpetra::version() << endl << endl;
00151 
00152   // Set up Tpetra typedefs.
00153   typedef double scalar_type;
00154   typedef int local_ordinal_type;
00155   typedef long global_ordinal_type;
00156   typedef NodeType node_type;
00157   typedef Tpetra::CrsMatrix<scalar_type, local_ordinal_type,
00158                             global_ordinal_type, node_type> matrix_type;
00159 
00160   // The type of the Tpetra::Map that describes how the matrix is distributed.
00161   typedef Tpetra::Map<local_ordinal_type, global_ordinal_type, node_type> map_type;
00162 
00163   // The global number of rows in the matrix A to create.  We scale
00164   // this relative to the number of (MPI) processes, so that no matter
00165   // how many MPI processes you run, every process will have 10 rows.
00166   const GST numGlobalElements = 10 * comm->getSize ();
00167 
00168   const global_ordinal_type indexBase = 0;
00169 
00170   // Construct a Map that is global (not locally replicated), but puts
00171   // all the equations on MPI Proc 0.
00172   RCP<const map_type> procZeroMap;
00173   {
00174     const size_t numLocalElements =
00175       (comm->getRank() == 0) ? numGlobalElements : 0;
00176     procZeroMap = rcp (new map_type (numGlobalElements, numLocalElements,
00177                                      indexBase, comm, node));
00178   }
00179 
00180   // Construct a Map that puts approximately the same number of
00181   // equations on each processor.
00182   RCP<const map_type> globalMap =
00183     rcp (new map_type (numGlobalElements, indexBase, comm,
00184                        Tpetra::GloballyDistributed, node));
00185 
00186   // Create a sparse matrix using procZeroMap.
00187   RCP<const matrix_type> A = MatrixFactory<matrix_type> ().create (procZeroMap);
00188 
00189   //
00190   // We've created a sparse matrix that lives entirely on MPI Proc 0.
00191   // Now we want to distribute it over all the processes.
00192   //
00193 
00194   // Make a timer for sparse matrix redistribution.
00195   RCP<Time> exportTimer =
00196     TimeMonitor::getNewCounter ("Sparse matrix redistribution");
00197 
00198   // Redistribute the matrix.  Since both the source and target Maps
00199   // are one-to-one, we could use either an Import or an Export.  If
00200   // only the source Map were one-to-one, we would have to use an
00201   // Import; if only the target Map were one-to-one, we would have to
00202   // use an Export.  We do not allow redistribution using Import or
00203   // Export if neither source nor target Map is one-to-one.
00204   RCP<matrix_type> B;
00205   {
00206     TimeMonitor monitor (*exportTimer); // Time the redistribution
00207 
00208     // Make an export object with procZeroMap as the source Map, and
00209     // globalMap as the target Map.  The Export type has the same
00210     // template parameters as a Map.  Note that Export does not depend
00211     // on the Scalar template parameter of the objects it
00212     // redistributes.  You can reuse the same Export for different
00213     // Tpetra object types, or for Tpetra objects of the same type but
00214     // different Scalar template parameters (e.g., Scalar=float or
00215     // Scalar=double).
00216     typedef Tpetra::Export<local_ordinal_type, global_ordinal_type,
00217                            node_type> export_type;
00218     export_type exporter (procZeroMap, globalMap);
00219 
00220     // Make a new sparse matrix whose row map is the global Map.
00221     B = rcp (new matrix_type (globalMap, 0));
00222 
00223     // Redistribute the data, NOT in place, from matrix A (which lives
00224     // entirely on Proc 0) to matrix B (which is distributed evenly over
00225     // the processes).
00226     B->doExport (*A, exporter, Tpetra::INSERT);
00227   }
00228 
00229   // We time redistribution of B separately from fillComplete().
00230   B->fillComplete ();
00231 }
00232 
00233 
00234 int
00235 main (int argc, char *argv[])
00236 {
00237   using std::endl;
00238   using Teuchos::RCP;
00239   using Teuchos::Time;
00240   using Teuchos::TimeMonitor;
00241 
00242   Teuchos::oblackholestream blackHole;
00243   Teuchos::GlobalMPISession mpiSession (&argc, &argv, &blackHole);
00244   RCP<const Teuchos::Comm<int> > comm =
00245     Tpetra::DefaultPlatform::getDefaultPlatform().getComm();
00246 
00247   typedef Kokkos::DefaultNode::DefaultNodeType node_type;
00248   RCP<node_type> node = Kokkos::DefaultNode::getDefaultNode ();
00249 
00250   const int myRank = comm->getRank();
00251   //const int numProcs = comm->getSize();
00252   std::ostream& out = (myRank == 0) ? std::cout : blackHole;
00253   std::ostream& err = (myRank == 0) ? std::cerr : blackHole;
00254 
00255   // Make a timer for sparse matrix redistribution.
00256   //
00257   // If you are using Trilinos 10.6 instead of the development branch
00258   // (10.7), just delete this line of code, and make the other change
00259   // mentioned above.
00260   RCP<Time >exportTimer =
00261     TimeMonitor::getNewCounter ("Sparse matrix redistribution");
00262 
00263   // Run the whole example: create the sparse matrix, and compute the preconditioner.
00264   example (comm, node, out, err);
00265 
00266   // Summarize global performance timing results, for all timers
00267   // created using TimeMonitor::getNewCounter().
00268   TimeMonitor::summarize (out);
00269 
00270   // This tells the Trilinos test framework that the test passed.
00271   if (myRank == 0) {
00272     std::cout << "End Result: TEST PASSED" << std::endl;
00273   }
00274 
00275   return 0;
00276 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines