// Copyright (c) 2010-2023, 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. #ifndef MFEM_HANDLE_HPP #define MFEM_HANDLE_HPP #include "../config/config.hpp" #include "operator.hpp" #ifdef MFEM_USE_MPI #include "hypre.hpp" #endif namespace mfem { /// Pointer to an Operator of a specified type /** This class provides a common interface for global, matrix-type operators to be used in bilinear forms, gradients of nonlinear forms, static condensation, hybridization, etc. The following backends are currently supported: - HYPRE parallel sparse matrix (Hypre_ParCSR) - PETSC globally assembled parallel sparse matrix (PETSC_MATAIJ) - PETSC parallel matrix assembled on each processor (PETSC_MATIS) See also Operator::Type. */ class OperatorHandle { protected: static const char not_supported_msg[]; Operator *oper; Operator::Type type_id; bool own_oper; Operator::Type CheckType(Operator::Type tid); template void pSet(OpType *A, bool own_A = true) { oper = A; type_id = A->GetType(); own_oper = own_A; } public: /** @brief Create an OperatorHandle with type id = Operator::MFEM_SPARSEMAT without allocating the actual matrix. */ OperatorHandle() : oper(NULL), type_id(Operator::MFEM_SPARSEMAT), own_oper(false) { } /** @brief Create a OperatorHandle with a specified type id, @a tid, without allocating the actual matrix. */ explicit OperatorHandle(Operator::Type tid) : oper(NULL), type_id(CheckType(tid)), own_oper(false) { } /// Create an OperatorHandle for the given OpType pointer, @a A. /** Presently, OpType can be SparseMatrix, HypreParMatrix, or PetscParMatrix. The operator ownership flag is set to the value of @a own_A. It is expected that @a A points to a valid object. */ template explicit OperatorHandle(OpType *A, bool own_A = true) { pSet(A, own_A); } /// Shallow copy. The ownership flag of the target is set to false. OperatorHandle(const OperatorHandle &other) : oper(other.oper), type_id(other.type_id), own_oper(false) { } ~OperatorHandle() { if (own_oper) { delete oper; } } /// Shallow copy. The ownership flag of the target is set to false. OperatorHandle &operator=(const OperatorHandle &master) { Clear(); oper = master.oper; type_id = master.type_id; own_oper = false; return *this; } /// Access the underlying Operator pointer. Operator *Ptr() const { return oper; } /// Support the use of -> to call methods of the underlying Operator. Operator *operator->() const { return oper; } /// Access the underlying Operator. Operator &operator*() { return *oper; } /// Access the underlying Operator. const Operator &operator*() const { return *oper; } /// Get the currently set operator type id. Operator::Type Type() const { return type_id; } /** @brief Return the Operator pointer statically cast to a specified OpType. Similar to the method Get(). */ template OpType *As() const { return static_cast(oper); } /// Return the Operator pointer dynamically cast to a specified OpType. template OpType *Is() const { return dynamic_cast(oper); } /// Return the Operator pointer statically cast to a given OpType. /** Similar to the method As(), however the template type OpType can be derived automatically from the argument @a A. */ template void Get(OpType *&A) const { A = static_cast(oper); } /// Return true if the OperatorHandle owns the held Operator. bool OwnsOperator() const { return own_oper; } /// Set the ownership flag for the held Operator. void SetOperatorOwner(bool own = true) { own_oper = own; } /** @brief Clear the OperatorHandle, deleting the held Operator (if owned), while leaving the type id unchanged. */ void Clear() { if (own_oper) { delete oper; } oper = NULL; own_oper = false; } /// Invoke Clear() and set a new type id. void SetType(Operator::Type tid) { Clear(); type_id = CheckType(tid); } /// Reset the OperatorHandle to the given OpType pointer, @a A. /** Presently, OpType can be SparseMatrix, HypreParMatrix, or PetscParMatrix. The operator ownership flag is set to the value of @a own_A. It is expected that @a A points to a valid object. */ template void Reset(OpType *A, bool own_A = true) { if (own_oper) { delete oper; } pSet(A, own_A); } #ifdef MFEM_USE_MPI /** @brief Reset the OperatorHandle to hold a parallel square block-diagonal matrix using the currently set type id. */ /** The operator ownership flag is set to true. */ void MakeSquareBlockDiag(MPI_Comm comm, HYPRE_BigInt glob_size, HYPRE_BigInt *row_starts, SparseMatrix *diag); /** @brief Reset the OperatorHandle to hold a parallel rectangular block-diagonal matrix using the currently set type id. */ /** The operator ownership flag is set to true. */ void MakeRectangularBlockDiag(MPI_Comm comm, HYPRE_BigInt glob_num_rows, HYPRE_BigInt glob_num_cols, HYPRE_BigInt *row_starts, HYPRE_BigInt *col_starts, SparseMatrix *diag); #endif // MFEM_USE_MPI /// Reset the OperatorHandle to hold the product @a P^t @a A @a P. /** The type id of the result is determined by that of @a A and @a P. The operator ownership flag is set to true. */ void MakePtAP(OperatorHandle &A, OperatorHandle &P); /** @brief Reset the OperatorHandle to hold the product R @a A @a P, where R = @a Rt^t. */ /** The type id of the result is determined by that of @a Rt, @a A, and @a P. The operator ownership flag is set to true. */ void MakeRAP(OperatorHandle &Rt, OperatorHandle &A, OperatorHandle &P); /// Convert the given OperatorHandle @a A to the currently set type id. /** The operator ownership flag is set to false if the object held by @a A will be held by this object as well, e.g. when the source and destination types are the same; otherwise it is set to true. */ void ConvertFrom(OperatorHandle &A); /// Convert the given OpType pointer, @a A, to the currently set type id. /** This method creates a temporary OperatorHandle for @a A and invokes ConvertFrom(OperatorHandle &) with it. */ template void ConvertFrom(OpType *A) { OperatorHandle Ah(A, false); ConvertFrom(Ah); } /** @brief Reset the OperatorHandle to be the eliminated part of @a A after elimination of the essential dofs @a ess_dof_list. */ void EliminateRowsCols(OperatorHandle &A, const Array &ess_dof_list); /// Eliminate the rows corresponding to the essential dofs @a ess_dof_list void EliminateRows(const Array &ess_dof_list); /// Eliminate columns corresponding to the essential dofs @a ess_dof_list void EliminateCols(const Array &ess_dof_list); /// Eliminate essential dofs from the solution @a X into the r.h.s. @a B. /** The argument @a A_e is expected to be the result of the method EliminateRowsCols(). */ void EliminateBC(const OperatorHandle &A_e, const Array &ess_dof_list, const Vector &X, Vector &B) const; }; /// Add an alternative name for OperatorHandle -- OperatorPtr. typedef OperatorHandle OperatorPtr; } // namespace mfem #endif