![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
00002 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
00003 // reserved. See file COPYRIGHT for details.
00004 //
00005 // This file is part of the MFEM library. For more information and source code
00006 // availability see http://mfem.org.
00007 //
00008 // MFEM is free software; you can redistribute it and/or modify it under the
00009 // terms of the GNU Lesser General Public License (as published by the Free
00010 // Software Foundation) version 2.1 dated February 1999.
00011
00012 #include "HypreParVector.hpp"
00013 #include "HypreParMatrix.hpp"
00014
00015 #ifdef MOAB_HAVE_MPI
00016
00017 #include "hypre_parcsr.hpp"
00018
00019 #include
00020 #include
00021 #include
00022 #include
00023 #include
00024
00025 using namespace std;
00026
00027 #define MOAB_DEBUG
00028
00029 namespace moab
00030 {
00031 #define moab_hypre_assert( a, b ) \
00032 { \
00033 }
00034 #define moab_hypre_assert_t( a, b ) \
00035 { \
00036 if( !a ) \
00037 { \
00038 std::cout << "HYPRE Error: " << b << std::endl; \
00039 exit( -1 ); \
00040 } \
00041 }
00042
00043 template < typename TargetT, typename SourceT >
00044 static TargetT* DuplicateAs( const SourceT* array, int size, bool cplusplus = true )
00045 {
00046 TargetT* target_array = cplusplus ? new TargetT[size]
00047 /* */
00048 : hypre_TAlloc( TargetT, size );
00049
00050 for( int i = 0; i < size; i++ )
00051 {
00052 target_array[i] = array[i];
00053 }
00054
00055 return target_array;
00056 }
00057
00058 void HypreParMatrix::Init()
00059 {
00060 A = NULL;
00061 A_parcsr = NULL;
00062 ParCSROwner = 1;
00063 }
00064
00065 HypreParMatrix::HypreParMatrix( moab::ParallelComm* p_comm ) : pcomm( p_comm )
00066 {
00067 Init();
00068 height = width = 0;
00069 }
00070
00071 // Square block-diagonal constructor
00072 HypreParMatrix::HypreParMatrix( moab::ParallelComm* p_comm,
00073 HYPRE_Int glob_size,
00074 HYPRE_Int* row_starts,
00075 HYPRE_Int nnz_pr )
00076 : pcomm( p_comm )
00077 {
00078 Init();
00079 resize( glob_size, row_starts, nnz_pr );
00080 }
00081
00082 void HypreParMatrix::resize( HYPRE_Int glob_size,
00083 HYPRE_Int* row_starts,
00084 HYPRE_Int nnz_pr_diag,
00085 HYPRE_Int nnz_pr_offdiag )
00086 {
00087 /* Create the matrix.
00088 Note that this is a square matrix, so we indicate the row partition
00089 size twice (since number of rows = number of cols) */
00090 HYPRE_IJMatrixCreate( pcomm->comm(), row_starts[0], row_starts[1], row_starts[0], row_starts[1], &A );
00091 /* Choose a parallel csr format storage (see the User's Manual) */
00092 HYPRE_IJMatrixSetObjectType( A, HYPRE_PARCSR );
00093
00094 int locsize = row_starts[1] - row_starts[0] + 1;
00095 int num_procs, rank;
00096 MPI_Comm_size( pcomm->comm(), &num_procs );
00097 MPI_Comm_rank( pcomm->comm(), &rank );
00098
00099 if( nnz_pr_diag != 0 || nnz_pr_offdiag != 0 )
00100 {
00101 if( num_procs > 1 )
00102 {
00103 std::vector< HYPRE_Int > m_nnz_pr_diag( locsize, nnz_pr_diag );
00104 std::vector< HYPRE_Int > m_onz_pr_diag( locsize, nnz_pr_offdiag );
00105 HYPRE_IJMatrixSetDiagOffdSizes( A, &m_nnz_pr_diag[0], &m_onz_pr_diag[0] );
00106 }
00107 else
00108 {
00109 std::vector< HYPRE_Int > m_nnz_pr_diag( locsize, nnz_pr_diag );
00110 HYPRE_IJMatrixSetRowSizes( A, &m_nnz_pr_diag[0] );
00111 }
00112 }
00113
00114 /* Initialize before setting coefficients */
00115 HYPRE_IJMatrixInitialize( A );
00116 /* Get the parcsr matrix object to use */
00117 HYPRE_IJMatrixGetObject( A, (void**)&A_parcsr );
00118
00119 /* define an interpreter for the ParCSR interface */
00120 HYPRE_MatvecFunctions matvec_fn;
00121 interpreter = hypre_CTAlloc( mv_InterfaceInterpreter, 1 );
00122 HYPRE_ParCSRSetupInterpreter( interpreter );
00123 HYPRE_ParCSRSetupMatvec( &matvec_fn );
00124 gnrows = glob_size;
00125 gncols = glob_size;
00126 height = GetNumRows();
00127 width = GetNumCols();
00128 }
00129
00130 void HypreParMatrix::resize( HYPRE_Int global_num_rows,
00131 HYPRE_Int global_num_cols,
00132 HYPRE_Int* row_starts,
00133 HYPRE_Int* col_starts,
00134 HYPRE_Int* nnz_pr_diag,
00135 HYPRE_Int* onz_pr_diag,
00136 HYPRE_Int nnz_pr_offdiag )
00137 {
00138 /* Create the matrix.
00139 Note that this is a square matrix, so we indicate the row partition
00140 size twice (since number of rows = number of cols) */
00141 HYPRE_IJMatrixCreate( pcomm->comm(), row_starts[0], row_starts[1], col_starts[0], col_starts[1], &A );
00142 /* Choose a parallel csr format storage (see the User's Manual) */
00143 HYPRE_IJMatrixSetObjectType( A, HYPRE_PARCSR );
00144
00145 int num_procs;
00146 MPI_Comm_size( pcomm->comm(), &num_procs );
00147
00148 /* Set the matrix pre-allocation data */
00149 if( num_procs > 1 )
00150 {
00151 if( nnz_pr_diag == NULL && onz_pr_diag == NULL )
00152 {
00153 std::cout << "Parameter nnz_pr_diag and onz_pr_diag cannot be NULL.\n";
00154 moab_hypre_assert_t( nnz_pr_diag, true );
00155 }
00156
00157 HYPRE_IJMatrixSetDiagOffdSizes( A, nnz_pr_diag, onz_pr_diag );
00158 }
00159 else
00160 {
00161 HYPRE_IJMatrixSetRowSizes( A, nnz_pr_diag );
00162 }
00163
00164 if( nnz_pr_offdiag )
00165 {
00166 HYPRE_IJMatrixSetMaxOffProcElmts( A, nnz_pr_offdiag );
00167 }
00168
00169 /* Initialize before setting coefficients */
00170 HYPRE_IJMatrixInitialize( A );
00171 /* Get the parcsr matrix object to use */
00172 HYPRE_IJMatrixGetObject( A, (void**)&A_parcsr );
00173
00174 /* define an interpreter for the ParCSR interface */
00175 HYPRE_MatvecFunctions matvec_fn;
00176 interpreter = hypre_CTAlloc( mv_InterfaceInterpreter, 1 );
00177 HYPRE_ParCSRSetupInterpreter( interpreter );
00178 HYPRE_ParCSRSetupMatvec( &matvec_fn );
00179 gnrows = global_num_rows;
00180 gncols = global_num_cols;
00181 height = GetNumRows();
00182 width = GetNumCols();
00183 }
00184
00185 // Rectangular block-diagonal constructor
00186 HypreParMatrix::HypreParMatrix( moab::ParallelComm* p_comm,
00187 HYPRE_Int global_num_rows,
00188 HYPRE_Int global_num_cols,
00189 HYPRE_Int* row_starts,
00190 HYPRE_Int* col_starts,
00191 HYPRE_Int nnz_pr_diag,
00192 HYPRE_Int onz_pr_diag,
00193 HYPRE_Int nnz_pr_offdiag )
00194 : pcomm( p_comm )
00195 {
00196 Init();
00197 std::vector< HYPRE_Int > m_nnz_pr_diag( row_starts[1] - row_starts[0], nnz_pr_diag );
00198 std::vector< HYPRE_Int > m_onz_pr_diag( row_starts[1] - row_starts[0], onz_pr_diag );
00199 resize( global_num_rows, global_num_cols, row_starts, col_starts, &m_nnz_pr_diag[0], &m_onz_pr_diag[0],
00200 nnz_pr_offdiag );
00201 }
00202
00203 void HypreParMatrix::MakeRef( const HypreParMatrix& master )
00204 {
00205 Destroy();
00206 Init();
00207 A = master.A;
00208 A_parcsr = master.A_parcsr;
00209 ParCSROwner = 0;
00210 height = master.GetNumRows();
00211 width = master.GetNumCols();
00212 }
00213
00214 HYPRE_IJMatrix HypreParMatrix::StealData()
00215 {
00216 // Only safe when (diagOwner == -1 && offdOwner == -1 && colMapOwner == -1)
00217 // Otherwise, there may be memory leaks or hypre may destroy arrays allocated
00218 // with operator new.
00219 moab_hypre_assert( diagOwner == -1 && offdOwner == -1 && colMapOwner == -1, "" );
00220 moab_hypre_assert( ParCSROwner, "" );
00221 HYPRE_IJMatrix R = A;
00222 A = NULL;
00223 ParCSROwner = 0;
00224 Destroy();
00225 Init();
00226 return R;
00227 }
00228
00229 void HypreParMatrix::StealData( HypreParMatrix& X )
00230 {
00231 // Only safe when (diagOwner == -1 && offdOwner == -1 && colMapOwner == -1)
00232 // Otherwise, there may be memory leaks or hypre may destroy arrays allocated
00233 // with operator new.
00234 moab_hypre_assert( diagOwner == -1 && offdOwner == -1 && colMapOwner == -1, "" );
00235 moab_hypre_assert( ParCSROwner, "" );
00236 moab_hypre_assert( X.diagOwner == -1 && X.offdOwner == -1 && X.colMapOwner == -1, "" );
00237 moab_hypre_assert( X.ParCSROwner, "" );
00238 A = X.A;
00239 A_parcsr = X.A_parcsr;
00240 ParCSROwner = 1;
00241 X.A = NULL;
00242 X.A_parcsr = NULL;
00243 X.ParCSROwner = 0;
00244 X.Destroy();
00245 X.Init();
00246 }
00247
00248 void HypreParMatrix::GetDiag( Eigen::VectorXd& diag ) const
00249 {
00250 int size = this->height;
00251 diag.resize( size );
00252
00253 for( int j = 0; j < size; j++ )
00254 {
00255 diag( j ) = A_parcsr->diag->data[A_parcsr->diag->i[j]];
00256 moab_hypre_assert( A_parcsr->diag->j[A_parcsr->diag->i[j]] == j,
00257 "the first entry in each row must be the diagonal one" );
00258 }
00259 }
00260
00261 static void MakeWrapper( const hypre_CSRMatrix* mat, Eigen::SparseMatrix< double, Eigen::RowMajor >& wrapper )
00262 {
00263 HYPRE_Int nr = hypre_CSRMatrixNumRows( mat );
00264 HYPRE_Int nc = hypre_CSRMatrixNumCols( mat );
00265 Eigen::SparseMatrix< double, Eigen::RowMajor > tmp( nr, nc );
00266 typedef Eigen::Triplet< double > T;
00267 HYPRE_Int nnz = hypre_CSRMatrixNumNonzeros( mat );
00268 int *rindx, *cindx;
00269 double* dindx;
00270 #ifndef HYPRE_BIGINT
00271 rindx = hypre_CSRMatrixI( mat );
00272 cindx = hypre_CSRMatrixJ( mat );
00273 dindx = hypre_CSRMatrixData( mat );
00274 #else
00275 rindx = DuplicateAs< int >( hypre_CSRMatrixI( mat ), nr + 1 );
00276 cindx = DuplicateAs< int >( hypre_CSRMatrixJ( mat ), nnz );
00277 dindx = hypre_CSRMatrixData( mat );
00278 #endif
00279 std::vector< T > tripletList( nnz );
00280
00281 for( int i = 0; i < nnz; ++i )
00282 {
00283 tripletList.push_back( T( rindx[i], cindx[i], dindx[i] ) );
00284 }
00285
00286 tmp.setFromTriplets( tripletList.begin(), tripletList.end() );
00287 wrapper.swap( tmp );
00288 }
00289
00290 void HypreParMatrix::GetDiag( Eigen::SparseMatrix< double, Eigen::RowMajor >& diag ) const
00291 {
00292 MakeWrapper( A_parcsr->diag, diag );
00293 }
00294
00295 void HypreParMatrix::GetOffd( Eigen::SparseMatrix< double, Eigen::RowMajor >& offd, HYPRE_Int*& cmap ) const
00296 {
00297 MakeWrapper( A_parcsr->offd, offd );
00298 cmap = A_parcsr->col_map_offd;
00299 }
00300
00301 // void HypreParMatrix::GetBlocks(Eigen::Array
00302 // &blocks,
00303 // bool interleaved_rows,
00304 // bool interleaved_cols) const
00305 // {
00306 // int nr = blocks.rows();
00307 // int nc = blocks.cols();
00308
00309 // hypre_ParCSRMatrix **hypre_blocks = new hypre_ParCSRMatrix*[nr * nc];
00310 // internal::hypre_ParCSRMatrixSplit(A, nr, nc, hypre_blocks,
00311 // interleaved_rows, interleaved_cols);
00312
00313 // for (int i = 0; i < nr; i++)
00314 // {
00315 // for (int j = 0; j < nc; j++)
00316 // {
00317 // blocks[i][j] = new HypreParMatrix(hypre_blocks[i*nc + j]);
00318 // }
00319 // }
00320
00321 // delete [] hypre_blocks;
00322 // }
00323
00324 // HypreParMatrix * HypreParMatrix::Transpose()
00325 // {
00326 // hypre_ParCSRMatrix * At;
00327 // hypre_ParCSRMatrixTranspose(A_parcsr, &At, 1);
00328 // hypre_ParCSRMatrixSetNumNonzeros(At);
00329
00330 // hypre_MatvecCommPkgCreate(At);
00331
00332 // return new HypreParMatrix(At);
00333 // }
00334
00335 HYPRE_Int HypreParMatrix::Mult( HypreParVector& x, HypreParVector& y, double a, double b )
00336 {
00337 return hypre_ParCSRMatrixMatvec( a, A_parcsr, x.x_par, b, y.x_par );
00338 }
00339
00340 void HypreParMatrix::Mult( double a, const HypreParVector& x, double b, HypreParVector& y ) const
00341 {
00342 hypre_ParCSRMatrixMatvec( a, A_parcsr, x.x_par, b, y.x_par );
00343 }
00344
00345 void HypreParMatrix::MultTranspose( double a, const HypreParVector& x, double b, HypreParVector& y ) const
00346 {
00347 hypre_ParCSRMatrixMatvecT( a, A_parcsr, y.x_par, b, x.x_par );
00348 }
00349
00350 HYPRE_Int HypreParMatrix::Mult( HYPRE_ParVector x, HYPRE_ParVector y, double a, double b )
00351 {
00352 return hypre_ParCSRMatrixMatvec( a, A_parcsr, (hypre_ParVector*)x, b, (hypre_ParVector*)y );
00353 }
00354
00355 HYPRE_Int HypreParMatrix::MultTranspose( HypreParVector& x, HypreParVector& y, double a, double b )
00356 {
00357 return hypre_ParCSRMatrixMatvecT( a, A_parcsr, x.x_par, b, y.x_par );
00358 }
00359
00360 // HypreParMatrix* HypreParMatrix::LeftDiagMult(const Eigen::SparseMatrix
00361 // &D,
00362 // HYPRE_Int* row_starts) const
00363 // {
00364 // const bool assumed_partition = HYPRE_AssumedPartitionCheck();
00365 // const bool same_rows = (D.rows() == hypre_CSRMatrixNumRows(A_parcsr->diag));
00366
00367 // int part_size;
00368 // if (assumed_partition)
00369 // {
00370 // part_size = 2;
00371 // }
00372 // else
00373 // {
00374 // MPI_Comm_size(GetComm(), &part_size);
00375 // part_size++;
00376 // }
00377
00378 // HYPRE_Int global_num_rows;
00379 // if (same_rows)
00380 // {
00381 // row_starts = hypre_ParCSRMatrixRowStarts(A_parcsr);
00382 // global_num_rows = hypre_ParCSRMatrixGlobalNumRows(A_parcsr);
00383 // }
00384 // else
00385 // {
00386 // // MFEM_VERIFY(row_starts != NULL, "the number of rows in D and A is not "
00387 // // "the same; row_starts must be given (not NULL)");
00388 // // Here, when assumed_partition is true we use row_starts[2], so
00389 // // row_starts must come from the GetDofOffsets/GetTrueDofOffsets methods
00390 // // of ParFiniteElementSpace (HYPRE's partitions have only 2 entries).
00391 // global_num_rows =
00392 // assumed_partition ? row_starts[2] : row_starts[part_size-1];
00393 // }
00394
00395 // HYPRE_Int *col_starts = hypre_ParCSRMatrixColStarts(A_parcsr);
00396 // HYPRE_Int *col_map_offd;
00397
00398 // // get the diag and offd blocks as SparseMatrix wrappers
00399 // Eigen::SparseMatrix A_diag, A_offd;
00400 // GetDiag(A_diag);
00401 // GetOffd(A_offd, col_map_offd);
00402
00403 // // multiply the blocks with D and create a new HypreParMatrix
00404 // Eigen::SparseMatrix DA_diag = (D * A_diag);
00405 // Eigen::SparseMatrix DA_offd = (D * A_offd);
00406
00407 // HypreParMatrix* DA =
00408 // new HypreParMatrix(GetComm(),
00409 // global_num_rows, hypre_ParCSRMatrixGlobalNumCols(A),
00410 // DuplicateAs(row_starts, part_size, false),
00411 // DuplicateAs(col_starts, part_size, false),
00412 // &DA_diag, &DA_offd,
00413 // DuplicateAs(col_map_offd, A_offd.cols()));
00414
00415 // // When HYPRE_BIGINT is defined, we want DA_{diag,offd} to delete their I and
00416 // // J arrays but not their data arrays; when HYPRE_BIGINT is not defined, we
00417 // // don't want DA_{diag,offd} to delete anything.
00418 // // #ifndef HYPRE_BIGINT
00419 // // DA_diag.LoseData();
00420 // // DA_offd.LoseData();
00421 // // #else
00422 // // DA_diag.SetDataOwner(false);
00423 // // DA_offd.SetDataOwner(false);
00424 // // #endif
00425
00426 // // delete DA_diag;
00427 // // delete DA_offd;
00428
00429 // hypre_ParCSRMatrixSetRowStartsOwner(DA->A, 1);
00430 // hypre_ParCSRMatrixSetColStartsOwner(DA->A, 1);
00431
00432 // DA->diagOwner = DA->offdOwner = 3;
00433 // DA->colMapOwner = 1;
00434
00435 // return DA;
00436 // }
00437
00438 void HypreParMatrix::ScaleRows( const Eigen::VectorXd& diag )
00439 {
00440 if( hypre_CSRMatrixNumRows( A_parcsr->diag ) != hypre_CSRMatrixNumRows( A_parcsr->offd ) )
00441 {
00442 MB_SET_ERR_RET( "Row does not match" );
00443 }
00444
00445 if( hypre_CSRMatrixNumRows( A_parcsr->diag ) != diag.size() )
00446 {
00447 MB_SET_ERR_RET( "Note the Eigen::VectorXd diag is not of compatible dimensions with A\n" );
00448 }
00449
00450 int size = this->height;
00451 double* Adiag_data = hypre_CSRMatrixData( A_parcsr->diag );
00452 HYPRE_Int* Adiag_i = hypre_CSRMatrixI( A_parcsr->diag );
00453 double* Aoffd_data = hypre_CSRMatrixData( A_parcsr->offd );
00454 HYPRE_Int* Aoffd_i = hypre_CSRMatrixI( A_parcsr->offd );
00455 double val;
00456 HYPRE_Int jj;
00457
00458 for( int i( 0 ); i < size; ++i )
00459 {
00460 val = diag[i];
00461
00462 for( jj = Adiag_i[i]; jj < Adiag_i[i + 1]; ++jj )
00463 {
00464 Adiag_data[jj] *= val;
00465 }
00466
00467 for( jj = Aoffd_i[i]; jj < Aoffd_i[i + 1]; ++jj )
00468 {
00469 Aoffd_data[jj] *= val;
00470 }
00471 }
00472 }
00473
00474 void HypreParMatrix::InvScaleRows( const Eigen::VectorXd& diag )
00475 {
00476 if( hypre_CSRMatrixNumRows( A_parcsr->diag ) != hypre_CSRMatrixNumRows( A_parcsr->offd ) )
00477 {
00478 MB_SET_ERR_RET( "Row does not match" );
00479 }
00480
00481 if( hypre_CSRMatrixNumRows( A_parcsr->diag ) != diag.size() )
00482 {
00483 MB_SET_ERR_RET( "Note the Eigen::VectorXd diag is not of compatible dimensions with A_parcsr\n" );
00484 }
00485
00486 int size = this->height;
00487 double* Adiag_data = hypre_CSRMatrixData( A_parcsr->diag );
00488 HYPRE_Int* Adiag_i = hypre_CSRMatrixI( A_parcsr->diag );
00489 double* Aoffd_data = hypre_CSRMatrixData( A_parcsr->offd );
00490 HYPRE_Int* Aoffd_i = hypre_CSRMatrixI( A_parcsr->offd );
00491 double val;
00492 HYPRE_Int jj;
00493
00494 for( int i( 0 ); i < size; ++i )
00495 {
00496 #ifdef MOAB_DEBUG
00497
00498 if( 0.0 == diag( i ) )
00499 {
00500 MB_SET_ERR_RET( "HypreParMatrix::InvDiagScale : Division by 0" );
00501 }
00502
00503 #endif
00504 val = 1. / diag( i );
00505
00506 for( jj = Adiag_i[i]; jj < Adiag_i[i + 1]; ++jj )
00507 {
00508 Adiag_data[jj] *= val;
00509 }
00510
00511 for( jj = Aoffd_i[i]; jj < Aoffd_i[i + 1]; ++jj )
00512 {
00513 Aoffd_data[jj] *= val;
00514 }
00515 }
00516 }
00517
00518 void HypreParMatrix::operator*=( double s )
00519 {
00520 if( hypre_CSRMatrixNumRows( A_parcsr->diag ) != hypre_CSRMatrixNumRows( A_parcsr->offd ) )
00521 {
00522 MB_SET_ERR_RET( "Row does not match" );
00523 }
00524
00525 HYPRE_Int size = hypre_CSRMatrixNumRows( A_parcsr->diag );
00526 HYPRE_Int jj;
00527 double* Adiag_data = hypre_CSRMatrixData( A_parcsr->diag );
00528 HYPRE_Int* Adiag_i = hypre_CSRMatrixI( A_parcsr->diag );
00529
00530 for( jj = 0; jj < Adiag_i[size]; ++jj )
00531 {
00532 Adiag_data[jj] *= s;
00533 }
00534
00535 double* Aoffd_data = hypre_CSRMatrixData( A_parcsr->offd );
00536 HYPRE_Int* Aoffd_i = hypre_CSRMatrixI( A_parcsr->offd );
00537
00538 for( jj = 0; jj < Aoffd_i[size]; ++jj )
00539 {
00540 Aoffd_data[jj] *= s;
00541 }
00542 }
00543
00544 HYPRE_Int HypreParMatrix::GetValues( const HYPRE_Int nrows,
00545 HYPRE_Int* ncols,
00546 HYPRE_Int* rows,
00547 HYPRE_Int* cols,
00548 HYPRE_Complex* values )
00549 {
00550 return HYPRE_IJMatrixGetValues( A, nrows, ncols, rows, cols, values );
00551 }
00552
00553 HYPRE_Int HypreParMatrix::SetValues( const HYPRE_Int nrows,
00554 HYPRE_Int* ncols,
00555 const HYPRE_Int* rows,
00556 const HYPRE_Int* cols,
00557 const HYPRE_Complex* values )
00558 {
00559 return HYPRE_IJMatrixSetValues( A, nrows, ncols, rows, cols, values );
00560 }
00561
00562 HYPRE_Int HypreParMatrix::AddToValues( const HYPRE_Int nrows,
00563 HYPRE_Int* ncols,
00564 const HYPRE_Int* rows,
00565 const HYPRE_Int* cols,
00566 const HYPRE_Complex* values )
00567 {
00568 return HYPRE_IJMatrixAddToValues( A, nrows, ncols, rows, cols, values );
00569 }
00570
00571 HYPRE_Int HypreParMatrix::verbosity( const HYPRE_Int level )
00572 {
00573 return HYPRE_IJMatrixSetPrintLevel( A, level );
00574 }
00575
00576 HYPRE_Int HypreParMatrix::FinalizeAssembly()
00577 {
00578 return HYPRE_IJMatrixAssemble( A );
00579 }
00580
00581 static void get_sorted_rows_cols( const std::vector< HYPRE_Int >& rows_cols, std::vector< HYPRE_Int >& hypre_sorted )
00582 {
00583 hypre_sorted.resize( rows_cols.size() );
00584 std::copy( rows_cols.begin(), rows_cols.end(), hypre_sorted.begin() );
00585 std::sort( hypre_sorted.begin(), hypre_sorted.end() );
00586 }
00587
00588 void HypreParMatrix::Threshold( double threshold )
00589 {
00590 int ierr = 0;
00591 int num_procs;
00592 hypre_CSRMatrix* csr_A;
00593 hypre_CSRMatrix* csr_A_wo_z;
00594 hypre_ParCSRMatrix* parcsr_A_ptr;
00595 int* row_starts = NULL;
00596 int* col_starts = NULL;
00597 int row_start = -1;
00598 int row_end = -1;
00599 int col_start = -1;
00600 int col_end = -1;
00601 MPI_Comm_size( pcomm->comm(), &num_procs );
00602 ierr += hypre_ParCSRMatrixGetLocalRange( A_parcsr, &row_start, &row_end, &col_start, &col_end );
00603 row_starts = hypre_ParCSRMatrixRowStarts( A_parcsr );
00604 col_starts = hypre_ParCSRMatrixColStarts( A_parcsr );
00605 parcsr_A_ptr = hypre_ParCSRMatrixCreate( pcomm->comm(), row_starts[num_procs], col_starts[num_procs], row_starts,
00606 col_starts, 0, 0, 0 );
00607 csr_A = hypre_MergeDiagAndOffd( A_parcsr );
00608 csr_A_wo_z = hypre_CSRMatrixDeleteZeros( csr_A, threshold );
00609
00610 /* hypre_CSRMatrixDeleteZeros will return a NULL pointer rather than a usable
00611 CSR matrix if it finds no non-zeros */
00612 if( csr_A_wo_z == NULL )
00613 {
00614 csr_A_wo_z = csr_A;
00615 }
00616 else
00617 {
00618 ierr += hypre_CSRMatrixDestroy( csr_A );
00619 }
00620
00621 ierr += GenerateDiagAndOffd( csr_A_wo_z, parcsr_A_ptr, col_start, col_end );
00622 ierr += hypre_CSRMatrixDestroy( csr_A_wo_z );
00623 ierr += hypre_ParCSRMatrixDestroy( A_parcsr );
00624 hypre_IJMatrixObject( A ) = parcsr_A_ptr;
00625 /* Get the parcsr matrix object to use */
00626 HYPRE_IJMatrixGetObject( A, (void**)A_parcsr );
00627 }
00628
00629 void HypreParMatrix::EliminateRowsCols( const std::vector< HYPRE_Int >& rows_cols,
00630 const HypreParVector& X,
00631 HypreParVector& B )
00632 {
00633 std::vector< HYPRE_Int > rc_sorted;
00634 get_sorted_rows_cols( rows_cols, rc_sorted );
00635 internal::hypre_ParCSRMatrixEliminateAXB( A_parcsr, rc_sorted.size(), rc_sorted.data(), X.x_par, B.x_par );
00636 }
00637
00638 HypreParMatrix* HypreParMatrix::EliminateRowsCols( const std::vector< HYPRE_Int >& rows_cols )
00639 {
00640 std::vector< HYPRE_Int > rc_sorted;
00641 get_sorted_rows_cols( rows_cols, rc_sorted );
00642 hypre_ParCSRMatrix* Ae;
00643 internal::hypre_ParCSRMatrixEliminateAAe( A_parcsr, &Ae, rc_sorted.size(), rc_sorted.data() );
00644 HypreParMatrix* tmpMat = new HypreParMatrix( pcomm, M(), N(), RowPart(), ColPart(), 0, 0 );
00645 hypre_IJMatrixObject( tmpMat->A ) = Ae;
00646 /* Get the parcsr matrix object to use */
00647 HYPRE_IJMatrixGetObject( tmpMat->A, (void**)tmpMat->A_parcsr );
00648 return tmpMat;
00649 }
00650
00651 void HypreParMatrix::Print( const char* fname, HYPRE_Int offi, HYPRE_Int offj )
00652 {
00653 hypre_ParCSRMatrixPrintIJ( A_parcsr, offi, offj, fname );
00654 }
00655
00656 void HypreParMatrix::Read( const char* fname )
00657 {
00658 Destroy();
00659 Init();
00660 HYPRE_Int base_i, base_j;
00661 hypre_ParCSRMatrixReadIJ( pcomm->comm(), fname, &base_i, &base_j, &A_parcsr );
00662 hypre_ParCSRMatrixSetNumNonzeros( A_parcsr );
00663 hypre_MatvecCommPkgCreate( A_parcsr );
00664 height = GetNumRows();
00665 width = GetNumCols();
00666 }
00667
00668 void HypreParMatrix::Destroy()
00669 {
00670 if( interpreter )
00671 {
00672 hypre_TFree( interpreter );
00673 }
00674
00675 if( A == NULL )
00676 {
00677 return;
00678 }
00679
00680 else
00681 {
00682 HYPRE_IJMatrixDestroy( A );
00683 }
00684 }
00685
00686 HypreParMatrix* ParMult( HypreParMatrix* A, HypreParMatrix* B )
00687 {
00688 hypre_ParCSRMatrix* ab;
00689 ab = hypre_ParMatmul( A->A_parcsr, B->A_parcsr );
00690 hypre_MatvecCommPkgCreate( ab );
00691 HypreParMatrix* tmpMat = new HypreParMatrix( A->pcomm, A->M(), A->N(), A->RowPart(), A->ColPart(), 0, 0 );
00692 hypre_IJMatrixObject( tmpMat->A ) = ab;
00693 /* Get the parcsr matrix object to use */
00694 HYPRE_IJMatrixGetObject( tmpMat->A, (void**)tmpMat->A_parcsr );
00695 return tmpMat;
00696 }
00697
00698 HypreParMatrix* RAP( HypreParMatrix* A, HypreParMatrix* P )
00699 {
00700 HYPRE_Int P_owns_its_col_starts = hypre_ParCSRMatrixOwnsColStarts( (hypre_ParCSRMatrix*)( P->A_parcsr ) );
00701 hypre_ParCSRMatrix* rap;
00702 hypre_BoomerAMGBuildCoarseOperator( P->A_parcsr, A->A_parcsr, P->A_parcsr, &rap );
00703 hypre_ParCSRMatrixSetNumNonzeros( rap );
00704 // hypre_MatvecCommPkgCreate(rap);
00705 /* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
00706 from P (even if it does not own them)! */
00707 hypre_ParCSRMatrixSetRowStartsOwner( rap, 0 );
00708 hypre_ParCSRMatrixSetColStartsOwner( rap, 0 );
00709
00710 if( P_owns_its_col_starts )
00711 {
00712 hypre_ParCSRMatrixSetColStartsOwner( P->A_parcsr, 1 );
00713 }
00714
00715 HypreParMatrix* tmpMat = new HypreParMatrix( A->pcomm, A->M(), A->N(), A->RowPart(), A->ColPart(), 0, 0 );
00716 hypre_IJMatrixObject( tmpMat->A ) = rap;
00717 /* Get the parcsr matrix object to use */
00718 HYPRE_IJMatrixGetObject( tmpMat->A, (void**)tmpMat->A_parcsr );
00719 return tmpMat;
00720 }
00721
00722 HypreParMatrix* RAP( HypreParMatrix* Rt, HypreParMatrix* A, HypreParMatrix* P )
00723 {
00724 HYPRE_Int P_owns_its_col_starts = hypre_ParCSRMatrixOwnsColStarts( (hypre_ParCSRMatrix*)( P->A_parcsr ) );
00725 HYPRE_Int Rt_owns_its_col_starts = hypre_ParCSRMatrixOwnsColStarts( (hypre_ParCSRMatrix*)( Rt->A_parcsr ) );
00726 hypre_ParCSRMatrix* rap;
00727 hypre_BoomerAMGBuildCoarseOperator( Rt->A_parcsr, A->A_parcsr, P->A_parcsr, &rap );
00728 hypre_ParCSRMatrixSetNumNonzeros( rap );
00729
00730 // hypre_MatvecCommPkgCreate(rap);
00731 if( !P_owns_its_col_starts )
00732 {
00733 /* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
00734 from P (even if it does not own them)! */
00735 hypre_ParCSRMatrixSetColStartsOwner( rap, 0 );
00736 }
00737
00738 if( !Rt_owns_its_col_starts )
00739 {
00740 /* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts
00741 from P (even if it does not own them)! */
00742 hypre_ParCSRMatrixSetRowStartsOwner( rap, 0 );
00743 }
00744
00745 HypreParMatrix* tmpMat = new HypreParMatrix( A->pcomm, A->M(), A->N(), A->RowPart(), A->ColPart(), 0, 0 );
00746 hypre_IJMatrixObject( tmpMat->A ) = rap;
00747 /* Get the parcsr matrix object to use */
00748 HYPRE_IJMatrixGetObject( tmpMat->A, (void**)tmpMat->A_parcsr );
00749 return tmpMat;
00750 }
00751
00752 void EliminateBC( HypreParMatrix& A,
00753 HypreParMatrix& Ae,
00754 const std::vector< int >& ess_dof_list,
00755 const HypreParVector& X,
00756 HypreParVector& B )
00757 {
00758 // B -= Ae*X
00759 Ae.Mult( -1.0, X, 1.0, B );
00760 hypre_CSRMatrix* A_diag = hypre_ParCSRMatrixDiag( (hypre_ParCSRMatrix*)A.A_parcsr );
00761 double* data = hypre_CSRMatrixData( A_diag );
00762 HYPRE_Int* I = hypre_CSRMatrixI( A_diag );
00763 #ifdef MOAB_DEBUG
00764 HYPRE_Int* J = hypre_CSRMatrixJ( A_diag );
00765 hypre_CSRMatrix* A_offd = hypre_ParCSRMatrixOffd( (hypre_ParCSRMatrix*)A.A_parcsr );
00766 HYPRE_Int* I_offd = hypre_CSRMatrixI( A_offd );
00767 double* data_offd = hypre_CSRMatrixData( A_offd );
00768 #endif
00769 std::vector< HYPRE_Complex > bdata( ess_dof_list.size() ), xdata( ess_dof_list.size() );
00770 B.GetValues( ess_dof_list.size(), ess_dof_list.data(), bdata.data() );
00771 X.GetValues( ess_dof_list.size(), ess_dof_list.data(), xdata.data() );
00772
00773 for( size_t i = 0; i < ess_dof_list.size(); i++ )
00774 {
00775 int r = ess_dof_list[i];
00776 bdata[r] = data[I[r]] * xdata[r];
00777 #ifdef MOAB_DEBUG
00778
00779 // Check that in the rows specified by the ess_dof_list, the matrix A has
00780 // only one entry -- the diagonal.
00781 // if (I[r+1] != I[r]+1 || J[I[r]] != r || I_offd[r] != I_offd[r+1])
00782 if( J[I[r]] != r )
00783 {
00784 MB_SET_ERR_RET( "the diagonal entry must be the first entry in the row!" );
00785 }
00786
00787 for( int j = I[r] + 1; j < I[r + 1]; j++ )
00788 {
00789 if( data[j] != 0.0 )
00790 {
00791 MB_SET_ERR_RET( "all off-diagonal entries must be zero!" );
00792 }
00793 }
00794
00795 for( int j = I_offd[r]; j < I_offd[r + 1]; j++ )
00796 {
00797 if( data_offd[j] != 0.0 )
00798 {
00799 MB_SET_ERR_RET( "all off-diagonal entries must be zero!" );
00800 }
00801 }
00802
00803 #endif
00804 }
00805 }
00806
00807 // Taubin or "lambda-mu" scheme, which alternates between positive and
00808 // negative step sizes to approximate low-pass filter effect.
00809
00810 int ParCSRRelax_Taubin( hypre_ParCSRMatrix* A, // matrix to relax with
00811 hypre_ParVector* f, // right-hand side
00812 double lambda,
00813 double mu,
00814 int N,
00815 double max_eig,
00816 hypre_ParVector* u, // initial/updated approximation
00817 hypre_ParVector* r // another temp vector
00818 )
00819 {
00820 hypre_CSRMatrix* A_diag = hypre_ParCSRMatrixDiag( A );
00821 HYPRE_Int num_rows = hypre_CSRMatrixNumRows( A_diag );
00822 double* u_data = hypre_VectorData( hypre_ParVectorLocalVector( u ) );
00823 double* r_data = hypre_VectorData( hypre_ParVectorLocalVector( r ) );
00824
00825 for( int i = 0; i < N; i++ )
00826 {
00827 // get residual: r = f - A*u
00828 hypre_ParVectorCopy( f, r );
00829 hypre_ParCSRMatrixMatvec( -1.0, A, u, 1.0, r );
00830 double coef;
00831 ( 0 == ( i % 2 ) ) ? coef = lambda : coef = mu;
00832
00833 for( HYPRE_Int j = 0; j < num_rows; j++ )
00834 {
00835 u_data[j] += coef * r_data[j] / max_eig;
00836 }
00837 }
00838
00839 return 0;
00840 }
00841
00842 // FIR scheme, which uses Chebyshev polynomials and a window function
00843 // to approximate a low-pass step filter.
00844
00845 int ParCSRRelax_FIR( hypre_ParCSRMatrix* A, // matrix to relax with
00846 hypre_ParVector* f, // right-hand side
00847 double max_eig,
00848 int poly_order,
00849 double* fir_coeffs,
00850 hypre_ParVector* u, // initial/updated approximation
00851 hypre_ParVector* x0, // temporaries
00852 hypre_ParVector* x1,
00853 hypre_ParVector* x2,
00854 hypre_ParVector* x3 )
00855
00856 {
00857 hypre_CSRMatrix* A_diag = hypre_ParCSRMatrixDiag( A );
00858 HYPRE_Int num_rows = hypre_CSRMatrixNumRows( A_diag );
00859 double* u_data = hypre_VectorData( hypre_ParVectorLocalVector( u ) );
00860 double* x0_data = hypre_VectorData( hypre_ParVectorLocalVector( x0 ) );
00861 double* x1_data = hypre_VectorData( hypre_ParVectorLocalVector( x1 ) );
00862 double* x2_data = hypre_VectorData( hypre_ParVectorLocalVector( x2 ) );
00863 double* x3_data = hypre_VectorData( hypre_ParVectorLocalVector( x3 ) );
00864 hypre_ParVectorCopy( u, x0 );
00865 // x1 = f -A*x0/max_eig
00866 hypre_ParVectorCopy( f, x1 );
00867 hypre_ParCSRMatrixMatvec( -1.0, A, x0, 1.0, x1 );
00868
00869 for( HYPRE_Int i = 0; i < num_rows; i++ )
00870 {
00871 x1_data[i] /= -max_eig;
00872 }
00873
00874 // x1 = x0 -x1
00875 for( HYPRE_Int i = 0; i < num_rows; i++ )
00876 {
00877 x1_data[i] = x0_data[i] - x1_data[i];
00878 }
00879
00880 // x3 = f0*x0 +f1*x1
00881 for( HYPRE_Int i = 0; i < num_rows; i++ )
00882 {
00883 x3_data[i] = fir_coeffs[0] * x0_data[i] + fir_coeffs[1] * x1_data[i];
00884 }
00885
00886 for( int n = 2; n <= poly_order; n++ )
00887 {
00888 // x2 = f - A*x1/max_eig
00889 hypre_ParVectorCopy( f, x2 );
00890 hypre_ParCSRMatrixMatvec( -1.0, A, x1, 1.0, x2 );
00891
00892 for( HYPRE_Int i = 0; i < num_rows; i++ )
00893 {
00894 x2_data[i] /= -max_eig;
00895 }
00896
00897 // x2 = (x1-x0) +(x1-2*x2)
00898 // x3 = x3 +f[n]*x2
00899 // x0 = x1
00900 // x1 = x2
00901
00902 for( HYPRE_Int i = 0; i < num_rows; i++ )
00903 {
00904 x2_data[i] = ( x1_data[i] - x0_data[i] ) + ( x1_data[i] - 2 * x2_data[i] );
00905 x3_data[i] += fir_coeffs[n] * x2_data[i];
00906 x0_data[i] = x1_data[i];
00907 x1_data[i] = x2_data[i];
00908 }
00909 }
00910
00911 for( HYPRE_Int i = 0; i < num_rows; i++ )
00912 {
00913 u_data[i] = x3_data[i];
00914 }
00915
00916 return 0;
00917 }
00918
00919 } // namespace moab
00920
00921 #endif