]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Introduce TpetraWrappers::BlockSparseMatrix
authorSebastian Kinnewig <kinnewig@ifam.uni-hannover.de>
Wed, 31 Jan 2024 08:43:35 +0000 (09:43 +0100)
committerSebastian Kinnewig <sebastian@kinnewig.org>
Sun, 18 Feb 2024 15:20:27 +0000 (16:20 +0100)
include/deal.II/lac/affine_constraints.templates.h
include/deal.II/lac/trilinos_tpetra_block_sparse_matrix.h [new file with mode: 0644]
include/deal.II/lac/trilinos_tpetra_block_sparse_matrix.templates.h [new file with mode: 0644]
include/deal.II/lac/trilinos_tpetra_block_vector.h
source/lac/CMakeLists.txt
source/lac/affine_constraints.inst.in
source/lac/trilinos_tpetra_block_sparse_matrix.cc [new file with mode: 0644]

index 0bcc94c9b23e853aed261cb82e5f8b8bae13b2dd..c6d24ec4969c2f0a5fb5520d32e868ee81a5cf32 100644 (file)
@@ -48,6 +48,8 @@
 #include <deal.II/lac/trilinos_block_sparse_matrix.h>
 #include <deal.II/lac/trilinos_parallel_block_vector.h>
 #include <deal.II/lac/trilinos_sparse_matrix.h>
+#include <deal.II/lac/trilinos_tpetra_block_sparse_matrix.h>
+#include <deal.II/lac/trilinos_tpetra_block_vector.h>
 #include <deal.II/lac/trilinos_tpetra_sparse_matrix.h>
 #include <deal.II/lac/trilinos_tpetra_vector.h>
 #include <deal.II/lac/trilinos_vector.h>
