Tpetra Matrix/Vector Services  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
Tpetra_Core.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 
00042 #include <Tpetra_Core.hpp>
00043 #ifdef HAVE_TPETRA_MPI
00044 #  include <Teuchos_DefaultMpiComm.hpp>// this includes mpi.h too
00045 #else
00046 #  include <Teuchos_DefaultSerialComm.hpp>
00047 #endif // HAVE_TPETRA_MPI
00048 #ifdef TPETRA_HAVE_KOKKOS_REFACTOR
00049 #  include <Kokkos_Core.hpp>
00050 #endif // TPETRA_HAVE_KOKKOS_REFACTOR
00051 
00052 namespace Tpetra {
00053   namespace { // (anonymous)
00054     // Whether one of the Tpetra::initialize() functions has been called before.
00055     bool tpetraIsInitialized_ = false;
00056 
00057     // Tpetra's default communicator, wrapped in a Teuchos wrapper.
00058     // After Tpetra::finalize() is called, this GOES AWAY (is set to null).
00059     Teuchos::RCP<const Teuchos::Comm<int> > wrappedDefaultComm_;
00060 
00061 #ifdef HAVE_TPETRA_MPI
00062     // Initialize MPI, if needed, and check for errors.
00063     void initMpi (int* argc, char*** argv)
00064     {
00065       int isInitialized = 0;
00066       int err = MPI_Initialized (&isInitialized);
00067 
00068       TEUCHOS_TEST_FOR_EXCEPTION(
00069         err != MPI_SUCCESS, std::runtime_error, "MPI_Initialized failed with "
00070         "error code " << err << " != MPI_SUCCESS.  This probably indicates "
00071         "that your MPI library is corrupted or that it is incorrectly linked "
00072         "to your program, since this function should otherwise always "
00073         "succeed.");
00074 
00075       if (isInitialized == 0) { // MPI not yet initialized
00076         // Tpetra doesn't currently need to call MPI_Init_thread, since
00077         // with Tpetra, only one thread ever calls MPI functions.  If we
00078         // ever want to explore MPI_THREAD_MULTIPLE, here would be the
00079         // place to call MPI_Init_thread.
00080         err = MPI_Init (argc, argv);
00081       }
00082 
00083       TEUCHOS_TEST_FOR_EXCEPTION(
00084         err != MPI_SUCCESS, std::runtime_error, "MPI_Init failed with error "
00085         "code " << err << " != MPI_SUCCESS.  If MPI was set up correctly, this "
00086         "should not happen, since we have already checked that MPI_Init (or "
00087         "MPI_Init_thread) has not yet been called.  This may indicate that "
00088         "your MPI library is corrupted or that it is incorrectly linked to "
00089         "your program.");
00090     }
00091 #endif // HAVE_TPETRA_MPI
00092 
00093   } // namespace (anonymous)
00094 
00095   bool isInitialized () {
00096     return tpetraIsInitialized_;
00097   }
00098 
00099   Teuchos::RCP<const Teuchos::Comm<int> > getDefaultComm ()
00100   {
00101     TEUCHOS_TEST_FOR_EXCEPTION(
00102       tpetraIsInitialized_, std::runtime_error, "Tpetra::getDefaultComm: "
00103       "You must call Tpetra::initialize before you may get a default "
00104       "communicator.");
00105     TEUCHOS_TEST_FOR_EXCEPTION(
00106       wrappedDefaultComm_.is_null (), std::logic_error,
00107       "Tpetra::getDefaultComm: wrappedDefaultComm_ is null!  "
00108       "This should never happen, because Tpetra claims that it has been "
00109       "initialized.  Please report this bug to the Tpetra developers.");
00110     return wrappedDefaultComm_;
00111   }
00112 
00113 
00114   void initialize (int* argc, char*** argv)
00115   {
00116 #ifdef HAVE_TPETRA_MPI
00117     initMpi (argc, argv);
00118 #endif // HAVE_TPETRA_MPI
00119 
00120     if (! tpetraIsInitialized_) {
00121 #ifdef TPETRA_HAVE_KOKKOS_REFACTOR
00122       // Unlike MPI_Init, Kokkos promises not to modify argc and argv.
00123       Kokkos::initialize (*argc, *argv);
00124 #endif // TPETRA_HAVE_KOKKOS_REFACTOR
00125 
00126 #ifdef HAVE_TPETRA_MPI
00127       wrappedDefaultComm_ =
00128         Teuchos::rcp (new Teuchos::MpiComm<int> (MPI_COMM_WORLD));
00129 #else
00130       wrappedDefaultComm_ = Teuchos::rcp (new Teuchos::SerialComm<int> ());
00131 #endif // HAVE_TPETRA_MPI
00132       tpetraIsInitialized_ = true;
00133     }
00134   }
00135 
00136 
00137 #ifdef HAVE_TPETRA_MPI
00138   void initialize (int* argc, char*** argv, MPI_Comm comm)
00139   {
00140 #ifdef HAVE_TPETRA_MPI
00141     initMpi (argc, argv);
00142 #endif // HAVE_TPETRA_MPI
00143 
00144     // Set the default communicator.  What if users have already
00145     // called initialize() before, but with a different default
00146     // communicator?  There are two possible things we could do here:
00147     //
00148     //   1. Test via MPI_Comm_compare whether comm differs from the
00149     //      raw MPI communicator in wrappedDefaultComm_ (if indeed it
00150     //      is an MpiComm).
00151     //   2. Accept that the user might want to change the default
00152     //      communicator, and let them do it.
00153     //
00154     // I prefer #2.  Perhaps it would be sensible to print a warning
00155     // here, but on which process?  Would we use the old or the new
00156     // communicator to find that process' rank?  We don't want to
00157     // use MPI_COMM_WORLD's Process 0, since neither communicator
00158     // might include that process.  Furthermore, in some
00159     // environments, only Process 0 in MPI_COMM_WORLD is allowed to
00160     // do I/O.  Thus, we just let the change go without a warning.
00161     wrappedDefaultComm_ = Teuchos::rcp (new Teuchos::MpiComm<int> (comm));
00162 
00163     if (! tpetraIsInitialized_) {
00164 #ifdef TPETRA_HAVE_KOKKOS_REFACTOR
00165       // Unlike MPI_Init, Kokkos promises not to modify argc and argv.
00166       Kokkos::initialize (*argc, *argv);
00167 #endif // TPETRA_HAVE_KOKKOS_REFACTOR
00168       tpetraIsInitialized_ = true;
00169     }
00170   }
00171 #endif // HAVE_TPETRA_MPI
00172 
00173 
00174   void
00175   initialize (int* argc, char*** argv,
00176               const Teuchos::RCP<const Teuchos::Comm<int> >& comm)
00177   {
00178 #ifdef HAVE_TPETRA_MPI
00179     initMpi (argc, argv);
00180 #endif // HAVE_TPETRA_MPI
00181 
00182     // Set the default communicator.  What if users have already
00183     // called initialize() before, but with a different default
00184     // communicator?  There are two possible things we could do here:
00185     //
00186     //   1. Test via MPI_Comm_compare whether comm differs from the
00187     //      raw MPI communicator in wrappedDefaultComm_ (if indeed it
00188     //      is an MpiComm).
00189     //   2. Accept that the user might want to change the default
00190     //      communicator, and let them do it.
00191     //
00192     // I prefer #2.  Perhaps it would be sensible to print a warning
00193     // here, but on which process?  Would we use the old or the new
00194     // communicator to find that process' rank?  We don't want to
00195     // use MPI_COMM_WORLD's Process 0, since neither communicator
00196     // might include that process.  Furthermore, in some
00197     // environments, only Process 0 in MPI_COMM_WORLD is allowed to
00198     // do I/O.  Thus, we just let the change go without a warning.
00199     wrappedDefaultComm_ = comm;
00200 
00201     if (! tpetraIsInitialized_) {
00202 #ifdef TPETRA_HAVE_KOKKOS_REFACTOR
00203       // Unlike MPI_Init, Kokkos promises not to modify argc and argv.
00204       Kokkos::initialize (*argc, *argv);
00205 #endif // TPETRA_HAVE_KOKKOS_REFACTOR
00206       tpetraIsInitialized_ = true;
00207     }
00208   }
00209 
00210 
00211   void finalize ()
00212   {
00213     using std::cerr;
00214     using std::endl;
00215 
00216     if (! tpetraIsInitialized_) {
00217       // If the user didn't call initialize(), then we shouldn't call
00218       // MPI_Finalize() or otherwise shut anything else off.  For
00219       // example, the user might want to use Kokkos without Tpetra, so
00220       // they might have called Kokkos::initialize() without calling
00221       // Tpetra::initialize().  In that case, we shouldn't call
00222       // Kokkos::initialize() here.
00223       return;
00224     }
00225 
00226 #ifdef TPETRA_HAVE_KOKKOS_REFACTOR
00227     Kokkos::finalize ();
00228 #endif // TPETRA_HAVE_KOKKOS_REFACTOR
00229 
00230     // Make sure that no outstanding references to the communicator
00231     // remain.  If users gave initialize() an MPI_Comm, _they_ are
00232     // responsible for freeing it before calling finalize().
00233     wrappedDefaultComm_ = Teuchos::null;
00234 
00235 #ifdef HAVE_TPETRA_MPI
00236     int isInitialized = 0;
00237     int err = MPI_Initialized (&isInitialized);
00238 
00239     // finalize() is a kind of destructor, so it's a bad idea to throw
00240     // an exception.  Instead, just print out an error message and
00241     // hope for the best.
00242     if (err != MPI_SUCCESS) {
00243       cerr << "MPI_Initialized failed with error code " << err << " != "
00244         "MPI_SUCCESS.  This probably indicates that your MPI library is "
00245         "corrupted or that it is incorrectly linked to your program, since "
00246         "this function should otherwise always succeed." << endl;
00247     }
00248     else if (isInitialized != 0) {
00249       // This must be called by the same thread that called MPI_Init
00250       // (possibly, but not necessarily, in Tpetra::initialize()).
00251       err = MPI_Finalize ();
00252 
00253       // finalize() is a kind of destructor, so it's a bad idea to
00254       // throw an exception.  Instead, just print out an error message
00255       // and hope for the best.
00256       if (err != MPI_SUCCESS) {
00257         cerr << "MPI_Finalize failed with error code " << err << " != "
00258           "MPI_SUCCESS.  I'm not sure how to recover from this safely, "
00259           "so I will keep going and hope for the best." << endl;
00260       }
00261     }
00262 #endif // HAVE_TPETRA_MPI
00263 
00264     tpetraIsInitialized_ = false; // it's not anymore.
00265   }
00266 } // namespace Tpetra
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines