PetscTools.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 
00030 #include "PetscTools.hpp"
00031 #include "Exception.hpp"
00032 #include "Warnings.hpp"
00033 #include <iostream>
00034 #include <sstream>
00035 #include <cassert>
00036 #include <cstring> //For strcmp etc. Needed in gcc-4.3
00037 
00038 bool PetscTools::mPetscIsInitialised = false;
00039 unsigned PetscTools::mNumProcessors = 0;
00040 unsigned PetscTools::mRank = 0;
00041 //unsigned PetscTools::mMaxNumNonzerosIfMatMpiAij = 54;
00042 
00043 #ifdef DEBUG_BARRIERS
00044 unsigned PetscTools::mNumBarriers = 0u;
00045 #endif
00046 
00047 void PetscTools::ResetCache()
00048 {
00049 #ifdef SPECIAL_SERIAL
00050     mPetscIsInitialised = false;
00051     mNumProcessors = 1;
00052     mRank = 0;
00053 #else
00054     PetscTruth is_there;
00055     PetscInitialized(&is_there);
00056     if (is_there)
00057     {
00058         mPetscIsInitialised = true;
00059 
00060         PetscInt num_procs;
00061         MPI_Comm_size(PETSC_COMM_WORLD, &num_procs);
00062         mNumProcessors = (unsigned) num_procs;
00063 
00064         PetscInt my_rank;
00065         MPI_Comm_rank(PETSC_COMM_WORLD, &my_rank);
00066         mRank = (unsigned) my_rank;
00067     }
00068     else
00069     {
00070         // No PETSc
00071         mPetscIsInitialised = false;
00072         mNumProcessors = 1;
00073         mRank = 0;
00074     }
00075 #endif
00076 }
00077 
00078 //
00079 // Information methods
00080 //
00081 
00082 bool PetscTools::IsSequential()
00083 {
00084     CheckCache();
00085     return (mNumProcessors == 1);
00086 }
00087 
00088 bool PetscTools::IsParallel()
00089 {
00090     CheckCache();
00091     return (mNumProcessors > 1);
00092 }
00093 
00094 unsigned PetscTools::GetNumProcs()
00095 {
00096     CheckCache();
00097     return mNumProcessors;
00098 }
00099 
00100 unsigned PetscTools::GetMyRank()
00101 {
00102     CheckCache();
00103     return mRank;
00104 }
00105 
00106 bool PetscTools::AmMaster()
00107 {
00108     CheckCache();
00109     return (mRank == MASTER_RANK);
00110 }
00111 
00112 bool PetscTools::AmTopMost()
00113 {
00114     CheckCache();
00115     return (mRank == mNumProcessors - 1);
00116 }
00117 
00118 //
00119 // Little utility methods
00120 //
00121 
00122 void PetscTools::Barrier(const std::string callerId)
00123 {
00124     CheckCache();
00125     if (mPetscIsInitialised)
00126     {
00127 #ifdef DEBUG_BARRIERS
00128         std::cout << "DEBUG: proc " << PetscTools::GetMyRank() << ": Pre " << callerId << " Barrier " << mNumBarriers << "." << std::endl << std::flush;
00129 #endif
00130         PetscBarrier(PETSC_NULL);
00131 #ifdef DEBUG_BARRIERS
00132         std::cout << "DEBUG: proc " << PetscTools::GetMyRank() << ": Post " << callerId << " Barrier " << mNumBarriers++ << "." << std::endl << std::flush;
00133 #endif
00134     }
00135 }
00136 
00137 void PetscTools::BeginRoundRobin()
00138 {
00139     Barrier("PetscTools::RoundRobin"); // We want barriers both before all and after all, just in case
00140     const unsigned my_rank = GetMyRank();
00141     for (unsigned turn=0; turn<my_rank; turn++)
00142     {
00143         Barrier("PetscTools::RoundRobin");
00144     }
00145 }
00146 
00147 
00148 void PetscTools::EndRoundRobin()
00149 {
00150     const unsigned num_procs = GetNumProcs();
00151     for (unsigned turn=GetMyRank(); turn<num_procs; turn++)
00152     {
00153         Barrier("PetscTools::RoundRobin");
00154     }
00155 }
00156 
00157 
00158 #ifndef SPECIAL_SERIAL
00159 
00160 bool PetscTools::ReplicateBool(bool flag)
00161 {
00162     unsigned my_flag = (unsigned) flag;
00163     unsigned anyones_flag_is_true;
00164     MPI_Allreduce(&my_flag, &anyones_flag_is_true, 1, MPI_UNSIGNED, MPI_MAX, PETSC_COMM_WORLD);
00165     return (anyones_flag_is_true == 1);
00166 }
00167 
00168 void PetscTools::ReplicateException(bool flag)
00169 {
00170     bool anyones_error=ReplicateBool(flag);
00171     if (flag)
00172     {
00173         // Return control to exception thrower
00174         return;
00175     }
00176     if (anyones_error)
00177     {
00178         EXCEPTION("Another process threw an exception; bailing out.");
00179     }
00180 }
00181 
00182 //
00183 // Vector & Matrix creation routines
00184 //
00185 
00186 Vec PetscTools::CreateVec(int size, int localSize, bool ignoreOffProcEntries)
00187 {
00188     assert(size>=0); //There is one test where we create a zero-sized vector
00189     Vec ret;
00190     VecCreate(PETSC_COMM_WORLD, &ret);
00191     VecSetSizes(ret, localSize, size); //localSize usually defaults to PETSC_DECIDE
00192     VecSetFromOptions(ret);
00193 
00194     if (ignoreOffProcEntries)
00195     {
00196 #if (PETSC_VERSION_MAJOR == 3)
00197         VecSetOption(ret, VEC_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
00198 #else
00199         VecSetOption(ret, VEC_IGNORE_OFF_PROC_ENTRIES);
00200 #endif
00201     }
00202 
00203     return ret;
00204 }
00205 
00206 Vec PetscTools::CreateVec(std::vector<double> data)
00207 {
00208     assert(data.size() > 0);
00209     Vec ret = CreateVec(data.size());
00210 
00211     double* p_ret;
00212     VecGetArray(ret, &p_ret);
00213     int lo, hi;
00214     VecGetOwnershipRange(ret, &lo, &hi);
00215 
00216     for (int global_index=lo; global_index<hi; global_index++)
00217     {
00218         int local_index = global_index - lo;
00219         p_ret[local_index] = data[global_index];
00220     }
00221     VecRestoreArray(ret, &p_ret);
00222 
00223     return ret;
00224 }
00225 
00226 Vec PetscTools::CreateAndSetVec(int size, double value)
00227 {
00228     assert(size>0);
00229     Vec ret = CreateVec(size);
00230 
00231 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00232     VecSet(&value, ret);
00233 #else
00234     VecSet(ret, value);
00235 #endif
00236 
00237     return ret;
00238 }
00239 
00240 void PetscTools::SetupMat(Mat& rMat, int numRows, int numColumns,
00241                           unsigned rowPreallocation,
00242                           int numLocalRows,
00243                           int numLocalColumns,
00244                           bool ignoreOffProcEntries)
00245 {
00246     assert(numRows>0);
00247     assert(numColumns>0);
00248     if((int) rowPreallocation>numColumns)
00249     {
00250         WARNING("Preallocation failure: requested number of nonzeros per row greater than number of columns");//+rowPreallocation+">"+numColumns);
00251         rowPreallocation=numColumns;
00252     }
00253 
00254 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00255     MatCreate(PETSC_COMM_WORLD,numLocalRows,numLocalColumns,numRows,numColumns,&rMat);
00256 #else //New API
00257     MatCreate(PETSC_COMM_WORLD,&rMat);
00258     MatSetSizes(rMat,numLocalRows,numLocalColumns,numRows,numColumns);
00259 #endif
00260 
00261 
00262     if(PetscTools::IsSequential())
00263     {
00264         MatSetType(rMat, MATSEQAIJ);
00265         if(rowPreallocation>0)
00266         {
00267             MatSeqAIJSetPreallocation(rMat, rowPreallocation, PETSC_NULL);
00268         }
00269     }
00270     else
00271     {
00272         MatSetType(rMat, MATMPIAIJ);
00273         if(rowPreallocation>0)
00274         {
00276             MatMPIAIJSetPreallocation(rMat, rowPreallocation, PETSC_NULL, (PetscInt) (rowPreallocation*0.7), PETSC_NULL);
00277         }
00278     }
00279 
00280     MatSetFromOptions(rMat);
00281 
00282 
00283 
00284     if (ignoreOffProcEntries)//&& IsParallel())
00285     {
00286         if (rowPreallocation == 0)
00287         {
00288             // We aren't allowed to do non-zero allocation after setting MAT_IGNORE_OFF_PROC_ENTRIES
00289             WARNING("Ignoring MAT_IGNORE_OFF_PROC_ENTRIES flag because we might set non-zeroes later");
00290         }
00291         else
00292         {
00293 #if (PETSC_VERSION_MAJOR == 3)
00294             MatSetOption(rMat, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
00295 #else
00296             MatSetOption(rMat, MAT_IGNORE_OFF_PROC_ENTRIES);
00297 #endif
00298         }
00299     }
00300 }
00301 
00302 
00303 void PetscTools::DumpPetscObject(const Mat& rMat, const std::string& rOutputFileFullPath)
00304 {
00305     PetscViewer view;
00306 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00307     PetscViewerFileType type = PETSC_FILE_CREATE;
00308 #else
00309     PetscFileMode type = FILE_MODE_WRITE;
00310 #endif
00311 
00312     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00313                           type, &view);
00314     MatView(rMat, view);
00315     PetscViewerDestroy(view);
00316 }
00317 
00318 void PetscTools::DumpPetscObject(const Vec& rVec, const std::string& rOutputFileFullPath)
00319 {
00320     PetscViewer view;
00321 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00322     PetscViewerFileType type = PETSC_FILE_CREATE;
00323 #else
00324     PetscFileMode type = FILE_MODE_WRITE;
00325 #endif
00326 
00327     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00328                           type, &view);
00329     VecView(rVec, view);
00330     PetscViewerDestroy(view);
00331 }
00332 
00333 void PetscTools::ReadPetscObject(Mat& rMat, const std::string& rOutputFileFullPath, Vec rParallelLayout)
00334 {
00335     /*
00336      *  PETSc (as of 3.1) doesn't provide any method for loading a Mat object with a user-defined parallel
00337      * layout, i.e. there's no equivalent to VecLoadIntoVector for Mat's.
00338      *
00339      * It seems to be in their future plans though: http://lists.mcs.anl.gov/pipermail/petsc-users/2010-March/006062.html
00340      */
00341 
00342     PetscViewer view;
00343 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00344     PetscViewerFileType type = PETSC_FILE_RDONLY;
00345 #else
00346     PetscFileMode type = FILE_MODE_READ;
00347 #endif
00348 
00349     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00350                           type, &view);
00351     MatLoad(view, MATMPIAIJ, &rMat);
00352     PetscViewerDestroy(view);
00353 
00354     if (rParallelLayout != NULL)
00355     {
00356         /*
00357          *  The idea is to copy rMat into a matrix that has the appropriate
00358          * parallel layout. Inefficient...
00359          */
00360         PetscInt num_rows, num_local_rows;
00361 
00362         VecGetSize(rParallelLayout, &num_rows);
00363         VecGetLocalSize(rParallelLayout, &num_local_rows);
00364 
00365         Mat temp_mat;
00367         PetscTools::SetupMat(temp_mat, num_rows, num_rows, 100, num_local_rows, num_local_rows, false);
00368 
00369         MatCopy(rMat, temp_mat, DIFFERENT_NONZERO_PATTERN);
00370 
00371         MatDestroy(rMat);
00372         rMat = temp_mat;
00373 
00374     }
00375 }
00376 
00377 void PetscTools::ReadPetscObject(Vec& rVec, const std::string& rOutputFileFullPath, Vec rParallelLayout)
00378 {
00379     PetscViewer view;
00380 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00381     PetscViewerFileType type = PETSC_FILE_RDONLY;
00382 #else
00383     PetscFileMode type = FILE_MODE_READ;
00384 #endif
00385 
00386     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00387                           type, &view);
00388     if (rParallelLayout == NULL)
00389     {
00390         VecLoad(view, VECMPI, &rVec);
00391     }
00392     else
00393     {
00394         VecDuplicate(rParallelLayout, &rVec);
00395         VecLoadIntoVector(view, rVec);
00396     }
00397     PetscViewerDestroy(view);
00398 }
00399 #endif //SPECIAL_SERIAL (ifndef)
00400 
00401 #define COVERAGE_IGNORE //Termination NEVER EVER happens under normal testing conditions.
00402 void PetscTools::Terminate(const std::string& rMessage, const std::string& rFilename, unsigned lineNumber)
00403 {
00404     std::stringstream error_message;
00405 
00406     error_message<<"\nChaste termination: " << rFilename << ":" << lineNumber  << ": " << rMessage<<"\n";
00407     std::cerr<<error_message.str();
00408 
00409     //double check for PETSc.  We could use mPetscIsInitialised, but only if we are certain that the
00410     //PetscTools class has been used previously.
00411     PetscTruth is_there;
00412     PetscInitialized(&is_there);
00413     if (is_there)
00414     {
00415         MPI_Abort(PETSC_COMM_WORLD, EXIT_FAILURE);
00416     }
00417     else
00418     {
00419         exit(EXIT_FAILURE);
00420     }
00421 }
00422 #undef COVERAGE_IGNORE //Termination NEVER EVER happens under normal testing conditions.

Generated on Tue May 31 14:31:41 2011 for Chaste by  doxygen 1.5.5