]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Introduce TpetraWrappers::BlockVector
authorSebastian Kinnewig <kinnewig@ifam.uni-hannover.de>
Mon, 29 Jan 2024 20:55:26 +0000 (21:55 +0100)
committerSebastian Kinnewig <sebastian@kinnewig.org>
Sun, 18 Feb 2024 15:20:17 +0000 (16:20 +0100)
include/deal.II/lac/trilinos_tpetra_block_vector.h [new file with mode: 0644]
include/deal.II/lac/trilinos_tpetra_block_vector.templates.h [new file with mode: 0644]
source/lac/CMakeLists.txt
source/lac/trilinos_tpetra_block_vector.cc [new file with mode: 0644]

diff --git a/include/deal.II/lac/trilinos_tpetra_block_vector.h b/include/deal.II/lac/trilinos_tpetra_block_vector.h
new file mode 100644 (file)
index 0000000..73da7c1
--- /dev/null
@@ -0,0 +1,249 @@
+// ---------------------------------------------------------------------
+//
+// 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_trilinos_tpetra_block_vector_h
+#define dealii_trilinos_tpetra_block_vector_h
+
+#include <deal.II/base/config.h>
+
+#ifdef DEAL_II_TRILINOS_WITH_TPETRA
+
+#  include <deal.II/lac/block_indices.h>
+#  include <deal.II/lac/block_vector_base.h>
+#  include <deal.II/lac/trilinos_tpetra_vector.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+// forward declaration
+#  ifndef DOXYGEN
+template <typename Number>
+class BlockVectorBase;
+
+namespace LinearAlgebra
+{
+  // forward declaration
+  namespace TpetraWrappers
+  {
+    template <typename Number, typename MemorySpace>
+    class BlockVector;
+
+    // TODO
+    // template <typename Number, typename MemorySpace>
+    // class BlockSparseMatrix;
+  } // namespace TpetraWrappers
+} // namespace LinearAlgebra
+#  endif // DOXYGEN
+
+namespace LinearAlgebra
+{
+  /**
+   * @addtogroup TpetraWrappers
+   * @{
+   */
+  namespace TpetraWrappers
+  {
+    /**
+     * An implementation of block vectors based on the vector class
+     * implemented in LinearAlgebra::TpetraWrappers.
+     * While the base class provides for most of the interface, this class
+     * handles the actual allocation of vectors and provides functions that
+     * are specific to the underlying vector type.
+     *
+     * The model of distribution of data is such that each of the blocks is
+     * distributed across all MPI processes named in the MPI communicator.
+     * I.e. we don't just distribute the whole vector, but each component. In
+     * the constructors and reinit() functions, one therefore not only has to
+     * specify the sizes of the individual blocks, but also the number of
+     * elements of each of these blocks to be stored on the local process.
+     *
+     * @ingroup Vectors
+     * @ingroup TrilinosWrappers @see
+     * @ref GlossBlockLA "Block (linear algebra)"
+     */
+    template <typename Number, typename MemorySpace = dealii::MemorySpace::Host>
+    class BlockVector : public dealii::BlockVectorBase<
+                          TpetraWrappers::Vector<Number, MemorySpace>>
+    {
+    public:
+      /**
+       * Typedef the base class for simpler access to its own alias.
+       */
+      using BaseClass =
+        dealii::BlockVectorBase<TpetraWrappers::Vector<Number, MemorySpace>>;
+
+      /**
+       * Typedef the type of the underlying vector.
+       */
+      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;
+
+      /**
+       * Default constructor. Generate an empty vector without any blocks.
+       */
+      BlockVector() = default;
+
+      /**
+       * Constructor. Generate a block vector with as many blocks as there are
+       * entries in @p partitioning.  Each IndexSet together with the MPI
+       * communicator contains the layout of the distribution of data among
+       * the MPI processes.
+       */
+      BlockVector(const std::vector<IndexSet> &parallel_partitioning,
+                  const MPI_Comm               communicator = MPI_COMM_WORLD);
+
+      /**
+       * Creates a BlockVector with ghost elements. See the respective
+       * reinit() method for more details. @p ghost_values may contain any
+       * elements in @p parallel_partitioning, they will be ignored.
+       */
+      BlockVector(const std::vector<IndexSet> &parallel_partitioning,
+                  const std::vector<IndexSet> &ghost_values,
+                  const MPI_Comm               communicator,
+                  const bool                   vector_writable = false);
+
+      /**
+       * Copy-Constructor. Set all the properties of the parallel vector to
+       * those of the given argument and copy the elements.
+       */
+      BlockVector(const BlockVector<Number, MemorySpace> &v);
+
+      /**
+       * Creates a block vector consisting of <tt>num_blocks</tt> components,
+       * but there is no content in the individual components and the user has
+       * to fill appropriate data using a reinit of the blocks.
+       */
+      explicit BlockVector(const size_type num_blocks);
+
+      /**
+       * Destructor. Clears memory
+       */
+      ~BlockVector() override = default;
+
+      /**
+       * Copy operator: fill all components of the vector that are locally
+       * stored with the given scalar value.
+       */
+      BlockVector<Number, MemorySpace> &
+      operator=(const Number s);
+
+      /**
+       * Copy operator for arguments of the same type.
+       */
+      BlockVector<Number, MemorySpace> &
+      operator=(const BlockVector<Number, MemorySpace> &v);
+
+      /**
+       * Reinitialize the BlockVector to contain as many blocks as there are
+       * index sets given in the input argument, according to the parallel
+       * distribution of the individual components described in the maps.
+       *
+       * If <tt>omit_zeroing_entries==false</tt>, the vector is filled with
+       * zeros.
+       */
+      void
+      reinit(const std::vector<IndexSet> &parallel_partitioning,
+             const MPI_Comm               communicator         = MPI_COMM_WORLD,
+             const bool                   omit_zeroing_entries = false);
+
+      /**
+       * Reinit functionality. This function destroys the old vector content
+       * and generates a new one based on the input partitioning. In addition
+       * to just specifying one index set as in all the other methods above,
+       * this method allows to supply an additional set of ghost entries.
+       * There are two different versions of a vector that can be created. If
+       * the flag @p vector_writable is set to @p false, the vector only
+       * allows read access to the joint set of @p parallel_partitioning and
+       * @p ghost_entries. The effect of the reinit method is then equivalent
+       * to calling the other reinit method with an index set containing both
+       * the locally owned entries and the ghost entries.
+       *
+       * If the flag @p vector_writable is set to true, this creates an
+       * alternative storage scheme for ghost elements that allows multiple
+       * threads to write into the vector (for the other reinit methods, only
+       * one thread is allowed to write into the ghost entries at a time).
+       */
+      void
+      reinit(const std::vector<IndexSet> &partitioning,
+             const std::vector<IndexSet> &ghost_values,
+             const MPI_Comm               communicator    = MPI_COMM_WORLD,
+             const bool                   vector_writable = false);
+
+      /**
+       * Change the dimension to that of the vector <tt>V</tt>. The same
+       * applies as for the other reinit() function.
+       *
+       * The elements of <tt>V</tt> are not copied, i.e.  this function is the
+       * same as calling <tt>reinit (V.size(), omit_zeroing_entries)</tt>.
+       *
+       * Note that you must call this (or the other reinit() functions)
+       * function, rather than calling the reinit() functions of an individual
+       * block, to allow the block vector to update its caches of vector
+       * sizes. If you call reinit() on one of the blocks, then subsequent
+       * actions on this object may yield unpredictable results since they may
+       * be routed to the wrong block.
+       */
+      void
+      reinit(const BlockVector<Number, MemorySpace> &V,
+             const bool omit_zeroing_entries = false);
+
+      /**
+       * Change the number of blocks to <tt>num_blocks</tt>. The individual
+       * blocks will get initialized with zero size, so it is assumed that the
+       * user resizes the individual blocks by herself in an appropriate way,
+       * and calls <tt>collect_sizes</tt> afterwards.
+       */
+      void
+      reinit(const size_type num_blocks);
+
+      /**
+       * Return if this Vector contains ghost elements.
+       *
+       * @see
+       * @ref GlossGhostedVector "vectors with ghost elements"
+       */
+      bool
+      has_ghost_elements() const;
+
+      /**
+       * Print to a stream.
+       */
+      void
+      print(std::ostream      &out,
+            const unsigned int precision  = 3,
+            const bool         scientific = true,
+            const bool         across     = true) const;
+    };
+  } // namespace TpetraWrappers
+
+  /** @} */
+
+} // namespace LinearAlgebra
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // DEAL_II_TRILINOS_WITH_TPETRA
+
+#endif // dealii_trilinos_tpetra_block_vector_h
diff --git a/include/deal.II/lac/trilinos_tpetra_block_vector.templates.h b/include/deal.II/lac/trilinos_tpetra_block_vector.templates.h
new file mode 100644 (file)
index 0000000..4ed8f65
--- /dev/null
@@ -0,0 +1,237 @@
+// ---------------------------------------------------------------------
+//
+// 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_trilinos_tpetra_block_vector_templates_h
+#define dealii_trilinos_tpetra_block_vector_templates_h
+
+#include <deal.II/base/config.h>
+
+#include <deal.II/lac/trilinos_tpetra_block_vector.h>
+
+#ifdef DEAL_II_TRILINOS_WITH_TPETRA
+
+#  include <deal.II/base/index_set.h>
+#  include <deal.II/base/trilinos_utilities.h>
+
+DEAL_II_NAMESPACE_OPEN
+
+namespace LinearAlgebra
+{
+  namespace TpetraWrappers
+  {
+    template <typename Number, typename MemorySpace>
+    BlockVector<Number, MemorySpace>::BlockVector(
+      const std::vector<IndexSet> &parallel_partitioning,
+      const MPI_Comm               communicator)
+    {
+      reinit(parallel_partitioning, communicator, false);
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    BlockVector<Number, MemorySpace>::BlockVector(
+      const std::vector<IndexSet> &parallel_partitioning,
+      const std::vector<IndexSet> &ghost_values,
+      const MPI_Comm               communicator,
+      const bool                   vector_writable)
+    {
+      reinit(parallel_partitioning,
+             ghost_values,
+             communicator,
+             vector_writable);
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    BlockVector<Number, MemorySpace>::BlockVector(
+      const BlockVector<Number, MemorySpace> &v)
+      : dealii::BlockVectorBase<TpetraWrappers::Vector<Number, MemorySpace>>()
+    {
+      this->block_indices = v.block_indices;
+
+      this->components.resize(this->n_blocks());
+      for (unsigned int i = 0; i < this->n_blocks(); ++i)
+        this->components[i] = v.components[i];
+
+      this->collect_sizes();
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    BlockVector<Number, MemorySpace>::BlockVector(const size_type num_blocks)
+      : dealii::BlockVectorBase<TpetraWrappers::Vector<Number, MemorySpace>>()
+    {
+      reinit(num_blocks);
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    BlockVector<Number, MemorySpace> &
+    BlockVector<Number, MemorySpace>::operator=(const Number s)
+    {
+      BaseClass::operator=(s);
+      return *this;
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    BlockVector<Number, MemorySpace> &
+    BlockVector<Number, MemorySpace>::operator=(const BlockVector &v)
+    {
+      // we only allow assignment to vectors with the same number of blocks
+      // or to an empty BlockVector
+      Assert(this->n_blocks() == 0 || this->n_blocks() == v.n_blocks(),
+             ExcDimensionMismatch(this->n_blocks(), v.n_blocks()));
+
+      if (this->n_blocks() != v.n_blocks())
+        this->block_indices = v.block_indices;
+
+      this->components.resize(this->n_blocks());
+      for (unsigned int i = 0; i < this->n_blocks(); ++i)
+        this->components[i] = v.components[i];
+
+      this->collect_sizes();
+
+      return *this;
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    void
+    BlockVector<Number, MemorySpace>::reinit(
+      const std::vector<IndexSet> &parallel_partitioning,
+      const MPI_Comm               communicator,
+      const bool                   omit_zeroing_entries)
+    {
+      // update the number of blocks
+      this->block_indices.reinit(parallel_partitioning.size(), 0);
+
+      // initialize each block
+      this->components.resize(this->n_blocks());
+      for (unsigned int i = 0; i < this->n_blocks(); ++i)
+        this->components[i].reinit(parallel_partitioning[i],
+                                   communicator,
+                                   omit_zeroing_entries);
+
+      // update block_indices content
+      this->collect_sizes();
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    void
+    BlockVector<Number, MemorySpace>::reinit(
+      const std::vector<IndexSet> &parallel_partitioning,
+      const std::vector<IndexSet> &ghost_values,
+      const MPI_Comm               communicator,
+      const bool                   vector_writable)
+    {
+      AssertDimension(parallel_partitioning.size(), ghost_values.size());
+
+      // update the number of blocks
+      this->block_indices.reinit(parallel_partitioning.size(), 0);
+
+      // initialize each block
+      this->components.resize(this->n_blocks());
+      for (unsigned int i = 0; i < this->n_blocks(); ++i)
+        this->components[i].reinit(parallel_partitioning[i],
+                                   ghost_values[i],
+                                   communicator,
+                                   vector_writable);
+
+      // update block_indices content
+      this->collect_sizes();
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    void
+    BlockVector<Number, MemorySpace>::reinit(
+      const BlockVector<Number, MemorySpace> &v,
+      const bool                              omit_zeroing_entries)
+    {
+      if (this->n_blocks() != v.n_blocks())
+        this->block_indices = v.get_block_indices();
+
+      this->components.resize(this->n_blocks());
+      for (unsigned int i = 0; i < this->n_blocks(); ++i)
+        this->components[i].reinit(v.components[i], omit_zeroing_entries);
+
+      this->collect_sizes();
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    void
+    BlockVector<Number, MemorySpace>::reinit(const size_type num_blocks)
+    {
+      this->block_indices.reinit(num_blocks, 0);
+
+      this->components.resize(this->n_blocks());
+      for (auto &c : this->components)
+        c.clear();
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    bool
+    BlockVector<Number, MemorySpace>::has_ghost_elements() const
+    {
+      bool ghosted = this->block(0).has_ghost_elements();
+#  ifdef DEBUG
+      for (unsigned int i = 0; i < this->n_blocks(); ++i)
+        Assert(this->block(i).has_ghost_elements() == ghosted,
+               ExcInternalError());
+#  endif
+      return ghosted;
+    }
+
+
+
+    template <typename Number, typename MemorySpace>
+    void
+    BlockVector<Number, MemorySpace>::print(std::ostream      &out,
+                                            const unsigned int precision,
+                                            const bool         scientific,
+                                            const bool         across) const
+    {
+      for (unsigned int i = 0; i < this->n_blocks(); ++i)
+        {
+          if (across)
+            out << 'C' << i << ':';
+          else
+            out << "Component " << i << std::endl;
+          this->components[i].print(out, precision, scientific, across);
+        }
+    }
+
+  } // namespace TpetraWrappers
+} // namespace LinearAlgebra
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif // DEAL_II_TRILINOS_WITH_TPETRA
+
+#endif // dealii_trilinos_tpetra_block_vector_templates_h
index f2548f3924abb1f1661d998fed3adc5cc7eb4b73..624d668cc41af82172efbc54c67a17a0c76aa5db 100644 (file)
@@ -143,6 +143,7 @@ if(DEAL_II_WITH_TRILINOS)
     trilinos_solver.cc
     trilinos_sparse_matrix.cc
     trilinos_sparsity_pattern.cc
+    trilinos_tpetra_block_vector.cc
     trilinos_tpetra_communication_pattern.cc
     trilinos_tpetra_solver_direct.cc
     trilinos_tpetra_sparse_matrix.cc
diff --git a/source/lac/trilinos_tpetra_block_vector.cc b/source/lac/trilinos_tpetra_block_vector.cc
new file mode 100644 (file)
index 0000000..8eccf19
--- /dev/null
@@ -0,0 +1,67 @@
+// ---------------------------------------------------------------------
+//
+// 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/lac/trilinos_tpetra_block_vector.templates.h>
+
+#ifdef DEAL_II_TRILINOS_WITH_TPETRA
+
+DEAL_II_NAMESPACE_OPEN
+
+namespace LinearAlgebra
+{
+  namespace TpetraWrappers
+  {
+    // Instantiate these vectors types for specific scalar types.
+    //
+    // While there:
+    // Check that the class we declare here satisfies the
+    // vector-space-vector concept. If we catch it here,
+    // any mistake in the vector class declaration would
+    // show up in uses of this class later on as well.
+
+#  ifdef HAVE_TPETRA_INST_FLOAT
+#    ifdef DEAL_II_HAVE_CXX20
+    static_assert(concepts::is_vector_space_vector<BlockVector<float>>);
+#    endif
+    template class BlockVector<float>;
+#  endif
+#  ifdef HAVE_TPETRA_INST_DOUBLE
+#    ifdef DEAL_II_HAVE_CXX20
+    static_assert(concepts::is_vector_space_vector<BlockVector<double>>);
+#    endif
+    template class BlockVector<double>;
+#  endif
+#  ifdef DEAL_II_WITH_COMPLEX_VALUES
+#    ifdef HAVE_TPETRA_INST_COMPLEX_FLOAT
+#      ifdef DEAL_II_HAVE_CXX20
+    static_assert(concepts::is_vector_space_vector <
+                  BlockVector<std::complex<float>>);
+#      endif
+    template class BlockVector<std::complex<float>>;
+#    endif
+#    ifdef HAVE_TPETRA_INST_COMPLEX_DOUBLE
+#      ifdef DEAL_II_HAVE_CXX20
+    static_assert(concepts::is_vector_space_vector <
+                  BlockVector<std::complex<double>>);
+#      endif
+    template class BlockVector<std::complex<double>>;
+#    endif
+#  endif
+  } // namespace TpetraWrappers
+} // namespace LinearAlgebra
+
+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.