]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Add parallel support to TpetraWrappers::Vector.
authorSebastian Kinnewig <sebastian@kinnewig.org>
Fri, 17 Nov 2023 17:56:29 +0000 (18:56 +0100)
committerSebastian Kinnewig <kinnewig@ifam.uni-hannover.de>
Thu, 11 Jan 2024 16:18:47 +0000 (17:18 +0100)
include/deal.II/lac/affine_constraints.templates.h
include/deal.II/lac/read_write_vector.templates.h
include/deal.II/lac/trilinos_tpetra_vector.h
include/deal.II/lac/trilinos_tpetra_vector.templates.h
include/deal.II/numerics/data_out_dof_data.templates.h
tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=off.mpirun=2.output
tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=off.mpirun=4.output
tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=on.mpirun=2.output
tests/trilinos/tpetra_vector_03.with_trilinos_with_tpetra=on.with_complex_values=on.mpirun=4.output

index fe265b85946310a8151ffd57688409403d59c7f2..b99edfb2fee6ca5fd9b51b7e309eab1da6782451 100644 (file)
@@ -2650,6 +2650,35 @@ namespace internal
   }
 #endif
 
+
+
+#ifdef DEAL_II_TRILINOS_WITH_TPETRA
+  template <typename Number>
+  inline void
+  import_vector_with_ghost_elements(
+    const LinearAlgebra::TpetraWrappers::Vector<Number> &vec,
+    const IndexSet                                      &locally_owned_elements,
+    const IndexSet                                      &needed_elements,
+    LinearAlgebra::TpetraWrappers::Vector<Number>       &output,
+    const std::bool_constant<false> /*is_block_vector*/)
+  {
+    Assert(!vec.has_ghost_elements(), ExcGhostsPresent());
+    IndexSet parallel_partitioner = locally_owned_elements;
+    parallel_partitioner.add_indices(needed_elements);
+
+    const MPI_Comm mpi_comm =
+      Trilinos::teuchos_comm_to_mpi_comm(vec.trilinos_rcp()->getMap()->getComm());
+
+    output.reinit(locally_owned_elements,
+                  needed_elements,
+                  mpi_comm);
+
+    output = vec;
+  }
+#endif // DEAL_II_TRILINOS_WITH_TPETRA
+
+
+
 #ifdef DEAL_II_WITH_PETSC
   inline void
   import_vector_with_ghost_elements(
index 710c5c7f85771778cd0fd5228e005ddec6716aac..652990854b0ebcac7ae5aa1dc757547f2fbf9200 100644 (file)
@@ -1036,12 +1036,12 @@ namespace LinearAlgebra
     const MPI_Comm  mpi_comm)
   {
     source_stored_elements = source_index_set;
-    TpetraWrappers::CommunicationPattern epetra_comm_pattern(
+    TpetraWrappers::CommunicationPattern tpetra_comm_pattern(
       source_stored_elements, stored_elements, mpi_comm);
     comm_pattern = std::make_shared<TpetraWrappers::CommunicationPattern>(
       source_stored_elements, stored_elements, mpi_comm);
 
-    return epetra_comm_pattern;
+    return tpetra_comm_pattern;
   }
 #  endif
 
index 50a037292f273c9328cf4cf12d8c6e58f11aa44a..856bb7456e35726b0f966ddb5475595ed389a7a0 100644 (file)
@@ -260,6 +260,10 @@ namespace LinearAlgebra
       using MapType = Tpetra::Map<int, dealii::types::signed_global_dof_index>;
       using VectorType =
         Tpetra::Vector<Number, int, dealii::types::signed_global_dof_index>;
+      using ExportType =
+        Tpetra::Export<int, dealii::types::signed_global_dof_index>;
+      using ImportType =
+        Tpetra::Import<int, dealii::types::signed_global_dof_index>;
 
       /**
        * @name 1: Basic Object-handling
@@ -420,6 +424,32 @@ namespace LinearAlgebra
       reference
       operator()(const size_type index);
 
+      /**
+       * Provide read-only access to an element.
+       *
+       * When using a vector distributed with MPI, this operation only makes
+       * sense for elements that are actually present on the calling processor.
+       * Otherwise, an exception is thrown.
+       */
+      Number
+      operator()(const size_type index) const;
+
+      /**
+       * Provide access to a given element, both read and write.
+       *
+       * Exactly the same as operator().
+       */
+      reference
+      operator[](const size_type index);
+
+      /**
+       * Provide read-only access to an element.
+       *
+       * Exactly the same as operator().
+       */
+      Number
+      operator[](const size_type index) const;
+
       /** @} */
 
 
@@ -611,8 +641,7 @@ namespace LinearAlgebra
       /** @{ */
 
       /**
-       * This function always returns false and is present only for backward
-       * compatibility.
+       * Return whether the vector has ghost elements or not.
        */
       bool
       has_ghost_elements() const;
@@ -631,6 +660,14 @@ namespace LinearAlgebra
       size_type
       locally_owned_size() const;
 
+      /**
+       * Return the state of the vector, i.e., whether compress() needs to be
+       * called after an operation requiring data exchange. A call to compress()
+       * is also needed when the method set() or add() has been called.
+       */
+      bool
+      is_compressed() const;
+
       /**
        * Return the underlying MPI communicator.
        */
@@ -664,6 +701,11 @@ namespace LinearAlgebra
        * necessary after writing into a vector element-by-element and before
        * anything else can be done on it.
        *
+       * @param operation The compress mode (<code>Add</code> or <code>Insert</code>)
+       * in case the vector has not been written to since the last time this
+       * function was called. The argument is ignored if the vector has been
+       * added or written to since the last time compress() was called.
+       *
        * See
        * @ref GlossCompress "Compressing distributed objects"
        * for more information.
@@ -739,6 +781,47 @@ namespace LinearAlgebra
        */
       DeclException0(ExcVectorTypeNotCompatible);
 
+      /*
+       * Access to a an element that is not (locally-)owned.
+       *
+       * @ingroup Exceptions
+       */
+      DeclException4(
+        ExcAccessToNonLocalElement,
+        size_type,
+        size_type,
+        size_type,
+        size_type,
+        << "You are trying to access element " << arg1
+        << " of a distributed vector, but this element is not stored "
+        << "on the current processor. Note: There are " << arg2
+        << " elements stored "
+        << "on the current processor from within the range [" << arg3 << ','
+        << arg4 << "] but Trilinos vectors need not store contiguous "
+        << "ranges on each processor, and not every element in "
+        << "this range may in fact be stored locally."
+        << "\n\n"
+        << "A common source for this kind of problem is that you "
+        << "are passing a 'fully distributed' vector into a function "
+        << "that needs read access to vector elements that correspond "
+        << "to degrees of freedom on ghost cells (or at least to "
+        << "'locally active' degrees of freedom that are not also "
+        << "'locally owned'). You need to pass a vector that has these "
+        << "elements as ghost entries.");
+
+      /**
+       * Missing index set.
+       *
+       * @ingroup Exceptions
+       */
+      DeclExceptionMsg(ExcMissingIndexSet,
+                       "To compress a vector, a locally_relevant_dofs "
+                       "index set, and a locally_owned_dofs index set "
+                       "must be provided. These index sets must be "
+                       "provided either when the vector is initialized "
+                       "or when compress is called. See the documentation "
+                       "of compress() for more information.");
+
       /**
        * Exception thrown by an error in Trilinos.
        *
@@ -759,15 +842,38 @@ namespace LinearAlgebra
       create_tpetra_comm_pattern(const IndexSet &source_index_set,
                                  const MPI_Comm  mpi_comm);
 
+      /**
+       * Store whether the vector has ghost elements or not.
+       *
+       * If the vector has no ghost elements, it can only access and modify
+       * entries included in the locally owned index set.
+       * And if the vector has ghost elements it can access and modify
+       * entries included in the locally relevant index set.
+       */
+      bool has_ghost;
+
       /**
        * Teuchos::RCP to the actual Tpetra vector object.
        */
       Teuchos::RCP<VectorType> vector;
 
+      /**
+       * Pointer to the Tpetra::Map storing the owned elemenets
+       * per rank. This map has a one-to-one mapping.
+       */
+      Teuchos::RCP<MapType> locally_owned_map;
+
+      /**
+       * Pointer to the Tpetra::Map storing the relevant elements
+       * per rank. There are entries in this map, that belong to multiple
+       * ranks.
+       */
+      Teuchos::RCP<MapType> locally_relevant_map;
+
       /**
        * IndexSet of the elements of the last imported vector.
        */
-      ::dealii::IndexSet source_stored_elements;
+      dealii::IndexSet source_stored_elements;
 
       /**
        * CommunicationPattern for the communication between the
@@ -787,7 +893,16 @@ namespace LinearAlgebra
     inline bool
     Vector<Number>::has_ghost_elements() const
     {
-      return false;
+      return has_ghost;
+    }
+
+
+
+    template <typename Number>
+    inline bool
+    Vector<Number>::is_compressed() const
+    {
+      return !has_ghost;
     }
 
 
@@ -826,10 +941,27 @@ namespace LinearAlgebra
 
       for (size_type i = 0; i < n_elements; ++i)
         {
-          const size_type                         row = indices[i];
-          const TrilinosWrappers::types::int_type local_row =
+          const size_type                   row = indices[i];
+          TrilinosWrappers::types::int_type local_row =
             vector->getMap()->getLocalElement(row);
 
+#  if DEAL_II_TRILINOS_VERSION_GTE(14, 0, 0)
+          Assert(
+            local_row != Teuchos::OrdinalTraits<int>::invalid(),
+            ExcAccessToNonLocalElement(row,
+                                       vector->getMap()->getLocalNumElements(),
+                                       vector->getMap()->getMinLocalIndex(),
+                                       vector->getMap()->getMaxLocalIndex()));
+#  else
+          Assert(
+            local_row != Teuchos::OrdinalTraits<int>::invalid(),
+            ExcAccessToNonLocalElement(row,
+                                       vector->getMap()->getNodeNumElements(),
+                                       vector->getMap()->getMinLocalIndex(),
+                                       vector->getMap()->getMaxLocalIndex()));
+
+#  endif
+
           if (local_row != Teuchos::OrdinalTraits<int>::invalid())
             vector_1d(local_row) += values[i];
         }
@@ -863,10 +995,26 @@ namespace LinearAlgebra
 
       for (size_type i = 0; i < n_elements; ++i)
         {
-          const size_type                         row = indices[i];
-          const TrilinosWrappers::types::int_type local_row =
+          const size_type                   row = indices[i];
+          TrilinosWrappers::types::int_type local_row =
             vector->getMap()->getLocalElement(row);
 
+#  if DEAL_II_TRILINOS_VERSION_GTE(14, 0, 0)
+          Assert(
+            local_row != Teuchos::OrdinalTraits<int>::invalid(),
+            ExcAccessToNonLocalElement(row,
+                                       vector->getMap()->getLocalNumElements(),
+                                       vector->getMap()->getMinLocalIndex(),
+                                       vector->getMap()->getMaxLocalIndex()));
+#  else
+          Assert(
+            local_row != Teuchos::OrdinalTraits<int>::invalid(),
+            ExcAccessToNonLocalElement(row,
+                                       vector->getMap()->getNodeNumElements(),
+                                       vector->getMap()->getMinLocalIndex(),
+                                       vector->getMap()->getMaxLocalIndex()));
+#  endif
+
           if (local_row != Teuchos::OrdinalTraits<int>::invalid())
             vector_1d(local_row) = values[i];
         }
@@ -887,6 +1035,20 @@ namespace LinearAlgebra
       return internal::VectorReference(*this, index);
     }
 
+    template <typename Number>
+    inline internal::VectorReference<Number>
+    Vector<Number>::operator[](const size_type index)
+    {
+      return operator()(index);
+    }
+
+    template <typename Number>
+    inline Number
+    Vector<Number>::operator[](const size_type index) const
+    {
+      return operator()(index);
+    }
+
 #  ifndef DOXYGEN
 
     // VectorReference
index ad5b04d76e003d4ebb1437d4c3711bc610efadd8..2a7f11edb679267b4a9a60c8390f2560861baa33 100644 (file)
@@ -47,6 +47,7 @@ namespace LinearAlgebra
     template <typename Number>
     Vector<Number>::Vector()
       : Subscriptor()
+      , has_ghost(false)
       , vector(Utilities::Trilinos::internal::make_rcp<VectorType>(
           Utilities::Trilinos::internal::make_rcp<MapType>(
             0,
@@ -59,9 +60,12 @@ namespace LinearAlgebra
     template <typename Number>
     Vector<Number>::Vector(const Vector<Number> &V)
       : Subscriptor()
+      , has_ghost(V.has_ghost)
       , vector(Utilities::Trilinos::internal::make_rcp<VectorType>(
           V.trilinos_vector(),
           Teuchos::Copy))
+      , locally_owned_map(V.locally_owned_map)
+      , locally_relevant_map(V.locally_relevant_map)
     {}
 
 
@@ -69,8 +73,20 @@ namespace LinearAlgebra
     template <typename Number>
     Vector<Number>::Vector(const Teuchos::RCP<VectorType> V)
       : Subscriptor()
+      , has_ghost(false)
       , vector(V)
-    {}
+    {
+      if (vector->getMap()->isOneToOne())
+        {
+          locally_owned_map =
+            Teuchos::rcp_const_cast<MapType>(vector->getMap());
+        }
+      else
+        {
+          locally_relevant_map =
+            Teuchos::rcp_const_cast<MapType>(vector->getMap());
+        }
+    }
 
 
 
@@ -78,9 +94,13 @@ namespace LinearAlgebra
     Vector<Number>::Vector(const IndexSet &parallel_partitioner,
                            const MPI_Comm  communicator)
       : Subscriptor()
-      , vector(Utilities::Trilinos::internal::make_rcp<VectorType>(
-          parallel_partitioner.make_tpetra_map_rcp(communicator, false)))
-    {}
+      , has_ghost(false)
+      , locally_owned_map(
+          parallel_partitioner.make_tpetra_map_rcp(communicator, false))
+    {
+      vector = Utilities::Trilinos::internal::make_rcp<VectorType>(
+        locally_owned_map);
+    }
 
 
 
@@ -90,12 +110,23 @@ namespace LinearAlgebra
                            const MPI_Comm  communicator,
                            const bool      omit_zeroing_entries)
     {
-      Teuchos::RCP<MapType> input_map =
+      // release memory before reallocation
+      vector.reset();
+      locally_owned_map.reset();
+      locally_relevant_map.reset();
+      source_stored_elements.clear();
+
+      // Here we assume, that the index set is non-overlapping.
+      // If the index set is overlapping the function
+      // make_tpetra_map_rcp() will throw an assert.
+      has_ghost = false;
+      locally_owned_map =
         parallel_partitioner.make_tpetra_map_rcp(communicator, false);
 
-      if (vector->getMap()->isSameAs(*input_map) == false)
-        vector = Utilities::Trilinos::internal::make_rcp<VectorType>(input_map);
-      else if (omit_zeroing_entries == false)
+      if (!vector->getMap()->isSameAs(*locally_owned_map))
+        vector = Utilities::Trilinos::internal::make_rcp<VectorType>(
+          locally_owned_map);
+      if (!omit_zeroing_entries)
         {
           vector->putScalar(0.);
         }
@@ -109,13 +140,23 @@ namespace LinearAlgebra
                            const IndexSet &ghost_entries,
                            const MPI_Comm  communicator)
     {
+      // release memory before reallocation
+      vector.reset();
+      locally_owned_map.reset();
+      locally_relevant_map.reset();
+
+      locally_owned_map =
+        locally_owned_entries.make_tpetra_map_rcp(communicator, false);
+
       IndexSet parallel_partitioner = locally_owned_entries;
       parallel_partitioner.add_indices(ghost_entries);
-
-      Teuchos::RCP<MapType> input_map =
+      locally_relevant_map =
         parallel_partitioner.make_tpetra_map_rcp(communicator, true);
 
-      vector = Utilities::Trilinos::internal::make_rcp<VectorType>(input_map);
+      vector = Utilities::Trilinos::internal::make_rcp<VectorType>(
+        locally_relevant_map);
+
+      has_ghost = false;
     }
 
 
@@ -139,11 +180,9 @@ namespace LinearAlgebra
       ArrayView<Number>                              &elements) const
     {
       AssertDimension(indices.size(), elements.size());
-      const auto &vector = trilinos_vector();
-      const auto &map    = vector.getMap();
 
 #  if DEAL_II_TRILINOS_VERSION_GTE(13, 2, 0)
-      auto vector_2d = vector.template getLocalView<Kokkos::HostSpace>(
+      auto vector_2d = vector->template getLocalView<Kokkos::HostSpace>(
         Tpetra::Access::ReadOnly);
 #  else
       /*
@@ -156,16 +195,35 @@ namespace LinearAlgebra
        * Let us choose to simply ignore this problem for such an old
        * Trilinos version.
        */
-      auto vector_2d = vector.template getLocalView<Kokkos::HostSpace>();
+      auto vector_2d = vector->template getLocalView<Kokkos::HostSpace>();
 #  endif
       auto vector_1d = Kokkos::subview(vector_2d, Kokkos::ALL(), 0);
 
       for (unsigned int i = 0; i < indices.size(); ++i)
         {
           AssertIndexRange(indices[i], size());
-          const auto trilinos_i = map->getLocalElement(
-            static_cast<TrilinosWrappers::types::int_type>(indices[i]));
-          elements[i] = vector_1d(trilinos_i);
+          const size_type                   row = indices[i];
+          TrilinosWrappers::types::int_type local_row =
+            vector->getMap()->getLocalElement(row);
+
+
+          Assert(
+            local_row != Teuchos::OrdinalTraits<int>::invalid(),
+#  if DEAL_II_TRILINOS_VERSION_GTE(14, 0, 0)
+            ExcAccessToNonLocalElement(row,
+                                       vector->getMap()->getLocalNumElements(),
+                                       vector->getMap()->getMinLocalIndex(),
+                                       vector->getMap()->getMaxLocalIndex()));
+#  else
+            ExcAccessToNonLocalElement(row,
+                                       vector->getMap()->getNodeNumElements(),
+                                       vector->getMap()->getMinLocalIndex(),
+                                       vector->getMap()->getMaxLocalIndex()));
+
+#  endif
+
+          if (local_row != Teuchos::OrdinalTraits<int>::invalid())
+            elements[i] = vector_1d(local_row);
         }
     }
 
