$extrastylesheet
petsc_matrix.C
Go to the documentation of this file.
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