PetscTools.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
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 unsigned PetscTools::GetNumProcs()
00089 {
00090     CheckCache();
00091     return mNumProcessors;
00092 }
00093 
00094 unsigned PetscTools::GetMyRank()
00095 {
00096     CheckCache();
00097     return mRank;
00098 }
00099 
00100 bool PetscTools::AmMaster()
00101 {
00102     CheckCache();
00103     return (mRank == MASTER_RANK);
00104 }
00105 
00106 bool PetscTools::AmTopMost()
00107 {
00108     CheckCache();
00109     return (mRank == mNumProcessors - 1);
00110 }
00111 
00112 //
00113 // Little utility methods
00114 //
00115 
00116 void PetscTools::Barrier(const std::string callerId)
00117 {
00118     CheckCache();
00119     if (mPetscIsInitialised)
00120     {
00121 #ifdef DEBUG_BARRIERS
00122         std::cout << "DEBUG: proc " << PetscTools::GetMyRank() << ": Pre " << callerId << " Barrier " << mNumBarriers << "." << std::endl << std::flush;
00123 #endif
00124         PetscBarrier(PETSC_NULL);
00125 #ifdef DEBUG_BARRIERS
00126         std::cout << "DEBUG: proc " << PetscTools::GetMyRank() << ": Post " << callerId << " Barrier " << mNumBarriers++ << "." << std::endl << std::flush;
00127 #endif
00128     }
00129 }
00130 
00131 #ifndef SPECIAL_SERIAL
00132 
00133 bool PetscTools::ReplicateBool(bool flag)
00134 {
00135     unsigned my_flag = (unsigned) flag;
00136     unsigned anyones_flag_is_true;
00137     MPI_Allreduce(&my_flag, &anyones_flag_is_true, 1, MPI_UNSIGNED, MPI_MAX, PETSC_COMM_WORLD);
00138     return (anyones_flag_is_true == 1);
00139 }
00140 
00141 void PetscTools::ReplicateException(bool flag)
00142 {
00143     bool anyones_error=ReplicateBool(flag);
00144     if (flag)
00145     {
00146         // Return control to exception thrower
00147         return;
00148     }
00149     if (anyones_error)
00150     {
00151         EXCEPTION("Another process threw an exception; bailing out.");
00152     }
00153 }
00154 
00155 //
00156 // Vector & Matrix creation routines
00157 //
00158 
00159 Vec PetscTools::CreateVec(int size, int localSize)
00160 {
00161     assert(size>=0); //There is one test where we create a zero-sized vector
00162     Vec ret;
00163     VecCreate(PETSC_COMM_WORLD, &ret);
00164     VecSetSizes(ret, localSize, size); //localSize usually defaults to PETSC_DECIDE
00165     VecSetFromOptions(ret);
00166     return ret;
00167 }
00168 
00169 Vec PetscTools::CreateVec(std::vector<double> data)
00170 {
00171     assert(data.size() > 0);
00172     Vec ret = CreateVec(data.size());
00173 
00174     double* p_ret;
00175     VecGetArray(ret, &p_ret);
00176     int lo, hi;
00177     VecGetOwnershipRange(ret, &lo, &hi);
00178 
00179     for (int global_index=lo; global_index<hi; global_index++)
00180     {
00181         int local_index = global_index - lo;
00182         p_ret[local_index] = data[global_index];
00183     }
00184     VecRestoreArray(ret, &p_ret);
00185     VecAssemblyBegin(ret);
00186     VecAssemblyEnd(ret);
00187 
00188     return ret;
00189 }
00190 
00191 Vec PetscTools::CreateAndSetVec(int size, double value)
00192 {
00193     assert(size>0);
00194     Vec ret = CreateVec(size);
00195 
00196 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00197     VecSet(&value, ret);
00198 #else
00199     VecSet(ret, value);
00200 #endif
00201 
00202     VecAssemblyBegin(ret);
00203     VecAssemblyEnd(ret);
00204     return ret;
00205 }
00206 
00207 void PetscTools::SetupMat(Mat& rMat, int numRows, int numColumns,
00208                           unsigned rowPreallocation,
00209                           int numLocalRows,
00210                           int numLocalColumns)
00211 {
00212     assert(numRows>0);
00213     assert(numColumns>0);
00214     if((int) rowPreallocation>numColumns)
00215     {
00216         WARNING("Preallocation failure: requested number of nonzeros per row greater than number of columns");//+rowPreallocation+">"+numColumns);
00217         rowPreallocation=numColumns;
00218     }
00219 
00220 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00221     MatCreate(PETSC_COMM_WORLD,numLocalRows,numLocalColumns,numRows,numColumns,&rMat);
00222 #else //New API
00223     MatCreate(PETSC_COMM_WORLD,&rMat);
00224     MatSetSizes(rMat,numLocalRows,numLocalColumns,numRows,numColumns);
00225 #endif
00226 
00227     
00228     if(PetscTools::IsSequential())
00229     {
00230         MatSetType(rMat, MATSEQAIJ);
00231         if(rowPreallocation>0)
00232         {
00233             MatSeqAIJSetPreallocation(rMat, rowPreallocation, PETSC_NULL);
00234         }
00235     }
00236     else
00237     {
00238         MatSetType(rMat, MATMPIAIJ);
00239         if(rowPreallocation>0)
00240         {
00242             MatMPIAIJSetPreallocation(rMat, rowPreallocation, PETSC_NULL, (PetscInt) (rowPreallocation*0.7), PETSC_NULL);
00243         }
00244     }
00245 
00246     MatSetFromOptions(rMat);
00247 }
00248 
00249 
00250 void PetscTools::DumpPetscObject(const Mat& rMat, const std::string& rOutputFileFullPath)
00251 {
00252     PetscViewer view;
00253 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00254     PetscViewerFileType type = PETSC_FILE_CREATE;
00255 #else
00256     PetscFileMode type = FILE_MODE_WRITE;
00257 #endif
00258 
00259     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00260                           type, &view);
00261     MatView(rMat, view);
00262     PetscViewerDestroy(view);
00263 }
00264 
00265 void PetscTools::DumpPetscObject(const Vec& rVec, const std::string& rOutputFileFullPath)
00266 {
00267     PetscViewer view;
00268 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00269     PetscViewerFileType type = PETSC_FILE_CREATE;
00270 #else
00271     PetscFileMode type = FILE_MODE_WRITE;
00272 #endif
00273 
00274     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00275                           type, &view);
00276     VecView(rVec, view);
00277     PetscViewerDestroy(view);
00278 }
00279 
00280 void PetscTools::ReadPetscObject(Mat& rMat, const std::string& rOutputFileFullPath, Vec rParallelLayout)
00281 {
00282     /*
00283      *  PETSc (as of 3.1) doesn't provide any method for loading a Mat object with a user-defined parallel 
00284      * layout, i.e. there's no equivalent to VecLoadIntoVector for Mat's. 
00285      * 
00286      * It seems to be in their future plans though: http://lists.mcs.anl.gov/pipermail/petsc-users/2010-March/006062.html
00287      */
00288         
00289     PetscViewer view;
00290 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00291     PetscViewerFileType type = PETSC_FILE_RDONLY;
00292 #else
00293     PetscFileMode type = FILE_MODE_READ;
00294 #endif
00295 
00296     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00297                           type, &view);
00298     MatLoad(view, MATMPIAIJ, &rMat);
00299     PetscViewerDestroy(view);
00300     
00301     if (rParallelLayout != NULL)
00302     {
00303         /*
00304          *  The idea is to copy rMat into a matrix that has the appropriate
00305          * parallel layout. Inefficient...
00306          */
00307         PetscInt num_rows, num_local_rows;
00308         
00309         VecGetSize(rParallelLayout, &num_rows);
00310         VecGetLocalSize(rParallelLayout, &num_local_rows);               
00311         
00312         Mat temp_mat;
00314         PetscTools::SetupMat(temp_mat, num_rows, num_rows, 100, num_local_rows, num_local_rows);
00315      
00316         MatCopy(rMat, temp_mat, DIFFERENT_NONZERO_PATTERN);        
00317         
00318         MatDestroy(rMat);
00319         rMat = temp_mat;
00320         
00321     }        
00322 }
00323 
00324 void PetscTools::ReadPetscObject(Vec& rVec, const std::string& rOutputFileFullPath, Vec rParallelLayout)
00325 {
00326     PetscViewer view;
00327 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00328     PetscViewerFileType type = PETSC_FILE_RDONLY;
00329 #else
00330     PetscFileMode type = FILE_MODE_READ;
00331 #endif
00332 
00333     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00334                           type, &view);
00335     if (rParallelLayout == NULL)
00336     {
00337         VecLoad(view, VECMPI, &rVec);
00338     }
00339     else
00340     {
00341         VecDuplicate(rParallelLayout, &rVec);
00342         VecLoadIntoVector(view, rVec);
00343     }
00344     PetscViewerDestroy(view);
00345 }
00346 #endif //SPECIAL_SERIAL (ifndef)
00347 
00348 #define COVERAGE_IGNORE //Termination NEVER EVER happens under normal testing conditions.
00349 void PetscTools::Terminate(const std::string& rMessage, const std::string& rFilename, unsigned lineNumber)
00350 {
00351     std::stringstream error_message;
00352     
00353     error_message<<"\nChaste termination: " << rFilename << ":" << lineNumber  << ": " << rMessage<<"\n";
00354     std::cerr<<error_message.str();
00355     
00356     //double check for PETSc.  We could use mPetscIsInitialised, but only if we are certain that the 
00357     //PetscTools class has been used previously.
00358     PetscTruth is_there;
00359     PetscInitialized(&is_there);
00360     if (is_there)
00361     {
00362         MPI_Abort(PETSC_COMM_WORLD, EXIT_FAILURE); 
00363     }
00364     else
00365     {
00366         exit(EXIT_FAILURE);
00367     } 
00368 }
00369 #undef COVERAGE_IGNORE //Termination NEVER EVER happens under normal testing conditions.

Generated on Mon Nov 1 12:35:16 2010 for Chaste by  doxygen 1.5.5