@@ -179,22 +237,45 @@ namespace LinearAlgebra
       //  - First case: both vectors have the same layout.
       //  - Second case: both vectors have the same size but different layout.
       //  - Third case: the vectors have different size.
-      if (vector->getMap()->isSameAs(*(V.trilinos_vector().getMap())))
-        *vector = V.trilinos_vector();
+      if (vector->getMap()->isSameAs(*V.vector->getMap()))
+        {
+          *vector = *V.vector;
+        }
+      else if (size() == V.size())
+        {
+          // We expect the origin vector to have a one-to-one map, otherwise
+          // we can not call Import
+          Assert(V.vector->getMap()->isOneToOne(),
+                 ExcMessage(
+                   "You are trying to map one vector distributed "
+                   "between processors, where some elements belong "
+                   "to multiple processors, onto another distribution "
+                   "pattern, where some elements belong to multiple "
+                   "processors. It is unclear how to deal with elements "
+                   "in the vector belonging to multiple processors. "
+                   "Therefore, compress() must be called on this "
+                   "vector first."));
+
+          Teuchos::RCP<const ImportType> importer =
+            Tpetra::createImport(V.vector->getMap(), vector->getMap());
+
+          // Since we are distributing the vector from a one-to-one map
+          // we can always use the VectorOperation::insert / Tpetra::INSERT
+          // here.
+          vector->doImport(*V.vector, *importer, Tpetra::INSERT);
+        }
       else
         {
-          if (size() == V.size())
-            {
-              Tpetra::Import<int, types::signed_global_dof_index> data_exchange(
-                vector->getMap(), V.trilinos_vector().getMap());
-
-              vector->doImport(V.trilinos_vector(),
-                               data_exchange,
-                               Tpetra::REPLACE);
-            }
-          else
-            vector = Utilities::Trilinos::internal::make_rcp<VectorType>(
-              V.trilinos_vector());
+          vector.reset();
+          vector = Utilities::Trilinos::internal::make_rcp<VectorType>(
+            V.vector->getMap());
+          Tpetra::deep_copy(*vector, *V.vector);
+
+          has_ghost              = V.has_ghost;
+          locally_owned_map      = V.locally_owned_map;
+          locally_relevant_map   = V.locally_relevant_map;
+          source_stored_elements = V.source_stored_elements;
+          tpetra_comm_pattern    = V.tpetra_comm_pattern;
         }
 
       return *this;
