![]() |
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 "hypre_parcsr.hpp"
00013
00014 #ifdef MOAB_HAVE_MPI
00015
00016 #include
00017
00018 namespace moab
00019 {
00020
00021 namespace internal
00022 {
00023
00024 /*--------------------------------------------------------------------------
00025 * A*X = B style elimination
00026 *--------------------------------------------------------------------------*/
00027
00028 /*
00029 Function: hypre_CSRMatrixEliminateAXB
00030
00031 Eliminate the rows and columns of A corresponding to the
00032 given sorted (!) list of rows. Put I on the eliminated diagonal,
00033 subtract columns times X from B.
00034 */
00035 void hypre_CSRMatrixEliminateAXB( hypre_CSRMatrix* A,
00036 HYPRE_Int nrows_to_eliminate,
00037 HYPRE_Int* rows_to_eliminate,
00038 hypre_Vector* X,
00039 hypre_Vector* B )
00040 {
00041 HYPRE_Int i, j;
00042 HYPRE_Int irow, jcol, ibeg, iend, pos;
00043 HYPRE_Real a;
00044
00045 HYPRE_Int* Ai = hypre_CSRMatrixI( A );
00046 HYPRE_Int* Aj = hypre_CSRMatrixJ( A );
00047 HYPRE_Real* Adata = hypre_CSRMatrixData( A );
00048 HYPRE_Int nrows = hypre_CSRMatrixNumRows( A );
00049
00050 HYPRE_Real* Xdata = hypre_VectorData( X );
00051 HYPRE_Real* Bdata = hypre_VectorData( B );
00052
00053 /* eliminate the columns */
00054 for( i = 0; i < nrows; i++ )
00055 {
00056 ibeg = Ai[i];
00057 iend = Ai[i + 1];
00058 for( j = ibeg; j < iend; j++ )
00059 {
00060 jcol = Aj[j];
00061 pos = hypre_BinarySearch( rows_to_eliminate, jcol, nrows_to_eliminate );
00062 if( pos != -1 )
00063 {
00064 a = Adata[j];
00065 Adata[j] = 0.0;
00066 Bdata[i] -= a * Xdata[jcol];
00067 }
00068 }
00069 }
00070
00071 /* remove the rows and set the diagonal equal to 1 */
00072 for( i = 0; i < nrows_to_eliminate; i++ )
00073 {
00074 irow = rows_to_eliminate[i];
00075 ibeg = Ai[irow];
00076 iend = Ai[irow + 1];
00077 for( j = ibeg; j < iend; j++ )
00078 {
00079 if( Aj[j] == irow )
00080 {
00081 Adata[j] = 1.0;
00082 }
00083 else
00084 {
00085 Adata[j] = 0.0;
00086 }
00087 }
00088 }
00089 }
00090
00091 /*
00092 Function: hypre_CSRMatrixEliminateOffdColsAXB
00093
00094 Eliminate the given sorted (!) list of columns of A, subtract them from B.
00095 */
00096 void hypre_CSRMatrixEliminateOffdColsAXB( hypre_CSRMatrix* A,
00097 HYPRE_Int ncols_to_eliminate,
00098 HYPRE_Int* eliminate_cols,
00099 HYPRE_Real* eliminate_coefs,
00100 hypre_Vector* B )
00101 {
00102 HYPRE_Int i, j;
00103 HYPRE_Int ibeg, iend, pos;
00104 HYPRE_Real a;
00105
00106 HYPRE_Int* Ai = hypre_CSRMatrixI( A );
00107 HYPRE_Int* Aj = hypre_CSRMatrixJ( A );
00108 HYPRE_Real* Adata = hypre_CSRMatrixData( A );
00109 HYPRE_Int nrows = hypre_CSRMatrixNumRows( A );
00110
00111 HYPRE_Real* Bdata = hypre_VectorData( B );
00112
00113 for( i = 0; i < nrows; i++ )
00114 {
00115 ibeg = Ai[i];
00116 iend = Ai[i + 1];
00117 for( j = ibeg; j < iend; j++ )
00118 {
00119 pos = hypre_BinarySearch( eliminate_cols, Aj[j], ncols_to_eliminate );
00120 if( pos != -1 )
00121 {
00122 a = Adata[j];
00123 Adata[j] = 0.0;
00124 Bdata[i] -= a * eliminate_coefs[pos];
00125 }
00126 }
00127 }
00128 }
00129
00130 /*
00131 Function: hypre_CSRMatrixEliminateOffdRowsAXB
00132
00133 Eliminate (zero) the given list of rows of A.
00134 */
00135 void hypre_CSRMatrixEliminateOffdRowsAXB( hypre_CSRMatrix* A,
00136 HYPRE_Int nrows_to_eliminate,
00137 HYPRE_Int* rows_to_eliminate )
00138 {
00139 HYPRE_Int* Ai = hypre_CSRMatrixI( A );
00140 HYPRE_Real* Adata = hypre_CSRMatrixData( A );
00141
00142 HYPRE_Int i, j;
00143 HYPRE_Int irow, ibeg, iend;
00144
00145 for( i = 0; i < nrows_to_eliminate; i++ )
00146 {
00147 irow = rows_to_eliminate[i];
00148 ibeg = Ai[irow];
00149 iend = Ai[irow + 1];
00150 for( j = ibeg; j < iend; j++ )
00151 {
00152 Adata[j] = 0.0;
00153 }
00154 }
00155 }
00156
00157 /*
00158 Function: hypre_ParCSRMatrixEliminateAXB
00159
00160 This function eliminates the global rows and columns of a matrix
00161 A corresponding to given lists of sorted (!) local row numbers,
00162 so that the solution to the system A*X = B is X_b for the given rows.
00163
00164 The elimination is done as follows:
00165
00166 (input) (output)
00167
00168 / A_ii | A_ib \ / A_ii | 0 \
00169 A = | -----+----- | ---> | -----+----- |
00170 \ A_bi | A_bb / \ 0 | I /
00171
00172 / X_i \ / X_i \
00173 X = | --- | ---> | --- | (no change)
00174 \ X_b / \ X_b /
00175
00176 / B_i \ / B_i - A_ib * X_b \
00177 B = | --- | ---> | ---------------- |
00178 \ B_b / \ X_b /
00179
00180 */
00181 void hypre_ParCSRMatrixEliminateAXB( hypre_ParCSRMatrix* A,
00182 HYPRE_Int num_rowscols_to_elim,
00183 HYPRE_Int* rowscols_to_elim,
00184 hypre_ParVector* X,
00185 hypre_ParVector* B )
00186 {
00187 hypre_CSRMatrix* diag = hypre_ParCSRMatrixDiag( A );
00188 hypre_CSRMatrix* offd = hypre_ParCSRMatrixOffd( A );
00189 HYPRE_Int diag_nrows = hypre_CSRMatrixNumRows( diag );
00190 HYPRE_Int offd_ncols = hypre_CSRMatrixNumCols( offd );
00191
00192 hypre_Vector* Xlocal = hypre_ParVectorLocalVector( X );
00193 hypre_Vector* Blocal = hypre_ParVectorLocalVector( B );
00194
00195 HYPRE_Real* Bdata = hypre_VectorData( Blocal );
00196 HYPRE_Real* Xdata = hypre_VectorData( Xlocal );
00197
00198 HYPRE_Int num_offd_cols_to_elim;
00199 HYPRE_Int* offd_cols_to_elim;
00200 HYPRE_Real* eliminate_coefs;
00201
00202 /* figure out which offd cols should be eliminated and with what coef */
00203 hypre_ParCSRCommHandle* comm_handle;
00204 hypre_ParCSRCommPkg* comm_pkg;
00205 HYPRE_Int num_sends;
00206 HYPRE_Int index, start;
00207 HYPRE_Int i, j, k, irow;
00208
00209 HYPRE_Real* eliminate_row = hypre_CTAlloc( HYPRE_Real, diag_nrows );
00210 HYPRE_Real* eliminate_col = hypre_CTAlloc( HYPRE_Real, offd_ncols );
00211 HYPRE_Real *buf_data, coef;
00212
00213 /* make sure A has a communication package */
00214 comm_pkg = hypre_ParCSRMatrixCommPkg( A );
00215 if( !comm_pkg )
00216 {
00217 hypre_MatvecCommPkgCreate( A );
00218 comm_pkg = hypre_ParCSRMatrixCommPkg( A );
00219 }
00220
00221 /* HACK: rows that shouldn't be eliminated are marked with quiet NaN;
00222 those that should are set to the boundary value from X; this is to
00223 avoid sending complex type (int+double) or communicating twice. */
00224 for( i = 0; i < diag_nrows; i++ )
00225 {
00226 eliminate_row[i] = std::numeric_limits< HYPRE_Real >::quiet_NaN();
00227 }
00228 for( i = 0; i < num_rowscols_to_elim; i++ )
00229 {
00230 irow = rowscols_to_elim[i];
00231 eliminate_row[irow] = Xdata[irow];
00232 }
00233
00234 /* use a Matvec communication pattern to find (in eliminate_col)
00235 which of the local offd columns are to be eliminated */
00236 num_sends = hypre_ParCSRCommPkgNumSends( comm_pkg );
00237 buf_data = hypre_CTAlloc( HYPRE_Real, hypre_ParCSRCommPkgSendMapStart( comm_pkg, num_sends ) );
00238 index = 0;
00239 for( i = 0; i < num_sends; i++ )
00240 {
00241 start = hypre_ParCSRCommPkgSendMapStart( comm_pkg, i );
00242 for( j = start; j < hypre_ParCSRCommPkgSendMapStart( comm_pkg, i + 1 ); j++ )
00243 {
00244 k = hypre_ParCSRCommPkgSendMapElmt( comm_pkg, j );
00245 buf_data[index++] = eliminate_row[k];
00246 }
00247 }
00248 comm_handle = hypre_ParCSRCommHandleCreate( 1, comm_pkg, buf_data, eliminate_col );
00249
00250 /* do sequential part of the elimination while stuff is getting sent */
00251 hypre_CSRMatrixEliminateAXB( diag, num_rowscols_to_elim, rowscols_to_elim, Xlocal, Blocal );
00252
00253 /* finish the communication */
00254 hypre_ParCSRCommHandleDestroy( comm_handle );
00255
00256 /* received eliminate_col[], count offd columns to eliminate */
00257 num_offd_cols_to_elim = 0;
00258 for( i = 0; i < offd_ncols; i++ )
00259 {
00260 coef = eliminate_col[i];
00261 if( coef == coef ) // test for NaN
00262 {
00263 num_offd_cols_to_elim++;
00264 }
00265 }
00266
00267 offd_cols_to_elim = hypre_CTAlloc( HYPRE_Int, num_offd_cols_to_elim );
00268 eliminate_coefs = hypre_CTAlloc( HYPRE_Real, num_offd_cols_to_elim );
00269
00270 /* get a list of offd column indices and coefs */
00271 num_offd_cols_to_elim = 0;
00272 for( i = 0; i < offd_ncols; i++ )
00273 {
00274 coef = eliminate_col[i];
00275 if( coef == coef ) // test for NaN
00276 {
00277 offd_cols_to_elim[num_offd_cols_to_elim] = i;
00278 eliminate_coefs[num_offd_cols_to_elim] = coef;
00279 num_offd_cols_to_elim++;
00280 }
00281 }
00282
00283 hypre_TFree( buf_data );
00284 hypre_TFree( eliminate_row );
00285 hypre_TFree( eliminate_col );
00286
00287 /* eliminate the off-diagonal part */
00288 hypre_CSRMatrixEliminateOffdColsAXB( offd, num_offd_cols_to_elim, offd_cols_to_elim, eliminate_coefs, Blocal );
00289
00290 hypre_CSRMatrixEliminateOffdRowsAXB( offd, num_rowscols_to_elim, rowscols_to_elim );
00291
00292 /* set boundary values in the rhs */
00293 for( int m = 0; m < num_rowscols_to_elim; m++ )
00294 {
00295 irow = rowscols_to_elim[m];
00296 Bdata[irow] = Xdata[irow];
00297 }
00298
00299 hypre_TFree( offd_cols_to_elim );
00300 hypre_TFree( eliminate_coefs );
00301 }
00302
00303 /*--------------------------------------------------------------------------
00304 * (A + Ae) style elimination
00305 *--------------------------------------------------------------------------*/
00306
00307 /*
00308 Function: hypre_CSRMatrixElimCreate
00309
00310 Prepare the Ae matrix: count nnz, initialize I, allocate J and data.
00311 */
00312 void hypre_CSRMatrixElimCreate( hypre_CSRMatrix* A,
00313 hypre_CSRMatrix* Ae,
00314 HYPRE_Int nrows,
00315 HYPRE_Int* rows,
00316 HYPRE_Int ncols,
00317 HYPRE_Int* cols,
00318 HYPRE_Int* col_mark )
00319 {
00320 HYPRE_Int i, j, col;
00321 HYPRE_Int A_beg, A_end;
00322
00323 HYPRE_Int* A_i = hypre_CSRMatrixI( A );
00324 HYPRE_Int* A_j = hypre_CSRMatrixJ( A );
00325 HYPRE_Int A_rows = hypre_CSRMatrixNumRows( A );
00326
00327 hypre_CSRMatrixI( Ae ) = hypre_TAlloc( HYPRE_Int, A_rows + 1 );
00328
00329 HYPRE_Int* Ae_i = hypre_CSRMatrixI( Ae );
00330 HYPRE_Int nnz = 0;
00331
00332 for( i = 0; i < A_rows; i++ )
00333 {
00334 Ae_i[i] = nnz;
00335
00336 A_beg = A_i[i];
00337 A_end = A_i[i + 1];
00338
00339 if( hypre_BinarySearch( rows, i, nrows ) >= 0 )
00340 {
00341 /* full row */
00342 nnz += A_end - A_beg;
00343
00344 if( col_mark )
00345 {
00346 for( j = A_beg; j < A_end; j++ )
00347 {
00348 col_mark[A_j[j]] = 1;
00349 }
00350 }
00351 }
00352 else
00353 {
00354 /* count columns */
00355 for( j = A_beg; j < A_end; j++ )
00356 {
00357 col = A_j[j];
00358 if( hypre_BinarySearch( cols, col, ncols ) >= 0 )
00359 {
00360 nnz++;
00361 if( col_mark )
00362 {
00363 col_mark[col] = 1;
00364 }
00365 }
00366 }
00367 }
00368 }
00369 Ae_i[A_rows] = nnz;
00370
00371 hypre_CSRMatrixJ( Ae ) = hypre_TAlloc( HYPRE_Int, nnz );
00372 hypre_CSRMatrixData( Ae ) = hypre_TAlloc( HYPRE_Real, nnz );
00373 hypre_CSRMatrixNumNonzeros( Ae ) = nnz;
00374 }
00375
00376 /*
00377 Function: hypre_CSRMatrixEliminateRowsCols
00378
00379 Eliminate rows and columns of A, store eliminated values in Ae.
00380 If 'diag' is nonzero, the eliminated diagonal of A is set to identity.
00381 If 'col_remap' is not NULL it specifies renumbering of columns of Ae.
00382 */
00383 void hypre_CSRMatrixEliminateRowsCols( hypre_CSRMatrix* A,
00384 hypre_CSRMatrix* Ae,
00385 HYPRE_Int nrows,
00386 HYPRE_Int* rows,
00387 HYPRE_Int ncols,
00388 HYPRE_Int* cols,
00389 int diag,
00390 HYPRE_Int* col_remap )
00391 {
00392 HYPRE_Int i, j, k, col;
00393 HYPRE_Int A_beg, Ae_beg, A_end;
00394 HYPRE_Real a;
00395
00396 HYPRE_Int* A_i = hypre_CSRMatrixI( A );
00397 HYPRE_Int* A_j = hypre_CSRMatrixJ( A );
00398 HYPRE_Real* A_data = hypre_CSRMatrixData( A );
00399 HYPRE_Int A_rows = hypre_CSRMatrixNumRows( A );
00400
00401 HYPRE_Int* Ae_i = hypre_CSRMatrixI( Ae );
00402 HYPRE_Int* Ae_j = hypre_CSRMatrixJ( Ae );
00403 HYPRE_Real* Ae_data = hypre_CSRMatrixData( Ae );
00404
00405 for( i = 0; i < A_rows; i++ )
00406 {
00407 A_beg = A_i[i];
00408 A_end = A_i[i + 1];
00409 Ae_beg = Ae_i[i];
00410
00411 if( hypre_BinarySearch( rows, i, nrows ) >= 0 )
00412 {
00413 /* eliminate row */
00414 for( j = A_beg, k = Ae_beg; j < A_end; j++, k++ )
00415 {
00416 col = A_j[j];
00417 Ae_j[k] = col_remap ? col_remap[col] : col;
00418 a = ( diag && col == i ) ? 1.0 : 0.0;
00419 Ae_data[k] = A_data[j] - a;
00420 A_data[j] = a;
00421 }
00422 }
00423 else
00424 {
00425 /* eliminate columns */
00426 for( j = A_beg, k = Ae_beg; j < A_end; j++ )
00427 {
00428 col = A_j[j];
00429 if( hypre_BinarySearch( cols, col, ncols ) >= 0 )
00430 {
00431 Ae_j[k] = col_remap ? col_remap[col] : col;
00432 Ae_data[k] = A_data[j];
00433 A_data[j] = 0.0;
00434 k++;
00435 }
00436 }
00437 }
00438 }
00439 }
00440
00441 /*
00442 Function: hypre_ParCSRMatrixEliminateAAe
00443
00444 (input) (output)
00445
00446 / A_ii | A_ib \ / A_ii | 0 \
00447 A = | -----+----- | ---> | -----+----- |
00448 \ A_bi | A_bb / \ 0 | I /
00449
00450
00451 / 0 | A_ib
00452 \ Ae = | -----+--------- | \ A_bi | A_bb - I /
00453
00454 */
00455 void hypre_ParCSRMatrixEliminateAAe( hypre_ParCSRMatrix* A,
00456 hypre_ParCSRMatrix** Ae,
00457 HYPRE_Int num_rowscols_to_elim,
00458 HYPRE_Int* rowscols_to_elim )
00459 {
00460 HYPRE_Int i, j, k;
00461
00462 hypre_CSRMatrix* A_diag = hypre_ParCSRMatrixDiag( A );
00463 hypre_CSRMatrix* A_offd = hypre_ParCSRMatrixOffd( A );
00464 HYPRE_Int A_diag_nrows = hypre_CSRMatrixNumRows( A_diag );
00465 HYPRE_Int A_offd_ncols = hypre_CSRMatrixNumCols( A_offd );
00466
00467 *Ae = hypre_ParCSRMatrixCreate( hypre_ParCSRMatrixComm( A ), hypre_ParCSRMatrixGlobalNumRows( A ),
00468 hypre_ParCSRMatrixGlobalNumCols( A ), hypre_ParCSRMatrixRowStarts( A ),
00469 hypre_ParCSRMatrixColStarts( A ), 0, 0, 0 );
00470
00471 hypre_ParCSRMatrixSetRowStartsOwner( *Ae, 0 );
00472 hypre_ParCSRMatrixSetColStartsOwner( *Ae, 0 );
00473
00474 hypre_CSRMatrix* Ae_diag = hypre_ParCSRMatrixDiag( *Ae );
00475 hypre_CSRMatrix* Ae_offd = hypre_ParCSRMatrixOffd( *Ae );
00476 HYPRE_Int Ae_offd_ncols;
00477
00478 HYPRE_Int num_offd_cols_to_elim;
00479 HYPRE_Int* offd_cols_to_elim;
00480
00481 HYPRE_Int* A_col_map_offd = hypre_ParCSRMatrixColMapOffd( A );
00482 HYPRE_Int* Ae_col_map_offd;
00483
00484 HYPRE_Int* col_mark;
00485 HYPRE_Int* col_remap;
00486
00487 /* figure out which offd cols should be eliminated */
00488 {
00489 hypre_ParCSRCommHandle* comm_handle;
00490 hypre_ParCSRCommPkg* comm_pkg;
00491 HYPRE_Int num_sends, *int_buf_data;
00492 HYPRE_Int index, start;
00493
00494 HYPRE_Int* eliminate_row = hypre_CTAlloc( HYPRE_Int, A_diag_nrows );
00495 HYPRE_Int* eliminate_col = hypre_CTAlloc( HYPRE_Int, A_offd_ncols );
00496
00497 /* make sure A has a communication package */
00498 comm_pkg = hypre_ParCSRMatrixCommPkg( A );
00499 if( !comm_pkg )
00500 {
00501 hypre_MatvecCommPkgCreate( A );
00502 comm_pkg = hypre_ParCSRMatrixCommPkg( A );
00503 }
00504
00505 /* which of the local rows are to be eliminated */
00506 for( i = 0; i < A_diag_nrows; i++ )
00507 {
00508 eliminate_row[i] = 0;
00509 }
00510 for( i = 0; i < num_rowscols_to_elim; i++ )
00511 {
00512 eliminate_row[rowscols_to_elim[i]] = 1;
00513 }
00514
00515 /* use a Matvec communication pattern to find (in eliminate_col)
00516 which of the local offd columns are to be eliminated */
00517 num_sends = hypre_ParCSRCommPkgNumSends( comm_pkg );
00518 int_buf_data = hypre_CTAlloc( HYPRE_Int, hypre_ParCSRCommPkgSendMapStart( comm_pkg, num_sends ) );
00519 index = 0;
00520 for( i = 0; i < num_sends; i++ )
00521 {
00522 start = hypre_ParCSRCommPkgSendMapStart( comm_pkg, i );
00523 for( j = start; j < hypre_ParCSRCommPkgSendMapStart( comm_pkg, i + 1 ); j++ )
00524 {
00525 k = hypre_ParCSRCommPkgSendMapElmt( comm_pkg, j );
00526 int_buf_data[index++] = eliminate_row[k];
00527 }
00528 }
00529 comm_handle = hypre_ParCSRCommHandleCreate( 11, comm_pkg, int_buf_data, eliminate_col );
00530
00531 /* eliminate diagonal part, overlapping it with communication */
00532 hypre_CSRMatrixElimCreate( A_diag, Ae_diag, num_rowscols_to_elim, rowscols_to_elim, num_rowscols_to_elim,
00533 rowscols_to_elim, NULL );
00534
00535 hypre_CSRMatrixEliminateRowsCols( A_diag, Ae_diag, num_rowscols_to_elim, rowscols_to_elim,
00536 num_rowscols_to_elim, rowscols_to_elim, 1, NULL );
00537 hypre_CSRMatrixReorder( Ae_diag );
00538
00539 /* finish the communication */
00540 hypre_ParCSRCommHandleDestroy( comm_handle );
00541
00542 /* received eliminate_col[], count offd columns to eliminate */
00543 num_offd_cols_to_elim = 0;
00544 for( i = 0; i < A_offd_ncols; i++ )
00545 {
00546 if( eliminate_col[i] )
00547 {
00548 num_offd_cols_to_elim++;
00549 }
00550 }
00551
00552 offd_cols_to_elim = hypre_CTAlloc( HYPRE_Int, num_offd_cols_to_elim );
00553
00554 /* get a list of offd column indices and coefs */
00555 num_offd_cols_to_elim = 0;
00556 for( i = 0; i < A_offd_ncols; i++ )
00557 {
00558 if( eliminate_col[i] )
00559 {
00560 offd_cols_to_elim[num_offd_cols_to_elim++] = i;
00561 }
00562 }
00563
00564 hypre_TFree( int_buf_data );
00565 hypre_TFree( eliminate_row );
00566 hypre_TFree( eliminate_col );
00567 }
00568
00569 /* eliminate the off-diagonal part */
00570 col_mark = hypre_CTAlloc( HYPRE_Int, A_offd_ncols );
00571 col_remap = hypre_CTAlloc( HYPRE_Int, A_offd_ncols );
00572
00573 hypre_CSRMatrixElimCreate( A_offd, Ae_offd, num_rowscols_to_elim, rowscols_to_elim, num_offd_cols_to_elim,
00574 offd_cols_to_elim, col_mark );
00575
00576 for( i = k = 0; i < A_offd_ncols; i++ )
00577 {
00578 if( col_mark[i] )
00579 {
00580 col_remap[i] = k++;
00581 }
00582 }
00583
00584 hypre_CSRMatrixEliminateRowsCols( A_offd, Ae_offd, num_rowscols_to_elim, rowscols_to_elim,
00585 num_offd_cols_to_elim, offd_cols_to_elim, 0, col_remap );
00586
00587 /* create col_map_offd for Ae */
00588 Ae_offd_ncols = 0;
00589 for( i = 0; i < A_offd_ncols; i++ )
00590 {
00591 if( col_mark[i] )
00592 {
00593 Ae_offd_ncols++;
00594 }
00595 }
00596
00597 Ae_col_map_offd = hypre_CTAlloc( HYPRE_Int, Ae_offd_ncols );
00598
00599 Ae_offd_ncols = 0;
00600 for( i = 0; i < A_offd_ncols; i++ )
00601 {
00602 if( col_mark[i] )
00603 {
00604 Ae_col_map_offd[Ae_offd_ncols++] = A_col_map_offd[i];
00605 }
00606 }
00607
00608 hypre_ParCSRMatrixColMapOffd( *Ae ) = Ae_col_map_offd;
00609 hypre_CSRMatrixNumCols( Ae_offd ) = Ae_offd_ncols;
00610
00611 hypre_TFree( col_remap );
00612 hypre_TFree( col_mark );
00613 hypre_TFree( offd_cols_to_elim );
00614
00615 hypre_ParCSRMatrixSetNumNonzeros( *Ae );
00616 hypre_MatvecCommPkgCreate( *Ae );
00617 }
00618
00619 /*--------------------------------------------------------------------------
00620 * Split
00621 *--------------------------------------------------------------------------*/
00622
00623 void hypre_CSRMatrixSplit( hypre_CSRMatrix* A,
00624 HYPRE_Int nr,
00625 HYPRE_Int nc,
00626 HYPRE_Int* row_block_num,
00627 HYPRE_Int* col_block_num,
00628 hypre_CSRMatrix** blocks )
00629 {
00630 HYPRE_Int i, j, k, bi, bj;
00631
00632 HYPRE_Int* A_i = hypre_CSRMatrixI( A );
00633 HYPRE_Int* A_j = hypre_CSRMatrixJ( A );
00634 HYPRE_Complex* A_data = hypre_CSRMatrixData( A );
00635
00636 HYPRE_Int A_rows = hypre_CSRMatrixNumRows( A );
00637 HYPRE_Int A_cols = hypre_CSRMatrixNumCols( A );
00638
00639 HYPRE_Int* num_rows = hypre_CTAlloc( HYPRE_Int, nr );
00640 HYPRE_Int* num_cols = hypre_CTAlloc( HYPRE_Int, nc );
00641
00642 HYPRE_Int* block_row = hypre_TAlloc( HYPRE_Int, A_rows );
00643 HYPRE_Int* block_col = hypre_TAlloc( HYPRE_Int, A_cols );
00644
00645 for( i = 0; i < A_rows; i++ )
00646 {
00647 block_row[i] = num_rows[row_block_num[i]]++;
00648 }
00649 for( j = 0; j < A_cols; j++ )
00650 {
00651 block_col[j] = num_cols[col_block_num[j]]++;
00652 }
00653
00654 /* allocate the blocks */
00655 for( i = 0; i < nr; i++ )
00656 {
00657 for( j = 0; j < nc; j++ )
00658 {
00659 hypre_CSRMatrix* B = hypre_CSRMatrixCreate( num_rows[i], num_cols[j], 0 );
00660 hypre_CSRMatrixI( B ) = hypre_CTAlloc( HYPRE_Int, num_rows[i] + 1 );
00661 blocks[i * nc + j] = B;
00662 }
00663 }
00664
00665 /* count block row nnz */
00666 for( i = 0; i < A_rows; i++ )
00667 {
00668 bi = row_block_num[i];
00669 for( j = A_i[i]; j < A_i[i + 1]; j++ )
00670 {
00671 bj = col_block_num[A_j[j]];
00672 hypre_CSRMatrix* B = blocks[bi * nc + bj];
00673 hypre_CSRMatrixI( B )[block_row[i] + 1]++;
00674 }
00675 }
00676
00677 /* count block nnz */
00678 for( k = 0; k < nr * nc; k++ )
00679 {
00680 hypre_CSRMatrix* B = blocks[k];
00681 HYPRE_Int* B_i = hypre_CSRMatrixI( B );
00682
00683 HYPRE_Int nnz = 0, rs;
00684 for( int m = 1; m <= hypre_CSRMatrixNumRows( B ); m++ )
00685 {
00686 rs = B_i[m], B_i[m] = nnz, nnz += rs;
00687 }
00688
00689 hypre_CSRMatrixJ( B ) = hypre_TAlloc( HYPRE_Int, nnz );
00690 hypre_CSRMatrixData( B ) = hypre_TAlloc( HYPRE_Complex, nnz );
00691 hypre_CSRMatrixNumNonzeros( B ) = nnz;
00692 }
00693
00694 /* populate blocks */
00695 for( i = 0; i < A_rows; i++ )
00696 {
00697 bi = row_block_num[i];
00698 for( j = A_i[i]; j < A_i[i + 1]; j++ )
00699 {
00700 k = A_j[j];
00701 bj = col_block_num[k];
00702 hypre_CSRMatrix* B = blocks[bi * nc + bj];
00703 HYPRE_Int* bii = hypre_CSRMatrixI( B ) + block_row[i] + 1;
00704 hypre_CSRMatrixJ( B )[*bii] = block_col[k];
00705 hypre_CSRMatrixData( B )[*bii] = A_data[j];
00706 ( *bii )++;
00707 }
00708 }
00709
00710 hypre_TFree( block_col );
00711 hypre_TFree( block_row );
00712
00713 hypre_TFree( num_cols );
00714 hypre_TFree( num_rows );
00715 }
00716
00717 void hypre_ParCSRMatrixSplit( hypre_ParCSRMatrix* A,
00718 HYPRE_Int nr,
00719 HYPRE_Int nc,
00720 hypre_ParCSRMatrix** blocks,
00721 int interleaved_rows,
00722 int interleaved_cols )
00723 {
00724 HYPRE_Int i, j, k;
00725
00726 MPI_Comm comm = hypre_ParCSRMatrixComm( A );
00727
00728 hypre_CSRMatrix* Adiag = hypre_ParCSRMatrixDiag( A );
00729 hypre_CSRMatrix* Aoffd = hypre_ParCSRMatrixOffd( A );
00730
00731 HYPRE_Int global_rows = hypre_ParCSRMatrixGlobalNumRows( A );
00732 HYPRE_Int global_cols = hypre_ParCSRMatrixGlobalNumCols( A );
00733
00734 HYPRE_Int local_rows = hypre_CSRMatrixNumRows( Adiag );
00735 HYPRE_Int local_cols = hypre_CSRMatrixNumCols( Adiag );
00736 HYPRE_Int offd_cols = hypre_CSRMatrixNumCols( Aoffd );
00737
00738 hypre_assert( local_rows % nr == 0 && local_cols % nc == 0 );
00739 hypre_assert( global_rows % nr == 0 && global_cols % nc == 0 );
00740
00741 HYPRE_Int block_rows = local_rows / nr;
00742 HYPRE_Int block_cols = local_cols / nc;
00743 HYPRE_Int num_blocks = nr * nc;
00744
00745 /* mark local rows and columns with block number */
00746 HYPRE_Int* row_block_num = hypre_TAlloc( HYPRE_Int, local_rows );
00747 HYPRE_Int* col_block_num = hypre_TAlloc( HYPRE_Int, local_cols );
00748
00749 for( i = 0; i < local_rows; i++ )
00750 {
00751 row_block_num[i] = interleaved_rows ? ( i % nr ) : ( i / block_rows );
00752 }
00753 for( i = 0; i < local_cols; i++ )
00754 {
00755 col_block_num[i] = interleaved_cols ? ( i % nc ) : ( i / block_cols );
00756 }
00757
00758 /* determine the block numbers for offd columns */
00759 HYPRE_Int* offd_col_block_num = hypre_TAlloc( HYPRE_Int, offd_cols );
00760 hypre_ParCSRCommHandle* comm_handle;
00761 HYPRE_Int* int_buf_data;
00762 {
00763 /* make sure A has a communication package */
00764 hypre_ParCSRCommPkg* comm_pkg = hypre_ParCSRMatrixCommPkg( A );
00765 if( !comm_pkg )
00766 {
00767 hypre_MatvecCommPkgCreate( A );
00768 comm_pkg = hypre_ParCSRMatrixCommPkg( A );
00769 }
00770
00771 /* calculate the final global column numbers for each block */
00772 HYPRE_Int* count = hypre_CTAlloc( HYPRE_Int, nc );
00773 HYPRE_Int* block_global_col = hypre_TAlloc( HYPRE_Int, local_cols );
00774 HYPRE_Int first_col = hypre_ParCSRMatrixFirstColDiag( A ) / nc;
00775 for( i = 0; i < local_cols; i++ )
00776 {
00777 block_global_col[i] = first_col + count[col_block_num[i]]++;
00778 }
00779 hypre_TFree( count );
00780
00781 /* use a Matvec communication pattern to determine offd_col_block_num */
00782 HYPRE_Int num_sends = hypre_ParCSRCommPkgNumSends( comm_pkg );
00783 int_buf_data = hypre_CTAlloc( HYPRE_Int, hypre_ParCSRCommPkgSendMapStart( comm_pkg, num_sends ) );
00784 HYPRE_Int start, index = 0;
00785 for( i = 0; i < num_sends; i++ )
00786 {
00787 start = hypre_ParCSRCommPkgSendMapStart( comm_pkg, i );
00788 for( j = start; j < hypre_ParCSRCommPkgSendMapStart( comm_pkg, i + 1 ); j++ )
00789 {
00790 k = hypre_ParCSRCommPkgSendMapElmt( comm_pkg, j );
00791 int_buf_data[index++] = col_block_num[k] + nc * block_global_col[k];
00792 }
00793 }
00794 hypre_TFree( block_global_col );
00795
00796 comm_handle = hypre_ParCSRCommHandleCreate( 11, comm_pkg, int_buf_data, offd_col_block_num );
00797 }
00798
00799 /* create the block matrices */
00800 HYPRE_Int num_procs = 1;
00801 if( !hypre_ParCSRMatrixAssumedPartition( A ) )
00802 {
00803 hypre_MPI_Comm_size( comm, &num_procs );
00804 }
00805
00806 HYPRE_Int* row_starts = hypre_TAlloc( HYPRE_Int, num_procs + 1 );
00807 HYPRE_Int* col_starts = hypre_TAlloc( HYPRE_Int, num_procs + 1 );
00808 for( i = 0; i <= num_procs; i++ )
00809 {
00810 row_starts[i] = hypre_ParCSRMatrixRowStarts( A )[i] / nr;
00811 col_starts[i] = hypre_ParCSRMatrixColStarts( A )[i] / nc;
00812 }
00813
00814 for( i = 0; i < num_blocks; i++ )
00815 {
00816 blocks[i] =
00817 hypre_ParCSRMatrixCreate( comm, global_rows / nr, global_cols / nc, row_starts, col_starts, 0, 0, 0 );
00818 }
00819
00820 /* split diag part */
00821 hypre_CSRMatrix** csr_blocks = hypre_TAlloc( hypre_CSRMatrix*, nr * nc );
00822 hypre_CSRMatrixSplit( Adiag, nr, nc, row_block_num, col_block_num, csr_blocks );
00823
00824 for( i = 0; i < num_blocks; i++ )
00825 {
00826 hypre_TFree( hypre_ParCSRMatrixDiag( blocks[i] ) );
00827 hypre_ParCSRMatrixDiag( blocks[i] ) = csr_blocks[i];
00828 }
00829
00830 /* finish communication, receive offd_col_block_num */
00831 hypre_ParCSRCommHandleDestroy( comm_handle );
00832 hypre_TFree( int_buf_data );
00833
00834 /* decode global offd column numbers */
00835 HYPRE_Int* offd_global_col = hypre_TAlloc( HYPRE_Int, offd_cols );
00836 for( i = 0; i < offd_cols; i++ )
00837 {
00838 offd_global_col[i] = offd_col_block_num[i] / nc;
00839 offd_col_block_num[i] %= nc;
00840 }
00841
00842 /* split offd part */
00843 hypre_CSRMatrixSplit( Aoffd, nr, nc, row_block_num, offd_col_block_num, csr_blocks );
00844
00845 for( i = 0; i < num_blocks; i++ )
00846 {
00847 hypre_TFree( hypre_ParCSRMatrixOffd( blocks[i] ) );
00848 hypre_ParCSRMatrixOffd( blocks[i] ) = csr_blocks[i];
00849 }
00850
00851 hypre_TFree( csr_blocks );
00852 hypre_TFree( col_block_num );
00853 hypre_TFree( row_block_num );
00854
00855 /* update block col-maps */
00856 for( int bi = 0; bi < nr; bi++ )
00857 {
00858 for( int bj = 0; bj < nc; bj++ )
00859 {
00860 hypre_ParCSRMatrix* block = blocks[bi * nc + bj];
00861 hypre_CSRMatrix* block_offd = hypre_ParCSRMatrixOffd( block );
00862 HYPRE_Int block_offd_cols = hypre_CSRMatrixNumCols( block_offd );
00863
00864 HYPRE_Int* block_col_map = hypre_TAlloc( HYPRE_Int, block_offd_cols );
00865 for( i = j = 0; i < offd_cols; i++ )
00866 {
00867 HYPRE_Int bn = offd_col_block_num[i];
00868 if( bn == bj )
00869 {
00870 block_col_map[j++] = offd_global_col[i];
00871 }
00872 }
00873 hypre_assert( j == block_offd_cols );
00874
00875 hypre_ParCSRMatrixColMapOffd( block ) = block_col_map;
00876 }
00877 }
00878
00879 hypre_TFree( offd_global_col );
00880 hypre_TFree( offd_col_block_num );
00881
00882 /* finish the new matrices, make them own all the stuff */
00883 for( i = 0; i < num_blocks; i++ )
00884 {
00885 hypre_ParCSRMatrixSetNumNonzeros( blocks[i] );
00886 hypre_MatvecCommPkgCreate( blocks[i] );
00887
00888 hypre_ParCSRMatrixOwnsData( blocks[i] ) = 1;
00889
00890 /* only the first block will own the row/col_starts */
00891 hypre_ParCSRMatrixOwnsRowStarts( blocks[i] ) = !i;
00892 hypre_ParCSRMatrixOwnsColStarts( blocks[i] ) = !i;
00893 }
00894 }
00895
00896 /* Based on hypre_CSRMatrixMatvec in hypre's csr_matvec.c */
00897 void hypre_CSRMatrixBooleanMatvec( hypre_CSRMatrix* A,
00898 HYPRE_Bool alpha,
00899 HYPRE_Bool* x,
00900 HYPRE_Bool beta,
00901 HYPRE_Bool* y )
00902 {
00903 /* HYPRE_Complex *A_data = hypre_CSRMatrixData(A); */
00904 HYPRE_Int* A_i = hypre_CSRMatrixI( A );
00905 HYPRE_Int* A_j = hypre_CSRMatrixJ( A );
00906 HYPRE_Int num_rows = hypre_CSRMatrixNumRows( A );
00907
00908 HYPRE_Int* A_rownnz = hypre_CSRMatrixRownnz( A );
00909 HYPRE_Int num_rownnz = hypre_CSRMatrixNumRownnz( A );
00910
00911 HYPRE_Bool* x_data = x;
00912 HYPRE_Bool* y_data = y;
00913
00914 HYPRE_Bool temp, tempx;
00915
00916 HYPRE_Int i, jj;
00917
00918 HYPRE_Int m;
00919
00920 HYPRE_Real xpar = 0.7;
00921
00922 /*-----------------------------------------------------------------------
00923 * Do (alpha == 0.0) computation - RDF: USE MACHINE EPS
00924 *-----------------------------------------------------------------------*/
00925
00926 if( alpha == 0 )
00927 {
00928 #ifdef HYPRE_USING_OPENMP
00929 #pragma omp parallel for private( i ) HYPRE_SMP_SCHEDULE
00930 #endif
00931 for( i = 0; i < num_rows; i++ )
00932 {
00933 y_data[i] = y_data[i] && beta;
00934 }
00935 return;
00936 }
00937
00938 /*-----------------------------------------------------------------------
00939 * y = (beta/alpha)*y
00940 *-----------------------------------------------------------------------*/
00941
00942 if( beta == 0 )
00943 {
00944 #ifdef HYPRE_USING_OPENMP
00945 #pragma omp parallel for private( i ) HYPRE_SMP_SCHEDULE
00946 #endif
00947 for( i = 0; i < num_rows; i++ )
00948 {
00949 y_data[i] = 0;
00950 }
00951 }
00952 else
00953 {
00954 /* beta is true -> no change to y_data */
00955 }
00956
00957 /*-----------------------------------------------------------------
00958 * y += A*x
00959 *-----------------------------------------------------------------*/
00960
00961 /* use rownnz pointer to do the A*x multiplication when num_rownnz is smaller than num_rows
00962 */
00963
00964 if( num_rownnz < xpar * ( num_rows ) )
00965 {
00966 #ifdef HYPRE_USING_OPENMP
00967 #pragma omp parallel for private( i, jj, m, tempx ) HYPRE_SMP_SCHEDULE
00968 #endif
00969 for( i = 0; i < num_rownnz; i++ )
00970 {
00971 m = A_rownnz[i];
00972
00973 tempx = 0;
00974 for( jj = A_i[m]; jj < A_i[m + 1]; jj++ )
00975 {
00976 /* tempx = tempx || ((A_data[jj] != 0.0) && x_data[A_j[jj]]); */
00977 tempx = tempx || x_data[A_j[jj]];
00978 }
00979 y_data[m] = y_data[m] || tempx;
00980 }
00981 }
00982 else
00983 {
00984 #ifdef HYPRE_USING_OPENMP
00985 #pragma omp parallel for private( i, jj, temp ) HYPRE_SMP_SCHEDULE
00986 #endif
00987 for( i = 0; i < num_rows; i++ )
00988 {
00989 temp = 0;
00990 for( jj = A_i[i]; jj < A_i[i + 1]; jj++ )
00991 {
00992 /* temp = temp || ((A_data[jj] != 0.0) && x_data[A_j[jj]]); */
00993 temp = temp || x_data[A_j[jj]];
00994 }
00995 y_data[i] = y_data[i] || temp;
00996 }
00997 }
00998
00999 /*-----------------------------------------------------------------
01000 * y = alpha*y
01001 *-----------------------------------------------------------------*/
01002 /* alpha is true */
01003 }
01004
01005 /* Based on hypre_ParCSRCommHandleCreate in hypre's par_csr_communication.c. The
01006 input variable job controls the communication type: 1=Matvec, 2=MatvecT. */
01007 hypre_ParCSRCommHandle* hypre_ParCSRCommHandleCreate_bool( HYPRE_Int job,
01008 hypre_ParCSRCommPkg* comm_pkg,
01009 HYPRE_Bool* send_data,
01010 HYPRE_Bool* recv_data )
01011 {
01012 HYPRE_Int num_sends = hypre_ParCSRCommPkgNumSends( comm_pkg );
01013 HYPRE_Int num_recvs = hypre_ParCSRCommPkgNumRecvs( comm_pkg );
01014 MPI_Comm comm = hypre_ParCSRCommPkgComm( comm_pkg );
01015
01016 hypre_ParCSRCommHandle* comm_handle;
01017 HYPRE_Int num_requests;
01018 hypre_MPI_Request* requests;
01019
01020 HYPRE_Int i, j;
01021 HYPRE_Int my_id, num_procs;
01022 HYPRE_Int ip, vec_start, vec_len;
01023
01024 num_requests = num_sends + num_recvs;
01025 requests = hypre_CTAlloc( hypre_MPI_Request, num_requests );
01026
01027 hypre_MPI_Comm_size( comm, &num_procs );
01028 hypre_MPI_Comm_rank( comm, &my_id );
01029
01030 j = 0;
01031 switch( job )
01032 {
01033 case 1: {
01034 HYPRE_Bool* d_send_data = (HYPRE_Bool*)send_data;
01035 HYPRE_Bool* d_recv_data = (HYPRE_Bool*)recv_data;
01036 for( i = 0; i < num_recvs; i++ )
01037 {
01038 ip = hypre_ParCSRCommPkgRecvProc( comm_pkg, i );
01039 vec_start = hypre_ParCSRCommPkgRecvVecStart( comm_pkg, i );
01040 vec_len = hypre_ParCSRCommPkgRecvVecStart( comm_pkg, i + 1 ) - vec_start;
01041 hypre_MPI_Irecv( &d_recv_data[vec_start], vec_len, HYPRE_MPI_BOOL, ip, 0, comm, &requests[j++] );
01042 }
01043 for( i = 0; i < num_sends; i++ )
01044 {
01045 vec_start = hypre_ParCSRCommPkgSendMapStart( comm_pkg, i );
01046 vec_len = hypre_ParCSRCommPkgSendMapStart( comm_pkg, i + 1 ) - vec_start;
01047 ip = hypre_ParCSRCommPkgSendProc( comm_pkg, i );
01048 hypre_MPI_Isend( &d_send_data[vec_start], vec_len, HYPRE_MPI_BOOL, ip, 0, comm, &requests[j++] );
01049 }
01050 break;
01051 }
01052 case 2: {
01053 HYPRE_Bool* d_send_data = (HYPRE_Bool*)send_data;
01054 HYPRE_Bool* d_recv_data = (HYPRE_Bool*)recv_data;
01055 for( i = 0; i < num_sends; i++ )
01056 {
01057 vec_start = hypre_ParCSRCommPkgSendMapStart( comm_pkg, i );
01058 vec_len = hypre_ParCSRCommPkgSendMapStart( comm_pkg, i + 1 ) - vec_start;
01059 ip = hypre_ParCSRCommPkgSendProc( comm_pkg, i );
01060 hypre_MPI_Irecv( &d_recv_data[vec_start], vec_len, HYPRE_MPI_BOOL, ip, 0, comm, &requests[j++] );
01061 }
01062 for( i = 0; i < num_recvs; i++ )
01063 {
01064 ip = hypre_ParCSRCommPkgRecvProc( comm_pkg, i );
01065 vec_start = hypre_ParCSRCommPkgRecvVecStart( comm_pkg, i );
01066 vec_len = hypre_ParCSRCommPkgRecvVecStart( comm_pkg, i + 1 ) - vec_start;
01067 hypre_MPI_Isend( &d_send_data[vec_start], vec_len, HYPRE_MPI_BOOL, ip, 0, comm, &requests[j++] );
01068 }
01069 break;
01070 }
01071 }
01072 /*--------------------------------------------------------------------
01073 * set up comm_handle and return
01074 *--------------------------------------------------------------------*/
01075
01076 comm_handle = hypre_CTAlloc( hypre_ParCSRCommHandle, 1 );
01077
01078 hypre_ParCSRCommHandleCommPkg( comm_handle ) = comm_pkg;
01079 hypre_ParCSRCommHandleSendData( comm_handle ) = send_data;
01080 hypre_ParCSRCommHandleRecvData( comm_handle ) = recv_data;
01081 hypre_ParCSRCommHandleNumRequests( comm_handle ) = num_requests;
01082 hypre_ParCSRCommHandleRequests( comm_handle ) = requests;
01083
01084 return comm_handle;
01085 }
01086
01087 /* Based on hypre_ParCSRMatrixMatvec in par_csr_matvec.c */
01088 void hypre_ParCSRMatrixBooleanMatvec( hypre_ParCSRMatrix* A,
01089 HYPRE_Bool alpha,
01090 HYPRE_Bool* x,
01091 HYPRE_Bool beta,
01092 HYPRE_Bool* y )
01093 {
01094 hypre_ParCSRCommHandle* comm_handle;
01095 hypre_ParCSRCommPkg* comm_pkg = hypre_ParCSRMatrixCommPkg( A );
01096 hypre_CSRMatrix* diag = hypre_ParCSRMatrixDiag( A );
01097 hypre_CSRMatrix* offd = hypre_ParCSRMatrixOffd( A );
01098
01099 HYPRE_Int num_cols_offd = hypre_CSRMatrixNumCols( offd );
01100 HYPRE_Int num_sends, i, j, index;
01101
01102 HYPRE_Bool *x_tmp, *x_buf;
01103
01104 x_tmp = hypre_CTAlloc( HYPRE_Bool, num_cols_offd );
01105
01106 /*---------------------------------------------------------------------
01107 * If there exists no CommPkg for A, a CommPkg is generated using
01108 * equally load balanced partitionings
01109 *--------------------------------------------------------------------*/
01110 if( !comm_pkg )
01111 {
01112 hypre_MatvecCommPkgCreate( A );
01113 comm_pkg = hypre_ParCSRMatrixCommPkg( A );
01114 }
01115
01116 num_sends = hypre_ParCSRCommPkgNumSends( comm_pkg );
01117 x_buf = hypre_CTAlloc( HYPRE_Bool, hypre_ParCSRCommPkgSendMapStart( comm_pkg, num_sends ) );
01118
01119 index = 0;
01120 for( i = 0; i < num_sends; i++ )
01121 {
01122 j = hypre_ParCSRCommPkgSendMapStart( comm_pkg, i );
01123 for( ; j < hypre_ParCSRCommPkgSendMapStart( comm_pkg, i + 1 ); j++ )
01124 {
01125 x_buf[index++] = x[hypre_ParCSRCommPkgSendMapElmt( comm_pkg, j )];
01126 }
01127 }
01128
01129 comm_handle = hypre_ParCSRCommHandleCreate_bool( 1, comm_pkg, x_buf, x_tmp );
01130
01131 hypre_CSRMatrixBooleanMatvec( diag, alpha, x, beta, y );
01132
01133 hypre_ParCSRCommHandleDestroy( comm_handle );
01134
01135 if( num_cols_offd )
01136 {
01137 hypre_CSRMatrixBooleanMatvec( offd, alpha, x_tmp, 1, y );
01138 }
01139
01140 hypre_TFree( x_buf );
01141 hypre_TFree( x_tmp );
01142 }
01143
01144 HYPRE_Int hypre_CSRMatrixSum( hypre_CSRMatrix* A, HYPRE_Complex beta, hypre_CSRMatrix* B )
01145 {
01146 HYPRE_Complex* A_data = hypre_CSRMatrixData( A );
01147 HYPRE_Int* A_i = hypre_CSRMatrixI( A );
01148 HYPRE_Int* A_j = hypre_CSRMatrixJ( A );
01149 HYPRE_Int nrows_A = hypre_CSRMatrixNumRows( A );
01150 HYPRE_Int ncols_A = hypre_CSRMatrixNumCols( A );
01151 HYPRE_Complex* B_data = hypre_CSRMatrixData( B );
01152 HYPRE_Int* B_i = hypre_CSRMatrixI( B );
01153 HYPRE_Int* B_j = hypre_CSRMatrixJ( B );
01154 HYPRE_Int nrows_B = hypre_CSRMatrixNumRows( B );
01155 HYPRE_Int ncols_B = hypre_CSRMatrixNumCols( B );
01156
01157 HYPRE_Int ia, j, pos;
01158 HYPRE_Int* marker;
01159
01160 if( nrows_A != nrows_B || ncols_A != ncols_B )
01161 {
01162 return -1; /* error: incompatible matrix dimensions */
01163 }
01164
01165 marker = hypre_CTAlloc( HYPRE_Int, ncols_A );
01166 for( ia = 0; ia < ncols_A; ia++ )
01167 {
01168 marker[ia] = -1;
01169 }
01170
01171 for( ia = 0; ia < nrows_A; ia++ )
01172 {
01173 for( j = A_i[ia]; j < A_i[ia + 1]; j++ )
01174 {
01175 marker[A_j[j]] = j;
01176 }
01177
01178 for( j = B_i[ia]; j < B_i[ia + 1]; j++ )
01179 {
01180 pos = marker[B_j[j]];
01181 if( pos < A_i[ia] )
01182 {
01183 return -2; /* error: found an entry in B that is not present in A */
01184 }
01185 A_data[pos] += beta * B_data[j];
01186 }
01187 }
01188
01189 hypre_TFree( marker );
01190 return 0;
01191 }
01192
01193 hypre_ParCSRMatrix* hypre_ParCSRMatrixAdd( hypre_ParCSRMatrix* A, hypre_ParCSRMatrix* B )
01194 {
01195 MPI_Comm comm = hypre_ParCSRMatrixComm( A );
01196 hypre_CSRMatrix* A_diag = hypre_ParCSRMatrixDiag( A );
01197 hypre_CSRMatrix* A_offd = hypre_ParCSRMatrixOffd( A );
01198 HYPRE_Int* A_cmap = hypre_ParCSRMatrixColMapOffd( A );
01199 HYPRE_Int A_cmap_size = hypre_CSRMatrixNumCols( A_offd );
01200 hypre_CSRMatrix* B_diag = hypre_ParCSRMatrixDiag( B );
01201 hypre_CSRMatrix* B_offd = hypre_ParCSRMatrixOffd( B );
01202 HYPRE_Int* B_cmap = hypre_ParCSRMatrixColMapOffd( B );
01203 HYPRE_Int B_cmap_size = hypre_CSRMatrixNumCols( B_offd );
01204 hypre_ParCSRMatrix* C;
01205 hypre_CSRMatrix* C_diag;
01206 hypre_CSRMatrix* C_offd;
01207 HYPRE_Int* C_cmap;
01208 HYPRE_Int im;
01209 HYPRE_Int cmap_differ;
01210
01211 /* Check if A_cmap and B_cmap are the same. */
01212 cmap_differ = 0;
01213 if( A_cmap_size != B_cmap_size )
01214 {
01215 cmap_differ = 1; /* A and B have different cmap_size */
01216 }
01217 else
01218 {
01219 for( im = 0; im < A_cmap_size; im++ )
01220 {
01221 if( A_cmap[im] != B_cmap[im] )
01222 {
01223 cmap_differ = 1; /* A and B have different cmap arrays */
01224 break;
01225 }
01226 }
01227 }
01228
01229 if( cmap_differ == 0 )
01230 {
01231 /* A and B have the same column mapping for their off-diagonal blocks so
01232 we can sum the diagonal and off-diagonal blocks separately and reduce
01233 temporary memory usage. */
01234
01235 /* Add diagonals, off-diagonals, copy cmap. */
01236 C_diag = hypre_CSRMatrixAdd( A_diag, B_diag );
01237 if( !C_diag )
01238 {
01239 return NULL; /* error: A_diag and B_diag have different dimensions */
01240 }
01241 C_offd = hypre_CSRMatrixAdd( A_offd, B_offd );
01242 if( !C_offd )
01243 {
01244 hypre_CSRMatrixDestroy( C_diag );
01245 return NULL; /* error: A_offd and B_offd have different dimensions */
01246 }
01247 /* copy A_cmap -> C_cmap */
01248 C_cmap = hypre_TAlloc( HYPRE_Int, A_cmap_size );
01249 for( im = 0; im < A_cmap_size; im++ )
01250 {
01251 C_cmap[im] = A_cmap[im];
01252 }
01253
01254 C = hypre_ParCSRMatrixCreate( comm, hypre_ParCSRMatrixGlobalNumRows( A ),
01255 hypre_ParCSRMatrixGlobalNumCols( A ), hypre_ParCSRMatrixRowStarts( A ),
01256 hypre_ParCSRMatrixColStarts( A ), hypre_CSRMatrixNumCols( C_offd ),
01257 hypre_CSRMatrixNumNonzeros( C_diag ), hypre_CSRMatrixNumNonzeros( C_offd ) );
01258
01259 /* In C, destroy diag/offd (allocated by Create) and replace them with
01260 C_diag/C_offd. */
01261 hypre_CSRMatrixDestroy( hypre_ParCSRMatrixDiag( C ) );
01262 hypre_CSRMatrixDestroy( hypre_ParCSRMatrixOffd( C ) );
01263 hypre_ParCSRMatrixDiag( C ) = C_diag;
01264 hypre_ParCSRMatrixOffd( C ) = C_offd;
01265
01266 hypre_ParCSRMatrixColMapOffd( C ) = C_cmap;
01267 }
01268 else
01269 {
01270 /* A and B have different column mappings for their off-diagonal blocks so
01271 we need to use the column maps to create full-width CSR matricies. */
01272
01273 int ierr = 0;
01274 hypre_CSRMatrix* csr_A;
01275 hypre_CSRMatrix* csr_B;
01276 hypre_CSRMatrix* csr_C_temp;
01277
01278 /* merge diag and off-diag portions of A */
01279 csr_A = hypre_MergeDiagAndOffd( A );
01280
01281 /* merge diag and off-diag portions of B */
01282 csr_B = hypre_MergeDiagAndOffd( B );
01283
01284 /* add A and B */
01285 csr_C_temp = hypre_CSRMatrixAdd( csr_A, csr_B );
01286
01287 /* delete CSR versions of A and B */
01288 ierr += hypre_CSRMatrixDestroy( csr_A );
01289 ierr += hypre_CSRMatrixDestroy( csr_B );
01290
01291 /* create a new empty ParCSR matrix to contain the sum */
01292 C = hypre_ParCSRMatrixCreate( hypre_ParCSRMatrixComm( A ), hypre_ParCSRMatrixGlobalNumRows( A ),
01293 hypre_ParCSRMatrixGlobalNumCols( A ), hypre_ParCSRMatrixRowStarts( A ),
01294 hypre_ParCSRMatrixColStarts( A ), 0, 0, 0 );
01295
01296 /* split C into diag and off-diag portions */
01297 /* FIXME: GenerateDiagAndOffd() uses an int array of size equal to the
01298 number of columns in csr_C_temp which is the global number of columns
01299 in A and B. This does not scale well. */
01300 ierr += GenerateDiagAndOffd( csr_C_temp, C, hypre_ParCSRMatrixFirstColDiag( A ),
01301 hypre_ParCSRMatrixLastColDiag( A ) );
01302
01303 /* delete CSR version of C */
01304 ierr += hypre_CSRMatrixDestroy( csr_C_temp );
01305 }
01306
01307 /* hypre_ParCSRMatrixSetNumNonzeros(A); */
01308
01309 /* Make sure that the first entry in each row is the diagonal one. */
01310 hypre_CSRMatrixReorder( hypre_ParCSRMatrixDiag( C ) );
01311
01312 /* C owns diag, offd, and cmap. */
01313 hypre_ParCSRMatrixSetDataOwner( C, 1 );
01314 /* C does not own row and column starts. */
01315 hypre_ParCSRMatrixSetRowStartsOwner( C, 0 );
01316 hypre_ParCSRMatrixSetColStartsOwner( C, 0 );
01317
01318 return C;
01319 }
01320
01321 HYPRE_Int hypre_ParCSRMatrixSum( hypre_ParCSRMatrix* A, HYPRE_Complex beta, hypre_ParCSRMatrix* B )
01322 {
01323 hypre_CSRMatrix* A_diag = hypre_ParCSRMatrixDiag( A );
01324 hypre_CSRMatrix* A_offd = hypre_ParCSRMatrixOffd( A );
01325 hypre_CSRMatrix* B_diag = hypre_ParCSRMatrixDiag( B );
01326 hypre_CSRMatrix* B_offd = hypre_ParCSRMatrixOffd( B );
01327 HYPRE_Int error;
01328
01329 error = hypre_CSRMatrixSum( A_diag, beta, B_diag );
01330 error = error ? error : hypre_CSRMatrixSum( A_offd, beta, B_offd );
01331
01332 return error;
01333 }
01334
01335 HYPRE_Int hypre_CSRMatrixSetConstantValues( hypre_CSRMatrix* A, HYPRE_Complex value )
01336 {
01337 HYPRE_Complex* A_data = hypre_CSRMatrixData( A );
01338 HYPRE_Int A_nnz = hypre_CSRMatrixNumNonzeros( A );
01339 HYPRE_Int ia;
01340
01341 for( ia = 0; ia < A_nnz; ia++ )
01342 {
01343 A_data[ia] = value;
01344 }
01345
01346 return 0;
01347 }
01348
01349 HYPRE_Int hypre_ParCSRMatrixSetConstantValues( hypre_ParCSRMatrix* A, HYPRE_Complex value )
01350 {
01351 hypre_CSRMatrixSetConstantValues( hypre_ParCSRMatrixDiag( A ), value );
01352 hypre_CSRMatrixSetConstantValues( hypre_ParCSRMatrixOffd( A ), value );
01353
01354 return 0;
01355 }
01356
01357 } // namespace internal
01358
01359 } // namespace moab
01360
01361 #endif // MOAB_HAVE_MPI