diff --git a/include/deal.II/lac/trilinos_tpetra_block_sparse_matrix.h b/include/deal.II/lac/trilinos_tpetra_block_sparse_matrix.h
new file mode 100644 (file)
index 0000000..fea9cad
--- /dev/null
@@ -0,0 +1,463 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2024 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_tpetra_trilinos_block_sparse_matrix_h
+#define dealii_tpetra_trilinos_block_sparse_matrix_h
+
+
+#include <deal.II/base/config.h>
+
+#ifdef DEAL_II_TRILINOS_WITH_TPETRA
+
+#  include <deal.II/base/template_constraints.h>
+
+#  include <deal.II/lac/block_matrix_base.h>
+#  include <deal.II/lac/block_sparse_matrix.h>
+#  include <deal.II/lac/exceptions.h>
+#  include <deal.II/lac/full_matrix.h>
+#  include <deal.II/lac/trilinos_tpetra_block_vector.h>
+#  include <deal.II/lac/trilinos_tpetra_sparse_matrix.h>
+
+#  include <cmath>
+
+DEAL_II_NAMESPACE_OPEN
+
+// forward declarations
+#  ifndef DOXYGEN
+class BlockSparsityPattern;
+template <typename number>
+class BlockSparseMatrix;
+#  endif
+
+namespace LinearAlgebra
+{
+  /**
+   * @addtogroup TpetraWrappers
+   * @{
+   */
+  namespace TpetraWrappers
+  {
+    /**
+     * Blocked sparse matrix based on the
+     * LinearAlgebra::TpetraWrappers::SparseMatrix class. This class implements
+     * the functions that are specific to the Trilinos SparseMatrix base objects
+     * for a blocked sparse matrix, and leaves the actual work relaying most of
+     * the calls to the individual blocks to the functions implemented in the
+     * base class. See there also for a description of when this class is
+     * useful.
+     *
+     * In contrast to the deal.II-type SparseMatrix class, the Trilinos matrices
+     * do not have external objects for the sparsity patterns. Thus, one does
+     * not determine the size of the individual blocks of a block matrix of this
+     * type by attaching a block sparsity pattern, but by calling reinit() to
+     * set the number of blocks and then by setting the size of each block
+     * separately. In order to fix the data structures of the block matrix, it
+     * is then necessary to let it know that we have changed the sizes of the
+     * underlying matrices. For this, one has to call the collect_sizes()
+     * function, for much the same reason as is documented with the
+     * BlockSparsityPattern class.
+     *
+     * @ingroup Matrix1 @see
+     * @ref GlossBlockLA "Block (linear algebra)"
+     */
+    template <typename Number, typename MemorySpace = dealii::MemorySpace::Host>
+    class BlockSparseMatrix
+      : public BlockMatrixBase<SparseMatrix<Number, MemorySpace>>
+    {
+    public:
+      /**
+       * Typedef the base class for simpler access to its own alias.
+       */
+      using BaseClass = BlockMatrixBase<SparseMatrix<Number, MemorySpace>>;
+
+      /**
+       * Typedef the type of the underlying matrix.
+       */
+      using BlockType = typename BaseClass::BlockType;
+
+      /**
+       * Import the alias from the base class.
+       */
+      using value_type      = typename BaseClass::value_type;
+      using pointer         = typename BaseClass::pointer;
+      using const_pointer   = typename BaseClass::const_pointer;
+      using reference       = typename BaseClass::reference;
+      using const_reference = typename BaseClass::const_reference;
+      using size_type       = typename BaseClass::size_type;
+      using iterator        = typename BaseClass::iterator;
+      using const_iterator  = typename BaseClass::const_iterator;
+
+      /**
+       * Constructor; initializes the matrix to be empty, without any structure,
+       * i.e.  the matrix is not usable at all. This constructor is therefore
+       * only useful for matrices which are members of a class. All other
+       * matrices should be created at a point in the data flow where all
+       * necessary information is available.
+       *
+       * You have to initialize the matrix before usage with
+       * reinit(BlockSparsityPattern). The number of blocks per row and column
+       * are then determined by that function.
+       */
+      BlockSparseMatrix() = default;
+
+      /**
+       * Destructor.
+       */
+      ~BlockSparseMatrix() override;
+
+      /**
+       * Pseudo copy operator only copying empty objects. The sizes of the block
+       * matrices need to be the same.
+       */
+      BlockSparseMatrix<Number, MemorySpace> &
+      operator=(const BlockSparseMatrix<Number, MemorySpace> &) = default;
+
+      /**
+       * This operator assigns a scalar to a matrix. Since this does usually not
+       * make much sense (should we set all matrix entries to this value? Only
+       * the nonzero entries of the sparsity pattern?), this operation is only
+       * allowed if the actual value to be assigned is zero. This operator only
+       * exists to allow for the obvious notation <tt>matrix=0</tt>, which sets
+       * all elements of the matrix to zero, but keep the sparsity pattern
+       * previously used.
+       */
+      BlockSparseMatrix<Number, MemorySpace> &
+      operator=(const Number d);
+
+      /**
+       * Resize the matrix, by setting the number of block rows and columns.
+       * This deletes all blocks and replaces them with uninitialized ones, i.e.
+       * ones for which also the sizes are not yet set. You have to do that by
+       * calling the @p reinit functions of the blocks themselves. Do not forget
+       * to call collect_sizes() after that on this object.
+       *
+       * The reason that you have to set sizes of the blocks yourself is that
+       * the sizes may be varying, the maximum number of elements per row may be
+       * varying, etc. It is simpler not to reproduce the interface of the @p
+       * SparsityPattern class here but rather let the user call whatever
+       * function they desire.
+       */
+      void
+      reinit(const size_type n_block_rows, const size_type n_block_columns);
+
+      /**
+       * Resize the matrix, by using an array of index sets to determine the
+       * %parallel distribution of the individual matrices. This function
+       * assumes that a quadratic block matrix is generated.
+       */
+      template <typename BlockSparsityPatternType>
+      void
+      reinit(const std::vector<IndexSet>    &input_maps,
+             const BlockSparsityPatternType &block_sparsity_pattern,
+             const MPI_Comm                  communicator  = MPI_COMM_WORLD,
+             const bool                      exchange_data = false);
+
+      /**
+       * Resize the matrix and initialize it by the given sparsity pattern.
+       * Since no distribution map is given, the result is a block matrix for
+       * which all elements are stored locally.
+       */
+      template <typename BlockSparsityPatternType>
+      void
+      reinit(const BlockSparsityPatternType &block_sparsity_pattern);
+
+      /**
+       * This function initializes the Trilinos matrix using the deal.II sparse
+       * matrix and the entries stored therein. It uses a threshold to copy only
+       * elements whose modulus is larger than the threshold (so zeros in the
+       * deal.II matrix can be filtered away).
+       */
+      void
+      reinit(
+        const std::vector<IndexSet>               &parallel_partitioning,
+        const ::dealii::BlockSparseMatrix<double> &dealii_block_sparse_matrix,
+        const MPI_Comm communicator   = MPI_COMM_WORLD,
+        const double   drop_tolerance = 1e-13);
+
+      /**
+       * This function initializes the Trilinos matrix using the deal.II sparse
+       * matrix and the entries stored therein. It uses a threshold to copy only
+       * elements whose modulus is larger than the threshold (so zeros in the
+       * deal.II matrix can be filtered away). Since no Epetra_Map is given, all
+       * the elements will be locally stored.
+       */
+      void
+      reinit(const ::dealii::BlockSparseMatrix<double> &deal_ii_sparse_matrix,
+             const double                               drop_tolerance = 1e-13);
+
+      /**
+       * Return the state of the matrix, i.e., whether compress() needs to be
+       * called after an operation requiring data exchange. Does only return
+       * non-true values when used in <tt>debug</tt> mode, since it is quite
+       * expensive to keep track of all operations that lead to the need for
+       * compress().
+       */
+      bool
+      is_compressed() const;
+
+      /**
+       * This function collects the sizes of the sub-objects and stores them in
+       * internal arrays, in order to be able to relay global indices into the
+       * matrix to indices into the subobjects. You *must* call this function
+       * each time after you have changed the size of the sub-objects. Note that
+       * this is a @ref GlossCollectiveOperation "collective operation", i.e.,
+       * it needs to be called on all MPI
+       * processes. This command internally calls the method
+       * <tt>compress()</tt>, so you don't need to call that function in case
+       * you use <tt>collect_sizes()</tt>.
+       */
+      void
+      collect_sizes();
+
+      /**
+       * Return the total number of nonzero elements of this matrix (summed
+       * over all MPI processes).
+       */
+      std::uint64_t
+      n_nonzero_elements() const;
+
+      /**
+       * Return the underlying MPI communicator.
+       */
+      MPI_Comm
+      get_mpi_communicator() const;
+
+      /**
+       * Return the partitioning of the domain space for the individual blocks
+       * of this matrix, i.e., the partitioning of the block vectors this matrix
+       * has to be multiplied with.
+       */
+      std::vector<IndexSet>
+      locally_owned_domain_indices() const;
+
+      /**
+       * Return the partitioning of the range space for the individual blocks of
+       * this matrix, i.e., the partitioning of the block vectors that result
+       * from matrix-vector products.
+       */
+      std::vector<IndexSet>
+      locally_owned_range_indices() const;
+
+      /**
+       * Matrix-vector multiplication: let $dst = M*src$ with $M$ being this
+       * matrix. The vector types can be block vectors or non-block vectors
+       * (only if the matrix has only one row or column, respectively), and need
+       * to define TrilinosWrappers::SparseMatrix::vmult.
+       */
+      template <typename VectorType1, typename VectorType2>
+      void
+      vmult(VectorType1 &dst, const VectorType2 &src) const;
+
+      /**
+       * Matrix-vector multiplication: let $dst = M^T*src$ with $M$ being this
+       * matrix. This function does the same as vmult() but takes the transposed
+       * matrix.
+       */
+      template <typename VectorType1, typename VectorType2>
+      void
+      Tvmult(VectorType1 &dst, const VectorType2 &src) const;
+
+      /**
+       * Compute the residual of an equation <i>Mx=b</i>, where the residual is
+       * defined to be <i>r=b-Mx</i>. Write the residual into @p dst. The
+       * <i>l<sub>2</sub></i> norm of the residual vector is returned.
+       *
+       * Source <i>x</i> and destination <i>dst</i> must not be the same vector.
+       *
+       * Note that both vectors have to be distributed vectors generated using
+       * the same Map as was used for the matrix.
+       *
+       * This function only applicable if the matrix only has one block row.
+       */
+      template <typename VectorType1,
+                typename VectorType2,
+                typename VectorType3>
+      Number
+      residual(VectorType1       &dst,
+               const VectorType2 &x,
+               const VectorType3 &b) const;
+
+      /**
+       * Make the clear() function in the base class visible, though it is
+       * protected.
+       */
+      using BlockMatrixBase<SparseMatrix<Number, MemorySpace>>::clear;
+
+    private:
+      /**
+       * Internal version of (T)vmult with two block vectors
+       */
+      template <typename VectorType1, typename VectorType2>
+      void
+      vmult(VectorType1       &dst,
+            const VectorType2 &src,
+            const bool         transpose,
+            const std::bool_constant<true>,
+            const std::bool_constant<true>) const;
+
+      /**
+       * Internal version of (T)vmult where the source vector is a block vector
+       * but the destination vector is a non-block vector
+       */
+      template <typename VectorType1, typename VectorType2>
+      void
+      vmult(VectorType1       &dst,
+            const VectorType2 &src,
+            const bool         transpose,
+            const std::bool_constant<false>,
+            const std::bool_constant<true>) const;
+
+      /**
+       * Internal version of (T)vmult where the source vector is a non-block
+       * vector but the destination vector is a block vector
+       */
+      template <typename VectorType1, typename VectorType2>
+      void
+      vmult(VectorType1       &dst,
+            const VectorType2 &src,
+            const bool         transpose,
+            const std::bool_constant<true>,
+            const std::bool_constant<false>) const;
+
+      /**
+       * Internal version of (T)vmult where both source vector and the
+       * destination vector are non-block vectors (only defined if the matrix
+       * consists of only one block)
+       */
+      template <typename VectorType1, typename VectorType2>
+      void
+      vmult(VectorType1       &dst,
+            const VectorType2 &src,
+            const bool         transpose,
+            const std::bool_constant<false>,
+            const std::bool_constant<false>) const;
+    };
+
+  } // namespace TpetraWrappers
+
+  /** @} */
+
+  // ------------- inline and template functions -----------------
+  namespace TpetraWrappers
+  {
+    template <typename Number, typename MemorySpace>
+    template <typename VectorType1, typename VectorType2>
+    inline void
+    BlockSparseMatrix<Number, MemorySpace>::vmult(VectorType1       &dst,
+                                                  const VectorType2 &src) const
+    {
+      vmult(dst,
+            src,
+            false,
+            std::bool_constant<IsBlockVector<VectorType1>::value>(),
+            std::bool_constant<IsBlockVector<VectorType2>::value>());
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    template <typename VectorType1, typename VectorType2>
+    inline void
+    BlockSparseMatrix<Number, MemorySpace>::Tvmult(VectorType1       &dst,
+                                                   const VectorType2 &src) const
+    {
+      vmult(dst,
+            src,
+            true,
+            std::bool_constant<IsBlockVector<VectorType1>::value>(),
+            std::bool_constant<IsBlockVector<VectorType2>::value>());
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    template <typename VectorType1, typename VectorType2>
+    inline void
+    BlockSparseMatrix<Number, MemorySpace>::vmult(
+      VectorType1       &dst,
+      const VectorType2 &src,
+      const bool         transpose,
+      std::bool_constant<true>,
+      std::bool_constant<true>) const
+    {
+      if (transpose == true)
+        BaseClass::Tvmult_block_block(dst, src);
+      else
+        BaseClass::vmult_block_block(dst, src);
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    template <typename VectorType1, typename VectorType2>
+    inline void
+    BlockSparseMatrix<Number, MemorySpace>::vmult(
+      VectorType1       &dst,
+      const VectorType2 &src,
+      const bool         transpose,
+      std::bool_constant<false>,
+      std::bool_constant<true>) const
+    {
+      if (transpose == true)
+        BaseClass::Tvmult_nonblock_block(dst, src);
+      else
+        BaseClass::vmult_nonblock_block(dst, src);
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    template <typename VectorType1, typename VectorType2>
+    inline void
+    BlockSparseMatrix<Number, MemorySpace>::vmult(
+      VectorType1       &dst,
+      const VectorType2 &src,
+      const bool         transpose,
+      std::bool_constant<true>,
+      std::bool_constant<false>) const
+    {
+      if (transpose == true)
+        BaseClass::Tvmult_block_nonblock(dst, src);
+      else
+        BaseClass::vmult_block_nonblock(dst, src);
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    template <typename VectorType1, typename VectorType2>
+    inline void
+    BlockSparseMatrix<Number, MemorySpace>::vmult(
+      VectorType1       &dst,
+      const VectorType2 &src,
+      const bool         transpose,
+      std::bool_constant<false>,
+      std::bool_constant<false>) const
+    {
+      if (transpose == true)
+        BaseClass::Tvmult_nonblock_nonblock(dst, src);
+      else
+        BaseClass::vmult_nonblock_nonblock(dst, src);
+    }
+  } // namespace TpetraWrappers
+
+} // namespace LinearAlgebra
+
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // DEAL_II_TRILINOS_WITH_TPETRA
+
+#endif // dealii_tpetra_trilinos_block_sparse_matrix_h
diff --git a/include/deal.II/lac/trilinos_tpetra_block_sparse_matrix.templates.h b/include/deal.II/lac/trilinos_tpetra_block_sparse_matrix.templates.h
new file mode 100644 (file)
index 0000000..95305a7
--- /dev/null
@@ -0,0 +1,340 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2024 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#ifndef dealii_tpetra_trilinos_block_sparse_matrix_templates_h
+#define dealii_tpetra_trilinos_block_sparse_matrix_templates_h
+
+#include <deal.II/base/config.h>
+
+#ifdef DEAL_II_TRILINOS_WITH_TPETRA
+
+#  include <deal.II/lac/trilinos_tpetra_block_sparse_matrix.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+namespace LinearAlgebra
+{
+
+  namespace TpetraWrappers
+  {
+
+    template <typename Number, typename MemorySpace>
+    BlockSparseMatrix<Number, MemorySpace>::~BlockSparseMatrix()
+    {
+      // delete previous content of
+      // the subobjects array
+      try
+        {
+          clear();
+        }
+      catch (...)
+        {}
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    BlockSparseMatrix<Number, MemorySpace> &
+    BlockSparseMatrix<Number, MemorySpace>::operator=(const Number d)
+    {
+      Assert(d == 0, ExcScalarAssignmentOnlyForZeroValue());
+
+      for (size_type r = 0; r < this->n_block_rows(); ++r)
+        for (size_type c = 0; c < this->n_block_cols(); ++c)
+          this->block(r, c) = d;
+
+      return *this;
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    void
+    BlockSparseMatrix<Number, MemorySpace>::reinit(
+      const size_type n_block_rows,
+      const size_type n_block_columns)
+    {
+      // first delete previous content of
+      // the subobjects array
+      clear();
+
+      // then resize. set sizes of blocks to
+      // zero. user will later have to call
+      // collect_sizes for this
+      this->sub_objects.reinit(n_block_rows, n_block_columns);
+      this->row_block_indices.reinit(n_block_rows, 0);
+      this->column_block_indices.reinit(n_block_columns, 0);
+
+      // and reinitialize the blocks
+      for (size_type r = 0; r < this->n_block_rows(); ++r)
+        for (size_type c = 0; c < this->n_block_cols(); ++c)
+          {
+            BlockType *p = new BlockType();
+
+            Assert(this->sub_objects[r][c] == nullptr, ExcInternalError());
+            this->sub_objects[r][c] = p;
+          }
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    template <typename BlockSparsityPatternType>
+    void
+    BlockSparseMatrix<Number, MemorySpace>::reinit(
+      const std::vector<IndexSet>    &parallel_partitioning,
+      const BlockSparsityPatternType &block_sparsity_pattern,
+      const MPI_Comm                  communicator,
+      const bool                      exchange_data)
+    {
+#  ifdef DEBUG
+      std::vector<typename BlockType::MapType> tpetra_maps;
+      for (size_type i = 0; i < block_sparsity_pattern.n_block_rows(); ++i)
+        tpetra_maps.push_back(
+          parallel_partitioning[i].make_tpetra_map(communicator, false));
+
+      Assert(tpetra_maps.size() == block_sparsity_pattern.n_block_rows(),
+             ExcDimensionMismatch(tpetra_maps.size(),
+                                  block_sparsity_pattern.n_block_rows()));
+      Assert(tpetra_maps.size() == block_sparsity_pattern.n_block_cols(),
+             ExcDimensionMismatch(tpetra_maps.size(),
+                                  block_sparsity_pattern.n_block_cols()));
+
+      const size_type n_block_rows = tpetra_maps.size();
+      (void)n_block_rows;
+
+      Assert(n_block_rows == block_sparsity_pattern.n_block_rows(),
+             ExcDimensionMismatch(n_block_rows,
+                                  block_sparsity_pattern.n_block_rows()));
+      Assert(n_block_rows == block_sparsity_pattern.n_block_cols(),
+             ExcDimensionMismatch(n_block_rows,
+                                  block_sparsity_pattern.n_block_cols()));
+#  endif
+
+
+      // Call the other basic reinit function, ...
+      reinit(block_sparsity_pattern.n_block_rows(),
+             block_sparsity_pattern.n_block_cols());
+
+      // ... set the correct sizes, ...
+      this->row_block_indices    = block_sparsity_pattern.get_row_indices();
+      this->column_block_indices = block_sparsity_pattern.get_column_indices();
+
+      // ... and then assign the correct
+      // data to the blocks.
+      for (size_type r = 0; r < this->n_block_rows(); ++r)
+        for (size_type c = 0; c < this->n_block_cols(); ++c)
+          {
+            this->sub_objects[r][c]->reinit(parallel_partitioning[r],
+                                            parallel_partitioning[c],
+                                            block_sparsity_pattern.block(r, c),
+                                            communicator,
+                                            exchange_data);
+          }
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    template <typename BlockSparsityPatternType>
+    void
+    BlockSparseMatrix<Number, MemorySpace>::reinit(
+      const BlockSparsityPatternType &block_sparsity_pattern)
+    {
+      std::vector<IndexSet> parallel_partitioning;
+      for (size_type i = 0; i < block_sparsity_pattern.n_block_rows(); ++i)
+        parallel_partitioning.emplace_back(
+          complete_index_set(block_sparsity_pattern.block(i, 0).n_rows()));
+
+      reinit(parallel_partitioning, block_sparsity_pattern);
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    void
+    BlockSparseMatrix<Number, MemorySpace>::reinit(
+      const std::vector<IndexSet>               &parallel_partitioning,
+      const ::dealii::BlockSparseMatrix<double> &dealii_block_sparse_matrix,
+      const MPI_Comm                             communicator,
+      const double                               drop_tolerance)
+    {
+      const size_type n_block_rows = parallel_partitioning.size();
+
+      Assert(n_block_rows == dealii_block_sparse_matrix.n_block_rows(),
+             ExcDimensionMismatch(n_block_rows,
+                                  dealii_block_sparse_matrix.n_block_rows()));
+      Assert(n_block_rows == dealii_block_sparse_matrix.n_block_cols(),
+             ExcDimensionMismatch(n_block_rows,
+                                  dealii_block_sparse_matrix.n_block_cols()));
+
+      // Call the other basic reinit function ...
+      reinit(n_block_rows, n_block_rows);
+
+      // ... and then assign the correct
+      // data to the blocks.
+      for (size_type r = 0; r < this->n_block_rows(); ++r)
+        for (size_type c = 0; c < this->n_block_cols(); ++c)
+          {
+            this->sub_objects[r][c]->reinit(parallel_partitioning[r],
+                                            parallel_partitioning[c],
+                                            dealii_block_sparse_matrix.block(r,
+                                                                             c),
+                                            communicator,
+                                            drop_tolerance);
+          }
+
+      collect_sizes();
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    void
+    BlockSparseMatrix<Number, MemorySpace>::reinit(
+      const ::dealii::BlockSparseMatrix<double> &dealii_block_sparse_matrix,
+      const double                               drop_tolerance)
+    {
+      Assert(dealii_block_sparse_matrix.n_block_rows() ==
+               dealii_block_sparse_matrix.n_block_cols(),
+             ExcDimensionMismatch(dealii_block_sparse_matrix.n_block_rows(),
+                                  dealii_block_sparse_matrix.n_block_cols()));
+      Assert(dealii_block_sparse_matrix.m() == dealii_block_sparse_matrix.n(),
+             ExcDimensionMismatch(dealii_block_sparse_matrix.m(),
+                                  dealii_block_sparse_matrix.n()));
+
+      std::vector<IndexSet> parallel_partitioning;
+      for (size_type i = 0; i < dealii_block_sparse_matrix.n_block_rows(); ++i)
+        parallel_partitioning.emplace_back(
+          complete_index_set(dealii_block_sparse_matrix.block(i, 0).m()));
+
+      reinit(parallel_partitioning,
+             dealii_block_sparse_matrix,
+             MPI_COMM_SELF,
+             drop_tolerance);
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    inline bool
+    BlockSparseMatrix<Number, MemorySpace>::is_compressed() const
+    {
+      bool compressed = true;
+      for (size_type row = 0; row < this->n_block_rows(); ++row)
+        for (size_type col = 0; col < this->n_block_cols(); ++col)
+          if (this->block(row, col).is_compressed() == false)
+            {
+              compressed = false;
+              break;
+            }
+
+      return compressed;
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    void
+    BlockSparseMatrix<Number, MemorySpace>::collect_sizes()
+    {
+      // simply forward to the (non-public) function of the base class
+      BaseClass::collect_sizes();
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    std::uint64_t
+    BlockSparseMatrix<Number, MemorySpace>::n_nonzero_elements() const
+    {
+      std::uint64_t n_nonzero = 0;
+      for (size_type rows = 0; rows < this->n_block_rows(); ++rows)
+        for (size_type cols = 0; cols < this->n_block_cols(); ++cols)
+          n_nonzero += this->block(rows, cols).n_nonzero_elements();
+
+      return n_nonzero;
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    MPI_Comm
+    BlockSparseMatrix<Number, MemorySpace>::get_mpi_communicator() const
+    {
+      Assert(this->n_block_cols() != 0, ExcNotInitialized());
+      Assert(this->n_block_rows() != 0, ExcNotInitialized());
+      return this->sub_objects[0][0]->get_mpi_communicator();
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    inline std::vector<IndexSet>
+    BlockSparseMatrix<Number, MemorySpace>::locally_owned_domain_indices() const
+    {
+      Assert(this->n_block_cols() != 0, ExcNotInitialized());
+      Assert(this->n_block_rows() != 0, ExcNotInitialized());
+
+      std::vector<IndexSet> domain_indices;
+      for (size_type c = 0; c < this->n_block_cols(); ++c)
+        domain_indices.push_back(
+          this->sub_objects[0][c]->locally_owned_domain_indices());
+
+      return domain_indices;
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    inline std::vector<IndexSet>
+    BlockSparseMatrix<Number, MemorySpace>::locally_owned_range_indices() const
+    {
+      Assert(this->n_block_cols() != 0, ExcNotInitialized());
+      Assert(this->n_block_rows() != 0, ExcNotInitialized());
+
+      std::vector<IndexSet> range_indices;
+      for (size_type r = 0; r < this->n_block_rows(); ++r)
+        range_indices.push_back(
+          this->sub_objects[r][0]->locally_owned_range_indices());
+
+      return range_indices;
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    template <typename VectorType1, typename VectorType2, typename VectorType3>
+    Number
+    BlockSparseMatrix<Number, MemorySpace>::residual(VectorType1       &dst,
+                                                     const VectorType2 &x,
+                                                     const VectorType3 &b) const
+    {
+      vmult(dst, x);
+      dst -= b;
+      dst *= -1.;
+
+      return dst.l2_norm();
+    }
+
+  } // namespace TpetraWrappers
+
+} // namespace LinearAlgebra
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // DEAL_II_TRILINOS_WITH_TPETRA
+
+#endif // dealii_tpetra_trilinos_block_sparse_matrix_templates_h
index 73da7c105cdeb94b187a5592fb10c358d1ae8151..b47167fbb29bb0647e4da2ffef28d6e9ebd1944b 100644 (file)
@@ -22,6 +22,7 @@
 
 #  include <deal.II/lac/block_indices.h>
 #  include <deal.II/lac/block_vector_base.h>
+#  include <deal.II/lac/trilinos_tpetra_block_sparse_matrix.h>
 #  include <deal.II/lac/trilinos_tpetra_vector.h>
 
 DEAL_II_NAMESPACE_OPEN
@@ -39,9 +40,8 @@ namespace LinearAlgebra
     template <typename Number, typename MemorySpace>
     class BlockVector;
 
-    // TODO
-    // template <typename Number, typename MemorySpace>
-    // class BlockSparseMatrix;
+    template <typename Number, typename MemorySpace>
+    class BlockSparseMatrix;
   } // namespace TpetraWrappers
 } // namespace LinearAlgebra
 #  endif // DOXYGEN
index 624d668cc41af82172efbc54c67a17a0c76aa5db..cc9d8da6decec0ba0d62c7ab78160e630f8d92d2 100644 (file)
@@ -144,6 +144,7 @@ if(DEAL_II_WITH_TRILINOS)
     trilinos_sparse_matrix.cc
     trilinos_sparsity_pattern.cc
     trilinos_tpetra_block_vector.cc
+    trilinos_tpetra_block_sparse_matrix.cc
     trilinos_tpetra_communication_pattern.cc
     trilinos_tpetra_solver_direct.cc
     trilinos_tpetra_sparse_matrix.cc
index e3665527a84cbd89779e3e77f4f05d41170eef9f..1c232930de7384a19404d0ea2713258b0439b361 100644 (file)
@@ -256,8 +256,45 @@ for (S : TRILINOS_SCALARS)
       LinearAlgebra::TpetraWrappers::Vector<S> &,
       bool,
       std::integral_constant<bool, false>) const;
-  }
 
+    // BlockSparseMatrix
+    template void AffineConstraints<S>::distribute_local_to_global<
+      LinearAlgebra::TpetraWrappers::BlockSparseMatrix<S>,
+      LinearAlgebra::TpetraWrappers::Vector<S>>(
+      const FullMatrix<S> &,
+      const Vector<S> &,
+      const std::vector<AffineConstraints<S>::size_type> &,
+      LinearAlgebra::TpetraWrappers::BlockSparseMatrix<S> &,
+      LinearAlgebra::TpetraWrappers::Vector<S> &,
+      bool,
+      std::bool_constant<true>) const;
+
+    template void AffineConstraints<S>::distribute_local_to_global<
+      LinearAlgebra::TpetraWrappers::BlockSparseMatrix<S>,
+      LinearAlgebra::TpetraWrappers::BlockVector<S>>(
+      const FullMatrix<S> &,
+      const Vector<S> &,
+      const std::vector<AffineConstraints<S>::size_type> &,
+      LinearAlgebra::TpetraWrappers::BlockSparseMatrix<S> &,
+      LinearAlgebra::TpetraWrappers::BlockVector<S> &,
+      bool,
+      std::bool_constant<true>) const;
+
+    template void AffineConstraints<S>::distribute_local_to_global<
+      LinearAlgebra::TpetraWrappers::BlockSparseMatrix<S>>(
+      const FullMatrix<S> &,
+      const std::vector<AffineConstraints<S>::size_type> &,
+      const std::vector<AffineConstraints<S>::size_type> &,
+      LinearAlgebra::TpetraWrappers::BlockSparseMatrix<S> &) const;
+
+    template void AffineConstraints<S>::distribute_local_to_global<
+      LinearAlgebra::TpetraWrappers::BlockSparseMatrix<S>>(
+      const FullMatrix<S> &,
+      const std::vector<AffineConstraints<S>::size_type> &,
+      const AffineConstraints<S> &,
+      const std::vector<AffineConstraints<S>::size_type> &,
+      LinearAlgebra::TpetraWrappers::BlockSparseMatrix<S> &) const;
+  }
 
 
 // ---------------------------------------------------------------------
diff --git a/source/lac/trilinos_tpetra_block_sparse_matrix.cc b/source/lac/trilinos_tpetra_block_sparse_matrix.cc
new file mode 100644 (file)
index 0000000..fafcebe
--- /dev/null
@@ -0,0 +1,73 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2024 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE.md at
+// the top level directory of deal.II.
+//
+// ---------------------------------------------------------------------
+
+#include <deal.II/base/config.h>
+
+#ifdef DEAL_II_TRILINOS_WITH_TPETRA
+
+#  include <deal.II/lac/trilinos_tpetra_block_sparse_matrix.templates.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+#  ifndef DOXYGEN
+// explicit instantiations
+namespace LinearAlgebra
+{
+  namespace TpetraWrappers
+  {
+    template class BlockSparseMatrix<double>;
+
+    template void
+    BlockSparseMatrix<double>::reinit(
+      const ::dealii::BlockDynamicSparsityPattern &);
+
+    template void
+    BlockSparseMatrix<double>::vmult(
+      TpetraWrappers::Vector<double> &,
+      const TpetraWrappers::Vector<double> &) const;
+
+    template void
+    BlockSparseMatrix<double>::Tvmult(
+      TpetraWrappers::Vector<double> &,
+      const TpetraWrappers::Vector<double> &) const;
+
+    template void
+    BlockSparseMatrix<double>::vmult(
+      TpetraWrappers::BlockVector<double> &,
+      const TpetraWrappers::BlockVector<double> &) const;
+
+    template void
+    BlockSparseMatrix<double>::Tvmult(
+      TpetraWrappers::BlockVector<double> &,
+      const TpetraWrappers::BlockVector<double> &) const;
+
+    template void
+    BlockSparseMatrix<double>::vmult(
+      ::dealii::BlockVector<double> &,
+      const ::dealii::BlockVector<double> &) const;
+
+    template void
+    BlockSparseMatrix<double>::Tvmult(
+      ::dealii::BlockVector<double> &,
+      const ::dealii::BlockVector<double> &) const;
+
+
+  } // namespace TpetraWrappers
+} // namespace LinearAlgebra
+#  endif // DOXYGEN
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // DEAL_II_TRILINOS_WITH_TPETRA

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.