@@ -253,8 +334,8 @@ namespace LinearAlgebra
               "LinearAlgebra::TpetraWrappers::CommunicationPattern."));
         }
 
-      Teuchos::RCP<const Tpetra::Export<int, types::signed_global_dof_index>>
-        tpetra_export = tpetra_comm_pattern->get_tpetra_export_rcp();
+      Teuchos::RCP<const ExportType> tpetra_export =
+        tpetra_comm_pattern->get_tpetra_export_rcp();
 
       VectorType source_vector(tpetra_export->getSourceMap());
 
@@ -280,12 +361,15 @@ namespace LinearAlgebra
             device_type::memory_space>();
 #  endif
       }
+      Tpetra::CombineMode tpetra_operation = Tpetra::ZERO;
       if (operation == VectorOperation::insert)
-        vector->doExport(source_vector, *tpetra_export, Tpetra::REPLACE);
+        tpetra_operation = Tpetra::INSERT;
       else if (operation == VectorOperation::add)
-        vector->doExport(source_vector, *tpetra_export, Tpetra::ADD);
+        tpetra_operation = Tpetra::ADD;
       else
-        AssertThrow(false, ExcNotImplemented());
+        Assert(false, ExcNotImplemented());
+
+      vector->doExport(source_vector, *tpetra_export, tpetra_operation);
     }
 
 
