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 #include "PetscTools.hpp"
00030 #include "Exception.hpp"
00031 #include "Warnings.hpp"
00032 #include <iostream>
00033 #include <sstream>
00034 #include <cassert>
00035 #include <cstring> // For strcmp etc. Needed in gcc-4.3
00036 
00037 bool PetscTools::mPetscIsInitialised = false;
00038 unsigned PetscTools::mNumProcessors = 0;
00039 unsigned PetscTools::mRank = 0;
00040 bool PetscTools::mIsolateProcesses = false;
00041 //unsigned PetscTools::mMaxNumNonzerosIfMatMpiAij = 54;
00042 
00043 #ifdef DEBUG_BARRIERS
00044 unsigned PetscTools::mNumBarriers = 0u;
00045 #endif
00046 
00047 void PetscTools::ResetCache()
00048 {
00049     PetscTruth is_there;
00050     PetscInitialized(&is_there);
00051     if (is_there)
00052     {
00053         mPetscIsInitialised = true;
00054 
00055         PetscInt num_procs;
00056         MPI_Comm_size(PETSC_COMM_WORLD, &num_procs);
00057         mNumProcessors = (unsigned) num_procs;
00058 
00059         PetscInt my_rank;
00060         MPI_Comm_rank(PETSC_COMM_WORLD, &my_rank);
00061         mRank = (unsigned) my_rank;
00062     }
00063     else
00064     {
00065         // No PETSc
00066         mPetscIsInitialised = false;
00067         mNumProcessors = 1;
00068         mRank = 0;
00069     }
00070 }
00071 
00072 // Information methods
00073 
00074 bool PetscTools::IsSequential()
00075 {
00076     CheckCache();
00077     return (mNumProcessors == 1);
00078 }
00079 
00080 bool PetscTools::IsParallel()
00081 {
00082     CheckCache();
00083     return (mNumProcessors > 1);
00084 }
00085 
00086 unsigned PetscTools::GetNumProcs()
00087 {
00088     CheckCache();
00089     return mNumProcessors;
00090 }
00091 
00092 unsigned PetscTools::GetMyRank()
00093 {
00094     CheckCache();
00095     return mRank;
00096 }
00097 
00098 bool PetscTools::AmMaster()
00099 {
00100     CheckCache();
00101     return (mRank == MASTER_RANK || mIsolateProcesses);
00102 }
00103 
00104 bool PetscTools::AmTopMost()
00105 {
00106     CheckCache();
00107     return (mRank == mNumProcessors - 1);
00108 }
00109 
00110 // Little utility methods
00111 
00112 void PetscTools::Barrier(const std::string callerId)
00113 {
00114     CheckCache();
00115     if (mPetscIsInitialised && !mIsolateProcesses)
00116     {
00117 #ifdef DEBUG_BARRIERS
00118         std::cout << "DEBUG: proc " << PetscTools::GetMyRank() << ": Pre " << callerId << " Barrier " << mNumBarriers << "." << std::endl << std::flush;
00119 #endif
00120         PetscBarrier(PETSC_NULL);
00121 #ifdef DEBUG_BARRIERS
00122         std::cout << "DEBUG: proc " << PetscTools::GetMyRank() << ": Post " << callerId << " Barrier " << mNumBarriers++ << "." << std::endl << std::flush;
00123 #endif
00124     }
00125 }
00126 
00127 void PetscTools::BeginRoundRobin()
00128 {
00129     Barrier("PetscTools::RoundRobin"); // We want barriers both before all and after all, just in case
00130     const unsigned my_rank = GetMyRank();
00131     for (unsigned turn=0; turn<my_rank; turn++)
00132     {
00133         Barrier("PetscTools::RoundRobin");
00134     }
00135 }
00136 
00137 void PetscTools::EndRoundRobin()
00138 {
00139     const unsigned num_procs = GetNumProcs();
00140     for (unsigned turn=GetMyRank(); turn<num_procs; turn++)
00141     {
00142         Barrier("PetscTools::RoundRobin");
00143     }
00144 }
00145 
00146 void PetscTools::IsolateProcesses(bool isolate)
00147 {
00148     mIsolateProcesses = isolate;
00149 }
00150 
00151 bool PetscTools::ReplicateBool(bool flag)
00152 {
00153     CheckCache();
00154     unsigned my_flag = (unsigned) flag;
00155     unsigned anyones_flag_is_true = my_flag;
00156     if (mPetscIsInitialised && !mIsolateProcesses)
00157     {
00158         MPI_Allreduce(&my_flag, &anyones_flag_is_true, 1, MPI_UNSIGNED, MPI_MAX, PETSC_COMM_WORLD);
00159     }
00160     return (anyones_flag_is_true == 1);
00161 }
00162 
00163 void PetscTools::ReplicateException(bool flag)
00164 {
00165     bool anyones_error=ReplicateBool(flag);
00166     if (flag)
00167     {
00168         // Return control to exception thrower
00169         return;
00170     }
00171     if (anyones_error)
00172     {
00173         EXCEPTION("Another process threw an exception; bailing out.");
00174     }
00175 }
00176 
00177 // Vector & matrix creation routines
00178 
00179 Vec PetscTools::CreateVec(int size, int localSize, bool ignoreOffProcEntries)
00180 {
00181     assert(size >= 0); // There is one test where we create a zero-sized vector
00182     Vec ret;
00183     VecCreate(PETSC_COMM_WORLD, &ret);
00184     VecSetSizes(ret, localSize, size); // localSize usually defaults to PETSC_DECIDE
00185     VecSetFromOptions(ret);
00186 
00187     if (ignoreOffProcEntries)
00188     {
00189 #if (PETSC_VERSION_MAJOR == 3)
00190         VecSetOption(ret, VEC_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
00191 #else
00192         VecSetOption(ret, VEC_IGNORE_OFF_PROC_ENTRIES);
00193 #endif
00194     }
00195 
00196     return ret;
00197 }
00198 
00199 Vec PetscTools::CreateVec(std::vector<double> data)
00200 {
00201     assert(data.size() > 0);
00202     Vec ret = CreateVec(data.size());
00203 
00204     double* p_ret;
00205     VecGetArray(ret, &p_ret);
00206     int lo, hi;
00207     VecGetOwnershipRange(ret, &lo, &hi);
00208 
00209     for (int global_index=lo; global_index<hi; global_index++)
00210     {
00211         int local_index = global_index - lo;
00212         p_ret[local_index] = data[global_index];
00213     }
00214     VecRestoreArray(ret, &p_ret);
00215 
00216     return ret;
00217 }
00218 
00219 Vec PetscTools::CreateAndSetVec(int size, double value)
00220 {
00221     assert(size > 0);
00222     Vec ret = CreateVec(size);
00223 
00224 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00225     VecSet(&value, ret);
00226 #else
00227     VecSet(ret, value);
00228 #endif
00229 
00230     return ret;
00231 }
00232 
00233 void PetscTools::SetupMat(Mat& rMat, int numRows, int numColumns,
00234                           unsigned rowPreallocation,
00235                           int numLocalRows,
00236                           int numLocalColumns,
00237                           bool ignoreOffProcEntries)
00238 {
00239     assert(numRows > 0);
00240     assert(numColumns > 0);
00241     if ((int) rowPreallocation>numColumns)
00242     {
00243         WARNING("Preallocation failure: requested number of nonzeros per row greater than number of columns");//+rowPreallocation+">"+numColumns);
00244         rowPreallocation = numColumns;
00245     }
00246 
00247 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00248     MatCreate(PETSC_COMM_WORLD,numLocalRows,numLocalColumns,numRows,numColumns,&rMat);
00249 #else //New API
00250     MatCreate(PETSC_COMM_WORLD,&rMat);
00251     MatSetSizes(rMat,numLocalRows,numLocalColumns,numRows,numColumns);
00252 #endif
00253 
00254     if (PetscTools::IsSequential())
00255     {
00256         MatSetType(rMat, MATSEQAIJ);
00257         if (rowPreallocation > 0)
00258         {
00259             MatSeqAIJSetPreallocation(rMat, rowPreallocation, PETSC_NULL);
00260         }
00261     }
00262     else
00263     {
00264         MatSetType(rMat, MATMPIAIJ);
00265         if (rowPreallocation > 0)
00266         {
00268             MatMPIAIJSetPreallocation(rMat, rowPreallocation, PETSC_NULL, (PetscInt) (rowPreallocation*0.7), PETSC_NULL);
00269         }
00270     }
00271 
00272     MatSetFromOptions(rMat);
00273 
00274     if (ignoreOffProcEntries)//&& IsParallel())
00275     {
00276         if (rowPreallocation == 0)
00277         {
00278             // We aren't allowed to do non-zero allocation after setting MAT_IGNORE_OFF_PROC_ENTRIES
00279             WARNING("Ignoring MAT_IGNORE_OFF_PROC_ENTRIES flag because we might set non-zeroes later");
00280         }
00281         else
00282         {
00283 #if (PETSC_VERSION_MAJOR == 3)
00284             MatSetOption(rMat, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE);
00285 #else
00286             MatSetOption(rMat, MAT_IGNORE_OFF_PROC_ENTRIES);
00287 #endif
00288         }
00289     }
00290 }
00291 
00292 void PetscTools::DumpPetscObject(const Mat& rMat, const std::string& rOutputFileFullPath)
00293 {
00294     PetscViewer view;
00295 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00296     PetscViewerFileType type = PETSC_FILE_CREATE;
00297 #else
00298     PetscFileMode type = FILE_MODE_WRITE;
00299 #endif
00300 
00301     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(), type, &view);
00302     MatView(rMat, view);
00303     PetscViewerDestroy(view);
00304 }
00305 
00306 void PetscTools::DumpPetscObject(const Vec& rVec, const std::string& rOutputFileFullPath)
00307 {
00308     PetscViewer view;
00309 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00310     PetscViewerFileType type = PETSC_FILE_CREATE;
00311 #else
00312     PetscFileMode type = FILE_MODE_WRITE;
00313 #endif
00314 
00315     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(), type, &view);
00316     VecView(rVec, view);
00317     PetscViewerDestroy(view);
00318 }
00319 
00320 void PetscTools::ReadPetscObject(Mat& rMat, const std::string& rOutputFileFullPath, Vec rParallelLayout)
00321 {
00322     /*
00323      * PETSc (as of 3.1) doesn't provide any method for loading a Mat object with a user-defined parallel
00324      * layout, i.e. there's no equivalent to VecLoadIntoVector for Mat's.
00325      *
00326      * It seems to be in their future plans though: http://lists.mcs.anl.gov/pipermail/petsc-users/2010-March/006062.html
00327      */
00328 
00329     PetscViewer view;
00330 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00331     PetscViewerFileType type = PETSC_FILE_RDONLY;
00332 #else
00333     PetscFileMode type = FILE_MODE_READ;
00334 #endif
00335 
00336     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00337                           type, &view);
00338     MatLoad(view, MATMPIAIJ, &rMat);
00339     PetscViewerDestroy(view);
00340 
00341     if (rParallelLayout != NULL)
00342     {
00343         /*
00344          * The idea is to copy rMat into a matrix that has the appropriate
00345          * parallel layout. Inefficient...
00346          */
00347         PetscInt num_rows, num_local_rows;
00348 
00349         VecGetSize(rParallelLayout, &num_rows);
00350         VecGetLocalSize(rParallelLayout, &num_local_rows);
00351 
00352         Mat temp_mat;
00354         PetscTools::SetupMat(temp_mat, num_rows, num_rows, 100, num_local_rows, num_local_rows, false);
00355 
00356         MatCopy(rMat, temp_mat, DIFFERENT_NONZERO_PATTERN);
00357 
00358         MatDestroy(rMat);
00359         rMat = temp_mat;
00360     }
00361 }
00362 
00363 void PetscTools::ReadPetscObject(Vec& rVec, const std::string& rOutputFileFullPath, Vec rParallelLayout)
00364 {
00365     PetscViewer view;
00366 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2
00367     PetscViewerFileType type = PETSC_FILE_RDONLY;
00368 #else
00369     PetscFileMode type = FILE_MODE_READ;
00370 #endif
00371 
00372     PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(),
00373                           type, &view);
00374     if (rParallelLayout == NULL)
00375     {
00376         VecLoad(view, VECMPI, &rVec);
00377     }
00378     else
00379     {
00380         VecDuplicate(rParallelLayout, &rVec);
00381         VecLoadIntoVector(view, rVec);
00382     }
00383     PetscViewerDestroy(view);
00384 }
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3