$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 // C++ includes 00020 #include <unistd.h> // mkstemp 00021 #include <fstream> 00022 00023 #include "libmesh/libmesh_config.h" 00024 00025 #ifdef LIBMESH_HAVE_PETSC 00026 00027 // Local includes 00028 #include "libmesh/petsc_matrix.h" 00029 #include "libmesh/dof_map.h" 00030 #include "libmesh/dense_matrix.h" 00031 #include "libmesh/petsc_vector.h" 00032 00033 00034 00035 // For some reason, the blocked matrix API calls below seem to break with PETSC 3.2 & presumably earier. 00036 // For example: 00037 // [0]PETSC ERROR: --------------------- Error Message ------------------------------------ 00038 // [0]PETSC ERROR: Nonconforming object sizes! 00039 // [0]PETSC ERROR: Attempt to set block size 3 with BAIJ 1! 00040 // [0]PETSC ERROR: ------------------------------------------------------------------------ 00041 // so as a cowardly workaround disable the functionality in this translation unit for older PETSc's 00042 #if PETSC_VERSION_LESS_THAN(3,3,0) 00043 # undef LIBMESH_ENABLE_BLOCKED_STORAGE 00044 #endif 00045 00046 00047 00048 #ifdef LIBMESH_ENABLE_BLOCKED_STORAGE 00049 00050 namespace 00051 { 00052 using namespace libMesh; 00053 00054 // historic libMesh n_nz & n_oz arrays are set up for PETSc's AIJ format. 00055 // however, when the blocksize is >1, we need to transform these into 00056 // their BAIJ counterparts. 00057 inline 00058 void transform_preallocation_arrays (const PetscInt blocksize, 00059 const std::vector<numeric_index_type> &n_nz, 00060 const std::vector<numeric_index_type> &n_oz, 00061 std::vector<numeric_index_type> &b_n_nz, 00062 std::vector<numeric_index_type> &b_n_oz) 00063 { 00064 libmesh_assert_equal_to (n_nz.size(), n_oz.size()); 00065 libmesh_assert_equal_to (n_nz.size()%blocksize, 0); 00066 00067 b_n_nz.clear(); b_n_nz.reserve(n_nz.size()/blocksize); 00068 b_n_oz.clear(); b_n_oz.reserve(n_oz.size()/blocksize); 00069 00070 for (unsigned int nn=0; nn<n_nz.size(); nn += blocksize) 00071 { 00072 b_n_nz.push_back (n_nz[nn]/blocksize); 00073 b_n_oz.push_back (n_oz[nn]/blocksize); 00074 } 00075 } 00076 } 00077 00078 #endif 00079 00080 00081 00082 namespace libMesh 00083 { 00084 00085 00086 //----------------------------------------------------------------------- 00087 // PetscMatrix members 00088 00089 00090 // Constructor 00091 template <typename T> 00092 PetscMatrix<T>::PetscMatrix(const Parallel::Communicator &comm_in) 00093 : SparseMatrix<T>(comm_in), 00094 _destroy_mat_on_exit(true) 00095 {} 00096 00097 00098 00099 // Constructor taking an existing Mat but not the responsibility 00100 // for destroying it 00101 template <typename T> 00102 PetscMatrix<T>::PetscMatrix(Mat mat_in, 00103 const Parallel::Communicator &comm_in) 00104 : SparseMatrix<T>(comm_in), 00105 _destroy_mat_on_exit(false) 00106 { 00107 this->_mat = mat_in; 00108 this->_is_initialized = true; 00109 } 00110 00111 00112 00113 // Destructor 00114 template <typename T> 00115 PetscMatrix<T>::~PetscMatrix() 00116 { 00117 this->clear(); 00118 } 00119 00120 00121 template <typename T> 00122 void PetscMatrix<T>::init (const numeric_index_type m_in, 00123 const numeric_index_type n_in, 00124 const numeric_index_type m_l, 00125 const numeric_index_type n_l, 00126 const numeric_index_type nnz, 00127 const numeric_index_type noz, 00128 const numeric_index_type blocksize_in) 00129 { 00130 // So compilers don't warn when !LIBMESH_ENABLE_BLOCKED_STORAGE 00131 libmesh_ignore(blocksize_in); 00132 00133 // Clear initialized matrices 00134 if (this->initialized()) 00135 this->clear(); 00136 00137 this->_is_initialized = true; 00138 00139 00140 PetscErrorCode ierr = 0; 00141 PetscInt m_global = static_cast<PetscInt>(m_in); 00142 PetscInt n_global = static_cast<PetscInt>(n_in); 00143 PetscInt m_local = static_cast<PetscInt>(m_l); 00144 PetscInt n_local = static_cast<PetscInt>(n_l); 00145 PetscInt n_nz = static_cast<PetscInt>(nnz); 00146 PetscInt n_oz = static_cast<PetscInt>(noz); 00147 00148 ierr = MatCreate(this->comm().get(), &_mat); 00149 LIBMESH_CHKERRABORT(ierr); 00150 ierr = MatSetSizes(_mat, m_local, n_local, m_global, n_global); 00151 LIBMESH_CHKERRABORT(ierr); 00152 00153 #ifdef LIBMESH_ENABLE_BLOCKED_STORAGE 00154 PetscInt blocksize = static_cast<PetscInt>(blocksize_in); 00155 if (blocksize > 1) 00156 { 00157 // specified blocksize, bs>1. 00158 // double check sizes. 00159 libmesh_assert_equal_to (m_local % blocksize, 0); 00160 libmesh_assert_equal_to (n_local % blocksize, 0); 00161 libmesh_assert_equal_to (m_global % blocksize, 0); 00162 libmesh_assert_equal_to (n_global % blocksize, 0); 00163 libmesh_assert_equal_to (n_nz % blocksize, 0); 00164 libmesh_assert_equal_to (n_oz % blocksize, 0); 00165 00166 ierr = MatSetType(_mat, MATBAIJ); // Automatically chooses seqbaij or mpibaij 00167 LIBMESH_CHKERRABORT(ierr); 00168 ierr = MatSetBlockSize(_mat, blocksize); 00169 LIBMESH_CHKERRABORT(ierr); 00170 ierr = MatSeqBAIJSetPreallocation(_mat, blocksize, n_nz/blocksize, PETSC_NULL); 00171 LIBMESH_CHKERRABORT(ierr); 00172 ierr = MatMPIBAIJSetPreallocation(_mat, blocksize, 00173 n_nz/blocksize, PETSC_NULL, 00174 n_oz/blocksize, PETSC_NULL); 00175 LIBMESH_CHKERRABORT(ierr); 00176 } 00177 else 00178 #endif 00179 { 00180 ierr = MatSetType(_mat, MATAIJ); // Automatically chooses seqaij or mpiaij 00181 LIBMESH_CHKERRABORT(ierr); 00182 ierr = MatSeqAIJSetPreallocation(_mat, n_nz, PETSC_NULL); 00183 LIBMESH_CHKERRABORT(ierr); 00184 ierr = MatMPIAIJSetPreallocation(_mat, n_nz, PETSC_NULL, n_oz, PETSC_NULL); 00185 LIBMESH_CHKERRABORT(ierr); 00186 } 00187 00188 // Make it an error for PETSc to allocate new nonzero entries during assembly 00189 #if PETSC_VERSION_LESS_THAN(3,0,0) 00190 ierr = MatSetOption(_mat, MAT_NEW_NONZERO_ALLOCATION_ERR); 00191 #else 00192 ierr = MatSetOption(_mat, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE); 00193 #endif 00194 LIBMESH_CHKERRABORT(ierr); 00195 00196 // Is prefix information available somewhere? Perhaps pass in the system name? 00197 ierr = MatSetOptionsPrefix(_mat, ""); 00198 LIBMESH_CHKERRABORT(ierr); 00199 ierr = MatSetFromOptions(_mat); 00200 LIBMESH_CHKERRABORT(ierr); 00201 00202 this->zero (); 00203 } 00204 00205 00206 template <typename T> 00207 void PetscMatrix<T>::init (const numeric_index_type m_in, 00208 const numeric_index_type n_in, 00209 const numeric_index_type m_l, 00210 const numeric_index_type n_l, 00211 const std::vector<numeric_index_type>& n_nz, 00212 const std::vector<numeric_index_type>& n_oz, 00213 const numeric_index_type blocksize_in) 00214 { 00215 // So compilers don't warn when !LIBMESH_ENABLE_BLOCKED_STORAGE 00216 libmesh_ignore(blocksize_in); 00217 00218 // Clear initialized matrices 00219 if (this->initialized()) 00220 this->clear(); 00221 00222 this->_is_initialized = true; 00223 00224 // Make sure the sparsity pattern isn't empty unless the matrix is 0x0 00225 libmesh_assert_equal_to (n_nz.size(), m_l); 00226 libmesh_assert_equal_to (n_oz.size(), m_l); 00227 00228 PetscErrorCode ierr = 0; 00229 PetscInt m_global = static_cast<PetscInt>(m_in); 00230 PetscInt n_global = static_cast<PetscInt>(n_in); 00231 PetscInt m_local = static_cast<PetscInt>(m_l); 00232 PetscInt n_local = static_cast<PetscInt>(n_l); 00233 00234 ierr = MatCreate(this->comm().get(), &_mat); 00235 LIBMESH_CHKERRABORT(ierr); 00236 ierr = MatSetSizes(_mat, m_local, n_local, m_global, n_global); 00237 LIBMESH_CHKERRABORT(ierr); 00238 00239 #ifdef LIBMESH_ENABLE_BLOCKED_STORAGE 00240 PetscInt blocksize = static_cast<PetscInt>(blocksize_in); 00241 if (blocksize > 1) 00242 { 00243 // specified blocksize, bs>1. 00244 // double check sizes. 00245 libmesh_assert_equal_to (m_local % blocksize, 0); 00246 libmesh_assert_equal_to (n_local % blocksize, 0); 00247 libmesh_assert_equal_to (m_global % blocksize, 0); 00248 libmesh_assert_equal_to (n_global % blocksize, 0); 00249 00250 ierr = MatSetType(_mat, MATBAIJ); // Automatically chooses seqbaij or mpibaij 00251 LIBMESH_CHKERRABORT(ierr); 00252 ierr = MatSetBlockSize(_mat, blocksize); 00253 LIBMESH_CHKERRABORT(ierr); 00254 00255 // transform the per-entry n_nz and n_oz arrays into their block counterparts. 00256 std::vector<numeric_index_type> b_n_nz, b_n_oz; 00257 00258 transform_preallocation_arrays (blocksize, 00259 n_nz, n_oz, 00260 b_n_nz, b_n_oz); 00261 00262 ierr = MatSeqBAIJSetPreallocation (_mat, 00263 blocksize, 00264 0, 00265 numeric_petsc_cast(b_n_nz.empty() ? NULL : &b_n_nz[0])); 00266 LIBMESH_CHKERRABORT(ierr); 00267 00268 ierr = MatMPIBAIJSetPreallocation (_mat, 00269 blocksize, 00270 0, 00271 numeric_petsc_cast(b_n_nz.empty() ? NULL : &b_n_nz[0]), 00272 0, 00273 numeric_petsc_cast(b_n_oz.empty() ? NULL : &b_n_oz[0])); 00274 LIBMESH_CHKERRABORT(ierr); 00275 } 00276 else 00277 #endif 00278 { 00279 00280 ierr = MatSetType(_mat, MATAIJ); // Automatically chooses seqaij or mpiaij 00281 LIBMESH_CHKERRABORT(ierr); 00282 ierr = MatSeqAIJSetPreallocation (_mat, 00283 0, 00284 numeric_petsc_cast(n_nz.empty() ? NULL : &n_nz[0])); 00285 LIBMESH_CHKERRABORT(ierr); 00286 ierr = MatMPIAIJSetPreallocation (_mat, 00287 0, 00288 numeric_petsc_cast(n_nz.empty() ? NULL : &n_nz[0]), 00289 0, 00290 numeric_petsc_cast(n_oz.empty() ? NULL : &n_oz[0])); 00291 LIBMESH_CHKERRABORT(ierr); 00292 } 00293 00294 // Is prefix information available somewhere? Perhaps pass in the system name? 00295 ierr = MatSetOptionsPrefix(_mat, ""); 00296 LIBMESH_CHKERRABORT(ierr); 00297 ierr = MatSetFromOptions(_mat); 00298 LIBMESH_CHKERRABORT(ierr); 00299 00300 00301 this->zero(); 00302 } 00303 00304 00305 template <typename T> 00306 void PetscMatrix<T>::init () 00307 { 00308 libmesh_assert(this->_dof_map); 00309 00310 // Clear initialized matrices 00311 if (this->initialized()) 00312 this->clear(); 00313 00314 this->_is_initialized = true; 00315 00316 00317 const numeric_index_type my_m = this->_dof_map->n_dofs(); 00318 const numeric_index_type my_n = my_m; 00319 const numeric_index_type n_l = this->_dof_map->n_dofs_on_processor(this->processor_id()); 00320 const numeric_index_type m_l = n_l; 00321 00322 00323 const std::vector<numeric_index_type>& n_nz = this->_dof_map->get_n_nz(); 00324 const std::vector<numeric_index_type>& n_oz = this->_dof_map->get_n_oz(); 00325 00326 // Make sure the sparsity pattern isn't empty unless the matrix is 0x0 00327 libmesh_assert_equal_to (n_nz.size(), m_l); 00328 libmesh_assert_equal_to (n_oz.size(), m_l); 00329 00330 PetscErrorCode ierr = 0; 00331 PetscInt m_global = static_cast<PetscInt>(my_m); 00332 PetscInt n_global = static_cast<PetscInt>(my_n); 00333 PetscInt m_local = static_cast<PetscInt>(m_l); 00334 PetscInt n_local = static_cast<PetscInt>(n_l); 00335 00336 ierr = MatCreate(this->comm().get(), &_mat); 00337 LIBMESH_CHKERRABORT(ierr); 00338 ierr = MatSetSizes(_mat, m_local, n_local, m_global, n_global); 00339 LIBMESH_CHKERRABORT(ierr); 00340 00341 #ifdef LIBMESH_ENABLE_BLOCKED_STORAGE 00342 PetscInt blocksize = static_cast<PetscInt>(this->_dof_map->block_size()); 00343 if (blocksize > 1) 00344 { 00345 // specified blocksize, bs>1. 00346 // double check sizes. 00347 libmesh_assert_equal_to (m_local % blocksize, 0); 00348 libmesh_assert_equal_to (n_local % blocksize, 0); 00349 libmesh_assert_equal_to (m_global % blocksize, 0); 00350 libmesh_assert_equal_to (n_global % blocksize, 0); 00351 00352 ierr = MatSetType(_mat, MATBAIJ); // Automatically chooses seqbaij or mpibaij 00353 LIBMESH_CHKERRABORT(ierr); 00354 ierr = MatSetBlockSize(_mat, blocksize); 00355 LIBMESH_CHKERRABORT(ierr); 00356 00357 // transform the per-entry n_nz and n_oz arrays into their block counterparts. 00358 std::vector<numeric_index_type> b_n_nz, b_n_oz; 00359 00360 transform_preallocation_arrays (blocksize, 00361 n_nz, n_oz, 00362 b_n_nz, b_n_oz); 00363 00364 ierr = MatSeqBAIJSetPreallocation (_mat, 00365 blocksize, 00366 0, 00367 numeric_petsc_cast(b_n_nz.empty() ? NULL : &b_n_nz[0])); 00368 LIBMESH_CHKERRABORT(ierr); 00369 00370 ierr = MatMPIBAIJSetPreallocation (_mat, 00371 blocksize, 00372 0, 00373 numeric_petsc_cast(b_n_nz.empty() ? NULL : &b_n_nz[0]), 00374 0, 00375 numeric_petsc_cast(b_n_oz.empty() ? NULL : &b_n_oz[0])); 00376 LIBMESH_CHKERRABORT(ierr); 00377 } 00378 else 00379 #endif 00380 { 00381 // no block storage case 00382 ierr = MatSetType(_mat, MATAIJ); // Automatically chooses seqaij or mpiaij 00383 LIBMESH_CHKERRABORT(ierr); 00384 00385 ierr = MatSeqAIJSetPreallocation (_mat, 00386 0, 00387 numeric_petsc_cast(n_nz.empty() ? NULL : &n_nz[0])); 00388 LIBMESH_CHKERRABORT(ierr); 00389 ierr = MatMPIAIJSetPreallocation (_mat, 00390 0, 00391 numeric_petsc_cast(n_nz.empty() ? NULL : &n_nz[0]), 00392 0, 00393 numeric_petsc_cast(n_oz.empty() ? NULL : &n_oz[0])); 00394 LIBMESH_CHKERRABORT(ierr); 00395 } 00396 00397 // Is prefix information available somewhere? Perhaps pass in the system name? 00398 ierr = MatSetOptionsPrefix(_mat, ""); 00399 LIBMESH_CHKERRABORT(ierr); 00400 ierr = MatSetFromOptions(_mat); 00401 LIBMESH_CHKERRABORT(ierr); 00402 00403 this->zero(); 00404 } 00405 00406 00407 00408 template <typename T> 00409 void PetscMatrix<T>::zero () 00410 { 00411 libmesh_assert (this->initialized()); 00412 00413 semiparallel_only(); 00414 00415 PetscErrorCode ierr=0; 00416 00417 PetscInt m_l, n_l; 00418 00419 ierr = MatGetLocalSize(_mat,&m_l,&n_l); 00420 LIBMESH_CHKERRABORT(ierr); 00421 00422 if (n_l) 00423 { 00424 ierr = MatZeroEntries(_mat); 00425 LIBMESH_CHKERRABORT(ierr); 00426 } 00427 } 00428 00429 template <typename T> 00430 void PetscMatrix<T>::zero_rows (std::vector<numeric_index_type> & rows, T diag_value) 00431 { 00432 libmesh_assert (this->initialized()); 00433 00434 semiparallel_only(); 00435 00436 PetscErrorCode ierr=0; 00437 00438 #if PETSC_RELEASE_LESS_THAN(3,1,1) 00439 if(!rows.empty()) 00440 ierr = MatZeroRows(_mat, rows.size(), 00441 numeric_petsc_cast(&rows[0]), diag_value); 00442 else 00443 ierr = MatZeroRows(_mat, 0, PETSC_NULL, diag_value); 00444 #else 00445 // As of petsc-dev at the time of 3.1.0, MatZeroRows now takes two additional 00446 // optional arguments. The optional arguments (x,b) can be used to specify the 00447 // solutions for the zeroed rows (x) and right hand side (b) to update. 00448 // Could be useful for setting boundary conditions... 00449 if(!rows.empty()) 00450 ierr = MatZeroRows(_mat, cast_int<PetscInt>(rows.size()), 00451 numeric_petsc_cast(&rows[0]), diag_value, 00452 PETSC_NULL, PETSC_NULL); 00453 else 00454 ierr = MatZeroRows(_mat, 0, PETSC_NULL, diag_value, PETSC_NULL, 00455 PETSC_NULL); 00456 #endif 00457 00458 LIBMESH_CHKERRABORT(ierr); 00459 } 00460 00461 template <typename T> 00462 void PetscMatrix<T>::clear () 00463 { 00464 PetscErrorCode ierr=0; 00465 00466 if ((this->initialized()) && (this->_destroy_mat_on_exit)) 00467 { 00468 semiparallel_only(); 00469 00470 ierr = LibMeshMatDestroy (&_mat); 00471 LIBMESH_CHKERRABORT(ierr); 00472 00473 this->_is_initialized = false; 00474 } 00475 } 00476 00477 00478 00479 template <typename T> 00480 Real PetscMatrix<T>::l1_norm () const 00481 { 00482 libmesh_assert (this->initialized()); 00483 00484 semiparallel_only(); 00485 00486 PetscErrorCode ierr=0; 00487 PetscReal petsc_value; 00488 Real value; 00489 00490 libmesh_assert (this->closed()); 00491 00492 ierr = MatNorm(_mat, NORM_1, &petsc_value); 00493 LIBMESH_CHKERRABORT(ierr); 00494 00495 value = static_cast<Real>(petsc_value); 00496 00497 return value; 00498 } 00499 00500 00501 00502 template <typename T> 00503 Real PetscMatrix<T>::linfty_norm () const 00504 { 00505 libmesh_assert (this->initialized()); 00506 00507 semiparallel_only(); 00508 00509 PetscErrorCode ierr=0; 00510 PetscReal petsc_value; 00511 Real value; 00512 00513 libmesh_assert (this->closed()); 00514 00515 ierr = MatNorm(_mat, NORM_INFINITY, &petsc_value); 00516 LIBMESH_CHKERRABORT(ierr); 00517 00518 value = static_cast<Real>(petsc_value); 00519 00520 return value; 00521 } 00522 00523 00524 00525 template <typename T> 00526 void PetscMatrix<T>::print_matlab (const std::string& name) const 00527 { 00528 libmesh_assert (this->initialized()); 00529 00530 semiparallel_only(); 00531 00532 // libmesh_assert (this->closed()); 00533 this->close(); 00534 00535 PetscErrorCode ierr=0; 00536 PetscViewer petsc_viewer; 00537 00538 00539 ierr = PetscViewerCreate (this->comm().get(), 00540 &petsc_viewer); 00541 LIBMESH_CHKERRABORT(ierr); 00542 00547 if (name != "") 00548 { 00549 ierr = PetscViewerASCIIOpen( this->comm().get(), 00550 name.c_str(), 00551 &petsc_viewer); 00552 LIBMESH_CHKERRABORT(ierr); 00553 00554 ierr = PetscViewerSetFormat (petsc_viewer, 00555 PETSC_VIEWER_ASCII_MATLAB); 00556 LIBMESH_CHKERRABORT(ierr); 00557 00558 ierr = MatView (_mat, petsc_viewer); 00559 LIBMESH_CHKERRABORT(ierr); 00560 } 00561 00565 else 00566 { 00567 ierr = PetscViewerSetFormat (PETSC_VIEWER_STDOUT_WORLD, 00568 PETSC_VIEWER_ASCII_MATLAB); 00569 LIBMESH_CHKERRABORT(ierr); 00570 00571 ierr = MatView (_mat, PETSC_VIEWER_STDOUT_WORLD); 00572 LIBMESH_CHKERRABORT(ierr); 00573 } 00574 00575 00579 ierr = LibMeshPetscViewerDestroy (&petsc_viewer); 00580 LIBMESH_CHKERRABORT(ierr); 00581 } 00582 00583 00584 00585 00586 00587 template <typename T> 00588 void PetscMatrix<T>::print_personal(std::ostream& os) const 00589 { 00590 libmesh_assert (this->initialized()); 00591 00592 // Routine must be called in parallel on parallel matrices 00593 // and serial on serial matrices. 00594 semiparallel_only(); 00595 00596 // #ifndef NDEBUG 00597 // if (os != std::cout) 00598 // libMesh::err << "Warning! PETSc can only print to std::cout!" << std::endl; 00599 // #endif 00600 00601 // Matrix must be in an assembled state to be printed 00602 this->close(); 00603 00604 PetscErrorCode ierr=0; 00605 00606 // Print to screen if ostream is stdout 00607 if (os.rdbuf() == std::cout.rdbuf()) 00608 { 00609 ierr = MatView(_mat, PETSC_VIEWER_STDOUT_SELF); 00610 LIBMESH_CHKERRABORT(ierr); 00611 } 00612 00613 // Otherwise, print to the requested file, in a roundabout way... 00614 else 00615 { 00616 // We will create a temporary filename, and file, for PETSc to 00617 // write to. 00618 std::string temp_filename; 00619 00620 { 00621 // Template for temporary filename 00622 char c[] = "temp_petsc_matrix.XXXXXX"; 00623 00624 // Generate temporary, unique filename only on processor 0. We will 00625 // use this filename for PetscViewerASCIIOpen, before copying it into 00626 // the user's stream 00627 if (this->processor_id() == 0) 00628 { 00629 int fd = mkstemp(c); 00630 00631 // Check to see that mkstemp did not fail. 00632 if (fd == -1) 00633 libmesh_error_msg("mkstemp failed in PetscMatrix::print_personal()"); 00634 00635 // mkstemp returns a file descriptor for an open file, 00636 // so let's close it before we hand it to PETSc! 00637 ::close (fd); 00638 } 00639 00640 // Store temporary filename as string, makes it easier to broadcast 00641 temp_filename = c; 00642 } 00643 00644 // Now broadcast the filename from processor 0 to all processors. 00645 this->comm().broadcast(temp_filename); 00646 00647 // PetscViewer object for passing to MatView 00648 PetscViewer petsc_viewer; 00649 00650 // This PETSc function only takes a string and handles the opening/closing 00651 // of the file internally. Since print_personal() takes a reference to 00652 // an ostream, we have to do an extra step... print_personal() should probably 00653 // have a version that takes a string to get rid of this problem. 00654 ierr = PetscViewerASCIIOpen( this->comm().get(), 00655 temp_filename.c_str(), 00656 &petsc_viewer); 00657 LIBMESH_CHKERRABORT(ierr); 00658 00659 // Probably don't need to set the format if it's default... 00660 // ierr = PetscViewerSetFormat (petsc_viewer, 00661 // PETSC_VIEWER_DEFAULT); 00662 // LIBMESH_CHKERRABORT(ierr); 00663 00664 // Finally print the matrix using the viewer 00665 ierr = MatView (_mat, petsc_viewer); 00666 LIBMESH_CHKERRABORT(ierr); 00667 00668 if (this->processor_id() == 0) 00669 { 00670 // Now the inefficient bit: open temp_filename as an ostream and copy the contents 00671 // into the user's desired ostream. We can't just do a direct file copy, we don't even have the filename! 00672 std::ifstream input_stream(temp_filename.c_str()); 00673 os << input_stream.rdbuf(); // The "most elegant" way to copy one stream into another. 00674 // os.close(); // close not defined in ostream 00675 00676 // Now remove the temporary file 00677 input_stream.close(); 00678 std::remove(temp_filename.c_str()); 00679 } 00680 } 00681 } 00682 00683 00684 00685 00686 00687 00688 template <typename T> 00689 void PetscMatrix<T>::add_matrix(const DenseMatrix<T>& dm, 00690 const std::vector<numeric_index_type>& rows, 00691 const std::vector<numeric_index_type>& cols) 00692 { 00693 libmesh_assert (this->initialized()); 00694 00695 const numeric_index_type n_rows = dm.m(); 00696 const numeric_index_type n_cols = dm.n(); 00697 00698 libmesh_assert_equal_to (rows.size(), n_rows); 00699 libmesh_assert_equal_to (cols.size(), n_cols); 00700 00701 PetscErrorCode ierr=0; 00702 00703 // These casts are required for PETSc <= 2.1.5 00704 ierr = MatSetValues(_mat, 00705 n_rows, numeric_petsc_cast(&rows[0]), 00706 n_cols, numeric_petsc_cast(&cols[0]), 00707 const_cast<PetscScalar*>(&dm.get_values()[0]), 00708 ADD_VALUES); 00709 LIBMESH_CHKERRABORT(ierr); 00710 } 00711 00712 00713 00714 00715 00716 00717 template <typename T> 00718 void PetscMatrix<T>::add_block_matrix(const DenseMatrix<T>& dm, 00719 const std::vector<numeric_index_type>& brows, 00720 const std::vector<numeric_index_type>& bcols) 00721 { 00722 libmesh_assert (this->initialized()); 00723 00724 const numeric_index_type n_brows = 00725 cast_int<numeric_index_type>(brows.size()); 00726 const numeric_index_type n_bcols = 00727 cast_int<numeric_index_type>(bcols.size()); 00728 00729 PetscErrorCode ierr=0; 00730 00731 #ifndef NDEBUG 00732 const numeric_index_type n_rows = 00733 cast_int<numeric_index_type>(dm.m()); 00734 const numeric_index_type n_cols = 00735 cast_int<numeric_index_type>(dm.n()); 00736 const numeric_index_type blocksize = n_rows / n_brows; 00737 00738 libmesh_assert_equal_to (n_cols / n_bcols, blocksize); 00739 libmesh_assert_equal_to (blocksize*n_brows, n_rows); 00740 libmesh_assert_equal_to (blocksize*n_bcols, n_cols); 00741 00742 PetscInt petsc_blocksize; 00743 ierr = MatGetBlockSize(_mat, &petsc_blocksize); 00744 LIBMESH_CHKERRABORT(ierr); 00745 libmesh_assert_equal_to (blocksize, static_cast<numeric_index_type>(petsc_blocksize)); 00746 #endif 00747 00748 // These casts are required for PETSc <= 2.1.5 00749 ierr = MatSetValuesBlocked(_mat, 00750 n_brows, numeric_petsc_cast(&brows[0]), 00751 n_bcols, numeric_petsc_cast(&bcols[0]), 00752 const_cast<PetscScalar*>(&dm.get_values()[0]), 00753 ADD_VALUES); 00754 LIBMESH_CHKERRABORT(ierr); 00755 } 00756 00757 00758 00759 00760 00761 template <typename T> 00762 void PetscMatrix<T>::_get_submatrix(SparseMatrix<T>& submatrix, 00763 const std::vector<numeric_index_type> &rows, 00764 const std::vector<numeric_index_type> &cols, 00765 const bool reuse_submatrix) const 00766 { 00767 // Can only extract submatrices from closed matrices 00768 this->close(); 00769 00770 // Make sure the SparseMatrix passed in is really a PetscMatrix 00771 PetscMatrix<T>* petsc_submatrix = cast_ptr<PetscMatrix<T>*>(&submatrix); 00772 00773 // If we're not reusing submatrix and submatrix is already initialized 00774 // then we need to clear it, otherwise we get a memory leak. 00775 if( !reuse_submatrix && submatrix.initialized() ) 00776 submatrix.clear(); 00777 00778 // Construct row and column index sets. 00779 PetscErrorCode ierr=0; 00780 IS isrow, iscol; 00781 00782 ierr = ISCreateLibMesh(this->comm().get(), 00783 rows.size(), 00784 numeric_petsc_cast(&rows[0]), 00785 PETSC_USE_POINTER, 00786 &isrow); LIBMESH_CHKERRABORT(ierr); 00787 00788 ierr = ISCreateLibMesh(this->comm().get(), 00789 cols.size(), 00790 numeric_petsc_cast(&cols[0]), 00791 PETSC_USE_POINTER, 00792 &iscol); LIBMESH_CHKERRABORT(ierr); 00793 00794 // Extract submatrix 00795 ierr = MatGetSubMatrix(_mat, 00796 isrow, 00797 iscol, 00798 #if PETSC_RELEASE_LESS_THAN(3,0,1) 00799 PETSC_DECIDE, 00800 #endif 00801 (reuse_submatrix ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX), 00802 &(petsc_submatrix->_mat)); LIBMESH_CHKERRABORT(ierr); 00803 00804 // Specify that the new submatrix is initialized and close it. 00805 petsc_submatrix->_is_initialized = true; 00806 petsc_submatrix->close(); 00807 00808 // Clean up PETSc data structures 00809 ierr = LibMeshISDestroy(&isrow); LIBMESH_CHKERRABORT(ierr); 00810 ierr = LibMeshISDestroy(&iscol); LIBMESH_CHKERRABORT(ierr); 00811 } 00812 00813 00814 00815 template <typename T> 00816 void PetscMatrix<T>::get_diagonal (NumericVector<T>& dest) const 00817 { 00818 // Make sure the NumericVector passed in is really a PetscVector 00819 PetscVector<T>& petsc_dest = cast_ref<PetscVector<T>&>(dest); 00820 00821 // Call PETSc function. 00822 00823 #if PETSC_VERSION_LESS_THAN(2,3,1) 00824 00825 libmesh_error_msg("This method has been developed with PETSc 2.3.1. " \ 00826 << "No one has made it backwards compatible with older " \ 00827 << "versions of PETSc so far; however, it might work " \ 00828 << "without any change with some older version."); 00829 00830 #else 00831 00832 // Needs a const_cast since PETSc does not work with const. 00833 PetscErrorCode ierr = 00834 MatGetDiagonal(const_cast<PetscMatrix<T>*>(this)->mat(),petsc_dest.vec()); LIBMESH_CHKERRABORT(ierr); 00835 00836 #endif 00837 00838 } 00839 00840 00841 00842 template <typename T> 00843 void PetscMatrix<T>::get_transpose (SparseMatrix<T>& dest) const 00844 { 00845 // Make sure the SparseMatrix passed in is really a PetscMatrix 00846 PetscMatrix<T>& petsc_dest = cast_ref<PetscMatrix<T>&>(dest); 00847 00848 // If we aren't reusing the matrix then need to clear dest, 00849 // otherwise we get a memory leak 00850 if(&petsc_dest != this) 00851 dest.clear(); 00852 00853 PetscErrorCode ierr; 00854 #if PETSC_VERSION_LESS_THAN(3,0,0) 00855 if (&petsc_dest == this) 00856 ierr = MatTranspose(_mat,PETSC_NULL); 00857 else 00858 ierr = MatTranspose(_mat,&petsc_dest._mat); 00859 LIBMESH_CHKERRABORT(ierr); 00860 #else 00861 // FIXME - we can probably use MAT_REUSE_MATRIX in more situations 00862 if (&petsc_dest == this) 00863 ierr = MatTranspose(_mat,MAT_REUSE_MATRIX,&petsc_dest._mat); 00864 else 00865 ierr = MatTranspose(_mat,MAT_INITIAL_MATRIX,&petsc_dest._mat); 00866 LIBMESH_CHKERRABORT(ierr); 00867 #endif 00868 00869 // Specify that the transposed matrix is initialized and close it. 00870 petsc_dest._is_initialized = true; 00871 petsc_dest.close(); 00872 } 00873 00874 00875 00876 00877 00878 template <typename T> 00879 void PetscMatrix<T>::close () const 00880 { 00881 semiparallel_only(); 00882 00883 // BSK - 1/19/2004 00884 // strictly this check should be OK, but it seems to 00885 // fail on matrix-free matrices. Do they falsely 00886 // state they are assembled? Check with the developers... 00887 // if (this->closed()) 00888 // return; 00889 00890 PetscErrorCode ierr=0; 00891 00892 ierr = MatAssemblyBegin (_mat, MAT_FINAL_ASSEMBLY); 00893 LIBMESH_CHKERRABORT(ierr); 00894 ierr = MatAssemblyEnd (_mat, MAT_FINAL_ASSEMBLY); 00895 LIBMESH_CHKERRABORT(ierr); 00896 } 00897 00898 00899 00900 template <typename T> 00901 numeric_index_type PetscMatrix<T>::m () const 00902 { 00903 libmesh_assert (this->initialized()); 00904 00905 PetscInt petsc_m=0, petsc_n=0; 00906 PetscErrorCode ierr=0; 00907 00908 ierr = MatGetSize (_mat, &petsc_m, &petsc_n); 00909 LIBMESH_CHKERRABORT(ierr); 00910 00911 return static_cast<numeric_index_type>(petsc_m); 00912 } 00913 00914 00915 00916 template <typename T> 00917 numeric_index_type PetscMatrix<T>::n () const 00918 { 00919 libmesh_assert (this->initialized()); 00920 00921 PetscInt petsc_m=0, petsc_n=0; 00922 PetscErrorCode ierr=0; 00923 00924 ierr = MatGetSize (_mat, &petsc_m, &petsc_n); 00925 LIBMESH_CHKERRABORT(ierr); 00926 00927 return static_cast<numeric_index_type>(petsc_n); 00928 } 00929 00930 00931 00932 template <typename T> 00933 numeric_index_type PetscMatrix<T>::row_start () const 00934 { 00935 libmesh_assert (this->initialized()); 00936 00937 PetscInt start=0, stop=0; 00938 PetscErrorCode ierr=0; 00939 00940 ierr = MatGetOwnershipRange(_mat, &start, &stop); 00941 LIBMESH_CHKERRABORT(ierr); 00942 00943 return static_cast<numeric_index_type>(start); 00944 } 00945 00946 00947 00948 template <typename T> 00949 numeric_index_type PetscMatrix<T>::row_stop () const 00950 { 00951 libmesh_assert (this->initialized()); 00952 00953 PetscInt start=0, stop=0; 00954 PetscErrorCode ierr=0; 00955 00956 ierr = MatGetOwnershipRange(_mat, &start, &stop); 00957 LIBMESH_CHKERRABORT(ierr); 00958 00959 return static_cast<numeric_index_type>(stop); 00960 } 00961 00962 00963 00964 template <typename T> 00965 void PetscMatrix<T>::set (const numeric_index_type i, 00966 const numeric_index_type j, 00967 const T value) 00968 { 00969 libmesh_assert (this->initialized()); 00970 00971 PetscErrorCode ierr=0; 00972 PetscInt i_val=i, j_val=j; 00973 00974 PetscScalar petsc_value = static_cast<PetscScalar>(value); 00975 ierr = MatSetValues(_mat, 1, &i_val, 1, &j_val, 00976 &petsc_value, INSERT_VALUES); 00977 LIBMESH_CHKERRABORT(ierr); 00978 } 00979 00980 00981 00982 template <typename T> 00983 void PetscMatrix<T>::add (const numeric_index_type i, 00984 const numeric_index_type j, 00985 const T value) 00986 { 00987 libmesh_assert (this->initialized()); 00988 00989 PetscErrorCode ierr=0; 00990 PetscInt i_val=i, j_val=j; 00991 00992 PetscScalar petsc_value = static_cast<PetscScalar>(value); 00993 ierr = MatSetValues(_mat, 1, &i_val, 1, &j_val, 00994 &petsc_value, ADD_VALUES); 00995 LIBMESH_CHKERRABORT(ierr); 00996 } 00997 00998 00999 01000 template <typename T> 01001 void PetscMatrix<T>::add_matrix(const DenseMatrix<T>& dm, 01002 const std::vector<numeric_index_type>& dof_indices) 01003 { 01004 this->add_matrix (dm, dof_indices, dof_indices); 01005 } 01006 01007 01008 01009 01010 01011 01012 01013 template <typename T> 01014 void PetscMatrix<T>::add (const T a_in, SparseMatrix<T> &X_in) 01015 { 01016 libmesh_assert (this->initialized()); 01017 01018 // sanity check. but this cannot avoid 01019 // crash due to incompatible sparsity structure... 01020 libmesh_assert_equal_to (this->m(), X_in.m()); 01021 libmesh_assert_equal_to (this->n(), X_in.n()); 01022 01023 PetscScalar a = static_cast<PetscScalar> (a_in); 01024 PetscMatrix<T>* X = cast_ptr<PetscMatrix<T>*> (&X_in); 01025 01026 libmesh_assert (X); 01027 01028 PetscErrorCode ierr=0; 01029 01030 // the matrix from which we copy the values has to be assembled/closed 01031 // X->close (); 01032 libmesh_assert(X->closed()); 01033 01034 semiparallel_only(); 01035 01036 // 2.2.x & earlier style 01037 #if PETSC_VERSION_LESS_THAN(2,3,0) 01038 01039 ierr = MatAXPY(&a, X->_mat, _mat, SAME_NONZERO_PATTERN); 01040 LIBMESH_CHKERRABORT(ierr); 01041 01042 // 2.3.x & newer 01043 #else 01044 01045 ierr = MatAXPY(_mat, a, X->_mat, DIFFERENT_NONZERO_PATTERN); 01046 LIBMESH_CHKERRABORT(ierr); 01047 01048 #endif 01049 } 01050 01051 01052 01053 01054 template <typename T> 01055 T PetscMatrix<T>::operator () (const numeric_index_type i_in, 01056 const numeric_index_type j_in) const 01057 { 01058 libmesh_assert (this->initialized()); 01059 01060 #if PETSC_VERSION_LESS_THAN(2,2,1) 01061 01062 // PETSc 2.2.0 & older 01063 PetscScalar *petsc_row; 01064 int* petsc_cols; 01065 01066 #else 01067 01068 // PETSc 2.2.1 & newer 01069 const PetscScalar *petsc_row; 01070 const PetscInt *petsc_cols; 01071 01072 #endif 01073 01074 01075 // If the entry is not in the sparse matrix, it is 0. 01076 T value=0.; 01077 01078 PetscErrorCode 01079 ierr=0; 01080 PetscInt 01081 ncols=0, 01082 i_val=static_cast<PetscInt>(i_in), 01083 j_val=static_cast<PetscInt>(j_in); 01084 01085 01086 // the matrix needs to be closed for this to work 01087 // this->close(); 01088 // but closing it is a semiparallel operation; we want operator() 01089 // to run on one processor. 01090 libmesh_assert(this->closed()); 01091 01092 ierr = MatGetRow(_mat, i_val, &ncols, &petsc_cols, &petsc_row); 01093 LIBMESH_CHKERRABORT(ierr); 01094 01095 // Perform a binary search to find the contiguous index in 01096 // petsc_cols (resp. petsc_row) corresponding to global index j_val 01097 std::pair<const PetscInt*, const PetscInt*> p = 01098 std::equal_range (&petsc_cols[0], &petsc_cols[0] + ncols, j_val); 01099 01100 // Found an entry for j_val 01101 if (p.first != p.second) 01102 { 01103 // The entry in the contiguous row corresponding 01104 // to the j_val column of interest 01105 const std::size_t j = 01106 std::distance (const_cast<PetscInt*>(&petsc_cols[0]), 01107 const_cast<PetscInt*>(p.first)); 01108 01109 libmesh_assert_less (static_cast<PetscInt>(j), ncols); 01110 libmesh_assert_equal_to (petsc_cols[j], j_val); 01111 01112 value = static_cast<T> (petsc_row[j]); 01113 } 01114 01115 ierr = MatRestoreRow(_mat, i_val, 01116 &ncols, &petsc_cols, &petsc_row); 01117 LIBMESH_CHKERRABORT(ierr); 01118 01119 return value; 01120 } 01121 01122 01123 01124 01125 template <typename T> 01126 bool PetscMatrix<T>::closed() const 01127 { 01128 libmesh_assert (this->initialized()); 01129 01130 PetscErrorCode ierr=0; 01131 PetscBool assembled; 01132 01133 ierr = MatAssembled(_mat, &assembled); 01134 LIBMESH_CHKERRABORT(ierr); 01135 01136 return (assembled == PETSC_TRUE); 01137 } 01138 01139 01140 01141 template <typename T> 01142 void PetscMatrix<T>::swap(PetscMatrix<T> &m_in) 01143 { 01144 std::swap(_mat, m_in._mat); 01145 std::swap(_destroy_mat_on_exit, m_in._destroy_mat_on_exit); 01146 } 01147 01148 01149 01150 //------------------------------------------------------------------ 01151 // Explicit instantiations 01152 template class PetscMatrix<Number>; 01153 01154 } // namespace libMesh 01155 01156 01157 #endif // #ifdef LIBMESH_HAVE_PETSC