@@ -301,6 +385,7 @@ namespace LinearAlgebra
     }
 
 
+
     template <typename Number>
     void
     Vector<Number>::import_elements(const ReadWriteVector<Number> &V,
@@ -358,9 +443,8 @@ namespace LinearAlgebra
           // elements, maybe there is a better workaround.
           Tpetra::Vector<Number, int, types::signed_global_dof_index> dummy(
             vector->getMap(), false);
-          Tpetra::Import<int, types::signed_global_dof_index> data_exchange(
-            V.trilinos_vector().getMap(), dummy.getMap());
-
+          ImportType data_exchange(V.trilinos_vector().getMap(),
+                                   dummy.getMap());
           dummy.doImport(V.trilinos_vector(), data_exchange, Tpetra::INSERT);
 
           vector->update(1.0, dummy, 1.0);
@@ -396,6 +480,45 @@ namespace LinearAlgebra
 
 
 
+    template <typename Number>
+    Number
+    Vector<Number>::operator()(const size_type index) const
+    {
+      // Get the local index
+      const TrilinosWrappers::types::int_type local_index =
+        vector->getMap()->getLocalElement(
+          static_cast<TrilinosWrappers::types::int_type>(index));
+
+      Number value = 0.0;
+
+      // If the element is not present on the current processor, we can't
+      // continue. This is the main difference to the el() function.
+      if (local_index == -1)
+        {
+#  if DEAL_II_TRILINOS_VERSION_GTE(14, 0, 0)
+          Assert(
+            false,
+            ExcAccessToNonLocalElement(index,
+                                       vector->getMap()->getLocalNumElements(),
+                                       vector->getMap()->getMinLocalIndex(),
+                                       vector->getMap()->getMaxLocalIndex()));
+#  else
+          Assert(
+            false,
+            ExcAccessToNonLocalElement(index,
+                                       vector->getMap()->getNodeNumElements(),
+                                       vector->getMap()->getMinLocalIndex(),
+                                       vector->getMap()->getMaxLocalIndex()));
+#  endif
+        }
+      else
+        value = vector->getData()[local_index];
+
+      return value;
+    }
+
+
+
     template <typename Number>
     void
     Vector<Number>::add(const Number a)
@@ -643,8 +766,43 @@ namespace LinearAlgebra
 
     template <typename Number>
     void
-    Vector<Number>::compress(const VectorOperation::values /*operation*/)
-    {}
+    Vector<Number>::compress(const VectorOperation::values operation)
+    {
+      Assert(has_ghost == false,
+             ExcMessage("Calling compress() is only useful if a vector "
+                        "has been written into, but this is a vector with ghost "
+                        "elements and consequently is read-only. It does "
+                        "not make sense to call compress() for such "
+                        "vectors."));
+
+      if (!vector->getMap()->isOneToOne())
+        {
+          Tpetra::CombineMode tpetra_operation = Tpetra::ZERO;
+          if (operation == VectorOperation::insert)
+            tpetra_operation = Tpetra::INSERT;
+          else if (operation == VectorOperation::add)
+            tpetra_operation = Tpetra::ADD;
+          else
+            Assert(false, ExcNotImplemented());
+
+          if (locally_relevant_map.is_null())
+            locally_relevant_map =
+              Teuchos::rcp_const_cast<MapType>(vector->getMap());
+
+          Assert(!locally_relevant_map.is_null(), ExcMissingIndexSet());
+          Assert(!locally_owned_map.is_null(), ExcMissingIndexSet());
+
+          VectorType dummy = VectorType(locally_owned_map.getConst());
+
+          Teuchos::RCP<const ExportType> exporter =
+            Tpetra::createExport(locally_relevant_map.getConst(),
+                                 locally_owned_map.getConst());
+          dummy.doExport(*vector, *exporter, tpetra_operation);
+
+          *vector = dummy;
+        }
+    }
+
 
 
     template <typename Number>
@@ -714,13 +872,27 @@ namespace LinearAlgebra
       auto         vector_1d    = Kokkos::subview(vector_2d, Kokkos::ALL(), 0);
       const size_t local_length = vector->getLocalLength();
 
-      if (across)
-        for (unsigned int i = 0; i < local_length; ++i)
-          out << vector_1d(i) << ' ';
+      if (size() != local_length)
+        {
+          out << "size:" << size() << " locally_owned_size:" << local_length
+              << " :" << std::endl;
+          for (size_type i = 0; i < local_length; ++i)
+            {
+              const TrilinosWrappers::types::int_type global_row =
+                vector->getMap()->getGlobalElement(i);
+              out << "[" << global_row << "]: " << vector_1d(i) << std::endl;
+            }
+        }
       else
-        for (unsigned int i = 0; i < local_length; ++i)
-          out << vector_1d(i) << std::endl;
-      out << std::endl;
+        {
+          if (across)
+            for (unsigned int i = 0; i < local_length; ++i)
+              out << vector_1d(i) << ' ';
+          else
+            for (unsigned int i = 0; i < local_length; ++i)
+              out << vector_1d(i) << std::endl;
+          out << std::endl;
+        }
 
       // restore the representation
       // of the vector
@@ -754,10 +926,10 @@ namespace LinearAlgebra
                                                const MPI_Comm  mpi_comm)
     {
       source_stored_elements = source_index_set;
-      tpetra_comm_pattern    = Utilities::Trilinos::internal::make_rcp<
-        TpetraWrappers::CommunicationPattern>(locally_owned_elements(),
-                                              source_index_set,
-                                              mpi_comm);
+
+      tpetra_comm_pattern =
+        Teuchos::rcp(new TpetraWrappers::CommunicationPattern(
+          locally_owned_elements(), source_index_set, mpi_comm));
     }
   } // namespace TpetraWrappers
 } // namespace LinearAlgebra
index 32ce2c2212331ed044531f1c42b8f5263ddba314..a811f445577ad6178c1c3efbaa3822f34be94fc9 100644 (file)
@@ -829,6 +829,21 @@ namespace internal
       }
 #endif
 
+#ifdef DEAL_II_TRILINOS_WITH_TPETRA
+      template <typename Number>
+      void
+      copy_locally_owned_data_from(
+        const LinearAlgebra::TpetraWrappers::Vector<Number> &src,
+        LinearAlgebra::distributed::Vector<Number>          &dst)
+      {
+        // ReadWriteVector does not work for ghosted
+        // TrilinosWrappers::MPI::Vector objects. Fall back to copy the
+        // entries manually.
+        for (const auto i : dst.locally_owned_elements())
+          dst[i] = src[i];
+      }
+#endif
+
       /**
        * Create a ghosted-copy of a block dof vector.
        */
index 638319c2f1c301605717ad32147185097adec87b..ba921e5ad647cfbdd6251b3645b64800957cb760 100644 (file)
@@ -1,13 +1,17 @@
 
 DEAL:0::Tpetra first import add:
-2.000e+00 1.000e+02 
+size:4 locally_owned_size:2 :
+[0]: 2.000e+00
+[1]: 1.000e+02
 IndexSet: {[0,2]}
 
 [0]: 1.000e+00
 [1]: 1.000e+02
 [2]: 1.000e+01
 DEAL:0::Tpetra second import add:
-4.000e+00 2.000e+02 
+size:4 locally_owned_size:2 :
+[0]: 4.000e+00
+[1]: 2.000e+02
 IndexSet: {[0,2]}
 
 [0]: 2.000e+00
@@ -33,13 +37,17 @@ IndexSet: {[0,2]}
 [2]: 1.000e+02
 
 DEAL:1::Tpetra first import add:
-1.000e+01 1.010e+02 
+size:4 locally_owned_size:2 :
+[2]: 1.000e+01
+[3]: 1.010e+02
 IndexSet: {0, 3}
 
 [0]: 1.000e+00
 [3]: 1.010e+02
 DEAL:1::Tpetra second import add:
-3.000e+01 2.010e+02 
+size:4 locally_owned_size:2 :
+[2]: 3.000e+01
+[3]: 2.010e+02
 IndexSet: {0, 3}
 
 [0]: 2.000e+00
index f70ed13b09e8db14f4cc3f6faf8202de0a5e7d09..f643d65be17ede90c63d0a149ee106de0aa0392a 100644 (file)
@@ -1,13 +1,17 @@
 
 DEAL:0::Tpetra first import add:
-4.000e+00 1.000e+02 
+size:8 locally_owned_size:2 :
+[0]: 4.000e+00
+[1]: 1.000e+02
 IndexSet: {[0,2]}
 
 [0]: 1.000e+00
 [1]: 1.000e+02
 [2]: 1.000e+01
 DEAL:0::Tpetra second import add:
-8.000e+00 2.000e+02 
+size:8 locally_owned_size:2 :
+[0]: 8.000e+00
+[1]: 2.000e+02
 IndexSet: {[0,2]}
 
 [0]: 2.000e+00
@@ -33,14 +37,18 @@ IndexSet: {[0,2]}
 [2]: 1.000e+02
 
 DEAL:1::Tpetra first import add:
-1.000e+01 1.010e+02 
+size:8 locally_owned_size:2 :
+[2]: 1.000e+01
+[3]: 1.010e+02
 IndexSet: {0, [3,4]}
 
 [0]: 1.000e+00
 [3]: 1.010e+02
 [4]: 1.100e+01
 DEAL:1::Tpetra second import add:
-3.000e+01 2.010e+02 
+size:8 locally_owned_size:2 :
+[2]: 3.000e+01
+[3]: 2.010e+02
 IndexSet: {0, [3,4]}
 
 [0]: 2.000e+00
@@ -67,14 +75,18 @@ IndexSet: {0, [3,4]}
 
 
 DEAL:2::Tpetra first import add:
-1.100e+01 1.020e+02 
+size:8 locally_owned_size:2 :
+[4]: 1.100e+01
+[5]: 1.020e+02
 IndexSet: {0, [5,6]}
 
 [0]: 1.000e+00
 [5]: 1.020e+02
 [6]: 1.200e+01
 DEAL:2::Tpetra second import add:
-3.200e+01 2.020e+02 
+size:8 locally_owned_size:2 :
+[4]: 3.200e+01
+[5]: 2.020e+02
 IndexSet: {0, [5,6]}
 
 [0]: 2.000e+00
@@ -101,13 +113,17 @@ IndexSet: {0, [5,6]}
 
 
 DEAL:3::Tpetra first import add:
