petsc_matrix.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 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 00022 #include "libmesh/libmesh_config.h" 00023 00024 #ifdef LIBMESH_HAVE_PETSC 00025 00026 // Local includes 00027 #include "libmesh/petsc_matrix.h" 00028 #include "libmesh/dof_map.h" 00029 #include "libmesh/dense_matrix.h" 00030 #include "libmesh/petsc_vector.h" 00031 00032 namespace libMesh 00033 { 00034 00035 00036 //----------------------------------------------------------------------- 00037 // PetscMatrix members 00038 00039 00040 // Constructor 00041 template <typename T> 00042 PetscMatrix<T>::PetscMatrix() 00043 : _destroy_mat_on_exit(true) 00044 {} 00045 00046 00047 00048 // Constructor taking an existing Mat but not the responsibility 00049 // for destroying it 00050 template <typename T> 00051 PetscMatrix<T>::PetscMatrix(Mat mat_in) 00052 : _destroy_mat_on_exit(false) 00053 { 00054 this->_mat = mat_in; 00055 this->_is_initialized = true; 00056 } 00057 00058 00059 00060 // Destructor 00061 template <typename T> 00062 PetscMatrix<T>::~PetscMatrix() 00063 { 00064 this->clear(); 00065 } 00066 00067 00068 template <typename T> 00069 void PetscMatrix<T>::init (const numeric_index_type m_in, 00070 const numeric_index_type n_in, 00071 const numeric_index_type m_l, 00072 const numeric_index_type n_l, 00073 const numeric_index_type nnz, 00074 const numeric_index_type noz) 00075 { 00076 // We allow 0x0 matrices now 00077 //if ((m_in==0) || (n_in==0)) 00078 // return; 00079 00080 // Clear initialized matrices 00081 if (this->initialized()) 00082 this->clear(); 00083 00084 this->_is_initialized = true; 00085 00086 00087 PetscErrorCode ierr = 0; 00088 PetscInt m_global = static_cast<PetscInt>(m_in); 00089 PetscInt n_global = static_cast<PetscInt>(n_in); 00090 PetscInt m_local = static_cast<PetscInt>(m_l); 00091 PetscInt n_local = static_cast<PetscInt>(n_l); 00092 PetscInt n_nz = static_cast<PetscInt>(nnz); 00093 PetscInt n_oz = static_cast<PetscInt>(noz); 00094 00095 ierr = MatCreate(libMesh::COMM_WORLD, &_mat); 00096 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00097 ierr = MatSetSizes(_mat, m_local, n_local, m_global, n_global); 00098 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00099 ierr = MatSetType(_mat, MATAIJ); // Automatically chooses seqaij or mpiaij 00100 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00101 00102 // Make it an error for PETSc to allocate new nonzero entries during assembly 00103 #if PETSC_VERSION_LESS_THAN(3,0,0) 00104 ierr = MatSetOption(_mat, MAT_NEW_NONZERO_ALLOCATION_ERR); 00105 #else 00106 ierr = MatSetOption(_mat, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE); 00107 #endif 00108 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00109 00110 // Is prefix information available somewhere? Perhaps pass in the system name? 00111 ierr = MatSetOptionsPrefix(_mat, ""); 00112 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00113 ierr = MatSetFromOptions(_mat); 00114 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00115 ierr = MatSeqAIJSetPreallocation(_mat, n_nz, PETSC_NULL); 00116 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00117 ierr = MatMPIAIJSetPreallocation(_mat, n_nz, PETSC_NULL, n_oz, PETSC_NULL); 00118 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00119 00120 this->zero (); 00121 } 00122 00123 00124 template <typename T> 00125 void PetscMatrix<T>::init (const numeric_index_type m_in, 00126 const numeric_index_type n_in, 00127 const numeric_index_type m_l, 00128 const numeric_index_type n_l, 00129 const std::vector<numeric_index_type>& n_nz, 00130 const std::vector<numeric_index_type>& n_oz) 00131 { 00132 // Clear initialized matrices 00133 if (this->initialized()) 00134 this->clear(); 00135 00136 this->_is_initialized = true; 00137 00138 // Make sure the sparsity pattern isn't empty unless the matrix is 0x0 00139 libmesh_assert_equal_to (n_nz.size(), m_l); 00140 libmesh_assert_equal_to (n_oz.size(), m_l); 00141 00142 PetscErrorCode ierr = 0; 00143 PetscInt m_global = static_cast<PetscInt>(m_in); 00144 PetscInt n_global = static_cast<PetscInt>(n_in); 00145 PetscInt m_local = static_cast<PetscInt>(m_l); 00146 PetscInt n_local = static_cast<PetscInt>(n_l); 00147 00148 ierr = MatCreate(libMesh::COMM_WORLD, &_mat); 00149 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00150 ierr = MatSetSizes(_mat, m_local, n_local, m_global, n_global); 00151 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00152 ierr = MatSetType(_mat, MATAIJ); // Automatically chooses seqaij or mpiaij 00153 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00154 // Is prefix information available somewhere? Perhaps pass in the system name? 00155 ierr = MatSetOptionsPrefix(_mat, ""); 00156 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00157 ierr = MatSetFromOptions(_mat); 00158 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00159 00160 ierr = MatSeqAIJSetPreallocation(_mat, 0, (PetscInt*)(n_nz.empty()?NULL:&n_nz[0])); 00161 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00162 ierr = MatMPIAIJSetPreallocation(_mat, 0, (PetscInt*)(n_nz.empty()?NULL:&n_nz[0]), 00163 0, (PetscInt*)(n_oz.empty()?NULL:&n_oz[0])); 00164 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00165 00166 this->zero(); 00167 } 00168 00169 00170 template <typename T> 00171 void PetscMatrix<T>::init () 00172 { 00173 libmesh_assert(this->_dof_map); 00174 00175 // Clear initialized matrices 00176 if (this->initialized()) 00177 this->clear(); 00178 00179 this->_is_initialized = true; 00180 00181 00182 const numeric_index_type my_m = this->_dof_map->n_dofs(); 00183 const numeric_index_type my_n = my_m; 00184 const numeric_index_type n_l = this->_dof_map->n_dofs_on_processor(libMesh::processor_id()); 00185 const numeric_index_type m_l = n_l; 00186 00187 00188 const std::vector<numeric_index_type>& n_nz = this->_dof_map->get_n_nz(); 00189 const std::vector<numeric_index_type>& n_oz = this->_dof_map->get_n_oz(); 00190 00191 // Make sure the sparsity pattern isn't empty unless the matrix is 0x0 00192 libmesh_assert_equal_to (n_nz.size(), m_l); 00193 libmesh_assert_equal_to (n_oz.size(), m_l); 00194 00195 // We allow 0x0 matrices now 00196 //if (my_m==0) 00197 // return; 00198 00199 PetscErrorCode ierr = 0; 00200 PetscInt m_global = static_cast<PetscInt>(my_m); 00201 PetscInt n_global = static_cast<PetscInt>(my_n); 00202 PetscInt m_local = static_cast<PetscInt>(m_l); 00203 PetscInt n_local = static_cast<PetscInt>(n_l); 00204 00205 ierr = MatCreate(libMesh::COMM_WORLD, &_mat); 00206 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00207 ierr = MatSetSizes(_mat, m_local, n_local, m_global, n_global); 00208 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00209 ierr = MatSetType(_mat, MATAIJ); // Automatically chooses seqaij or mpiaij 00210 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00211 // Is prefix information available somewhere? Perhaps pass in the system name? 00212 ierr = MatSetOptionsPrefix(_mat, ""); 00213 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00214 ierr = MatSetFromOptions(_mat); 00215 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00216 00217 ierr = MatSeqAIJSetPreallocation(_mat, 0, (PetscInt*)(n_nz.empty()?NULL:&n_nz[0])); 00218 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00219 ierr = MatMPIAIJSetPreallocation(_mat, 0, (PetscInt*)(n_nz.empty()?NULL:&n_nz[0]), 00220 0, (PetscInt*)(n_oz.empty()?NULL:&n_oz[0])); 00221 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00222 00223 this->zero(); 00224 } 00225 00226 00227 00228 template <typename T> 00229 void PetscMatrix<T>::zero () 00230 { 00231 libmesh_assert (this->initialized()); 00232 00233 semiparallel_only(); 00234 00235 PetscErrorCode ierr=0; 00236 00237 PetscInt m_l, n_l; 00238 00239 ierr = MatGetLocalSize(_mat,&m_l,&n_l); 00240 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00241 00242 if (n_l) 00243 { 00244 ierr = MatZeroEntries(_mat); 00245 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00246 } 00247 } 00248 00249 template <typename T> 00250 void PetscMatrix<T>::zero_rows (std::vector<numeric_index_type> & rows, T diag_value) 00251 { 00252 libmesh_assert (this->initialized()); 00253 00254 semiparallel_only(); 00255 00256 PetscErrorCode ierr=0; 00257 00258 #if PETSC_VERSION_RELEASE && PETSC_VERSION_LESS_THAN(3,1,1) 00259 if(!rows.empty()) 00260 ierr = MatZeroRows(_mat, rows.size(), (PetscInt*)&rows[0], diag_value); 00261 else 00262 ierr = MatZeroRows(_mat, 0, PETSC_NULL, diag_value); 00263 #else 00264 // As of petsc-dev at the time of 3.1.0, MatZeroRows now takes two additional 00265 // optional arguments. The optional arguments (x,b) can be used to specify the 00266 // solutions for the zeroed rows (x) and right hand side (b) to update. 00267 // Could be useful for setting boundary conditions... 00268 if(!rows.empty()) 00269 ierr = MatZeroRows(_mat, rows.size(), (PetscInt*)&rows[0], diag_value, PETSC_NULL, PETSC_NULL); 00270 else 00271 ierr = MatZeroRows(_mat, 0, PETSC_NULL, diag_value, PETSC_NULL, PETSC_NULL); 00272 #endif 00273 00274 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00275 } 00276 00277 template <typename T> 00278 void PetscMatrix<T>::clear () 00279 { 00280 PetscErrorCode ierr=0; 00281 00282 if ((this->initialized()) && (this->_destroy_mat_on_exit)) 00283 { 00284 semiparallel_only(); 00285 00286 ierr = LibMeshMatDestroy (&_mat); 00287 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00288 00289 this->_is_initialized = false; 00290 } 00291 } 00292 00293 00294 00295 template <typename T> 00296 Real PetscMatrix<T>::l1_norm () const 00297 { 00298 libmesh_assert (this->initialized()); 00299 00300 semiparallel_only(); 00301 00302 PetscErrorCode ierr=0; 00303 PetscReal petsc_value; 00304 Real value; 00305 00306 libmesh_assert (this->closed()); 00307 00308 ierr = MatNorm(_mat, NORM_1, &petsc_value); 00309 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00310 00311 value = static_cast<Real>(petsc_value); 00312 00313 return value; 00314 } 00315 00316 00317 00318 template <typename T> 00319 Real PetscMatrix<T>::linfty_norm () const 00320 { 00321 libmesh_assert (this->initialized()); 00322 00323 semiparallel_only(); 00324 00325 PetscErrorCode ierr=0; 00326 PetscReal petsc_value; 00327 Real value; 00328 00329 libmesh_assert (this->closed()); 00330 00331 ierr = MatNorm(_mat, NORM_INFINITY, &petsc_value); 00332 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00333 00334 value = static_cast<Real>(petsc_value); 00335 00336 return value; 00337 } 00338 00339 00340 00341 template <typename T> 00342 void PetscMatrix<T>::print_matlab (const std::string name) const 00343 { 00344 libmesh_assert (this->initialized()); 00345 00346 semiparallel_only(); 00347 00348 // libmesh_assert (this->closed()); 00349 this->close(); 00350 00351 PetscErrorCode ierr=0; 00352 PetscViewer petsc_viewer; 00353 00354 00355 ierr = PetscViewerCreate (libMesh::COMM_WORLD, 00356 &petsc_viewer); 00357 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00358 00363 if (name != "NULL") 00364 { 00365 ierr = PetscViewerASCIIOpen( libMesh::COMM_WORLD, 00366 name.c_str(), 00367 &petsc_viewer); 00368 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00369 00370 ierr = PetscViewerSetFormat (petsc_viewer, 00371 PETSC_VIEWER_ASCII_MATLAB); 00372 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00373 00374 ierr = MatView (_mat, petsc_viewer); 00375 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00376 } 00377 00381 else 00382 { 00383 ierr = PetscViewerSetFormat (PETSC_VIEWER_STDOUT_WORLD, 00384 PETSC_VIEWER_ASCII_MATLAB); 00385 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00386 00387 ierr = MatView (_mat, PETSC_VIEWER_STDOUT_WORLD); 00388 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00389 } 00390 00391 00395 ierr = LibMeshPetscViewerDestroy (&petsc_viewer); 00396 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00397 } 00398 00399 00400 00401 00402 00403 template <typename T> 00404 void PetscMatrix<T>::print_personal(std::ostream& os) const 00405 { 00406 libmesh_assert (this->initialized()); 00407 00408 // Routine must be called in parallel on parallel matrices 00409 // and serial on serial matrices. 00410 semiparallel_only(); 00411 00412 // #ifndef NDEBUG 00413 // if (os != std::cout) 00414 // libMesh::err << "Warning! PETSc can only print to std::cout!" << std::endl; 00415 // #endif 00416 00417 // Matrix must be in an assembled state to be printed 00418 this->close(); 00419 00420 PetscErrorCode ierr=0; 00421 00422 // Print to screen if ostream is stdout 00423 if (os == std::cout) 00424 { 00425 ierr = MatView(_mat, PETSC_VIEWER_STDOUT_SELF); 00426 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00427 } 00428 00429 // Otherwise, print to the requested file, in a roundabout way... 00430 else 00431 { 00432 // We will create a temporary filename, and file, for PETSc to 00433 // write to. 00434 std::string temp_filename; 00435 00436 { 00437 // Template for temporary filename 00438 char c[] = "temp_petsc_matrix.XXXXXX"; 00439 00440 // Generate temporary, unique filename only on processor 0. We will 00441 // use this filename for PetscViewerASCIIOpen, before copying it into 00442 // the user's stream 00443 if (libMesh::processor_id() == 0) 00444 { 00445 int fd = mkstemp(c); 00446 00447 // Check to see that mkstemp did not fail. 00448 if (fd == -1) 00449 libmesh_error(); 00450 00451 // mkstemp returns a file descriptor for an open file, 00452 // so let's close it before we hand it to PETSc! 00453 ::close (fd); 00454 } 00455 00456 // Store temporary filename as string, makes it easier to broadcast 00457 temp_filename = c; 00458 } 00459 00460 // Now broadcast the filename from processor 0 to all processors. 00461 CommWorld.broadcast(temp_filename); 00462 00463 // PetscViewer object for passing to MatView 00464 PetscViewer petsc_viewer; 00465 00466 // This PETSc function only takes a string and handles the opening/closing 00467 // of the file internally. Since print_personal() takes a reference to 00468 // an ostream, we have to do an extra step... print_personal() should probably 00469 // have a version that takes a string to get rid of this problem. 00470 ierr = PetscViewerASCIIOpen( libMesh::COMM_WORLD, 00471 temp_filename.c_str(), 00472 &petsc_viewer); 00473 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00474 00475 // Probably don't need to set the format if it's default... 00476 // ierr = PetscViewerSetFormat (petsc_viewer, 00477 // PETSC_VIEWER_DEFAULT); 00478 // CHKERRABORT(libMesh::COMM_WORLD,ierr); 00479 00480 // Finally print the matrix using the viewer 00481 ierr = MatView (_mat, petsc_viewer); 00482 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00483 00484 if (libMesh::processor_id() == 0) 00485 { 00486 // Now the inefficient bit: open temp_filename as an ostream and copy the contents 00487 // into the user's desired ostream. We can't just do a direct file copy, we don't even have the filename! 00488 std::ifstream input_stream(temp_filename.c_str()); 00489 os << input_stream.rdbuf(); // The "most elegant" way to copy one stream into another. 00490 // os.close(); // close not defined in ostream 00491 00492 // Now remove the temporary file 00493 input_stream.close(); 00494 std::remove(temp_filename.c_str()); 00495 } 00496 } 00497 } 00498 00499 00500 00501 00502 00503 00504 template <typename T> 00505 void PetscMatrix<T>::add_matrix(const DenseMatrix<T>& dm, 00506 const std::vector<numeric_index_type>& rows, 00507 const std::vector<numeric_index_type>& cols) 00508 { 00509 libmesh_assert (this->initialized()); 00510 00511 const numeric_index_type n_rows = dm.m(); 00512 const numeric_index_type n_cols = dm.n(); 00513 00514 libmesh_assert_equal_to (rows.size(), n_rows); 00515 libmesh_assert_equal_to (cols.size(), n_cols); 00516 00517 PetscErrorCode ierr=0; 00518 00519 // These casts are required for PETSc <= 2.1.5 00520 ierr = MatSetValues(_mat, 00521 n_rows, (PetscInt*) &rows[0], 00522 n_cols, (PetscInt*) &cols[0], 00523 (PetscScalar*) &dm.get_values()[0], 00524 ADD_VALUES); 00525 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00526 } 00527 00528 00529 00530 00531 00532 template <typename T> 00533 void PetscMatrix<T>::_get_submatrix(SparseMatrix<T>& submatrix, 00534 const std::vector<numeric_index_type> &rows, 00535 const std::vector<numeric_index_type> &cols, 00536 const bool reuse_submatrix) const 00537 { 00538 // Can only extract submatrices from closed matrices 00539 this->close(); 00540 00541 // Make sure the SparseMatrix passed in is really a PetscMatrix 00542 PetscMatrix<T>* petsc_submatrix = libmesh_cast_ptr<PetscMatrix<T>*>(&submatrix); 00543 00544 // If we're not reusing submatrix and submatrix is already initialized 00545 // then we need to clear it, otherwise we get a memory leak. 00546 if( !reuse_submatrix && submatrix.initialized() ) 00547 submatrix.clear(); 00548 00549 // Construct row and column index sets. 00550 PetscErrorCode ierr=0; 00551 IS isrow, iscol; 00552 00553 ierr = ISCreateLibMesh(libMesh::COMM_WORLD, 00554 rows.size(), 00555 (PetscInt*) &rows[0], 00556 PETSC_USE_POINTER, 00557 &isrow); CHKERRABORT(libMesh::COMM_WORLD,ierr); 00558 00559 ierr = ISCreateLibMesh(libMesh::COMM_WORLD, 00560 cols.size(), 00561 (PetscInt*) &cols[0], 00562 PETSC_USE_POINTER, 00563 &iscol); CHKERRABORT(libMesh::COMM_WORLD,ierr); 00564 00565 // Extract submatrix 00566 #if !PETSC_VERSION_LESS_THAN(3,0,1) || !PETSC_VERSION_RELEASE 00567 ierr = MatGetSubMatrix(_mat, 00568 isrow, 00569 iscol, 00570 (reuse_submatrix ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX), 00571 &(petsc_submatrix->_mat)); CHKERRABORT(libMesh::COMM_WORLD,ierr); 00572 #else 00573 ierr = MatGetSubMatrix(_mat, 00574 isrow, 00575 iscol, 00576 PETSC_DECIDE, 00577 (reuse_submatrix ? MAT_REUSE_MATRIX : MAT_INITIAL_MATRIX), 00578 &(petsc_submatrix->_mat)); CHKERRABORT(libMesh::COMM_WORLD,ierr); 00579 #endif 00580 00581 // Specify that the new submatrix is initialized and close it. 00582 petsc_submatrix->_is_initialized = true; 00583 petsc_submatrix->close(); 00584 00585 // Clean up PETSc data structures 00586 ierr = LibMeshISDestroy(&isrow); CHKERRABORT(libMesh::COMM_WORLD,ierr); 00587 ierr = LibMeshISDestroy(&iscol); CHKERRABORT(libMesh::COMM_WORLD,ierr); 00588 } 00589 00590 00591 00592 template <typename T> 00593 void PetscMatrix<T>::get_diagonal (NumericVector<T>& dest) const 00594 { 00595 // Make sure the NumericVector passed in is really a PetscVector 00596 PetscVector<T>& petsc_dest = libmesh_cast_ref<PetscVector<T>&>(dest); 00597 00598 // Call PETSc function. 00599 00600 #if PETSC_VERSION_LESS_THAN(2,3,1) 00601 00602 libMesh::out << "This method has been developed with PETSc 2.3.1. " 00603 << "No one has made it backwards compatible with older " 00604 << "versions of PETSc so far; however, it might work " 00605 << "without any change with some older version." << std::endl; 00606 libmesh_error(); 00607 00608 #else 00609 00610 // Needs a const_cast since PETSc does not work with const. 00611 PetscErrorCode ierr = 00612 MatGetDiagonal(const_cast<PetscMatrix<T>*>(this)->mat(),petsc_dest.vec()); CHKERRABORT(libMesh::COMM_WORLD,ierr); 00613 00614 #endif 00615 00616 } 00617 00618 00619 00620 template <typename T> 00621 void PetscMatrix<T>::get_transpose (SparseMatrix<T>& dest) const 00622 { 00623 // Make sure the SparseMatrix passed in is really a PetscMatrix 00624 PetscMatrix<T>& petsc_dest = libmesh_cast_ref<PetscMatrix<T>&>(dest); 00625 00626 // If we aren't reusing the matrix then need to clear dest, 00627 // otherwise we get a memory leak 00628 if(&petsc_dest != this) 00629 dest.clear(); 00630 00631 PetscErrorCode ierr; 00632 #if PETSC_VERSION_LESS_THAN(3,0,0) 00633 if (&petsc_dest == this) 00634 ierr = MatTranspose(_mat,PETSC_NULL); 00635 else 00636 ierr = MatTranspose(_mat,&petsc_dest._mat); 00637 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00638 #else 00639 // FIXME - we can probably use MAT_REUSE_MATRIX in more situations 00640 if (&petsc_dest == this) 00641 ierr = MatTranspose(_mat,MAT_REUSE_MATRIX,&petsc_dest._mat); 00642 else 00643 ierr = MatTranspose(_mat,MAT_INITIAL_MATRIX,&petsc_dest._mat); 00644 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00645 #endif 00646 00647 // Specify that the transposed matrix is initialized and close it. 00648 petsc_dest._is_initialized = true; 00649 petsc_dest.close(); 00650 } 00651 00652 00653 00654 00655 00656 template <typename T> 00657 void PetscMatrix<T>::close () const 00658 { 00659 semiparallel_only(); 00660 00661 // BSK - 1/19/2004 00662 // strictly this check should be OK, but it seems to 00663 // fail on matrix-free matrices. Do they falsely 00664 // state they are assembled? Check with the developers... 00665 // if (this->closed()) 00666 // return; 00667 00668 PetscErrorCode ierr=0; 00669 00670 ierr = MatAssemblyBegin (_mat, MAT_FINAL_ASSEMBLY); 00671 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00672 ierr = MatAssemblyEnd (_mat, MAT_FINAL_ASSEMBLY); 00673 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00674 } 00675 00676 00677 00678 template <typename T> 00679 numeric_index_type PetscMatrix<T>::m () const 00680 { 00681 libmesh_assert (this->initialized()); 00682 00683 PetscInt petsc_m=0, petsc_n=0; 00684 PetscErrorCode ierr=0; 00685 00686 ierr = MatGetSize (_mat, &petsc_m, &petsc_n); 00687 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00688 00689 return static_cast<numeric_index_type>(petsc_m); 00690 } 00691 00692 00693 00694 template <typename T> 00695 numeric_index_type PetscMatrix<T>::n () const 00696 { 00697 libmesh_assert (this->initialized()); 00698 00699 PetscInt petsc_m=0, petsc_n=0; 00700 PetscErrorCode ierr=0; 00701 00702 ierr = MatGetSize (_mat, &petsc_m, &petsc_n); 00703 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00704 00705 return static_cast<numeric_index_type>(petsc_n); 00706 } 00707 00708 00709 00710 template <typename T> 00711 numeric_index_type PetscMatrix<T>::row_start () const 00712 { 00713 libmesh_assert (this->initialized()); 00714 00715 PetscInt start=0, stop=0; 00716 PetscErrorCode ierr=0; 00717 00718 ierr = MatGetOwnershipRange(_mat, &start, &stop); 00719 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00720 00721 return static_cast<numeric_index_type>(start); 00722 } 00723 00724 00725 00726 template <typename T> 00727 numeric_index_type PetscMatrix<T>::row_stop () const 00728 { 00729 libmesh_assert (this->initialized()); 00730 00731 PetscInt start=0, stop=0; 00732 PetscErrorCode ierr=0; 00733 00734 ierr = MatGetOwnershipRange(_mat, &start, &stop); 00735 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00736 00737 return static_cast<numeric_index_type>(stop); 00738 } 00739 00740 00741 00742 template <typename T> 00743 void PetscMatrix<T>::set (const numeric_index_type i, 00744 const numeric_index_type j, 00745 const T value) 00746 { 00747 libmesh_assert (this->initialized()); 00748 00749 PetscErrorCode ierr=0; 00750 PetscInt i_val=i, j_val=j; 00751 00752 PetscScalar petsc_value = static_cast<PetscScalar>(value); 00753 ierr = MatSetValues(_mat, 1, &i_val, 1, &j_val, 00754 &petsc_value, INSERT_VALUES); 00755 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00756 } 00757 00758 00759 00760 template <typename T> 00761 void PetscMatrix<T>::add (const numeric_index_type i, 00762 const numeric_index_type j, 00763 const T value) 00764 { 00765 libmesh_assert (this->initialized()); 00766 00767 PetscErrorCode ierr=0; 00768 PetscInt i_val=i, j_val=j; 00769 00770 PetscScalar petsc_value = static_cast<PetscScalar>(value); 00771 ierr = MatSetValues(_mat, 1, &i_val, 1, &j_val, 00772 &petsc_value, ADD_VALUES); 00773 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00774 } 00775 00776 00777 00778 template <typename T> 00779 void PetscMatrix<T>::add_matrix(const DenseMatrix<T>& dm, 00780 const std::vector<numeric_index_type>& dof_indices) 00781 { 00782 this->add_matrix (dm, dof_indices, dof_indices); 00783 } 00784 00785 00786 00787 00788 00789 00790 00791 template <typename T> 00792 void PetscMatrix<T>::add (const T a_in, SparseMatrix<T> &X_in) 00793 { 00794 libmesh_assert (this->initialized()); 00795 00796 // sanity check. but this cannot avoid 00797 // crash due to incompatible sparsity structure... 00798 libmesh_assert_equal_to (this->m(), X_in.m()); 00799 libmesh_assert_equal_to (this->n(), X_in.n()); 00800 00801 PetscScalar a = static_cast<PetscScalar> (a_in); 00802 PetscMatrix<T>* X = libmesh_cast_ptr<PetscMatrix<T>*> (&X_in); 00803 00804 libmesh_assert (X); 00805 00806 PetscErrorCode ierr=0; 00807 00808 // the matrix from which we copy the values has to be assembled/closed 00809 // X->close (); 00810 libmesh_assert(X->closed()); 00811 00812 semiparallel_only(); 00813 00814 // 2.2.x & earlier style 00815 #if PETSC_VERSION_LESS_THAN(2,3,0) 00816 00817 ierr = MatAXPY(&a, X->_mat, _mat, SAME_NONZERO_PATTERN); 00818 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00819 00820 // 2.3.x & newer 00821 #else 00822 00823 ierr = MatAXPY(_mat, a, X->_mat, DIFFERENT_NONZERO_PATTERN); 00824 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00825 00826 #endif 00827 } 00828 00829 00830 00831 00832 template <typename T> 00833 T PetscMatrix<T>::operator () (const numeric_index_type i_in, 00834 const numeric_index_type j_in) const 00835 { 00836 libmesh_assert (this->initialized()); 00837 00838 #if PETSC_VERSION_LESS_THAN(2,2,1) 00839 00840 // PETSc 2.2.0 & older 00841 PetscScalar *petsc_row; 00842 int* petsc_cols; 00843 00844 #else 00845 00846 // PETSc 2.2.1 & newer 00847 const PetscScalar *petsc_row; 00848 const PetscInt *petsc_cols; 00849 00850 #endif 00851 00852 00853 // If the entry is not in the sparse matrix, it is 0. 00854 T value=0.; 00855 00856 PetscErrorCode 00857 ierr=0; 00858 PetscInt 00859 ncols=0, 00860 i_val=static_cast<PetscInt>(i_in), 00861 j_val=static_cast<PetscInt>(j_in); 00862 00863 00864 // the matrix needs to be closed for this to work 00865 // this->close(); 00866 // but closing it is a semiparallel operation; we want operator() 00867 // to run on one processor. 00868 libmesh_assert(this->closed()); 00869 00870 ierr = MatGetRow(_mat, i_val, &ncols, &petsc_cols, &petsc_row); 00871 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00872 00873 // Perform a binary search to find the contiguous index in 00874 // petsc_cols (resp. petsc_row) corresponding to global index j_val 00875 std::pair<const PetscInt*, const PetscInt*> p = 00876 std::equal_range (&petsc_cols[0], &petsc_cols[0] + ncols, j_val); 00877 00878 // Found an entry for j_val 00879 if (p.first != p.second) 00880 { 00881 // The entry in the contiguous row corresponding 00882 // to the j_val column of interest 00883 const std::size_t j = 00884 std::distance (const_cast<PetscInt*>(&petsc_cols[0]), 00885 const_cast<PetscInt*>(p.first)); 00886 00887 libmesh_assert_less (static_cast<PetscInt>(j), ncols); 00888 libmesh_assert_equal_to (petsc_cols[j], j_val); 00889 00890 value = static_cast<T> (petsc_row[j]); 00891 } 00892 00893 ierr = MatRestoreRow(_mat, i_val, 00894 &ncols, &petsc_cols, &petsc_row); 00895 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00896 00897 return value; 00898 } 00899 00900 00901 00902 00903 template <typename T> 00904 bool PetscMatrix<T>::closed() const 00905 { 00906 libmesh_assert (this->initialized()); 00907 00908 PetscErrorCode ierr=0; 00909 PetscBool assembled; 00910 00911 ierr = MatAssembled(_mat, &assembled); 00912 CHKERRABORT(libMesh::COMM_WORLD,ierr); 00913 00914 return (assembled == PETSC_TRUE); 00915 } 00916 00917 00918 00919 template <typename T> 00920 void PetscMatrix<T>::swap(PetscMatrix<T> &m_in) 00921 { 00922 std::swap(_mat, m_in._mat); 00923 std::swap(_destroy_mat_on_exit, m_in._destroy_mat_on_exit); 00924 } 00925 00926 00927 00928 //------------------------------------------------------------------ 00929 // Explicit instantiations 00930 template class PetscMatrix<Number>; 00931 00932 } // namespace libMesh 00933 00934 00935 #endif // #ifdef LIBMESH_HAVE_PETSC
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:48 UTC
Hosted By: