MFEM v2.0
|
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.googlecode.com. 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 #ifdef MFEM_USE_MPI 00013 00014 #include <iostream> 00015 #include <fstream> 00016 #include <iomanip> 00017 #include <math.h> 00018 #include <stdlib.h> 00019 00020 #include "linalg.hpp" 00021 #include "../fem/fem.hpp" 00022 00023 HypreParVector::HypreParVector(int glob_size, int *col) : Vector() 00024 { 00025 x = hypre_ParVectorCreate(MPI_COMM_WORLD,glob_size,col); 00026 hypre_ParVectorInitialize(x); 00027 hypre_ParVectorSetPartitioningOwner(x,0); 00028 // The data will be destroyed by hypre (this is the default) 00029 hypre_ParVectorSetDataOwner(x,1); 00030 hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1); 00031 SetDataAndSize(hypre_VectorData(hypre_ParVectorLocalVector(x)), 00032 hypre_VectorSize(hypre_ParVectorLocalVector(x))); 00033 own_ParVector = 1; 00034 } 00035 00036 HypreParVector::HypreParVector(int glob_size, double *_data, int *col) 00037 : Vector() 00038 { 00039 x = hypre_ParVectorCreate(MPI_COMM_WORLD,glob_size,col); 00040 hypre_ParVectorSetDataOwner(x,1); // owns the seq vector 00041 hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),0); 00042 hypre_ParVectorSetPartitioningOwner(x,0); 00043 hypre_VectorData(hypre_ParVectorLocalVector(x)) = _data; 00044 // If hypre_ParVectorLocalVector(x) is non-NULL, hypre_ParVectorInitialize(x) 00045 // does not allocate memory! 00046 hypre_ParVectorInitialize(x); 00047 SetDataAndSize(hypre_VectorData(hypre_ParVectorLocalVector(x)), 00048 hypre_VectorSize(hypre_ParVectorLocalVector(x))); 00049 own_ParVector = 1; 00050 } 00051 00052 HypreParVector::HypreParVector(const HypreParVector &y) : Vector() 00053 { 00054 x = hypre_ParVectorCreate(MPI_COMM_WORLD, y.x -> global_size, 00055 y.x -> partitioning); 00056 hypre_ParVectorInitialize(x); 00057 hypre_ParVectorSetPartitioningOwner(x,0); 00058 hypre_ParVectorSetDataOwner(x,1); 00059 hypre_SeqVectorSetDataOwner(hypre_ParVectorLocalVector(x),1); 00060 SetDataAndSize(hypre_VectorData(hypre_ParVectorLocalVector(x)), 00061 hypre_VectorSize(hypre_ParVectorLocalVector(x))); 00062 own_ParVector = 1; 00063 } 00064 00065 HypreParVector::HypreParVector(HYPRE_ParVector y) : Vector() 00066 { 00067 x = (hypre_ParVector *) y; 00068 SetDataAndSize(hypre_VectorData(hypre_ParVectorLocalVector(x)), 00069 hypre_VectorSize(hypre_ParVectorLocalVector(x))); 00070 own_ParVector = 0; 00071 } 00072 00073 HypreParVector::operator hypre_ParVector*() const 00074 { 00075 return x; 00076 } 00077 00078 HypreParVector::operator HYPRE_ParVector() const 00079 { 00080 return (HYPRE_ParVector) x; 00081 } 00082 00083 Vector * HypreParVector::GlobalVector() 00084 { 00085 hypre_Vector *hv = hypre_ParVectorToVectorAll(*this); 00086 Vector *v = new Vector(hv->data, hv->size); 00087 v->MakeDataOwner(); 00088 hypre_SeqVectorSetDataOwner(hv,0); 00089 hypre_SeqVectorDestroy(hv); 00090 return v; 00091 } 00092 00093 HypreParVector& HypreParVector::operator=(double d) 00094 { 00095 hypre_ParVectorSetConstantValues(x,d); 00096 return *this; 00097 } 00098 00099 HypreParVector& HypreParVector::operator=(const HypreParVector &y) 00100 { 00101 #ifdef MFEM_DEBUG 00102 if (size != y.Size()) 00103 mfem_error("HypreParVector::operator="); 00104 #endif 00105 00106 for (int i = 0; i < size; i++) 00107 data[i] = y.data[i]; 00108 return *this; 00109 } 00110 00111 void HypreParVector::SetData(double *_data) 00112 { 00113 Vector::data = hypre_VectorData(hypre_ParVectorLocalVector(x)) = _data; 00114 } 00115 00116 int HypreParVector::Randomize(int seed) 00117 { 00118 return hypre_ParVectorSetRandomValues(x,seed); 00119 } 00120 00121 void HypreParVector::Print(const char *fname) 00122 { 00123 hypre_ParVectorPrint(x,fname); 00124 } 00125 00126 HypreParVector::~HypreParVector() 00127 { 00128 if (own_ParVector) 00129 hypre_ParVectorDestroy(x); 00130 } 00131 00132 00133 double InnerProduct(HypreParVector *x, HypreParVector *y) 00134 { 00135 return hypre_ParVectorInnerProd(*x, *y); 00136 } 00137 00138 double InnerProduct(HypreParVector &x, HypreParVector &y) 00139 { 00140 return hypre_ParVectorInnerProd(x, y); 00141 } 00142 00143 00144 HypreParMatrix::HypreParMatrix(int size, int *row, SparseMatrix *diag) 00145 : Operator(size) 00146 { 00147 A = hypre_ParCSRMatrixCreate(MPI_COMM_WORLD, size, size, row, row, 00148 0, diag->NumNonZeroElems(), 0); 00149 hypre_ParCSRMatrixSetDataOwner(A,0); 00150 hypre_ParCSRMatrixSetRowStartsOwner(A,0); 00151 hypre_ParCSRMatrixSetColStartsOwner(A,0); 00152 00153 hypre_CSRMatrixSetDataOwner(A->diag,0); 00154 hypre_CSRMatrixI(A->diag) = diag->GetI(); 00155 hypre_CSRMatrixJ(A->diag) = diag->GetJ(); 00156 hypre_CSRMatrixData(A->diag) = diag->GetData(); 00157 hypre_CSRMatrixSetRownnz(A->diag); 00158 00159 hypre_CSRMatrixSetDataOwner(A->offd,1); 00160 hypre_CSRMatrixI(A->offd) = hypre_CTAlloc(HYPRE_Int, diag->Size()+1); 00161 00162 /* Don't need to call these, since they allocate memory only 00163 if it was not already allocated */ 00164 // hypre_CSRMatrixInitialize(A->diag); 00165 // hypre_ParCSRMatrixInitialize(A); 00166 00167 hypre_ParCSRMatrixSetNumNonzeros(A); 00168 00169 hypre_MatvecCommPkgCreate(A); 00170 00171 CommPkg = NULL; 00172 X = Y = NULL; 00173 } 00174 00175 00176 HypreParMatrix::HypreParMatrix(int M, int N, int *row, int *col, 00177 SparseMatrix *diag) 00178 { 00179 A = hypre_ParCSRMatrixCreate(MPI_COMM_WORLD, M, N, row, col, 00180 0, diag->NumNonZeroElems(), 0); 00181 hypre_ParCSRMatrixSetDataOwner(A,0); 00182 hypre_ParCSRMatrixSetRowStartsOwner(A,0); 00183 hypre_ParCSRMatrixSetColStartsOwner(A,0); 00184 00185 hypre_CSRMatrixSetDataOwner(A->diag,0); 00186 hypre_CSRMatrixI(A->diag) = diag->GetI(); 00187 hypre_CSRMatrixJ(A->diag) = diag->GetJ(); 00188 hypre_CSRMatrixData(A->diag) = diag->GetData(); 00189 hypre_CSRMatrixSetRownnz(A->diag); 00190 00191 hypre_CSRMatrixSetDataOwner(A->offd,1); 00192 hypre_CSRMatrixI(A->offd) = hypre_CTAlloc(HYPRE_Int, diag->Size()+1); 00193 00194 hypre_ParCSRMatrixSetNumNonzeros(A); 00195 00196 hypre_MatvecCommPkgCreate(A); 00197 00198 CommPkg = NULL; 00199 X = Y = NULL; 00200 00201 size = GetNumRows(); 00202 } 00203 00204 HypreParMatrix::HypreParMatrix(int M, int N, int *row, int *col, 00205 SparseMatrix *diag, SparseMatrix *offd, 00206 int *cmap) 00207 { 00208 A = hypre_ParCSRMatrixCreate(MPI_COMM_WORLD, M, N, row, col, 00209 offd->Width(), diag->NumNonZeroElems(), 00210 offd->NumNonZeroElems()); 00211 hypre_ParCSRMatrixSetDataOwner(A,0); 00212 hypre_ParCSRMatrixSetRowStartsOwner(A,0); 00213 hypre_ParCSRMatrixSetColStartsOwner(A,0); 00214 00215 hypre_CSRMatrixSetDataOwner(A->diag,0); 00216 hypre_CSRMatrixI(A->diag) = diag->GetI(); 00217 hypre_CSRMatrixJ(A->diag) = diag->GetJ(); 00218 hypre_CSRMatrixData(A->diag) = diag->GetData(); 00219 hypre_CSRMatrixSetRownnz(A->diag); 00220 00221 hypre_CSRMatrixSetDataOwner(A->offd,0); 00222 hypre_CSRMatrixI(A->offd) = offd->GetI(); 00223 hypre_CSRMatrixJ(A->offd) = offd->GetJ(); 00224 hypre_CSRMatrixData(A->offd) = offd->GetData(); 00225 hypre_CSRMatrixSetRownnz(A->offd); 00226 00227 hypre_ParCSRMatrixColMapOffd(A) = cmap; 00228 00229 hypre_ParCSRMatrixSetNumNonzeros(A); 00230 00231 hypre_MatvecCommPkgCreate(A); 00232 00233 CommPkg = NULL; 00234 X = Y = NULL; 00235 00236 size = GetNumRows(); 00237 } 00238 00239 HypreParMatrix::HypreParMatrix(int *row, int *col, SparseMatrix *sm_a) 00240 { 00241 #ifdef MFEM_DEBUG 00242 if (sm_a == NULL) 00243 mfem_error("HypreParMatrix::HypreParMatrix: sm_a==NULL"); 00244 #endif 00245 00246 hypre_CSRMatrix *csr_a; 00247 00248 csr_a = hypre_CSRMatrixCreate(sm_a -> Size(), sm_a -> Width(), 00249 sm_a -> NumNonZeroElems()); 00250 00251 hypre_CSRMatrixSetDataOwner(csr_a,0); 00252 hypre_CSRMatrixI(csr_a) = sm_a -> GetI(); 00253 hypre_CSRMatrixJ(csr_a) = sm_a -> GetJ(); 00254 hypre_CSRMatrixData(csr_a) = sm_a -> GetData(); 00255 hypre_CSRMatrixSetRownnz(csr_a); 00256 00257 A = hypre_CSRMatrixToParCSRMatrix(MPI_COMM_WORLD,csr_a,row,col); 00258 00259 CommPkg = NULL; 00260 X = Y = NULL; 00261 00262 size = GetNumRows(); 00263 00264 hypre_MatvecCommPkgCreate(A); 00265 } 00266 00267 HypreParMatrix::HypreParMatrix(int M, int N, int *row, int *col, 00268 Table *diag) 00269 { 00270 int nnz = diag->Size_of_connections(); 00271 A = hypre_ParCSRMatrixCreate(MPI_COMM_WORLD, M, N, row, col, 00272 0, nnz, 0); 00273 hypre_ParCSRMatrixSetDataOwner(A,1); 00274 hypre_ParCSRMatrixSetRowStartsOwner(A,0); 00275 hypre_ParCSRMatrixSetColStartsOwner(A,0); 00276 00277 hypre_CSRMatrixSetDataOwner(A->diag,1); 00278 hypre_CSRMatrixI(A->diag) = diag->GetI(); 00279 hypre_CSRMatrixJ(A->diag) = diag->GetJ(); 00280 00281 hypre_CSRMatrixData(A->diag) = hypre_TAlloc(double, nnz); 00282 for (int k = 0; k < nnz; k++) 00283 (hypre_CSRMatrixData(A->diag))[k] = 1.0; 00284 00285 hypre_CSRMatrixSetRownnz(A->diag); 00286 00287 hypre_CSRMatrixSetDataOwner(A->offd,1); 00288 hypre_CSRMatrixI(A->offd) = hypre_CTAlloc(HYPRE_Int, diag->Size()+1); 00289 00290 hypre_ParCSRMatrixSetNumNonzeros(A); 00291 00292 hypre_MatvecCommPkgCreate(A); 00293 00294 CommPkg = NULL; 00295 X = Y = NULL; 00296 00297 size = GetNumRows(); 00298 } 00299 00300 HypreParMatrix::HypreParMatrix(MPI_Comm comm, int id, int np, 00301 int *row, int *col, 00302 int *i_diag, int *j_diag, 00303 int *i_offd, int *j_offd, 00304 int *cmap, int cmap_size) 00305 { 00306 int diag_col, offd_col; 00307 00308 if (HYPRE_AssumedPartitionCheck()) 00309 { 00310 diag_col = i_diag[row[1]-row[0]]; 00311 offd_col = i_offd[row[1]-row[0]]; 00312 00313 A = hypre_ParCSRMatrixCreate(comm, row[2], col[2], row, col, 00314 cmap_size, diag_col, offd_col); 00315 } 00316 else 00317 { 00318 diag_col = i_diag[row[id+1]-row[id]]; 00319 offd_col = i_offd[row[id+1]-row[id]]; 00320 00321 A = hypre_ParCSRMatrixCreate(comm, row[np], col[np], row, col, 00322 cmap_size, diag_col, offd_col); 00323 } 00324 00325 hypre_ParCSRMatrixSetDataOwner(A,1); 00326 hypre_ParCSRMatrixSetRowStartsOwner(A,0); 00327 hypre_ParCSRMatrixSetColStartsOwner(A,0); 00328 00329 int i; 00330 00331 double *a_diag = hypre_TAlloc(double, diag_col); 00332 for (i = 0; i < diag_col; i++) 00333 a_diag[i] = 1.0; 00334 00335 double *a_offd = hypre_TAlloc(double, offd_col); 00336 for (i = 0; i < offd_col; i++) 00337 a_offd[i] = 1.0; 00338 00339 hypre_CSRMatrixSetDataOwner(A->diag,1); 00340 hypre_CSRMatrixI(A->diag) = i_diag; 00341 hypre_CSRMatrixJ(A->diag) = j_diag; 00342 hypre_CSRMatrixData(A->diag) = a_diag; 00343 hypre_CSRMatrixSetRownnz(A->diag); 00344 00345 hypre_CSRMatrixSetDataOwner(A->offd,1); 00346 hypre_CSRMatrixI(A->offd) = i_offd; 00347 hypre_CSRMatrixJ(A->offd) = j_offd; 00348 hypre_CSRMatrixData(A->offd) = a_offd; 00349 hypre_CSRMatrixSetRownnz(A->offd); 00350 00351 hypre_ParCSRMatrixColMapOffd(A) = cmap; 00352 00353 hypre_ParCSRMatrixSetNumNonzeros(A); 00354 00355 hypre_MatvecCommPkgCreate(A); 00356 00357 CommPkg = NULL; 00358 X = Y = NULL; 00359 00360 size = GetNumRows(); 00361 } 00362 00363 HypreParMatrix::HypreParMatrix(MPI_Comm comm, int nrows, int glob_nrows, 00364 int glob_ncols, int *I, int *J, double *data, 00365 int *rows, int *cols) 00366 { 00367 // construct the local CSR matrix 00368 int nnz = I[nrows]; 00369 hypre_CSRMatrix *local = hypre_CSRMatrixCreate(nrows, glob_ncols, nnz); 00370 hypre_CSRMatrixI(local) = I; 00371 hypre_CSRMatrixJ(local) = J; 00372 hypre_CSRMatrixData(local) = data; 00373 hypre_CSRMatrixRownnz(local) = NULL; 00374 hypre_CSRMatrixOwnsData(local) = 1; 00375 hypre_CSRMatrixNumRownnz(local) = nrows; 00376 00377 int part_size, myid; 00378 if (HYPRE_AssumedPartitionCheck()) 00379 { 00380 myid = 0; 00381 part_size = 2; 00382 } 00383 else 00384 { 00385 MPI_Comm_rank(comm, &myid); 00386 MPI_Comm_size(comm, &part_size); 00387 part_size++; 00388 } 00389 00390 // copy in the row and column partitionings 00391 HYPRE_Int *row_starts = hypre_TAlloc(HYPRE_Int, part_size); 00392 HYPRE_Int *col_starts = hypre_TAlloc(HYPRE_Int, part_size); 00393 for (int i = 0; i < part_size; i++) 00394 { 00395 row_starts[i] = rows[i]; 00396 col_starts[i] = cols[i]; 00397 } 00398 00399 // construct the global ParCSR matrix 00400 A = hypre_ParCSRMatrixCreate(comm, glob_nrows, glob_ncols, 00401 row_starts, col_starts, 0, 0, 0); 00402 hypre_ParCSRMatrixOwnsRowStarts(A) = 1; 00403 hypre_ParCSRMatrixOwnsColStarts(A) = 1; 00404 GenerateDiagAndOffd(local, A, col_starts[myid], col_starts[myid+1]-1); 00405 hypre_ParCSRMatrixSetNumNonzeros(A); 00406 hypre_MatvecCommPkgCreate(A); 00407 00408 // delete the local CSR matrix 00409 hypre_CSRMatrixI(local) = NULL; 00410 hypre_CSRMatrixJ(local) = NULL; 00411 hypre_CSRMatrixData(local) = NULL; 00412 hypre_CSRMatrixDestroy(local); 00413 00414 CommPkg = NULL; 00415 X = Y = NULL; 00416 size = GetNumRows(); 00417 } 00418 00419 void HypreParMatrix::SetCommPkg(hypre_ParCSRCommPkg *comm_pkg) 00420 { 00421 CommPkg = comm_pkg; 00422 00423 if (hypre_ParCSRMatrixCommPkg(A)) 00424 hypre_MatvecCommPkgDestroy(hypre_ParCSRMatrixCommPkg(A)); 00425 00426 hypre_ParCSRMatrixCommPkg(A) = comm_pkg; 00427 } 00428 00429 void HypreParMatrix::CheckCommPkg() 00430 { 00431 #ifdef MFEM_DEBUG 00432 if (CommPkg == NULL || CommPkg != hypre_ParCSRMatrixCommPkg(A)) 00433 mfem_error("\nHypreParMatrix::CheckCommPkg()"); 00434 #endif 00435 } 00436 00437 void HypreParMatrix::DestroyCommPkg() 00438 { 00439 if (CommPkg == NULL) 00440 return; 00441 hypre_TFree(CommPkg->send_procs); 00442 hypre_TFree(CommPkg->send_map_starts); 00443 hypre_TFree(CommPkg->send_map_elmts); 00444 hypre_TFree(CommPkg->recv_procs); 00445 hypre_TFree(CommPkg->recv_vec_starts); 00446 if (CommPkg->send_mpi_types) 00447 hypre_TFree(CommPkg->send_mpi_types); 00448 if (CommPkg->recv_mpi_types) 00449 hypre_TFree(CommPkg->recv_mpi_types); 00450 if (hypre_ParCSRMatrixCommPkg(A) == CommPkg) 00451 hypre_ParCSRMatrixCommPkg(A) = NULL; 00452 delete CommPkg; 00453 CommPkg = NULL; 00454 } 00455 00456 HypreParMatrix::operator hypre_ParCSRMatrix*() 00457 { 00458 return (this) ? A : NULL; 00459 } 00460 00461 HypreParMatrix::operator HYPRE_ParCSRMatrix() 00462 { 00463 return (this) ? (HYPRE_ParCSRMatrix) A : (HYPRE_ParCSRMatrix) NULL; 00464 } 00465 00466 hypre_ParCSRMatrix* HypreParMatrix::StealData() 00467 { 00468 hypre_ParCSRMatrix *R = A; 00469 A = NULL; 00470 return R; 00471 } 00472 00473 void HypreParMatrix::GetDiag(Vector &diag) 00474 { 00475 int size=hypre_CSRMatrixNumRows(A->diag); 00476 diag.SetSize(size); 00477 for (int j = 0; j < size; j++) 00478 { 00479 diag(j) = A->diag->data[A->diag->i[j]]; 00480 #ifdef MFEM_DEBUG 00481 if (A->diag->j[A->diag->i[j]] != j) 00482 mfem_error("HypreParMatrix::GetDiag"); 00483 #endif 00484 } 00485 } 00486 00487 00488 HypreParMatrix * HypreParMatrix::Transpose() 00489 { 00490 hypre_ParCSRMatrix * At; 00491 hypre_ParCSRMatrixTranspose(A, &At, 1); 00492 hypre_ParCSRMatrixSetNumNonzeros(At); 00493 00494 hypre_MatvecCommPkgCreate(At); 00495 00496 return new HypreParMatrix(At); 00497 } 00498 00499 int HypreParMatrix::Mult(HypreParVector &x, HypreParVector &y, 00500 double a, double b) 00501 { 00502 return hypre_ParCSRMatrixMatvec(a, A, x, b, y); 00503 } 00504 00505 void HypreParMatrix::Mult(const Vector &x, Vector &y) const 00506 { 00507 if (X == NULL) 00508 { 00509 X = new HypreParVector(GetGlobalNumCols(), 00510 x.GetData(), 00511 GetColStarts()); 00512 Y = new HypreParVector(GetGlobalNumRows(), 00513 y.GetData(), 00514 GetRowStarts()); 00515 } 00516 else 00517 { 00518 X -> SetData(x.GetData()); 00519 Y -> SetData(y.GetData()); 00520 } 00521 00522 hypre_ParCSRMatrixMatvec(1.0, A, *X, 0.0, *Y); 00523 } 00524 00525 void HypreParMatrix::MultTranspose(const Vector &x, Vector &y) const 00526 { 00527 if (X == NULL) 00528 { 00529 X = new HypreParVector(GetGlobalNumCols(), 00530 x.GetData(), 00531 GetColStarts()); 00532 Y = new HypreParVector(GetGlobalNumRows(), 00533 y.GetData(), 00534 GetRowStarts()); 00535 } 00536 else 00537 { 00538 X -> SetData(x.GetData()); 00539 Y -> SetData(y.GetData()); 00540 } 00541 00542 hypre_ParCSRMatrixMatvecT(1.0, A, *X, 0.0, *Y); 00543 } 00544 00545 int HypreParMatrix::Mult(HYPRE_ParVector x, HYPRE_ParVector y, 00546 double a, double b) 00547 { 00548 return hypre_ParCSRMatrixMatvec(a,A,(hypre_ParVector *)x,b,(hypre_ParVector *)y); 00549 } 00550 00551 int HypreParMatrix::MultTranspose(HypreParVector & x, HypreParVector & y, 00552 double a, double b) 00553 { 00554 return hypre_ParCSRMatrixMatvecT(a,A,x,b,y); 00555 } 00556 00557 void HypreParMatrix::Print(const char *fname, int offi, int offj) 00558 { 00559 hypre_ParCSRMatrixPrintIJ(A,offi,offj,fname); 00560 } 00561 00562 void HypreParMatrix::Read(const char *fname) 00563 { 00564 if (A) hypre_ParCSRMatrixDestroy(A); 00565 int io,jo; 00566 hypre_ParCSRMatrixReadIJ(MPI_COMM_WORLD, fname, &io, &jo, &A); 00567 hypre_ParCSRMatrixSetNumNonzeros(A); 00568 00569 hypre_MatvecCommPkgCreate(A); 00570 } 00571 00572 HypreParMatrix::~HypreParMatrix() 00573 { 00574 DestroyCommPkg(); 00575 00576 if (A) 00577 { 00578 if (hypre_ParCSRMatrixCommPkg(A)) 00579 hypre_MatvecCommPkgDestroy(hypre_ParCSRMatrixCommPkg(A)); 00580 hypre_ParCSRMatrixCommPkg(A) = NULL; 00581 00582 if (hypre_CSRMatrixOwnsData(A->diag)) 00583 { 00584 hypre_CSRMatrixDestroy(A->diag); 00585 A->diag = NULL; 00586 } 00587 else 00588 { 00589 if (hypre_CSRMatrixRownnz(A->diag)) 00590 hypre_TFree(hypre_CSRMatrixRownnz(A->diag)); 00591 hypre_TFree(A->diag); 00592 A->diag = NULL; 00593 } 00594 00595 if (hypre_CSRMatrixOwnsData(A->offd)) 00596 { 00597 hypre_CSRMatrixDestroy(A->offd); 00598 A->offd = NULL; 00599 } 00600 else 00601 { 00602 if (hypre_CSRMatrixRownnz(A->offd)) 00603 hypre_TFree(hypre_CSRMatrixRownnz(A->offd)); 00604 } 00605 hypre_ParCSRMatrixDestroy(A); 00606 } 00607 00608 delete X; 00609 delete Y; 00610 } 00611 00612 HypreParMatrix * ParMult(HypreParMatrix *A, HypreParMatrix *B) 00613 { 00614 hypre_ParCSRMatrix * ab; 00615 ab = hypre_ParMatmul(*A,*B); 00616 00617 hypre_MatvecCommPkgCreate(ab); 00618 00619 return new HypreParMatrix(ab); 00620 } 00621 00622 HypreParMatrix * RAP(HypreParMatrix *A, HypreParMatrix *P) 00623 { 00624 int P_owns_its_col_starts = 00625 hypre_ParCSRMatrixOwnsColStarts((hypre_ParCSRMatrix*)(*P)); 00626 hypre_ParCSRMatrix * rap; 00627 hypre_BoomerAMGBuildCoarseOperator(*P,*A,*P,&rap); 00628 00629 hypre_ParCSRMatrixSetNumNonzeros(rap); 00630 // hypre_MatvecCommPkgCreate(rap); 00631 if (!P_owns_its_col_starts) 00632 { 00633 /* Warning: hypre_BoomerAMGBuildCoarseOperator steals the col_starts 00634 from P (even if it does not own them)! */ 00635 hypre_ParCSRMatrixSetRowStartsOwner(rap,0); 00636 hypre_ParCSRMatrixSetColStartsOwner(rap,0); 00637 } 00638 return new HypreParMatrix(rap); 00639 } 00640 00641 void EliminateBC(HypreParMatrix &A, HypreParMatrix &Ae, 00642 Array<int> &ess_dof_list, 00643 HypreParVector &x, HypreParVector &b) 00644 { 00645 // b -= Ae*x 00646 Ae.Mult(x, b, -1.0, 1.0); 00647 00648 hypre_CSRMatrix *A_diag = hypre_ParCSRMatrixDiag((hypre_ParCSRMatrix *)A); 00649 double *data = hypre_CSRMatrixData(A_diag); 00650 int *I = hypre_CSRMatrixI(A_diag); 00651 #ifdef MFEM_DEBUG 00652 int *J = hypre_CSRMatrixJ(A_diag); 00653 int *I_offd = 00654 hypre_CSRMatrixI(hypre_ParCSRMatrixOffd((hypre_ParCSRMatrix *)A)); 00655 #endif 00656 00657 for (int i = 0; i < ess_dof_list.Size(); i++) 00658 { 00659 int r = ess_dof_list[i]; 00660 b(r) = data[I[r]] * x(r); 00661 #ifdef MFEM_DEBUG 00662 // Check that in the rows specified by the ess_dof_list, the matrix A has 00663 // only one entry -- the diagonal. 00664 if (I[r+1] != I[r]+1 || J[I[r]] != r || I_offd[r] != I_offd[r+1]) 00665 mfem_error("EliminateBC (hypre.cpp)"); 00666 #endif 00667 } 00668 } 00669 00670 00671 HypreSolver::HypreSolver() 00672 { 00673 size = 0; 00674 00675 A = NULL; 00676 setup_called = 0; 00677 B = X = NULL; 00678 } 00679 00680 HypreSolver::HypreSolver(HypreParMatrix *_A) 00681 { 00682 size = _A -> GetNumRows(); 00683 00684 A = _A; 00685 setup_called = 0; 00686 B = X = NULL; 00687 } 00688 00689 void HypreSolver::Mult(const HypreParVector &b, HypreParVector &x) const 00690 { 00691 if (A == NULL) 00692 { 00693 mfem_error("HypreSolver::Mult (...) : HypreParMatrix A is missing"); 00694 return; 00695 } 00696 if (!setup_called) 00697 { 00698 SetupFcn()(*this, *A, b, x); 00699 setup_called = 1; 00700 } 00701 00702 SolveFcn()(*this, *A, b, x); 00703 } 00704 00705 void HypreSolver::Mult(const Vector &b, Vector &x) const 00706 { 00707 if (A == NULL) 00708 { 00709 mfem_error("HypreSolver::Mult (...) : HypreParMatrix A is missing"); 00710 return; 00711 } 00712 if (B == NULL) 00713 { 00714 B = new HypreParVector(A -> GetGlobalNumRows(), 00715 b.GetData(), 00716 A -> GetRowStarts()); 00717 X = new HypreParVector(A -> GetGlobalNumCols(), 00718 x.GetData(), 00719 A -> GetColStarts()); 00720 } 00721 else 00722 { 00723 B -> SetData(b.GetData()); 00724 X -> SetData(x.GetData()); 00725 } 00726 00727 Mult(*B, *X); 00728 } 00729 00730 HypreSolver::~HypreSolver() 00731 { 00732 if (B) delete B; 00733 if (X) delete X; 00734 } 00735 00736 00737 HyprePCG::HyprePCG(HypreParMatrix &_A) : HypreSolver(&_A) 00738 { 00739 MPI_Comm comm; 00740 00741 print_level = 0; 00742 use_zero_initial_iterate = 0; 00743 00744 HYPRE_ParCSRMatrixGetComm(*A, &comm); 00745 00746 HYPRE_ParCSRPCGCreate(comm, &pcg_solver); 00747 } 00748 00749 void HyprePCG::SetTol(double tol) 00750 { 00751 HYPRE_ParCSRPCGSetTol(pcg_solver, tol); 00752 } 00753 00754 void HyprePCG::SetMaxIter(int max_iter) 00755 { 00756 HYPRE_ParCSRPCGSetMaxIter(pcg_solver, max_iter); 00757 } 00758 00759 void HyprePCG::SetLogging(int logging) 00760 { 00761 HYPRE_ParCSRPCGSetLogging(pcg_solver, logging); 00762 } 00763 00764 void HyprePCG::SetPrintLevel(int print_lvl) 00765 { 00766 print_level = print_lvl; 00767 HYPRE_ParCSRPCGSetPrintLevel(pcg_solver, print_level); 00768 } 00769 00770 void HyprePCG::SetPreconditioner(HypreSolver &precond) 00771 { 00772 HYPRE_ParCSRPCGSetPrecond(pcg_solver, 00773 precond.SolveFcn(), 00774 precond.SetupFcn(), 00775 precond); 00776 } 00777 00778 void HyprePCG::SetResidualConvergenceOptions(int res_frequency, double rtol) 00779 { 00780 HYPRE_PCGSetTwoNorm(pcg_solver, 1); 00781 if (res_frequency > 0) 00782 HYPRE_PCGSetRecomputeResidualP(pcg_solver, res_frequency); 00783 if (rtol > 0.0) 00784 HYPRE_PCGSetResidualTol(pcg_solver, rtol); 00785 } 00786 00787 void HyprePCG::Mult(const HypreParVector &b, HypreParVector &x) const 00788 { 00789 int myid; 00790 int time_index; 00791 int num_iterations; 00792 double final_res_norm; 00793 MPI_Comm comm; 00794 00795 HYPRE_ParCSRMatrixGetComm(*A, &comm); 00796 00797 if (!setup_called) 00798 { 00799 if (print_level > 0) 00800 { 00801 time_index = hypre_InitializeTiming("PCG Setup"); 00802 hypre_BeginTiming(time_index); 00803 } 00804 00805 HYPRE_ParCSRPCGSetup(pcg_solver, *A, b, x); 00806 setup_called = 1; 00807 00808 if (print_level > 0) 00809 { 00810 hypre_EndTiming(time_index); 00811 hypre_PrintTiming("Setup phase times", comm); 00812 hypre_FinalizeTiming(time_index); 00813 hypre_ClearTiming(); 00814 } 00815 } 00816 00817 if (print_level > 0) 00818 { 00819 time_index = hypre_InitializeTiming("PCG Solve"); 00820 hypre_BeginTiming(time_index); 00821 } 00822 00823 if (use_zero_initial_iterate) 00824 x = 0.0; 00825 00826 HYPRE_ParCSRPCGSolve(pcg_solver, *A, b, x); 00827 00828 if (print_level > 0) 00829 { 00830 hypre_EndTiming(time_index); 00831 hypre_PrintTiming("Solve phase times", comm); 00832 hypre_FinalizeTiming(time_index); 00833 hypre_ClearTiming(); 00834 00835 HYPRE_ParCSRPCGGetNumIterations(pcg_solver, &num_iterations); 00836 HYPRE_ParCSRPCGGetFinalRelativeResidualNorm(pcg_solver, 00837 &final_res_norm); 00838 00839 MPI_Comm_rank(comm, &myid); 00840 00841 if (myid == 0) 00842 { 00843 cout << "PCG Iterations = " << num_iterations << endl 00844 << "Final PCG Relative Residual Norm = " << final_res_norm 00845 << endl; 00846 } 00847 } 00848 } 00849 00850 HyprePCG::~HyprePCG() 00851 { 00852 HYPRE_ParCSRPCGDestroy(pcg_solver); 00853 } 00854 00855 00856 HypreGMRES::HypreGMRES(HypreParMatrix &_A) : HypreSolver(&_A) 00857 { 00858 MPI_Comm comm; 00859 00860 int k_dim = 50; 00861 int max_iter = 100; 00862 double tol = 1e-6; 00863 00864 print_level = 0; 00865 use_zero_initial_iterate = 0; 00866 00867 HYPRE_ParCSRMatrixGetComm(*A, &comm); 00868 00869 HYPRE_ParCSRGMRESCreate(comm, &gmres_solver); 00870 HYPRE_ParCSRGMRESSetKDim(gmres_solver, k_dim); 00871 HYPRE_ParCSRGMRESSetMaxIter(gmres_solver, max_iter); 00872 HYPRE_ParCSRGMRESSetTol(gmres_solver, tol); 00873 } 00874 00875 void HypreGMRES::SetTol(double tol) 00876 { 00877 HYPRE_ParCSRGMRESSetTol(gmres_solver, tol); 00878 } 00879 00880 void HypreGMRES::SetMaxIter(int max_iter) 00881 { 00882 HYPRE_ParCSRGMRESSetMaxIter(gmres_solver, max_iter); 00883 } 00884 00885 void HypreGMRES::SetKDim(int k_dim) 00886 { 00887 HYPRE_ParCSRGMRESSetKDim(gmres_solver, k_dim); 00888 } 00889 00890 void HypreGMRES::SetLogging(int logging) 00891 { 00892 HYPRE_ParCSRGMRESSetLogging(gmres_solver, logging); 00893 } 00894 00895 void HypreGMRES::SetPrintLevel(int print_lvl) 00896 { 00897 print_level = print_lvl; 00898 HYPRE_ParCSRGMRESSetPrintLevel(gmres_solver, print_level); 00899 } 00900 00901 void HypreGMRES::SetPreconditioner(HypreSolver &precond) 00902 { 00903 HYPRE_ParCSRGMRESSetPrecond(gmres_solver, 00904 precond.SolveFcn(), 00905 precond.SetupFcn(), 00906 precond); 00907 } 00908 00909 void HypreGMRES::Mult(const HypreParVector &b, HypreParVector &x) const 00910 { 00911 int myid; 00912 int time_index; 00913 int num_iterations; 00914 double final_res_norm; 00915 MPI_Comm comm; 00916 00917 HYPRE_ParCSRMatrixGetComm(*A, &comm); 00918 00919 if (!setup_called) 00920 { 00921 if (print_level > 0) 00922 { 00923 time_index = hypre_InitializeTiming("GMRES Setup"); 00924 hypre_BeginTiming(time_index); 00925 } 00926 00927 HYPRE_ParCSRGMRESSetup(gmres_solver, *A, b, x); 00928 setup_called = 1; 00929 00930 if (print_level > 0) 00931 { 00932 hypre_EndTiming(time_index); 00933 hypre_PrintTiming("Setup phase times", comm); 00934 hypre_FinalizeTiming(time_index); 00935 hypre_ClearTiming(); 00936 } 00937 } 00938 00939 if (print_level > 0) 00940 { 00941 time_index = hypre_InitializeTiming("GMRES Solve"); 00942 hypre_BeginTiming(time_index); 00943 } 00944 00945 if (use_zero_initial_iterate) 00946 x = 0.0; 00947 00948 HYPRE_ParCSRGMRESSolve(gmres_solver, *A, b, x); 00949 00950 if (print_level > 0) 00951 { 00952 hypre_EndTiming(time_index); 00953 hypre_PrintTiming("Solve phase times", comm); 00954 hypre_FinalizeTiming(time_index); 00955 hypre_ClearTiming(); 00956 00957 HYPRE_ParCSRGMRESGetNumIterations(gmres_solver, &num_iterations); 00958 HYPRE_ParCSRGMRESGetFinalRelativeResidualNorm(gmres_solver, 00959 &final_res_norm); 00960 00961 MPI_Comm_rank(comm, &myid); 00962 00963 if (myid == 0) 00964 { 00965 cout << "GMRES Iterations = " << num_iterations << endl 00966 << "Final GMRES Relative Residual Norm = " << final_res_norm 00967 << endl; 00968 } 00969 } 00970 } 00971 00972 HypreGMRES::~HypreGMRES() 00973 { 00974 HYPRE_ParCSRGMRESDestroy(gmres_solver); 00975 } 00976 00977 00978 HypreParaSails::HypreParaSails(HypreParMatrix &A) : HypreSolver(&A) 00979 { 00980 MPI_Comm comm; 00981 00982 int sai_max_levels = 1; 00983 double sai_threshold = 0.1; 00984 double sai_filter = 0.1; 00985 int sai_sym = 0; 00986 double sai_loadbal = 0.0; 00987 int sai_reuse = 0; 00988 int sai_logging = 1; 00989 00990 HYPRE_ParCSRMatrixGetComm(A, &comm); 00991 00992 HYPRE_ParaSailsCreate(comm, &sai_precond); 00993 HYPRE_ParaSailsSetParams(sai_precond, sai_threshold, sai_max_levels); 00994 HYPRE_ParaSailsSetFilter(sai_precond, sai_filter); 00995 HYPRE_ParaSailsSetSym(sai_precond, sai_sym); 00996 HYPRE_ParaSailsSetLoadbal(sai_precond, sai_loadbal); 00997 HYPRE_ParaSailsSetReuse(sai_precond, sai_reuse); 00998 HYPRE_ParaSailsSetLogging(sai_precond, sai_logging); 00999 } 01000 01001 void HypreParaSails::SetSymmetry(int sym) 01002 { 01003 HYPRE_ParaSailsSetSym(sai_precond, sym); 01004 } 01005 01006 HypreParaSails::~HypreParaSails() 01007 { 01008 HYPRE_ParaSailsDestroy(sai_precond); 01009 } 01010 01011 01012 HypreBoomerAMG::HypreBoomerAMG(HypreParMatrix &A) : HypreSolver(&A) 01013 { 01014 int coarsen_type = 10; 01015 int agg_levels = 1; 01016 int relax_type = 8; 01017 int relax_sweeps = 1; 01018 double theta = 0.25; 01019 int interp_type = 6; 01020 int Pmax = 4; 01021 int print_level = 1; 01022 01023 HYPRE_BoomerAMGCreate(&amg_precond); 01024 01025 HYPRE_BoomerAMGSetCoarsenType(amg_precond, coarsen_type); 01026 HYPRE_BoomerAMGSetAggNumLevels(amg_precond, agg_levels); 01027 HYPRE_BoomerAMGSetRelaxType(amg_precond, relax_type); 01028 HYPRE_BoomerAMGSetNumSweeps(amg_precond, relax_sweeps); 01029 HYPRE_BoomerAMGSetMaxLevels(amg_precond, 25); 01030 HYPRE_BoomerAMGSetTol(amg_precond, 0.0); 01031 HYPRE_BoomerAMGSetMaxIter(amg_precond, 1); // one V-cycle 01032 HYPRE_BoomerAMGSetStrongThreshold(amg_precond, theta); 01033 HYPRE_BoomerAMGSetInterpType(amg_precond, interp_type); 01034 HYPRE_BoomerAMGSetPMaxElmts(amg_precond, Pmax); 01035 HYPRE_BoomerAMGSetPrintLevel(amg_precond, print_level); 01036 } 01037 01038 void HypreBoomerAMG::SetSystemsOptions(int dim) 01039 { 01040 HYPRE_BoomerAMGSetNumFunctions(amg_precond, dim); 01041 01042 // More robust options with respect to convergence 01043 HYPRE_BoomerAMGSetAggNumLevels(amg_precond, 0); 01044 HYPRE_BoomerAMGSetStrongThreshold(amg_precond, 0.5); 01045 } 01046 01047 HypreBoomerAMG::~HypreBoomerAMG() 01048 { 01049 HYPRE_BoomerAMGDestroy(amg_precond); 01050 } 01051 01052 01053 HypreAMS::HypreAMS(HypreParMatrix &A, ParFiniteElementSpace *edge_fespace) 01054 : HypreSolver(&A) 01055 { 01056 int cycle_type = 13; 01057 int rlx_type = 2; 01058 int rlx_sweeps = 1; 01059 double rlx_weight = 1.0; 01060 double rlx_omega = 1.0; 01061 int amg_coarsen_type = 10; 01062 int amg_agg_levels = 1; 01063 int amg_rlx_type = 8; 01064 double theta = 0.25; 01065 int amg_interp_type = 6; 01066 int amg_Pmax = 4; 01067 01068 int p = edge_fespace->GetOrder(0); 01069 int dim = edge_fespace->GetMesh()->Dimension(); 01070 01071 HYPRE_AMSCreate(&ams); 01072 01073 HYPRE_AMSSetDimension(ams, dim); // 2D H(div) and 3D H(curl) problems 01074 HYPRE_AMSSetTol(ams, 0.0); 01075 HYPRE_AMSSetMaxIter(ams, 1); // use as a preconditioner 01076 HYPRE_AMSSetCycleType(ams, cycle_type); 01077 HYPRE_AMSSetPrintLevel(ams, 1); 01078 01079 // define the nodal linear finite element space associated with edge_fespace 01080 ParMesh *pmesh = (ParMesh *) edge_fespace->GetMesh(); 01081 FiniteElementCollection *vert_fec = new H1_FECollection(p, dim); 01082 ParFiniteElementSpace *vert_fespace = new ParFiniteElementSpace(pmesh, vert_fec); 01083 01084 // generate and set the vertex coordinates 01085 if (p == 1) 01086 { 01087 ParGridFunction x_coord(vert_fespace); 01088 ParGridFunction y_coord(vert_fespace); 01089 ParGridFunction z_coord(vert_fespace); 01090 double *coord; 01091 for (int i = 0; i < pmesh->GetNV(); i++) 01092 { 01093 coord = pmesh -> GetVertex(i); 01094 x_coord(i) = coord[0]; 01095 y_coord(i) = coord[1]; 01096 if (dim == 3) 01097 z_coord(i) = coord[2]; 01098 } 01099 x = x_coord.ParallelAverage(); 01100 y = y_coord.ParallelAverage(); 01101 if (dim == 2) 01102 { 01103 z = NULL; 01104 HYPRE_AMSSetCoordinateVectors(ams, *x, *y, NULL); 01105 } 01106 else 01107 { 01108 z = z_coord.ParallelAverage(); 01109 HYPRE_AMSSetCoordinateVectors(ams, *x, *y, *z); 01110 } 01111 } 01112 else 01113 { 01114 x = NULL; 01115 y = NULL; 01116 z = NULL; 01117 } 01118 01119 // generate and set the discrete gradient 01120 ParDiscreteLinearOperator *grad; 01121 grad = new ParDiscreteLinearOperator(vert_fespace, edge_fespace); 01122 grad->AddDomainInterpolator(new GradientInterpolator); 01123 grad->Assemble(); 01124 grad->Finalize(); 01125 G = grad->ParallelAssemble(); 01126 HYPRE_AMSSetDiscreteGradient(ams, *G); 01127 delete grad; 01128 01129 // generate and set the Nedelec interpolation matrices 01130 Pi = Pix = Piy = Piz = NULL; 01131 if (p > 1) 01132 { 01133 ParFiniteElementSpace *vert_fespace_d; 01134 if (cycle_type < 10) 01135 vert_fespace_d = new ParFiniteElementSpace(pmesh, vert_fec, dim, 01136 Ordering::byVDIM); 01137 else 01138 vert_fespace_d = new ParFiniteElementSpace(pmesh, vert_fec, dim, 01139 Ordering::byNODES); 01140 01141 ParDiscreteLinearOperator *id_ND; 01142 id_ND = new ParDiscreteLinearOperator(vert_fespace_d, edge_fespace); 01143 id_ND->AddDomainInterpolator(new IdentityInterpolator); 01144 id_ND->Assemble(); 01145 01146 if (cycle_type < 10) 01147 { 01148 id_ND->Finalize(); 01149 Pi = id_ND->ParallelAssemble(); 01150 } 01151 else 01152 { 01153 Array2D<HypreParMatrix *> Pi_blocks; 01154 id_ND->GetParBlocks(Pi_blocks); 01155 Pix = Pi_blocks(0,0); 01156 Piy = Pi_blocks(0,1); 01157 if (dim == 3) 01158 Piz = Pi_blocks(0,2); 01159 } 01160 01161 HYPRE_AMSSetInterpolations(ams, *Pi, *Pix, *Piy, *Piz); 01162 01163 delete vert_fespace_d; 01164 } 01165 01166 delete vert_fespace; 01167 delete vert_fec; 01168 01169 // set additional AMS options 01170 HYPRE_AMSSetSmoothingOptions(ams, rlx_type, rlx_sweeps, rlx_weight, rlx_omega); 01171 HYPRE_AMSSetAlphaAMGOptions(ams, amg_coarsen_type, amg_agg_levels, amg_rlx_type, 01172 theta, amg_interp_type, amg_Pmax); 01173 HYPRE_AMSSetBetaAMGOptions(ams, amg_coarsen_type, amg_agg_levels, amg_rlx_type, 01174 theta, amg_interp_type, amg_Pmax); 01175 } 01176 01177 HypreAMS::~HypreAMS() 01178 { 01179 HYPRE_AMSDestroy(ams); 01180 01181 delete x; 01182 delete y; 01183 delete z; 01184 01185 delete G; 01186 delete Pi; 01187 delete Pix; 01188 delete Piy; 01189 delete Piz; 01190 } 01191 01192 HypreADS::HypreADS(HypreParMatrix &A, ParFiniteElementSpace *face_fespace) 01193 : HypreSolver(&A) 01194 { 01195 int cycle_type = 11; 01196 int rlx_type = 2; 01197 int rlx_sweeps = 1; 01198 double rlx_weight = 1.0; 01199 double rlx_omega = 1.0; 01200 int amg_coarsen_type = 10; 01201 int amg_agg_levels = 1; 01202 int amg_rlx_type = 6; 01203 double theta = 0.25; 01204 int amg_interp_type = 6; 01205 int amg_Pmax = 4; 01206 int ams_cycle_type = 14; 01207 01208 int p = face_fespace->GetOrder(0); 01209 01210 HYPRE_ADSCreate(&ads); 01211 01212 HYPRE_ADSSetTol(ads, 0.0); 01213 HYPRE_ADSSetMaxIter(ads, 1); // use as a preconditioner 01214 HYPRE_ADSSetCycleType(ads, cycle_type); 01215 HYPRE_ADSSetPrintLevel(ads, 1); 01216 01217 // define the nodal and edge finite element spaces associated with face_fespace 01218 ParMesh *pmesh = (ParMesh *) face_fespace->GetMesh(); 01219 FiniteElementCollection *vert_fec = new H1_FECollection(p, 3); 01220 ParFiniteElementSpace *vert_fespace = new ParFiniteElementSpace(pmesh, vert_fec); 01221 FiniteElementCollection *edge_fec = new ND_FECollection(p, 3); 01222 ParFiniteElementSpace *edge_fespace = new ParFiniteElementSpace(pmesh, edge_fec); 01223 01224 // generate and set the vertex coordinates 01225 if (p == 1) 01226 { 01227 ParGridFunction x_coord(vert_fespace); 01228 ParGridFunction y_coord(vert_fespace); 01229 ParGridFunction z_coord(vert_fespace); 01230 double *coord; 01231 for (int i = 0; i < pmesh->GetNV(); i++) 01232 { 01233 coord = pmesh -> GetVertex(i); 01234 x_coord(i) = coord[0]; 01235 y_coord(i) = coord[1]; 01236 z_coord(i) = coord[2]; 01237 } 01238 x = x_coord.ParallelAverage(); 01239 y = y_coord.ParallelAverage(); 01240 z = z_coord.ParallelAverage(); 01241 HYPRE_ADSSetCoordinateVectors(ads, *x, *y, *z); 01242 } 01243 else 01244 { 01245 x = NULL; 01246 y = NULL; 01247 z = NULL; 01248 } 01249 01250 // generate and set the discrete curl 01251 ParDiscreteLinearOperator *curl; 01252 curl = new ParDiscreteLinearOperator(edge_fespace, face_fespace); 01253 curl->AddDomainInterpolator(new CurlInterpolator); 01254 curl->Assemble(); 01255 curl->Finalize(); 01256 C = curl->ParallelAssemble(); 01257 HYPRE_ADSSetDiscreteCurl(ads, *C); 01258 delete curl; 01259 01260 // generate and set the discrete gradient 01261 ParDiscreteLinearOperator *grad; 01262 grad = new ParDiscreteLinearOperator(vert_fespace, edge_fespace); 01263 grad->AddDomainInterpolator(new GradientInterpolator); 01264 grad->Assemble(); 01265 grad->Finalize(); 01266 G = grad->ParallelAssemble(); 01267 HYPRE_ADSSetDiscreteGradient(ads, *G); 01268 delete grad; 01269 01270 // generate and set the Nedelec and Raviart-Thomas interpolation matrices 01271 RT_Pi = RT_Pix = RT_Piy = RT_Piz = NULL; 01272 ND_Pi = ND_Pix = ND_Piy = ND_Piz = NULL; 01273 if (p > 1) 01274 { 01275 ParFiniteElementSpace *vert_fespace_d; 01276 01277 if (ams_cycle_type < 10) 01278 vert_fespace_d = new ParFiniteElementSpace(pmesh, vert_fec, 3, 01279 Ordering::byVDIM); 01280 else 01281 vert_fespace_d = new ParFiniteElementSpace(pmesh, vert_fec, 3, 01282 Ordering::byNODES); 01283 01284 ParDiscreteLinearOperator *id_ND; 01285 id_ND = new ParDiscreteLinearOperator(vert_fespace_d, edge_fespace); 01286 id_ND->AddDomainInterpolator(new IdentityInterpolator); 01287 id_ND->Assemble(); 01288 01289 if (ams_cycle_type < 10) 01290 { 01291 id_ND->Finalize(); 01292 ND_Pi = id_ND->ParallelAssemble(); 01293 } 01294 else 01295 { 01296 Array2D<HypreParMatrix *> ND_Pi_blocks; 01297 id_ND->GetParBlocks(ND_Pi_blocks); 01298 ND_Pix = ND_Pi_blocks(0,0); 01299 ND_Piy = ND_Pi_blocks(0,1); 01300 ND_Piz = ND_Pi_blocks(0,2); 01301 } 01302 01303 if (cycle_type < 10 && ams_cycle_type > 10) 01304 { 01305 delete vert_fespace_d; 01306 vert_fespace_d = new ParFiniteElementSpace(pmesh, vert_fec, 3, 01307 Ordering::byVDIM); 01308 } 01309 else if (cycle_type > 10 && ams_cycle_type < 10) 01310 { 01311 delete vert_fespace_d; 01312 vert_fespace_d = new ParFiniteElementSpace(pmesh, vert_fec, 3, 01313 Ordering::byNODES); 01314 } 01315 01316 ParDiscreteLinearOperator *id_RT; 01317 id_RT = new ParDiscreteLinearOperator(vert_fespace_d, face_fespace); 01318 id_RT->AddDomainInterpolator(new IdentityInterpolator); 01319 id_RT->Assemble(); 01320 01321 if (cycle_type < 10) 01322 { 01323 id_RT->Finalize(); 01324 RT_Pi = id_RT->ParallelAssemble(); 01325 } 01326 else 01327 { 01328 Array2D<HypreParMatrix *> RT_Pi_blocks; 01329 id_RT->GetParBlocks(RT_Pi_blocks); 01330 RT_Pix = RT_Pi_blocks(0,0); 01331 RT_Piy = RT_Pi_blocks(0,1); 01332 RT_Piz = RT_Pi_blocks(0,2); 01333 } 01334 01335 HYPRE_ADSSetInterpolations(ads, 01336 *RT_Pi, *RT_Pix, *RT_Piy, *RT_Piz, 01337 *ND_Pi, *ND_Pix, *ND_Piy, *ND_Piz); 01338 01339 delete vert_fespace_d; 01340 } 01341 01342 delete vert_fec; 01343 delete vert_fespace; 01344 delete edge_fec; 01345 delete edge_fespace; 01346 01347 // set additional ADS options 01348 HYPRE_ADSSetSmoothingOptions(ads, rlx_type, rlx_sweeps, rlx_weight, rlx_omega); 01349 HYPRE_ADSSetAMGOptions(ads, amg_coarsen_type, amg_agg_levels, amg_rlx_type, 01350 theta, amg_interp_type, amg_Pmax); 01351 HYPRE_ADSSetAMSOptions(ads, ams_cycle_type, amg_coarsen_type, amg_agg_levels, 01352 amg_rlx_type, theta, amg_interp_type, amg_Pmax); 01353 } 01354 01355 HypreADS::~HypreADS() 01356 { 01357 HYPRE_ADSDestroy(ads); 01358 01359 delete x; 01360 delete y; 01361 delete z; 01362 01363 delete G; 01364 delete C; 01365 01366 delete RT_Pi; 01367 delete RT_Pix; 01368 delete RT_Piy; 01369 delete RT_Piz; 01370 01371 delete ND_Pi; 01372 delete ND_Pix; 01373 delete ND_Piy; 01374 delete ND_Piz; 01375 } 01376 01377 #endif