-1.200e+01 1.030e+02 
+size:8 locally_owned_size:2 :
+[6]: 1.200e+01
+[7]: 1.030e+02
 IndexSet: {0, 7}
 
 [0]: 1.000e+00
 [7]: 1.030e+02
 DEAL:3::Tpetra second import add:
-3.400e+01 2.030e+02 
+size:8 locally_owned_size:2 :
+[6]: 3.400e+01
+[7]: 2.030e+02
 IndexSet: {0, 7}
 
 [0]: 2.000e+00
index 638319c2f1c301605717ad32147185097adec87b..ba921e5ad647cfbdd6251b3645b64800957cb760 100644 (file)
@@ -1,13 +1,17 @@
 
 DEAL:0::Tpetra first import add:
-2.000e+00 1.000e+02 
+size:4 locally_owned_size:2 :
+[0]: 2.000e+00
+[1]: 1.000e+02
 IndexSet: {[0,2]}
 
 [0]: 1.000e+00
 [1]: 1.000e+02
 [2]: 1.000e+01
 DEAL:0::Tpetra second import add:
-4.000e+00 2.000e+02 
+size:4 locally_owned_size:2 :
+[0]: 4.000e+00
+[1]: 2.000e+02
 IndexSet: {[0,2]}
 
 [0]: 2.000e+00
@@ -33,13 +37,17 @@ IndexSet: {[0,2]}
 [2]: 1.000e+02
 
 DEAL:1::Tpetra first import add:
-1.000e+01 1.010e+02 
+size:4 locally_owned_size:2 :
+[2]: 1.000e+01
+[3]: 1.010e+02
 IndexSet: {0, 3}
 
 [0]: 1.000e+00
 [3]: 1.010e+02
 DEAL:1::Tpetra second import add:
-3.000e+01 2.010e+02 
+size:4 locally_owned_size:2 :
+[2]: 3.000e+01
+[3]: 2.010e+02
 IndexSet: {0, 3}
 
 [0]: 2.000e+00
index f70ed13b09e8db14f4cc3f6faf8202de0a5e7d09..f643d65be17ede90c63d0a149ee106de0aa0392a 100644 (file)
@@ -1,13 +1,17 @@
 
 DEAL:0::Tpetra first import add:
-4.000e+00 1.000e+02 
+size:8 locally_owned_size:2 :
+[0]: 4.000e+00
+[1]: 1.000e+02
 IndexSet: {[0,2]}
 
 [0]: 1.000e+00
 [1]: 1.000e+02
 [2]: 1.000e+01
 DEAL:0::Tpetra second import add:
-8.000e+00 2.000e+02 
+size:8 locally_owned_size:2 :
+[0]: 8.000e+00
+[1]: 2.000e+02
 IndexSet: {[0,2]}
 
 [0]: 2.000e+00
@@ -33,14 +37,18 @@ IndexSet: {[0,2]}
 [2]: 1.000e+02
 
 DEAL:1::Tpetra first import add:
-1.000e+01 1.010e+02 
+size:8 locally_owned_size:2 :
+[2]: 1.000e+01
+[3]: 1.010e+02
 IndexSet: {0, [3,4]}
 
 [0]: 1.000e+00
 [3]: 1.010e+02
 [4]: 1.100e+01
 DEAL:1::Tpetra second import add:
-3.000e+01 2.010e+02 
+size:8 locally_owned_size:2 :
+[2]: 3.000e+01
+[3]: 2.010e+02
 IndexSet: {0, [3,4]}
 
 [0]: 2.000e+00
@@ -67,14 +75,18 @@ IndexSet: {0, [3,4]}
 
 
 DEAL:2::Tpetra first import add:
-1.100e+01 1.020e+02 
+size:8 locally_owned_size:2 :
+[4]: 1.100e+01
+[5]: 1.020e+02
 IndexSet: {0, [5,6]}
 
 [0]: 1.000e+00
 [5]: 1.020e+02
 [6]: 1.200e+01
 DEAL:2::Tpetra second import add:
-3.200e+01 2.020e+02 
+size:8 locally_owned_size:2 :
+[4]: 3.200e+01
+[5]: 2.020e+02
 IndexSet: {0, [5,6]}
 
 [0]: 2.000e+00
@@ -101,13 +113,17 @@ IndexSet: {0, [5,6]}
 
 
 DEAL:3::Tpetra first import add:
-1.200e+01 1.030e+02 
+size:8 locally_owned_size:2 :
+[6]: 1.200e+01
+[7]: 1.030e+02
 IndexSet: {0, 7}
 
 [0]: 1.000e+00
 [7]: 1.030e+02
 DEAL:3::Tpetra second import add:
-3.400e+01 2.030e+02 
+size:8 locally_owned_size:2 :
+[6]: 3.400e+01
+[7]: 2.030e+02
 IndexSet: {0, 7}
 
 [0]: 2.000e+00

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.