Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 00036 #include "PetscTools.hpp" 00037 #include "Exception.hpp" 00038 #include "Warnings.hpp" 00039 #include <iostream> 00040 #include <sstream> 00041 #include <cassert> 00042 #include <cstring> // For strcmp etc. Needed in gcc-4.3 00043 00044 bool PetscTools::mPetscIsInitialised = false; 00045 unsigned PetscTools::mNumProcessors = 0; 00046 unsigned PetscTools::mRank = 0; 00047 bool PetscTools::mIsolateProcesses = false; 00048 //unsigned PetscTools::mMaxNumNonzerosIfMatMpiAij = 54; 00049 00050 #ifdef DEBUG_BARRIERS 00051 unsigned PetscTools::mNumBarriers = 0u; 00052 #endif 00053 00054 void PetscTools::ResetCache() 00055 { 00056 PetscTruth is_there; 00057 PetscInitialized(&is_there); 00058 if (is_there) 00059 { 00060 mPetscIsInitialised = true; 00061 00062 PetscInt num_procs; 00063 MPI_Comm_size(PETSC_COMM_WORLD, &num_procs); 00064 mNumProcessors = (unsigned) num_procs; 00065 00066 PetscInt my_rank; 00067 MPI_Comm_rank(PETSC_COMM_WORLD, &my_rank); 00068 mRank = (unsigned) my_rank; 00069 } 00070 else 00071 { 00072 // No PETSc 00073 mPetscIsInitialised = false; 00074 mNumProcessors = 1; 00075 mRank = 0; 00076 } 00077 } 00078 00079 // Information methods 00080 00081 bool PetscTools::IsSequential() 00082 { 00083 CheckCache(); 00084 return (mNumProcessors == 1); 00085 } 00086 00087 bool PetscTools::IsParallel() 00088 { 00089 CheckCache(); 00090 return (mNumProcessors > 1); 00091 } 00092 00093 unsigned PetscTools::GetNumProcs() 00094 { 00095 CheckCache(); 00096 return mNumProcessors; 00097 } 00098 00099 unsigned PetscTools::GetMyRank() 00100 { 00101 CheckCache(); 00102 return mRank; 00103 } 00104 00105 bool PetscTools::AmMaster() 00106 { 00107 CheckCache(); 00108 return (mRank == MASTER_RANK || mIsolateProcesses); 00109 } 00110 00111 bool PetscTools::AmTopMost() 00112 { 00113 CheckCache(); 00114 return (mRank == mNumProcessors - 1); 00115 } 00116 00117 // Little utility methods 00118 00119 void PetscTools::Barrier(const std::string callerId) 00120 { 00121 CheckCache(); 00122 if (mPetscIsInitialised && !mIsolateProcesses) 00123 { 00124 #ifdef DEBUG_BARRIERS 00125 std::cout << "DEBUG: proc " << PetscTools::GetMyRank() << ": Pre " << callerId << " Barrier " << mNumBarriers << "." << std::endl << std::flush; 00126 #endif 00127 PetscBarrier(PETSC_NULL); 00128 #ifdef DEBUG_BARRIERS 00129 std::cout << "DEBUG: proc " << PetscTools::GetMyRank() << ": Post " << callerId << " Barrier " << mNumBarriers++ << "." << std::endl << std::flush; 00130 #endif 00131 } 00132 } 00133 00134 void PetscTools::BeginRoundRobin() 00135 { 00136 Barrier("PetscTools::RoundRobin"); // We want barriers both before all and after all, just in case 00137 const unsigned my_rank = GetMyRank(); 00138 for (unsigned turn=0; turn<my_rank; turn++) 00139 { 00140 Barrier("PetscTools::RoundRobin"); 00141 } 00142 } 00143 00144 void PetscTools::EndRoundRobin() 00145 { 00146 const unsigned num_procs = GetNumProcs(); 00147 for (unsigned turn=GetMyRank(); turn<num_procs; turn++) 00148 { 00149 Barrier("PetscTools::RoundRobin"); 00150 } 00151 } 00152 00153 void PetscTools::IsolateProcesses(bool isolate) 00154 { 00155 mIsolateProcesses = isolate; 00156 } 00157 00158 bool PetscTools::ReplicateBool(bool flag) 00159 { 00160 CheckCache(); 00161 unsigned my_flag = (unsigned) flag; 00162 unsigned anyones_flag_is_true = my_flag; 00163 if (mPetscIsInitialised && !mIsolateProcesses) 00164 { 00165 MPI_Allreduce(&my_flag, &anyones_flag_is_true, 1, MPI_UNSIGNED, MPI_MAX, PETSC_COMM_WORLD); 00166 } 00167 return (anyones_flag_is_true == 1); 00168 } 00169 00170 void PetscTools::ReplicateException(bool flag) 00171 { 00172 bool anyones_error=ReplicateBool(flag); 00173 if (flag) 00174 { 00175 // Return control to exception thrower 00176 return; 00177 } 00178 if (anyones_error) 00179 { 00180 EXCEPTION("Another process threw an exception; bailing out."); 00181 } 00182 } 00183 00184 // Vector & matrix creation routines 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) //PETSc 3.x.x 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 if (PetscTools::IsSequential()) 00262 { 00263 MatSetType(rMat, MATSEQAIJ); 00264 if (rowPreallocation > 0) 00265 { 00266 MatSeqAIJSetPreallocation(rMat, rowPreallocation, PETSC_NULL); 00267 } 00268 } 00269 else 00270 { 00271 MatSetType(rMat, MATMPIAIJ); 00272 if (rowPreallocation > 0) 00273 { 00275 MatMPIAIJSetPreallocation(rMat, rowPreallocation, PETSC_NULL, (PetscInt) (rowPreallocation*0.7), PETSC_NULL); 00276 } 00277 } 00278 00279 MatSetFromOptions(rMat); 00280 00281 if (ignoreOffProcEntries)//&& IsParallel()) 00282 { 00283 if (rowPreallocation == 0) 00284 { 00285 // We aren't allowed to do non-zero allocation after setting MAT_IGNORE_OFF_PROC_ENTRIES 00286 WARNING("Ignoring MAT_IGNORE_OFF_PROC_ENTRIES flag because we might set non-zeroes later"); 00287 } 00288 else 00289 { 00290 #if (PETSC_VERSION_MAJOR == 3) //PETSc 3.x.x 00291 MatSetOption(rMat, MAT_IGNORE_OFF_PROC_ENTRIES, PETSC_TRUE); 00292 #else 00293 MatSetOption(rMat, MAT_IGNORE_OFF_PROC_ENTRIES); 00294 #endif 00295 } 00296 } 00297 } 00298 00299 void PetscTools::DumpPetscObject(const Mat& rMat, const std::string& rOutputFileFullPath) 00300 { 00301 PetscViewer view; 00302 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2 00303 PetscViewerFileType type = PETSC_FILE_CREATE; 00304 #else 00305 PetscFileMode type = FILE_MODE_WRITE; 00306 #endif 00307 00308 PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(), type, &view); 00309 MatView(rMat, view); 00310 PetscViewerDestroy(PETSC_DESTROY_PARAM(view)); 00311 } 00312 00313 void PetscTools::DumpPetscObject(const Vec& rVec, const std::string& rOutputFileFullPath) 00314 { 00315 PetscViewer view; 00316 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2 00317 PetscViewerFileType type = PETSC_FILE_CREATE; 00318 #else 00319 PetscFileMode type = FILE_MODE_WRITE; 00320 #endif 00321 00322 PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(), type, &view); 00323 VecView(rVec, view); 00324 PetscViewerDestroy(PETSC_DESTROY_PARAM(view)); 00325 } 00326 00327 void PetscTools::ReadPetscObject(Mat& rMat, const std::string& rOutputFileFullPath, Vec rParallelLayout) 00328 { 00329 /* 00330 * PETSc (as of 3.1) doesn't provide any method for loading a Mat object with a user-defined parallel 00331 * layout, i.e. there's no equivalent to VecLoadIntoVector for Mat's. 00332 * 00333 * It seems to be in their future plans though: http://lists.mcs.anl.gov/pipermail/petsc-users/2010-March/006062.html 00334 */ 00335 00336 PetscViewer view; 00337 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2 00338 PetscViewerFileType type = PETSC_FILE_RDONLY; 00339 #else 00340 PetscFileMode type = FILE_MODE_READ; 00341 #endif 00342 00343 PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(), 00344 type, &view); 00345 00346 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 2) //PETSc 3.2 or later 00347 MatCreate(PETSC_COMM_WORLD,&rMat); 00348 MatSetType(rMat,MATMPIAIJ); 00349 MatLoad(rMat,view); 00350 #else 00351 MatLoad(view, MATMPIAIJ, &rMat); 00352 #endif 00353 00354 PetscViewerDestroy(PETSC_DESTROY_PARAM(view)); 00355 00356 if (rParallelLayout != NULL) 00357 { 00358 /* 00359 * The idea is to copy rMat into a matrix that has the appropriate 00360 * parallel layout. Inefficient... 00361 */ 00362 PetscInt num_rows, num_local_rows; 00363 00364 VecGetSize(rParallelLayout, &num_rows); 00365 VecGetLocalSize(rParallelLayout, &num_local_rows); 00366 00367 Mat temp_mat; 00369 PetscTools::SetupMat(temp_mat, num_rows, num_rows, 100, num_local_rows, num_local_rows, false); 00370 00371 MatCopy(rMat, temp_mat, DIFFERENT_NONZERO_PATTERN); 00372 00373 PetscTools::Destroy(rMat); 00374 rMat = temp_mat; 00375 } 00376 } 00377 00378 void PetscTools::ReadPetscObject(Vec& rVec, const std::string& rOutputFileFullPath, Vec rParallelLayout) 00379 { 00380 PetscViewer view; 00381 #if (PETSC_VERSION_MAJOR == 2 && PETSC_VERSION_MINOR == 2) //PETSc 2.2 00382 PetscViewerFileType type = PETSC_FILE_RDONLY; 00383 #else 00384 PetscFileMode type = FILE_MODE_READ; 00385 #endif 00386 00387 PetscViewerBinaryOpen(PETSC_COMM_WORLD, rOutputFileFullPath.c_str(), 00388 type, &view); 00389 if (rParallelLayout == NULL) 00390 { 00391 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 2) //PETSc 3.2 or later 00392 VecCreate(PETSC_COMM_WORLD,&rVec); 00393 VecSetType(rVec,VECMPI); 00394 VecLoad(rVec,view); 00395 #else 00396 VecLoad(view, VECMPI, &rVec); 00397 #endif 00398 } 00399 else 00400 { 00401 VecDuplicate(rParallelLayout, &rVec); 00402 #if (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR >= 2) //PETSc 3.2 or later 00403 VecLoad(rVec,view); 00404 #else 00405 VecLoadIntoVector(view, rVec); 00406 #endif 00407 } 00408 PetscViewerDestroy(PETSC_DESTROY_PARAM(view)); 00409 } 00410 00411 bool PetscTools::HasParMetis() 00412 { 00413 #ifdef __INTEL_COMPILER 00414 //Old versions of the intel compiler can result in a PETSC ERROR and the program aborting if parmetis is checked for before 00415 //some other calls to Petsc are made. This nasty hack ensures that the HasParMetis method always works on Intel 00416 Mat mat; 00417 PetscTools::SetupMat(mat, 1, 1, 1); 00418 PetscTools::Destroy(mat); 00419 #endif 00420 00421 MatPartitioning part; 00422 MatPartitioningCreate(PETSC_COMM_WORLD, &part); 00423 00424 #if (PETSC_VERSION_MAJOR == 2 || (PETSC_VERSION_MAJOR == 3 && PETSC_VERSION_MINOR < 2)) 00425 PetscErrorCode parmetis_installed_error = MatPartitioningSetType(part,MAT_PARTITIONING_PARMETIS); 00426 #else 00427 PetscErrorCode parmetis_installed_error = MatPartitioningSetType(part,MATPARTITIONINGPARMETIS); 00428 #endif 00429 // Note that this method probably leaks memory inside PETSc because if MatPartitioningCreate fails 00430 // then there isn't a proper handle to destroy. 00431 MatPartitioningDestroy(PETSC_DESTROY_PARAM(part)); 00432 return (parmetis_installed_error == 0); 00433 } 00434 00435 00436