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 #ifndef SPECIAL_SERIAL
00138 
00139 bool PetscTools::ReplicateBool(bool flag)
00140 {
00141     unsigned my_flag = (unsigned) flag;
00142     unsigned anyones_flag_is_true;
00143     MPI_Allreduce(&my_flag, &anyones_flag_is_true, 1, MPI_UNSIGNED, MPI_MAX, PETSC_COMM_WORLD);
00144     return (anyones_flag_is_true == 1);
00145 }
00146 
00147 void PetscTools::ReplicateException(bool flag)
00148 {
00149     bool anyones_error=ReplicateBool(flag);
00150     if (flag)
00151     {
00152         // Return control to exception thrower
00153         return;
00154     }
00155     if (anyones_error)
00156     {
00157         EXCEPTION("Another process threw an exception; bailing out.");
00158     }
00159 }
00160 
00161 //
00162 // Vector & Matrix creation routines
00163 //
00164 
00165 Vec PetscTools::CreateVec(int size, int localSize, bool ignoreOffProcEntries)
00166 {
00167     assert(size>=0); //There is one test where we create a zero-sized vector
00168     Vec ret;
00169     VecCreate(PETSC_COMM_WORLD, &ret);
00170     VecSetSizes(ret, localSize, size); //localSize usually defaults to PETSC_DECIDE
00171     VecSetFromOptions(ret);
00172 
00173     if (ignoreOffProcEntries)
00174     {
00175 #if (PETSC_VERSION_MAJOR == 3)
00176         VecSetOption(ret, VEC_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
00177 #else
00178         VecSetOption(ret, VEC_IGNORE_OFF_PROC_ENTRIES);
00179 #endif
00180     }
00181 
00182     return ret;
00183 }
00184 
00185 Vec PetscTools::CreateVec(std::vector<double> data)
00186 {
00187     assert(data.size() > 0);
00188     Vec ret = CreateVec(data.size());
00189 
00190     double* p_ret;
00191     VecGetArray(ret, &p_ret);
00192     int lo, hi;
00193     VecGetOwnershipRange(ret, &lo, &hi);
00194 
00195     for (int global_index=lo; global_index<hi; global_index++)
00196     {
00197         int local_index = global_index - lo;
00198         p_ret[local_index] = data[global_index];
00199     }
00200     VecRestoreArray(ret, &p_ret);
00201 
00202     return ret;
00203 }
00204 
00205 Vec PetscTools::CreateAndSetVec(int size, double value)
00206 {
00207     assert(size>0);
00208     Vec ret = CreateVec(size);
00209 
00210 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00211     VecSet(&value, ret);
00212 #else
00213     VecSet(ret, value);
00214 #endif
00215 
00216     return ret;
00217 }
00218 
00219 void PetscTools::SetupMat(Mat& rMat, int numRows, int numColumns,
00220                           unsigned rowPreallocation,
00221                           int numLocalRows,
00222                           int numLocalColumns,
00223                           bool ignoreOffProcEntries)
00224 {
00225     assert(numRows>0);
00226     assert(numColumns>0);
00227     if((int) rowPreallocation>numColumns)
00228     {
00229         WARNING("Preallocation failure: requested number of nonzeros per row greater than number of columns");//+rowPreallocation+">"+numColumns);
00230         rowPreallocation=numColumns;
00231     }
00232 
00233 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00234     MatCreate(PETSC_COMM_WORLD,numLocalRows,numLocalColumns,numRows,numColumns,&rMat);
00235 #else //New API
00236     MatCreate(PETSC_COMM_WORLD,&rMat);
00237     MatSetSizes(rMat,numLocalRows,numLocalColumns,numRows,numColumns);
00238 #endif
00239 
00240     
00241     if(PetscTools::IsSequential())
00242     {
00243         MatSetType(rMat, MATSEQAIJ);
00244         if(rowPreallocation>0)
00245         {
00246             MatSeqAIJSetPreallocation(rMat, rowPreallocation, PETSC_NULL);
00247         }
00248     }
00249     else
00250     {
00251         MatSetType(rMat, MATMPIAIJ);
00252         if(rowPreallocation>0)
00253         {
00255             MatMPIAIJSetPreallocation(rMat, rowPreallocation, PETSC_NULL, (PetscInt) (rowPreallocation*0.7), PETSC_NULL);
00256         }
00257     }
00258     
00259     MatSetFromOptions(rMat);
00260 
00261 
00262         
00263     if (ignoreOffProcEntries)//&& IsParallel())
00264     {
00265         if (rowPreallocation == 0)
00266         {
00267            // We aren't allowed to do non-zero allocation after setting MAT_IGNORE_OFF_PROC_ENTRIES
00268            WARNING("Ignoring MAT_IGNORE_OFF_PROC_ENTRIES flag because we might set non-zeroes later");
00269         }
00270         else
00271         {
00272 #if (PETSC_VERSION_MAJOR == 3)
00273             MatSetOption(rMat, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
00274 #else
00275             MatSetOption(rMat, MAT_IGNORE_OFF_PROC_ENTRIES);
00276 #endif
00277         }
00278     }
00279 }
00280 
00281 
00282 void PetscTools::DumpPetscObject(const Mat& rMat, const std::string& rOutputFileFullPath)
00283 {
00284     PetscViewer view;
00285 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00286     PetscViewerFileType type = PETSC_FILE_CREATE;
00287 #else
00288     PetscFileMode type = FILE_MODE_WRITE;
00289 #endif
00290 
00291     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00292                           type, &view);
00293     MatView(rMat, view);
00294     PetscViewerDestroy(view);
00295 }
00296 
00297 void PetscTools::DumpPetscObject(const Vec& rVec, const std::string& rOutputFileFullPath)
00298 {
00299     PetscViewer view;
00300 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00301     PetscViewerFileType type = PETSC_FILE_CREATE;
00302 #else
00303     PetscFileMode type = FILE_MODE_WRITE;
00304 #endif
00305 
00306     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00307                           type, &view);
00308     VecView(rVec, view);
00309     PetscViewerDestroy(view);
00310 }
00311 
00312 void PetscTools::ReadPetscObject(Mat& rMat, const std::string& rOutputFileFullPath, Vec rParallelLayout)
00313 {
00314     /*
00315      *  PETSc (as of 3.1) doesn't provide any method for loading a Mat object with a user-defined parallel 
00316      * layout, i.e. there's no equivalent to VecLoadIntoVector for Mat's. 
00317      * 
00318      * It seems to be in their future plans though: http://lists.mcs.anl.gov/pipermail/petsc-users/2010-March/006062.html
00319      */
00320         
00321     PetscViewer view;
00322 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00323     PetscViewerFileType type = PETSC_FILE_RDONLY;
00324 #else
00325     PetscFileMode type = FILE_MODE_READ;
00326 #endif
00327 
00328     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00329                           type, &view);
00330     MatLoad(view, MATMPIAIJ, &rMat);
00331     PetscViewerDestroy(view);
00332     
00333     if (rParallelLayout != NULL)
00334     {
00335         /*
00336          *  The idea is to copy rMat into a matrix that has the appropriate
00337          * parallel layout. Inefficient...
00338          */
00339         PetscInt num_rows, num_local_rows;
00340         
00341         VecGetSize(rParallelLayout, &num_rows);
00342         VecGetLocalSize(rParallelLayout, &num_local_rows);               
00343         
00344         Mat temp_mat;
00346         PetscTools::SetupMat(temp_mat, num_rows, num_rows, 100, num_local_rows, num_local_rows, false);
00347      
00348         MatCopy(rMat, temp_mat, DIFFERENT_NONZERO_PATTERN);        
00349         
00350         MatDestroy(rMat);
00351         rMat = temp_mat;
00352         
00353     }        
00354 }
00355 
00356 void PetscTools::ReadPetscObject(Vec& rVec, const std::string& rOutputFileFullPath, Vec rParallelLayout)
00357 {
00358     PetscViewer view;
00359 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00360     PetscViewerFileType type = PETSC_FILE_RDONLY;
00361 #else
00362     PetscFileMode type = FILE_MODE_READ;
00363 #endif
00364 
00365     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00366                           type, &view);
00367     if (rParallelLayout == NULL)
00368     {
00369         VecLoad(view, VECMPI, &rVec);
00370     }
00371     else
00372     {
00373         VecDuplicate(rParallelLayout, &rVec);
00374         VecLoadIntoVector(view, rVec);
00375     }
00376     PetscViewerDestroy(view);
00377 }
00378 #endif //SPECIAL_SERIAL (ifndef)
00379 
00380 #define COVERAGE_IGNORE //Termination NEVER EVER happens under normal testing conditions.
00381 void PetscTools::Terminate(const std::string& rMessage, const std::string& rFilename, unsigned lineNumber)
00382 {
00383     std::stringstream error_message;
00384     
00385     error_message<<"\nChaste termination: " << rFilename << ":" << lineNumber  << ": " << rMessage<<"\n";
00386     std::cerr<<error_message.str();
00387     
00388     //double check for PETSc.  We could use mPetscIsInitialised, but only if we are certain that the 
00389     //PetscTools class has been used previously.
00390     PetscTruth is_there;
00391     PetscInitialized(&is_there);
00392     if (is_there)
00393     {
00394         MPI_Abort(PETSC_COMM_WORLD, EXIT_FAILURE); 
00395     }
00396     else
00397     {
00398         exit(EXIT_FAILURE);
00399     } 
00400 }
00401 #undef COVERAGE_IGNORE //Termination NEVER EVER happens under normal testing conditions.

Generated on Mon Apr 18 11:35:28 2011 for Chaste by  doxygen 1.5.5