20 bool ownReal,
bool ownImag,
22 :
Operator(2*((Op_Real)?Op_Real->Height():Op_Imag->Height()),
23 2*((Op_Real)?Op_Real->Width():Op_Imag->Width()))
28 , convention_(convention)
47 MFEM_ASSERT(
Op_Real_,
"ComplexOperator has no real part!");
53 MFEM_ASSERT(
Op_Imag_,
"ComplexOperator has no imaginary part!");
59 MFEM_ASSERT(
Op_Real_,
"ComplexOperator has no real part!");
65 MFEM_ASSERT(
Op_Imag_,
"ComplexOperator has no imaginary part!");
184 MFEM_ASSERT(
Op_Real_,
"ComplexSparseMatrix has no real part!");
190 MFEM_ASSERT(
Op_Imag_,
"ComplexSparseMatrix has no imaginary part!");
196 MFEM_ASSERT(
Op_Real_,
"ComplexSparseMatrix has no real part!");
202 MFEM_ASSERT(
Op_Imag_,
"ComplexSparseMatrix has no imaginary part!");
211 const int nrows_r = (A_r)?A_r->
Height():0;
212 const int nrows_i = (A_i)?A_i->
Height():0;
213 const int nrows = std::max(nrows_r, nrows_i);
215 const int *I_r = (A_r)?A_r->
GetI():NULL;
216 const int *I_i = (A_i)?A_i->
GetI():NULL;
218 const int *J_r = (A_r)?A_r->
GetJ():NULL;
219 const int *J_i = (A_i)?A_i->
GetJ():NULL;
221 const double *D_r = (A_r)?A_r->
GetData():NULL;
222 const double *D_i = (A_i)?A_i->
GetData():NULL;
224 const int nnz_r = (I_r)?I_r[nrows]:0;
225 const int nnz_i = (I_i)?I_i[nrows]:0;
226 const int nnz = 2 * (nnz_r + nnz_i);
235 I[nrows] = nnz_r + nnz_i;
236 for (
int i=0; i<nrows; i++)
238 I[i + 1] = ((I_r)?I_r[i+1]:0) + ((I_i)?I_i[i+1]:0);
239 I[i + nrows + 1] = I[i+1] + nnz_r + nnz_i;
243 const int off_i = (I_i)?(I_i[i+1] - I_i[i]):0;
244 for (
int j=0; j<I_r[i+1] - I_r[i]; j++)
246 J[I[i] + j] = J_r[I_r[i] + j];
247 D[I[i] + j] = D_r[I_r[i] + j];
249 J[I[i+nrows] + off_i + j] = J_r[I_r[i] + j] + nrows;
250 D[I[i+nrows] + off_i + j] = factor*D_r[I_r[i] + j];
255 const int off_r = (I_r)?(I_r[i+1] - I_r[i]):0;
256 for (
int j=0; j<I_i[i+1] - I_i[i]; j++)
258 J[I[i] + off_r + j] = J_i[I_i[i] + j] + nrows;
259 D[I[i] + off_r + j] = -D_i[I_i[i] + j];
261 J[I[i+nrows] + j] = J_i[I_i[i] + j];
262 D[I[i+nrows] + j] = factor*D_i[I_i[i] + j];
271 #ifdef MFEM_USE_SUITESPARSE
299 umfpack_zi_free_numeric(&
Numeric);
303 umfpack_zl_free_numeric(&
Numeric);
309 MFEM_VERIFY(
mat,
"not a ComplexSparseMatrix");
312 "Real and imag Sparsity pattern mismatch: Try setting Assemble (skip_zeros = 0)");
323 MFEM_VERIFY(
width ==
height,
"not a square matrix");
332 int status = umfpack_zi_symbolic(
width,
width,Ap,Ai,Ax,Az,&Symbolic,
337 umfpack_zi_report_status(
Control, status);
338 mfem_error(
"ComplexUMFPackSolver::SetOperator :"
339 " umfpack_zi_symbolic() failed!");
342 status = umfpack_zi_numeric(Ap, Ai, Ax, Az, Symbolic, &
Numeric,
347 umfpack_zi_report_status(
Control, status);
348 mfem_error(
"ComplexUMFPackSolver::SetOperator :"
349 " umfpack_zi_numeric() failed!");
351 umfpack_zi_free_symbolic(&Symbolic);
355 SuiteSparse_long status;
359 AI =
new SuiteSparse_long[
width + 1];
360 AJ =
new SuiteSparse_long[Ap[
width]];
361 for (
int i = 0; i <=
width; i++)
363 AI[i] = (SuiteSparse_long)(Ap[i]);
365 for (
int i = 0; i < Ap[
width]; i++)
367 AJ[i] = (SuiteSparse_long)(Ai[i]);
370 status = umfpack_zl_symbolic(
width,
width,
AI,
AJ, Ax, Az, &Symbolic,
375 umfpack_zl_report_status(
Control, status);
376 mfem_error(
"ComplexUMFPackSolver::SetOperator :"
377 " umfpack_zl_symbolic() failed!");
380 status = umfpack_zl_numeric(
AI,
AJ, Ax, Az, Symbolic, &
Numeric,
385 umfpack_zl_report_status(
Control, status);
386 mfem_error(
"ComplexUMFPackSolver::SetOperator :"
387 " umfpack_zl_numeric() failed!");
389 umfpack_zl_free_symbolic(&Symbolic);
396 mfem_error(
"ComplexUMFPackSolver::Mult : matrix is not set!"
397 " Call SetOperator first!");
406 if (conv == ComplexOperator::Convention::BLOCK_SYMMETRIC)
419 umfpack_zi_report_info(Control,
Info);
422 umfpack_zi_report_status(Control, status);
423 mfem_error(
"ComplexUMFPackSolver::Mult : umfpack_zi_solve() failed!");
428 SuiteSparse_long status =
433 umfpack_zl_report_info(Control,
Info);
436 umfpack_zl_report_status(Control, status);
437 mfem_error(
"ComplexUMFPackSolver::Mult : umfpack_zl_solve() failed!");
440 if (conv == ComplexOperator::Convention::BLOCK_SYMMETRIC)
449 mfem_error(
"ComplexUMFPackSolver::Mult : matrix is not set!"
450 " Call SetOperator first!");
473 umfpack_zi_report_info(Control,
Info);
476 umfpack_zi_report_status(Control, status);
477 mfem_error(
"ComplexUMFPackSolver::Mult : umfpack_zi_solve() failed!");
482 SuiteSparse_long status =
487 umfpack_zl_report_info(Control,
Info);
490 umfpack_zl_report_status(Control, status);
491 mfem_error(
"ComplexUMFPackSolver::Mult : umfpack_zl_solve() failed!");
515 umfpack_zi_free_numeric(&
Numeric);
519 umfpack_zl_free_numeric(&
Numeric);
530 bool ownReal,
bool ownImag,
534 comm_ = (A_Real) ? A_Real->
GetComm() :
535 ((A_Imag) ? A_Imag->
GetComm() : MPI_COMM_WORLD);
537 MPI_Comm_rank(comm_, &myid_);
538 MPI_Comm_size(comm_, &nranks_);
543 MFEM_ASSERT(
Op_Real_,
"ComplexHypreParMatrix has no real part!");
549 MFEM_ASSERT(
Op_Imag_,
"ComplexHypreParMatrix has no imaginary part!");
555 MFEM_ASSERT(
Op_Real_,
"ComplexHypreParMatrix has no real part!");
561 MFEM_ASSERT(
Op_Imag_,
"ComplexHypreParMatrix has no imaginary part!");
570 if ( A_r == NULL && A_i == NULL ) {
return NULL; }
574 HYPRE_Int global_num_rows = std::max(global_num_rows_r, global_num_rows_i);
578 HYPRE_Int global_num_cols = std::max(global_num_cols_r, global_num_cols_i);
580 int row_starts_size = (HYPRE_AssumedPartitionCheck()) ? 2 : nranks_ + 1;
581 HYPRE_Int * row_starts = mfem_hypre_CTAlloc(HYPRE_Int, row_starts_size);
582 HYPRE_Int * col_starts = mfem_hypre_CTAlloc(HYPRE_Int, row_starts_size);
584 const HYPRE_Int * row_starts_z = (A_r) ? A_r->
RowPart() :
585 ((A_i) ? A_i->
RowPart() : NULL);
586 const HYPRE_Int * col_starts_z = (A_r) ? A_r->
ColPart() :
587 ((A_i) ? A_i->
ColPart() : NULL);
589 for (
int i = 0; i < row_starts_size; i++)
591 row_starts[i] = 2 * row_starts_z[i];
592 col_starts[i] = 2 * col_starts_z[i];
596 HYPRE_Int * cmap_r, * cmap_i;
598 int nrows_r = 0, nrows_i = 0, ncols_r = 0, ncols_i = 0;
599 int ncols_offd_r = 0, ncols_offd_i = 0;
604 nrows_r = diag_r.
Height();
605 ncols_r = diag_r.
Width();
606 ncols_offd_r = offd_r.
Width();
612 nrows_i = diag_i.
Height();
613 ncols_i = diag_i.
Width();
614 ncols_offd_i = offd_i.
Width();
616 int nrows = std::max(nrows_r, nrows_i);
617 int ncols = std::max(ncols_r, ncols_i);
621 for (
int i=0; i<ncols_offd_r; i++)
623 cset.insert(cmap_r[i]);
625 for (
int i=0; i<ncols_offd_i; i++)
627 cset.insert(cmap_i[i]);
629 int num_cols_offd = (int)cset.size();
632 const int * diag_r_I = (A_r) ? diag_r.
GetI() : NULL;
633 const int * diag_i_I = (A_i) ? diag_i.
GetI() : NULL;
635 const int * diag_r_J = (A_r) ? diag_r.
GetJ() : NULL;
636 const int * diag_i_J = (A_i) ? diag_i.
GetJ() : NULL;
638 const double * diag_r_D = (A_r) ? diag_r.
GetData() : NULL;
639 const double * diag_i_D = (A_i) ? diag_i.
GetData() : NULL;
641 int diag_r_nnz = (diag_r_I) ? diag_r_I[nrows] : 0;
642 int diag_i_nnz = (diag_i_I) ? diag_i_I[nrows] : 0;
643 int diag_nnz = 2 * (diag_r_nnz + diag_i_nnz);
646 const int * offd_r_I = (A_r) ? offd_r.
GetI() : NULL;
647 const int * offd_i_I = (A_i) ? offd_i.
GetI() : NULL;
649 const int * offd_r_J = (A_r) ? offd_r.
GetJ() : NULL;
650 const int * offd_i_J = (A_i) ? offd_i.
GetJ() : NULL;
652 const double * offd_r_D = (A_r) ? offd_r.
GetData() : NULL;
653 const double * offd_i_D = (A_i) ? offd_i.
GetData() : NULL;
655 int offd_r_nnz = (offd_r_I) ? offd_r_I[nrows] : 0;
656 int offd_i_nnz = (offd_i_I) ? offd_i_I[nrows] : 0;
657 int offd_nnz = 2 * (offd_r_nnz + offd_i_nnz);
660 HYPRE_Int * diag_I = mfem_hypre_CTAlloc(HYPRE_Int, 2 * nrows + 1);
661 HYPRE_Int * diag_J = mfem_hypre_CTAlloc(HYPRE_Int, diag_nnz);
662 double * diag_D = mfem_hypre_CTAlloc(
double, diag_nnz);
664 HYPRE_Int * offd_I = mfem_hypre_CTAlloc(HYPRE_Int, 2 * nrows + 1);
665 HYPRE_Int * offd_J = mfem_hypre_CTAlloc(HYPRE_Int, offd_nnz);
666 double * offd_D = mfem_hypre_CTAlloc(
double, offd_nnz);
667 HYPRE_Int * cmap = mfem_hypre_CTAlloc(HYPRE_Int, 2 * num_cols_offd);
673 diag_I[nrows] = diag_r_nnz + diag_i_nnz;
674 for (
int i=0; i<nrows; i++)
676 diag_I[i + 1] = ((diag_r_I)?diag_r_I[i+1]:0) +
677 ((diag_i_I)?diag_i_I[i+1]:0);
678 diag_I[i + nrows + 1] = diag_I[i+1] + diag_r_nnz + diag_i_nnz;
682 for (
int j=0; j<diag_r_I[i+1] - diag_r_I[i]; j++)
684 diag_J[diag_I[i] + j] = diag_r_J[diag_r_I[i] + j];
685 diag_D[diag_I[i] + j] = diag_r_D[diag_r_I[i] + j];
687 diag_J[diag_I[i+nrows] + j] =
688 diag_r_J[diag_r_I[i] + j] + ncols;
689 diag_D[diag_I[i+nrows] + j] =
690 factor * diag_r_D[diag_r_I[i] + j];
695 const int off_r = (diag_r_I)?(diag_r_I[i+1] - diag_r_I[i]):0;
696 for (
int j=0; j<diag_i_I[i+1] - diag_i_I[i]; j++)
698 diag_J[diag_I[i] + off_r + j] = diag_i_J[diag_i_I[i] + j] + ncols;
699 diag_D[diag_I[i] + off_r + j] = -diag_i_D[diag_i_I[i] + j];
701 diag_J[diag_I[i+nrows] + off_r + j] = diag_i_J[diag_i_I[i] + j];
702 diag_D[diag_I[i+nrows] + off_r + j] =
703 factor * diag_i_D[diag_i_I[i] + j];
709 int num_recv_procs = 0;
710 HYPRE_Int * offd_col_start_stop = NULL;
711 this->getColStartStop(A_r, A_i, num_recv_procs, offd_col_start_stop);
713 std::set<int>::iterator sit;
714 std::map<int,int> cmapa, cmapb, cinvmap;
715 for (sit=cset.begin(); sit!=cset.end(); sit++)
720 for (
int i=0; i<num_recv_procs; i++)
722 if (offd_col_start_stop[2*i] <= col_orig &&
723 col_orig < offd_col_start_stop[2*i+1])
725 col_2x2 = offd_col_start_stop[2*i] + col_orig;
726 col_size = offd_col_start_stop[2*i+1] - offd_col_start_stop[2*i];
730 cmapa[*sit] = col_2x2;
731 cmapb[*sit] = col_2x2 + col_size;
732 cinvmap[col_2x2] = -1;
733 cinvmap[col_2x2 + col_size] = -1;
735 delete [] offd_col_start_stop;
737 std::map<int, int>::iterator mit;
739 for (mit=cinvmap.begin(); mit!=cinvmap.end(); mit++, i++)
742 cmap[i] = mit->first;
747 offd_I[nrows] = offd_r_nnz + offd_i_nnz;
748 for (
int i=0; i<nrows; i++)
750 offd_I[i + 1] = ((offd_r_I)?offd_r_I[i+1]:0) +
751 ((offd_i_I)?offd_i_I[i+1]:0);
752 offd_I[i + nrows + 1] = offd_I[i+1] + offd_r_nnz + offd_i_nnz;
756 const int off_i = (offd_i_I)?(offd_i_I[i+1] - offd_i_I[i]):0;
757 for (
int j=0; j<offd_r_I[i+1] - offd_r_I[i]; j++)
759 offd_J[offd_I[i] + j] =
760 cinvmap[cmapa[cmap_r[offd_r_J[offd_r_I[i] + j]]]];
761 offd_D[offd_I[i] + j] = offd_r_D[offd_r_I[i] + j];
763 offd_J[offd_I[i+nrows] + off_i + j] =
764 cinvmap[cmapb[cmap_r[offd_r_J[offd_r_I[i] + j]]]];
765 offd_D[offd_I[i+nrows] + off_i + j] =
766 factor * offd_r_D[offd_r_I[i] + j];
771 const int off_r = (offd_r_I)?(offd_r_I[i+1] - offd_r_I[i]):0;
772 for (
int j=0; j<offd_i_I[i+1] - offd_i_I[i]; j++)
774 offd_J[offd_I[i] + off_r + j] =
775 cinvmap[cmapb[cmap_i[offd_i_J[offd_i_I[i] + j]]]];
776 offd_D[offd_I[i] + off_r + j] = -offd_i_D[offd_i_I[i] + j];
778 offd_J[offd_I[i+nrows] + j] =
779 cinvmap[cmapa[cmap_i[offd_i_J[offd_i_I[i] + j]]]];
780 offd_D[offd_I[i+nrows] + j] = factor * offd_i_D[offd_i_I[i] + j];
789 row_starts, col_starts,
790 diag_I, diag_J, diag_D,
791 offd_I, offd_J, offd_D,
792 2 * num_cols_offd, cmap);
796 hypre_CSRMatrixSetDataOwner(((hypre_ParCSRMatrix*)(*A))->diag,1);
797 hypre_CSRMatrixSetDataOwner(((hypre_ParCSRMatrix*)(*A))->offd,1);
798 hypre_ParCSRMatrixSetRowStartsOwner((hypre_ParCSRMatrix*)(*A),1);
799 hypre_ParCSRMatrixSetColStartsOwner((hypre_ParCSRMatrix*)(*A),1);
805 ComplexHypreParMatrix::getColStartStop(
const HypreParMatrix * A_r,
807 int & num_recv_procs,
808 HYPRE_Int *& offd_col_start_stop)
const
810 hypre_ParCSRCommPkg * comm_pkg_r =
811 (A_r) ? hypre_ParCSRMatrixCommPkg((hypre_ParCSRMatrix*)(*A_r)) : NULL;
812 hypre_ParCSRCommPkg * comm_pkg_i =
813 (A_i) ? hypre_ParCSRMatrixCommPkg((hypre_ParCSRMatrix*)(*A_i)) : NULL;
815 std::set<HYPRE_Int> send_procs, recv_procs;
818 for (HYPRE_Int i=0; i<comm_pkg_r->num_sends; i++)
820 send_procs.insert(comm_pkg_r->send_procs[i]);
822 for (HYPRE_Int i=0; i<comm_pkg_r->num_recvs; i++)
824 recv_procs.insert(comm_pkg_r->recv_procs[i]);
829 for (HYPRE_Int i=0; i<comm_pkg_i->num_sends; i++)
831 send_procs.insert(comm_pkg_i->send_procs[i]);
833 for (HYPRE_Int i=0; i<comm_pkg_i->num_recvs; i++)
835 recv_procs.insert(comm_pkg_i->recv_procs[i]);
839 num_recv_procs = (int)recv_procs.size();
841 HYPRE_Int loc_start_stop[2];
842 offd_col_start_stop =
new HYPRE_Int[2 * num_recv_procs];
844 const HYPRE_Int * row_part = (A_r) ? A_r->
RowPart() :
845 ((A_i) ? A_i->
RowPart() : NULL);
847 int row_part_ind = (HYPRE_AssumedPartitionCheck()) ? 0 : myid_;
848 loc_start_stop[0] = row_part[row_part_ind];
849 loc_start_stop[1] = row_part[row_part_ind+1];
851 MPI_Request * req =
new MPI_Request[send_procs.size()+recv_procs.size()];
852 MPI_Status * stat =
new MPI_Status[send_procs.size()+recv_procs.size()];
857 std::set<HYPRE_Int>::iterator sit;
858 for (sit=send_procs.begin(); sit!=send_procs.end(); sit++)
860 MPI_Isend(loc_start_stop, 2, HYPRE_MPI_INT,
861 *sit, tag, comm_, &req[send_count]);
864 for (sit=recv_procs.begin(); sit!=recv_procs.end(); sit++)
866 MPI_Irecv(&offd_col_start_stop[2*recv_count], 2, HYPRE_MPI_INT,
867 *sit, tag, comm_, &req[send_count+recv_count]);
871 MPI_Waitall(send_count+recv_count, req, stat);
877 #endif // MFEM_USE_MPI
double Control[UMFPACK_CONTROL]
virtual int NumNonZeroElems() const
Returns the number of the nonzero elements in the matrix.
MPI_Comm GetComm() const
MPI communicator.
virtual Operator & real()
Real or imaginary part accessor methods.
virtual ~ComplexOperator()
ComplexSparseMatrix * mat
virtual ~ComplexUMFPackSolver()
ComplexHypreParMatrix(HypreParMatrix *A_Real, HypreParMatrix *A_Imag, bool ownReal, bool ownImag, Convention convention=HERMITIAN)
HYPRE_Int * ColPart()
Returns the column partitioning.
void SetSize(int s)
Resize the vector to size s.
Mimic the action of a complex operator using two real operators.
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
int * GetJ()
Return the array J.
void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
int Size() const
Returns the size of the vector.
int * GetI()
Return the array I.
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
Alternate convention for damping operators.
double * GetData() const
Return a pointer to the beginning of the Vector data.
ComplexOperator(Operator *Op_Real, Operator *Op_Imag, bool ownReal, bool ownImag, Convention convention=HERMITIAN)
Constructs complex operator object.
void SortColumnIndices()
Sort the column indices corresponding to each row.
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
double * GetData()
Return the element data, i.e. the array A.
HYPRE_Int GetGlobalNumRows() const
Return the global number of rows.
HYPRE_Int GetGlobalNumCols() const
Return the global number of columns.
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
void SetOwnerFlags(signed char diag, signed char offd, signed char colmap)
Explicitly set the three ownership flags, see docs for diagOwner etc.
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
void GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
virtual SparseMatrix & real()
Real or imaginary part accessor methods.
HYPRE_Int * RowPart()
Returns the row partitioning.
SparseMatrix * GetSystemMatrix() const
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
Specialization of the ComplexOperator built from a pair of Sparse Matrices.
virtual Operator & imag()
Convention GetConvention() const
void SetDataAndSize(double *d, int s)
Set the Vector data and size.
int height
Dimension of the output / number of rows in the matrix.
virtual void SetOperator(const Operator &op)
Factorize the given Operator op which must be a ComplexSparseMatrix.
Vector & Add(const double a, const Vector &Va)
(*this) += a * Va
const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
virtual void Mult(const Vector &b, Vector &x) const
This is solving the system A x = b.
virtual SparseMatrix & imag()
void Destroy()
Destroy a vector.
Native convention for Hermitian operators.
virtual void MultTranspose(const Vector &b, Vector &x) const
This is solving the system: A^H x = b (when transa = false) This is equivalent to solving the transpo...
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
void GetOffd(SparseMatrix &offd, HYPRE_Int *&cmap) const
Get the local off-diagonal block. NOTE: 'offd' will not own any data.
HypreParMatrix * GetSystemMatrix() const
virtual HypreParMatrix & imag()
Wrapper for hypre's ParCSR matrix class.
double Info[UMFPACK_INFO]
virtual HypreParMatrix & real()
Real or imaginary part accessor methods.
int width
Dimension of the input / number of columns in the matrix.
void SyncAliasMemory(const Vector &v)
Update the alias memory location of the vector to match v.