// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code // availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. #include "complex_operator.hpp" #include #include // Define macro wrappers for hypre_TAlloc, hypre_CTAlloc and hypre_TFree: // mfem_hypre_TAlloc, mfem_hypre_CTAlloc, and mfem_hypre_TFree, respectively. // Note: the same macros are defined in hypre.cpp and hypre_parser.cpp. #if MFEM_HYPRE_VERSION < 21400 #define mfem_hypre_TAlloc(type, size) hypre_TAlloc(type, size) #define mfem_hypre_CTAlloc(type, size) hypre_CTAlloc(type, size) #define mfem_hypre_TFree(ptr) hypre_TFree(ptr) #else // MFEM_HYPRE_VERSION >= 21400 // See the notes about hypre 2.14.0 in hypre.cpp #define mfem_hypre_TAlloc(type, size) \ hypre_TAlloc(type, size, HYPRE_MEMORY_HOST) #define mfem_hypre_CTAlloc(type, size) \ hypre_CTAlloc(type, size, HYPRE_MEMORY_HOST) #define mfem_hypre_TFree(ptr) hypre_TFree(ptr, HYPRE_MEMORY_HOST) #endif // #if MFEM_HYPRE_VERSION < 21400 namespace mfem { ComplexOperator::ComplexOperator(Operator * Op_Real, Operator * Op_Imag, bool ownReal, bool ownImag, Convention convention) : Operator(2*((Op_Real)?Op_Real->Height():Op_Imag->Height()), 2*((Op_Real)?Op_Real->Width():Op_Imag->Width())) , Op_Real_(Op_Real) , Op_Imag_(Op_Imag) , ownReal_(ownReal) , ownImag_(ownImag) , convention_(convention) , x_r_(NULL, width / 2) , x_i_(NULL, width / 2) , y_r_(NULL, height / 2) , y_i_(NULL, height / 2) , u_(NULL) , v_(NULL) {} ComplexOperator::~ComplexOperator() { if (ownReal_) { delete Op_Real_; } if (ownImag_) { delete Op_Imag_; } delete u_; delete v_; } Operator & ComplexOperator::real() { MFEM_ASSERT(Op_Real_, "ComplexOperator has no real part!"); return *Op_Real_; } Operator & ComplexOperator::imag() { MFEM_ASSERT(Op_Imag_, "ComplexOperator has no imaginary part!"); return *Op_Imag_; } const Operator & ComplexOperator::real() const { MFEM_ASSERT(Op_Real_, "ComplexOperator has no real part!"); return *Op_Real_; } const Operator & ComplexOperator::imag() const { MFEM_ASSERT(Op_Imag_, "ComplexOperator has no imaginary part!"); return *Op_Imag_; } void ComplexOperator::Mult(const Vector &x, Vector &y) const { double * x_data = x.GetData(); x_r_.SetData(x_data); x_i_.SetData(&x_data[width / 2]); y_r_.SetData(&y[0]); y_i_.SetData(&y[height / 2]); this->Mult(x_r_, x_i_, y_r_, y_i_); } void ComplexOperator::Mult(const Vector &x_r, const Vector &x_i, Vector &y_r, Vector &y_i) const { if (Op_Real_) { Op_Real_->Mult(x_r, y_r); Op_Real_->Mult(x_i, y_i); } else { y_r = 0.0; y_i = 0.0; } if (Op_Imag_) { if (!v_) { v_ = new Vector(Op_Imag_->Height()); } Op_Imag_->Mult(x_i, *v_); y_r_ -= *v_; Op_Imag_->Mult(x_r, *v_); y_i_ += *v_; } if (convention_ == BLOCK_SYMMETRIC) { y_i_ *= -1.0; } } void ComplexOperator::MultTranspose(const Vector &x, Vector &y) const { double * x_data = x.GetData(); y_r_.SetData(x_data); y_i_.SetData(&x_data[height / 2]); x_r_.SetData(&y[0]); x_i_.SetData(&y[width / 2]); this->MultTranspose(y_r_, y_i_, x_r_, x_i_); } void ComplexOperator::MultTranspose(const Vector &x_r, const Vector &x_i, Vector &y_r, Vector &y_i) const { if (Op_Real_) { Op_Real_->MultTranspose(x_r, y_r); Op_Real_->MultTranspose(x_i, y_i); if (convention_ == BLOCK_SYMMETRIC) { y_i *= -1.0; } } else { y_r = 0.0; y_i = 0.0; } if (Op_Imag_) { if (!u_) { u_ = new Vector(Op_Imag_->Width()); } Op_Imag_->MultTranspose(x_i, *u_); y_r_.Add(convention_ == BLOCK_SYMMETRIC ? -1.0 : 1.0, *u_); Op_Imag_->MultTranspose(x_r, *u_); y_i_ -= *u_; } } SparseMatrix & ComplexSparseMatrix::real() { MFEM_ASSERT(Op_Real_, "ComplexSparseMatrix has no real part!"); return dynamic_cast(*Op_Real_); } SparseMatrix & ComplexSparseMatrix::imag() { MFEM_ASSERT(Op_Imag_, "ComplexSparseMatrix has no imaginary part!"); return dynamic_cast(*Op_Imag_); } const SparseMatrix & ComplexSparseMatrix::real() const { MFEM_ASSERT(Op_Real_, "ComplexSparseMatrix has no real part!"); return dynamic_cast(*Op_Real_); } const SparseMatrix & ComplexSparseMatrix::imag() const { MFEM_ASSERT(Op_Imag_, "ComplexSparseMatrix has no imaginary part!"); return dynamic_cast(*Op_Imag_); } SparseMatrix * ComplexSparseMatrix::GetSystemMatrix() const { SparseMatrix * A_r = dynamic_cast(Op_Real_); SparseMatrix * A_i = dynamic_cast(Op_Imag_); const int nrows_r = (A_r)?A_r->Height():0; const int nrows_i = (A_i)?A_i->Height():0; const int nrows = std::max(nrows_r, nrows_i); const int *I_r = (A_r)?A_r->GetI():NULL; const int *I_i = (A_i)?A_i->GetI():NULL; const int *J_r = (A_r)?A_r->GetJ():NULL; const int *J_i = (A_i)?A_i->GetJ():NULL; const double *D_r = (A_r)?A_r->GetData():NULL; const double *D_i = (A_i)?A_i->GetData():NULL; const int nnz_r = (I_r)?I_r[nrows]:0; const int nnz_i = (I_i)?I_i[nrows]:0; const int nnz = 2 * (nnz_r + nnz_i); int *I = Memory(this->Height()+1); int *J = Memory(nnz); double *D = Memory(nnz); const double factor = (convention_ == HERMITIAN) ? 1.0 : -1.0; I[0] = 0; I[nrows] = nnz_r + nnz_i; for (int i=0; iHeight(), this->Width()); } #ifdef MFEM_USE_MPI ComplexHypreParMatrix::ComplexHypreParMatrix(HypreParMatrix * A_Real, HypreParMatrix * A_Imag, bool ownReal, bool ownImag, Convention convention) : ComplexOperator(A_Real, A_Imag, ownReal, ownImag, convention) { comm_ = (A_Real) ? A_Real->GetComm() : ((A_Imag) ? A_Imag->GetComm() : MPI_COMM_WORLD); MPI_Comm_rank(comm_, &myid_); MPI_Comm_size(comm_, &nranks_); } HypreParMatrix & ComplexHypreParMatrix::real() { MFEM_ASSERT(Op_Real_, "ComplexHypreParMatrix has no real part!"); return dynamic_cast(*Op_Real_); } HypreParMatrix & ComplexHypreParMatrix::imag() { MFEM_ASSERT(Op_Imag_, "ComplexHypreParMatrix has no imaginary part!"); return dynamic_cast(*Op_Imag_); } const HypreParMatrix & ComplexHypreParMatrix::real() const { MFEM_ASSERT(Op_Real_, "ComplexHypreParMatrix has no real part!"); return dynamic_cast(*Op_Real_); } const HypreParMatrix & ComplexHypreParMatrix::imag() const { MFEM_ASSERT(Op_Imag_, "ComplexHypreParMatrix has no imaginary part!"); return dynamic_cast(*Op_Imag_); } HypreParMatrix * ComplexHypreParMatrix::GetSystemMatrix() const { HypreParMatrix * A_r = dynamic_cast(Op_Real_); HypreParMatrix * A_i = dynamic_cast(Op_Imag_); if ( A_r == NULL && A_i == NULL ) { return NULL; } HYPRE_Int global_num_rows_r = (A_r) ? A_r->GetGlobalNumRows() : 0; HYPRE_Int global_num_rows_i = (A_i) ? A_i->GetGlobalNumRows() : 0; HYPRE_Int global_num_rows = std::max(global_num_rows_r, global_num_rows_i); HYPRE_Int global_num_cols_r = (A_r) ? A_r->GetGlobalNumCols() : 0; HYPRE_Int global_num_cols_i = (A_i) ? A_i->GetGlobalNumCols() : 0; HYPRE_Int global_num_cols = std::max(global_num_cols_r, global_num_cols_i); int row_starts_size = (HYPRE_AssumedPartitionCheck()) ? 2 : nranks_ + 1; HYPRE_Int * row_starts = mfem_hypre_CTAlloc(HYPRE_Int, row_starts_size); HYPRE_Int * col_starts = mfem_hypre_CTAlloc(HYPRE_Int, row_starts_size); const HYPRE_Int * row_starts_z = (A_r) ? A_r->RowPart() : ((A_i) ? A_i->RowPart() : NULL); const HYPRE_Int * col_starts_z = (A_r) ? A_r->ColPart() : ((A_i) ? A_i->ColPart() : NULL); for (int i = 0; i < row_starts_size; i++) { row_starts[i] = 2 * row_starts_z[i]; col_starts[i] = 2 * col_starts_z[i]; } SparseMatrix diag_r, diag_i, offd_r, offd_i; HYPRE_Int * cmap_r, * cmap_i; int nrows_r = 0, nrows_i = 0, ncols_r = 0, ncols_i = 0; int ncols_offd_r = 0, ncols_offd_i = 0; if (A_r) { A_r->GetDiag(diag_r); A_r->GetOffd(offd_r, cmap_r); nrows_r = diag_r.Height(); ncols_r = diag_r.Width(); ncols_offd_r = offd_r.Width(); } if (A_i) { A_i->GetDiag(diag_i); A_i->GetOffd(offd_i, cmap_i); nrows_i = diag_i.Height(); ncols_i = diag_i.Width(); ncols_offd_i = offd_i.Width(); } int nrows = std::max(nrows_r, nrows_i); int ncols = std::max(ncols_r, ncols_i); // Determine the unique set of off-diagonal columns global indices std::set cset; for (int i=0; igetColStartStop(A_r, A_i, num_recv_procs, offd_col_start_stop); std::set::iterator sit; std::map cmapa, cmapb, cinvmap; for (sit=cset.begin(); sit!=cset.end(); sit++) { int col_orig = *sit; int col_2x2 = -1; int col_size = 0; for (int i=0; i::iterator mit; int i = 0; for (mit=cinvmap.begin(); mit!=cinvmap.end(); mit++, i++) { mit->second = i; cmap[i] = mit->first; } // Fill the CSR arrays for the off-diagonal portion of the matrix offd_I[0] = 0; offd_I[nrows] = offd_r_nnz + offd_i_nnz; for (int i=0; iSetOwnerFlags(-1,-1,-1); hypre_CSRMatrixSetDataOwner(((hypre_ParCSRMatrix*)(*A))->diag,1); hypre_CSRMatrixSetDataOwner(((hypre_ParCSRMatrix*)(*A))->offd,1); hypre_ParCSRMatrixSetRowStartsOwner((hypre_ParCSRMatrix*)(*A),1); hypre_ParCSRMatrixSetColStartsOwner((hypre_ParCSRMatrix*)(*A),1); return A; } void ComplexHypreParMatrix::getColStartStop(const HypreParMatrix * A_r, const HypreParMatrix * A_i, int & num_recv_procs, HYPRE_Int *& offd_col_start_stop) const { hypre_ParCSRCommPkg * comm_pkg_r = (A_r) ? hypre_ParCSRMatrixCommPkg((hypre_ParCSRMatrix*)(*A_r)) : NULL; hypre_ParCSRCommPkg * comm_pkg_i = (A_i) ? hypre_ParCSRMatrixCommPkg((hypre_ParCSRMatrix*)(*A_i)) : NULL; std::set send_procs, recv_procs; if ( comm_pkg_r ) { for (HYPRE_Int i=0; inum_sends; i++) { send_procs.insert(comm_pkg_r->send_procs[i]); } for (HYPRE_Int i=0; inum_recvs; i++) { recv_procs.insert(comm_pkg_r->recv_procs[i]); } } if ( comm_pkg_i ) { for (HYPRE_Int i=0; inum_sends; i++) { send_procs.insert(comm_pkg_i->send_procs[i]); } for (HYPRE_Int i=0; inum_recvs; i++) { recv_procs.insert(comm_pkg_i->recv_procs[i]); } } num_recv_procs = (int)recv_procs.size(); HYPRE_Int loc_start_stop[2]; offd_col_start_stop = new HYPRE_Int[2 * num_recv_procs]; const HYPRE_Int * row_part = (A_r) ? A_r->RowPart() : ((A_i) ? A_i->RowPart() : NULL); int row_part_ind = (HYPRE_AssumedPartitionCheck()) ? 0 : myid_; loc_start_stop[0] = row_part[row_part_ind]; loc_start_stop[1] = row_part[row_part_ind+1]; MPI_Request * req = new MPI_Request[send_procs.size()+recv_procs.size()]; MPI_Status * stat = new MPI_Status[send_procs.size()+recv_procs.size()]; int send_count = 0; int recv_count = 0; int tag = 0; std::set::iterator sit; for (sit=send_procs.begin(); sit!=send_procs.end(); sit++) { MPI_Isend(loc_start_stop, 2, HYPRE_MPI_INT, *sit, tag, comm_, &req[send_count]); send_count++; } for (sit=recv_procs.begin(); sit!=recv_procs.end(); sit++) { MPI_Irecv(&offd_col_start_stop[2*recv_count], 2, HYPRE_MPI_INT, *sit, tag, comm_, &req[send_count+recv_count]); recv_count++; } MPI_Waitall(send_count+recv_count, req, stat); delete [] req; delete [] stat; } #endif // MFEM_USE_MPI }