]> https://gitweb.dealii.org/ - dealii.git/commitdiff
add BlockVector::multivector_inner_product_with_metric() 5884/head
authorDenis Davydov <davydden@gmail.com>
Sat, 10 Feb 2018 06:50:53 +0000 (07:50 +0100)
committerDenis Davydov <davydden@gmail.com>
Sun, 11 Feb 2018 17:04:29 +0000 (18:04 +0100)
and BlockVector::mmult(const BlockVector &, const FullMatrixType &)

18 files changed:
doc/news/changes/minor/20180210DenisDavydov [new file with mode: 0644]
include/deal.II/lac/la_parallel_block_vector.h
include/deal.II/lac/la_parallel_block_vector.templates.h
source/lac/la_parallel_block_vector.inst.in
tests/mpi/parallel_block_vector_07.cc [new file with mode: 0644]
tests/mpi/parallel_block_vector_07.with_p4est=true.mpirun=1.output [new file with mode: 0644]
tests/mpi/parallel_block_vector_07.with_p4est=true.mpirun=4.output [new file with mode: 0644]
tests/mpi/parallel_block_vector_08.cc [new file with mode: 0644]
tests/mpi/parallel_block_vector_08.with_p4est=true.mpirun=1.output [new file with mode: 0644]
tests/mpi/parallel_block_vector_08.with_p4est=true.mpirun=4.output [new file with mode: 0644]
tests/mpi/parallel_block_vector_09.cc [new file with mode: 0644]
tests/mpi/parallel_block_vector_09.with_p4est=true.mpirun=1.output [new file with mode: 0644]
tests/mpi/parallel_block_vector_09.with_p4est=true.mpirun=5.output [new file with mode: 0644]
tests/mpi/parallel_block_vector_10.cc [new file with mode: 0644]
tests/mpi/parallel_block_vector_10.with_p4est=true.mpirun=1.output [new file with mode: 0644]
tests/mpi/parallel_block_vector_10.with_p4est=true.mpirun=4.output [new file with mode: 0644]
tests/mpi/parallel_block_vector_11.cc [new file with mode: 0644]
tests/mpi/parallel_block_vector_11.with_p4est=true.mpirun=4.output [new file with mode: 0644]

diff --git a/doc/news/changes/minor/20180210DenisDavydov b/doc/news/changes/minor/20180210DenisDavydov
new file mode 100644 (file)
index 0000000..ddda926
--- /dev/null
@@ -0,0 +1,5 @@
+New: add parallel::distributed::BlockVector::mmult(const BlockVector &, const FullMatrixType &)
+and parallel::distributed::BlockVector::multivector_inner_product_with_metric(const FullMatrixType &, const BlockVector &V, const bool) const
+to operate on multivectors with a metric tensor.
+<br>
+(Denis Davydov, 2018/02/10)
index 81545c8bea872c1ba9f9668ea390002c8e075d58..31d644831ac8466091e82eca1fcf613c08cec9a2 100644 (file)
@@ -469,6 +469,39 @@ namespace LinearAlgebra
                                      const BlockVector<Number> &V,
                                      const bool symmetric = false) const;
 
+      /**
+       * Calculate the scalar product between each block of this vector and @p V
+       * using a metric tensor @p matrix. This function
+       * computes the result of $ \sum_{ij} A^{ij} U_i \cdot V_j$ where $U_i$
+       * and $V_j$ indicate the $i$th block (not element) of $U$ and the
+       * $j$th block of $V$, respectively. If @p symmetric is
+       * <code>true</code>, it is assumed that $U_i \cdot V_j$ and $A^{ij}$ are
+       * symmetric matrices and almost half of the scalar products can be avoided.
+       *
+       * Obviously, this function can only be used if all blocks of both vectors
+       * are of the same size.
+       *
+       * @note Internally, a single global reduction will be called to
+       * accumulate the scalar product between locally owned degrees of freedom.
+       */
+      template <typename FullMatrixType>
+      Number multivector_inner_product_with_metric(const FullMatrixType &matrix,
+                                                   const BlockVector<Number> &V,
+                                                   const bool symmetric = false) const;
+
+      /**
+       * Set each block of this vector as follows:
+       * $U^i = \sum_{j} V_j A^{ji}$ where $U^i$
+       * and $V_j$ indicate the $i$th block (not element) of $U$ and the
+       * $j$th block of $V$, respectively.
+       *
+       * Obviously, this function can only be used if all blocks of both vectors
+       * are of the same size.
+       */
+      template <typename FullMatrixType>
+      void mmult(const BlockVector<Number> &V,
+                 const FullMatrixType &matrix);
+
       /**
        * Add @p a to all components. Note that @p a is a scalar not a vector.
        */
index ed35e14ce9c8e46e46381913a398a7ca2dcb3ebb..0090e56c5c840a17b5f98635e3e4af96fc644ece 100644 (file)
@@ -866,6 +866,85 @@ namespace LinearAlgebra
       Utilities::MPI::sum(matrix, this->block(0).get_mpi_communicator(), matrix);
     }
 
+
+
+    template <typename Number>
+    template <typename FullMatrixType>
+    Number
+    BlockVector<Number>::multivector_inner_product_with_metric(const FullMatrixType &matrix,
+                                                               const BlockVector<Number> &V,
+                                                               const bool symmetric) const
+    {
+      Number res = Number(0.);
+
+      const unsigned int m = this->n_blocks();
+      const unsigned int n = V.n_blocks();
+
+      // in case one vector is empty and the second one is not, the
+      // FullMatrix resized to (m,n) will have 0 both in m() and n()
+      // which is how TableBase<N,T>::reinit() works.
+      // Since in this case there is nothing to do anyway -- return immediately.
+      if (n==0 || m==0)
+        return res;
+
+      Assert (matrix.m() == m,
+              dealii::ExcDimensionMismatch(matrix.m(),m));
+      Assert (matrix.n() == n,
+              dealii::ExcDimensionMismatch(matrix.n(),n));
+
+      if (symmetric)
+        {
+          Assert (m == n,
+                  dealii::ExcDimensionMismatch(m,n));
+
+          for (unsigned int i = 0; i < m; i++)
+            {
+              res += matrix(i,i) * this->block(i).inner_product_local(V.block(i));
+              for (unsigned int j = i+1; j < n; j++)
+                res += 2. * matrix(i,j) * this->block(i).inner_product_local(V.block(j));
+            }
+        }
+      else
+        {
+          for (unsigned int i = 0; i < m; i++)
+            for (unsigned int j = 0; j < n; j++)
+              res += matrix(i,j) * this->block(i).inner_product_local(V.block(j));
+        }
+
+      return Utilities::MPI::sum(res, this->block(0).get_mpi_communicator());
+    }
+
+
+
+    template <typename Number>
+    template <typename FullMatrixType>
+    void
+    BlockVector<Number>::mmult(const BlockVector<Number> &V,
+                               const FullMatrixType &matrix)
+    {
+      const unsigned int n = this->n_blocks();
+      const unsigned int m = V.n_blocks();
+
+      // in case one vector is empty and the second one is not, the
+      // FullMatrix resized to (m,n) will have 0 both in m() and n()
+      // which is how TableBase<N,T>::reinit() works.
+      // Since in this case there is nothing to do anyway -- return immediately.
+      if (n==0 || m==0)
+        return;
+
+      Assert (matrix.m() == m,
+              dealii::ExcDimensionMismatch(matrix.m(),m));
+      Assert (matrix.n() == n,
+              dealii::ExcDimensionMismatch(matrix.n(),n));
+
+      (*this) = Number();
+      for (unsigned int i = 0; i < n; i++)
+        for (unsigned int j = 0; j < m; j++)
+          this->block(i).add (matrix(j,i), V.block(j));
+    }
+
+
+
   } // end of namespace distributed
 
 } // end of namespace parallel
index 92ce202797a6a9bf695f285fffc1124b4c2fdd0a..657e150417dcdf42058892aef91a1915d0fa5041 100644 (file)
@@ -28,6 +28,18 @@ for (SCALAR : REAL_AND_COMPLEX_SCALARS)
     template
     void
     BlockVector<SCALAR>::multivector_inner_product(LAPACKFullMatrix<SCALAR> &, const BlockVector<SCALAR> &V, const bool) const;
+    template
+    SCALAR
+    BlockVector<SCALAR>::multivector_inner_product_with_metric(const FullMatrix<SCALAR> &, const BlockVector<SCALAR> &V, const bool) const;
+    template
+    SCALAR
+    BlockVector<SCALAR>::multivector_inner_product_with_metric(const LAPACKFullMatrix<SCALAR> &, const BlockVector<SCALAR> &V, const bool) const;
+    template
+    void
+    BlockVector<SCALAR>::mmult(const BlockVector<SCALAR> &V,const FullMatrix<SCALAR> &);
+    template
+    void
+    BlockVector<SCALAR>::mmult(const BlockVector<SCALAR> &V,const LAPACKFullMatrix<SCALAR> &);
     \}
     \}
 }
diff --git a/tests/mpi/parallel_block_vector_07.cc b/tests/mpi/parallel_block_vector_07.cc
new file mode 100644 (file)
index 0000000..7e7d67f
--- /dev/null
@@ -0,0 +1,160 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 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 at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+
+// this BlockVector<Number>::multivector_inner_product_with_metric().
+// Triangulation and Mass operator are the same as in matrix_free/mass_operator_01.cc
+
+#include "../tests.h"
+
+#include <deal.II/base/utilities.h>
+#include <deal.II/base/function.h>
+#include <deal.II/distributed/tria.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/manifold_lib.h>
+#include <deal.II/dofs/dof_tools.h>
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/lac/constraint_matrix.h>
+#include <deal.II/matrix_free/operators.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/lac/la_parallel_block_vector.h>
+
+#include <iostream>
+
+
+
+
+template <int dim, int fe_degree>
+void test (const unsigned int n_blocks = 5)
+{
+  typedef double number;
+
+  parallel::distributed::Triangulation<dim> tria (MPI_COMM_WORLD);
+  GridGenerator::hyper_cube (tria);
+  tria.refine_global(1);
+  typename Triangulation<dim>::active_cell_iterator
+  cell = tria.begin_active (),
+  endc = tria.end();
+  cell = tria.begin_active ();
+  for (; cell!=endc; ++cell)
+    if (cell->is_locally_owned())
+      if (cell->center().norm()<0.2)
+        cell->set_refine_flag();
+  tria.execute_coarsening_and_refinement();
+  if (dim < 3 && fe_degree < 2)
+    tria.refine_global(2);
+  else
+    tria.refine_global(1);
+  if (tria.begin(tria.n_levels()-1)->is_locally_owned())
+    tria.begin(tria.n_levels()-1)->set_refine_flag();
+  if (tria.last()->is_locally_owned())
+    tria.last()->set_refine_flag();
+  tria.execute_coarsening_and_refinement();
+  cell = tria.begin_active ();
+  for (unsigned int i=0; i<10-3*dim; ++i)
+    {
+      cell = tria.begin_active ();
+      unsigned int counter = 0;
+      for (; cell!=endc; ++cell, ++counter)
+        if (cell->is_locally_owned())
+          if (counter % (7-i) == 0)
+            cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+    }
+
+  FE_Q<dim> fe (fe_degree);
+  DoFHandler<dim> dof (tria);
+  dof.distribute_dofs(fe);
+
+  IndexSet owned_set = dof.locally_owned_dofs();
+  IndexSet relevant_set;
+  DoFTools::extract_locally_relevant_dofs (dof, relevant_set);
+
+  ConstraintMatrix constraints (relevant_set);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values (dof, 0, Functions::ZeroFunction<dim>(),
+                                            constraints);
+  constraints.close();
+
+  std::shared_ptr<MatrixFree<dim,number> > mf_data(new MatrixFree<dim,number> ());
+  {
+    const QGauss<1> quad (fe_degree+2);
+    typename MatrixFree<dim,number>::AdditionalData data;
+    data.tasks_parallel_scheme =
+      MatrixFree<dim,number>::AdditionalData::none;
+    data.tasks_block_size = 7;
+    mf_data->reinit (dof, constraints, quad, data);
+  }
+
+  MatrixFreeOperators::MassOperator<dim,fe_degree, fe_degree+2, 1, LinearAlgebra::distributed::Vector<number> > mf;
+  mf.initialize(mf_data);
+  mf.compute_diagonal();
+
+  LinearAlgebra::distributed::BlockVector<number> left(n_blocks), right(n_blocks);
+  for (unsigned int b = 0; b < n_blocks; ++b)
+    {
+      mf_data->initialize_dof_vector (left.block(b));
+      mf_data->initialize_dof_vector (right.block(b));
+      left.block(b) = 0.;
+      right.block(b) = 0.;
+      for (unsigned int i=0; i<right.block(b).local_size(); ++i)
+        {
+          const unsigned int glob_index =
+            owned_set.nth_index_in_set (i);
+          if (constraints.is_constrained(glob_index))
+            continue;
+          right.block(b).local_element(i) = random_value<double>();
+          left.block(b).local_element(i) = random_value<double>();
+        }
+    }
+
+  FullMatrix<number> metric(n_blocks,n_blocks);
+  for (unsigned int i = 0; i < n_blocks; ++i)
+    for (unsigned int j = 0; j < n_blocks; ++j)
+      metric(i,j) = 1. + (i*3 + j*7);
+
+  const double res = left.multivector_inner_product_with_metric(metric, right);
+
+  double res2 = 0.;
+  for (unsigned int i = 0; i < n_blocks; ++i)
+    for (unsigned int j = 0; j < n_blocks; ++j)
+      res2 += metric(i,j) * (left.block(i) * right.block(j));
+
+  const double diff_norm = std::abs(res-res2);
+  deallog << "Norm of difference: " << diff_norm << std::endl;
+}
+
+
+int main (int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, testing_max_num_threads());
+
+  unsigned int myid = Utilities::MPI::this_mpi_process (MPI_COMM_WORLD);
+  deallog.push(Utilities::int_to_string(myid));
+
+  if (myid == 0)
+    {
+      initlog();
+      deallog << std::setprecision(4);
+
+      test<2,1>();
+    }
+  else
+    {
+      test<2,1>();
+    }
+}
diff --git a/tests/mpi/parallel_block_vector_07.with_p4est=true.mpirun=1.output b/tests/mpi/parallel_block_vector_07.with_p4est=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..b3f4ed9
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL:0::Norm of difference: 0.000
diff --git a/tests/mpi/parallel_block_vector_07.with_p4est=true.mpirun=4.output b/tests/mpi/parallel_block_vector_07.with_p4est=true.mpirun=4.output
new file mode 100644 (file)
index 0000000..b3f4ed9
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL:0::Norm of difference: 0.000
diff --git a/tests/mpi/parallel_block_vector_08.cc b/tests/mpi/parallel_block_vector_08.cc
new file mode 100644 (file)
index 0000000..bccb635
--- /dev/null
@@ -0,0 +1,163 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 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 at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+
+// this BlockVector<Number>::mmult(const BlockVector<Number> &V,const FullMatrixType &matrix).
+// Triangulation and Mass operator are the same as in matrix_free/mass_operator_01.cc
+
+#include "../tests.h"
+
+#include <deal.II/base/utilities.h>
+#include <deal.II/base/function.h>
+#include <deal.II/distributed/tria.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/manifold_lib.h>
+#include <deal.II/dofs/dof_tools.h>
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/lac/constraint_matrix.h>
+#include <deal.II/matrix_free/operators.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/lac/la_parallel_block_vector.h>
+
+#include <iostream>
+
+
+
+
+template <int dim, int fe_degree>
+void test (const unsigned int n_blocks = 5)
+{
+  typedef double number;
+
+  parallel::distributed::Triangulation<dim> tria (MPI_COMM_WORLD);
+  GridGenerator::hyper_cube (tria);
+  tria.refine_global(1);
+  typename Triangulation<dim>::active_cell_iterator
+  cell = tria.begin_active (),
+  endc = tria.end();
+  cell = tria.begin_active ();
+  for (; cell!=endc; ++cell)
+    if (cell->is_locally_owned())
+      if (cell->center().norm()<0.2)
+        cell->set_refine_flag();
+  tria.execute_coarsening_and_refinement();
+  if (dim < 3 && fe_degree < 2)
+    tria.refine_global(2);
+  else
+    tria.refine_global(1);
+  if (tria.begin(tria.n_levels()-1)->is_locally_owned())
+    tria.begin(tria.n_levels()-1)->set_refine_flag();
+  if (tria.last()->is_locally_owned())
+    tria.last()->set_refine_flag();
+  tria.execute_coarsening_and_refinement();
+  cell = tria.begin_active ();
+  for (unsigned int i=0; i<10-3*dim; ++i)
+    {
+      cell = tria.begin_active ();
+      unsigned int counter = 0;
+      for (; cell!=endc; ++cell, ++counter)
+        if (cell->is_locally_owned())
+          if (counter % (7-i) == 0)
+            cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+    }
+
+  FE_Q<dim> fe (fe_degree);
+  DoFHandler<dim> dof (tria);
+  dof.distribute_dofs(fe);
+
+  IndexSet owned_set = dof.locally_owned_dofs();
+  IndexSet relevant_set;
+  DoFTools::extract_locally_relevant_dofs (dof, relevant_set);
+
+  ConstraintMatrix constraints (relevant_set);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values (dof, 0, Functions::ZeroFunction<dim>(),
+                                            constraints);
+  constraints.close();
+
+  std::shared_ptr<MatrixFree<dim,number> > mf_data(new MatrixFree<dim,number> ());
+  {
+    const QGauss<1> quad (fe_degree+2);
+    typename MatrixFree<dim,number>::AdditionalData data;
+    data.tasks_parallel_scheme =
+      MatrixFree<dim,number>::AdditionalData::none;
+    data.tasks_block_size = 7;
+    mf_data->reinit (dof, constraints, quad, data);
+  }
+
+  MatrixFreeOperators::MassOperator<dim,fe_degree, fe_degree+2, 1, LinearAlgebra::distributed::Vector<number> > mf;
+  mf.initialize(mf_data);
+  mf.compute_diagonal();
+
+  LinearAlgebra::distributed::BlockVector<number> left(n_blocks), right(n_blocks), left2(n_blocks);
+  for (unsigned int b = 0; b < n_blocks; ++b)
+    {
+      mf_data->initialize_dof_vector (left.block(b));
+      mf_data->initialize_dof_vector (left2.block(b));
+      mf_data->initialize_dof_vector (right.block(b));
+      left.block(b) = 0.;
+      left2.block(b) = 0.;
+      right.block(b) = 0.;
+      for (unsigned int i=0; i<right.block(b).local_size(); ++i)
+        {
+          const unsigned int glob_index =
+            owned_set.nth_index_in_set (i);
+          if (constraints.is_constrained(glob_index))
+            continue;
+          right.block(b).local_element(i) = random_value<double>();
+          left.block(b).local_element(i) = random_value<double>();
+        }
+    }
+
+  FullMatrix<number> metric(n_blocks,n_blocks);
+  for (unsigned int i = 0; i < n_blocks; ++i)
+    for (unsigned int j = 0; j < n_blocks; ++j)
+      metric(i,j) = 0.3 + (i*3 + j*7);
+
+  left.mmult(right,metric);
+
+  for (unsigned int i = 0; i < n_blocks; ++i)
+    for (unsigned int j = 0; j < n_blocks; ++j)
+      left2.block(i).add(metric(j,i), right.block(j));
+
+  left2.add(-1., left);
+
+  const double diff_norm = left2.linfty_norm();
+  deallog << "Norm of difference: " << diff_norm << std::endl;
+}
+
+
+int main (int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, testing_max_num_threads());
+
+  unsigned int myid = Utilities::MPI::this_mpi_process (MPI_COMM_WORLD);
+  deallog.push(Utilities::int_to_string(myid));
+
+  if (myid == 0)
+    {
+      initlog();
+      deallog << std::setprecision(4);
+
+      test<2,1>();
+    }
+  else
+    {
+      test<2,1>();
+    }
+}
diff --git a/tests/mpi/parallel_block_vector_08.with_p4est=true.mpirun=1.output b/tests/mpi/parallel_block_vector_08.with_p4est=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..b3f4ed9
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL:0::Norm of difference: 0.000
diff --git a/tests/mpi/parallel_block_vector_08.with_p4est=true.mpirun=4.output b/tests/mpi/parallel_block_vector_08.with_p4est=true.mpirun=4.output
new file mode 100644 (file)
index 0000000..b3f4ed9
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL:0::Norm of difference: 0.000
diff --git a/tests/mpi/parallel_block_vector_09.cc b/tests/mpi/parallel_block_vector_09.cc
new file mode 100644 (file)
index 0000000..a66bc37
--- /dev/null
@@ -0,0 +1,168 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 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 at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+
+// use BlockVector<Number>::mmult(const BlockVector<Number> &V, const FullMatrixType &matrix)
+// and multivector_inner_product_with_metric() to test that
+// [ S^{ij}u_i ] * u_j == S^{ij} [u_i * u_j]
+// In order to avoid taking S^T, just use symmetric matrix as a metric, which is
+// actually the way it should be anyway.
+// Triangulation and Mass operator are the same as in matrix_free/mass_operator_01.cc
+
+#include "../tests.h"
+
+#include <deal.II/base/utilities.h>
+#include <deal.II/base/function.h>
+#include <deal.II/distributed/tria.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/manifold_lib.h>
+#include <deal.II/dofs/dof_tools.h>
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/lac/constraint_matrix.h>
+#include <deal.II/matrix_free/operators.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/lac/la_parallel_block_vector.h>
+
+#include <iostream>
+
+
+
+
+template <int dim, int fe_degree>
+void test (const unsigned int n_blocks = 5)
+{
+  typedef double number;
+
+  parallel::distributed::Triangulation<dim> tria (MPI_COMM_WORLD);
+  GridGenerator::hyper_cube (tria);
+  tria.refine_global(1);
+  typename Triangulation<dim>::active_cell_iterator
+  cell = tria.begin_active (),
+  endc = tria.end();
+  cell = tria.begin_active ();
+  for (; cell!=endc; ++cell)
+    if (cell->is_locally_owned())
+      if (cell->center().norm()<0.2)
+        cell->set_refine_flag();
+  tria.execute_coarsening_and_refinement();
+  if (dim < 3 && fe_degree < 2)
+    tria.refine_global(2);
+  else
+    tria.refine_global(1);
+  if (tria.begin(tria.n_levels()-1)->is_locally_owned())
+    tria.begin(tria.n_levels()-1)->set_refine_flag();
+  if (tria.last()->is_locally_owned())
+    tria.last()->set_refine_flag();
+  tria.execute_coarsening_and_refinement();
+  cell = tria.begin_active ();
+  for (unsigned int i=0; i<10-3*dim; ++i)
+    {
+      cell = tria.begin_active ();
+      unsigned int counter = 0;
+      for (; cell!=endc; ++cell, ++counter)
+        if (cell->is_locally_owned())
+          if (counter % (7-i) == 0)
+            cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+    }
+
+  FE_Q<dim> fe (fe_degree);
+  DoFHandler<dim> dof (tria);
+  dof.distribute_dofs(fe);
+
+  IndexSet owned_set = dof.locally_owned_dofs();
+  IndexSet relevant_set;
+  DoFTools::extract_locally_relevant_dofs (dof, relevant_set);
+
+  ConstraintMatrix constraints (relevant_set);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values (dof, 0, Functions::ZeroFunction<dim>(),
+                                            constraints);
+  constraints.close();
+
+  std::shared_ptr<MatrixFree<dim,number> > mf_data(new MatrixFree<dim,number> ());
+  {
+    const QGauss<1> quad (fe_degree+2);
+    typename MatrixFree<dim,number>::AdditionalData data;
+    data.tasks_parallel_scheme =
+      MatrixFree<dim,number>::AdditionalData::none;
+    data.tasks_block_size = 7;
+    mf_data->reinit (dof, constraints, quad, data);
+  }
+
+  MatrixFreeOperators::MassOperator<dim,fe_degree, fe_degree+2, 1, LinearAlgebra::distributed::Vector<number> > mf;
+  mf.initialize(mf_data);
+  mf.compute_diagonal();
+
+  LinearAlgebra::distributed::BlockVector<number> left(n_blocks), right(n_blocks), left2(n_blocks);
+  for (unsigned int b = 0; b < n_blocks; ++b)
+    {
+      mf_data->initialize_dof_vector (left.block(b));
+      mf_data->initialize_dof_vector (left2.block(b));
+      mf_data->initialize_dof_vector (right.block(b));
+      left.block(b) = 0.;
+      left2.block(b) = 0.;
+      right.block(b) = 0.;
+      for (unsigned int i=0; i<right.block(b).local_size(); ++i)
+        {
+          const unsigned int glob_index =
+            owned_set.nth_index_in_set (i);
+          if (constraints.is_constrained(glob_index))
+            continue;
+          right.block(b).local_element(i) = random_value<double>();
+          left.block(b).local_element(i) = random_value<double>();
+        }
+    }
+
+  FullMatrix<number> metric(n_blocks,n_blocks);
+  metric = 0.;
+  for (unsigned int i = 0; i < n_blocks; ++i)
+    for (unsigned int j = i; j < n_blocks; ++j)
+      {
+        const double val = 0.3 + (3.3*i + 7.7*j);
+        metric(i,j) = val;
+        metric(j,i) = val;
+      }
+
+  const double res = left.multivector_inner_product_with_metric(metric, right);
+  left2.mmult(left, metric);
+  const double res2 = left2 * right;
+
+  const double diff_norm = std::abs(res - res2);
+  deallog << "Norm of difference: " << diff_norm << std::endl;
+}
+
+
+int main (int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, testing_max_num_threads());
+
+  unsigned int myid = Utilities::MPI::this_mpi_process (MPI_COMM_WORLD);
+  deallog.push(Utilities::int_to_string(myid));
+
+  if (myid == 0)
+    {
+      initlog();
+      deallog << std::setprecision(4);
+
+      test<2,1>();
+    }
+  else
+    {
+      test<2,1>();
+    }
+}
diff --git a/tests/mpi/parallel_block_vector_09.with_p4est=true.mpirun=1.output b/tests/mpi/parallel_block_vector_09.with_p4est=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..b3f4ed9
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL:0::Norm of difference: 0.000
diff --git a/tests/mpi/parallel_block_vector_09.with_p4est=true.mpirun=5.output b/tests/mpi/parallel_block_vector_09.with_p4est=true.mpirun=5.output
new file mode 100644 (file)
index 0000000..b3f4ed9
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL:0::Norm of difference: 0.000
diff --git a/tests/mpi/parallel_block_vector_10.cc b/tests/mpi/parallel_block_vector_10.cc
new file mode 100644 (file)
index 0000000..6a6e2bd
--- /dev/null
@@ -0,0 +1,161 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 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 at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+
+// same as _07 but use identity matrix as a metric so the result should be the same
+// as operator*
+
+#include "../tests.h"
+
+#include <deal.II/base/utilities.h>
+#include <deal.II/base/function.h>
+#include <deal.II/distributed/tria.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/manifold_lib.h>
+#include <deal.II/dofs/dof_tools.h>
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/lac/constraint_matrix.h>
+#include <deal.II/matrix_free/operators.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/lac/la_parallel_block_vector.h>
+
+#include <iostream>
+
+
+
+
+template <int dim, int fe_degree>
+void test (const unsigned int n_blocks = 5)
+{
+  typedef double number;
+
+  parallel::distributed::Triangulation<dim> tria (MPI_COMM_WORLD);
+  GridGenerator::hyper_cube (tria);
+  tria.refine_global(1);
+  typename Triangulation<dim>::active_cell_iterator
+  cell = tria.begin_active (),
+  endc = tria.end();
+  cell = tria.begin_active ();
+  for (; cell!=endc; ++cell)
+    if (cell->is_locally_owned())
+      if (cell->center().norm()<0.2)
+        cell->set_refine_flag();
+  tria.execute_coarsening_and_refinement();
+  if (dim < 3 && fe_degree < 2)
+    tria.refine_global(2);
+  else
+    tria.refine_global(1);
+  if (tria.begin(tria.n_levels()-1)->is_locally_owned())
+    tria.begin(tria.n_levels()-1)->set_refine_flag();
+  if (tria.last()->is_locally_owned())
+    tria.last()->set_refine_flag();
+  tria.execute_coarsening_and_refinement();
+  cell = tria.begin_active ();
+  for (unsigned int i=0; i<10-3*dim; ++i)
+    {
+      cell = tria.begin_active ();
+      unsigned int counter = 0;
+      for (; cell!=endc; ++cell, ++counter)
+        if (cell->is_locally_owned())
+          if (counter % (7-i) == 0)
+            cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+    }
+
+  FE_Q<dim> fe (fe_degree);
+  DoFHandler<dim> dof (tria);
+  dof.distribute_dofs(fe);
+
+  IndexSet owned_set = dof.locally_owned_dofs();
+  IndexSet relevant_set;
+  DoFTools::extract_locally_relevant_dofs (dof, relevant_set);
+
+  ConstraintMatrix constraints (relevant_set);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values (dof, 0, Functions::ZeroFunction<dim>(),
+                                            constraints);
+  constraints.close();
+
+  std::shared_ptr<MatrixFree<dim,number> > mf_data(new MatrixFree<dim,number> ());
+  {
+    const QGauss<1> quad (fe_degree+2);
+    typename MatrixFree<dim,number>::AdditionalData data;
+    data.tasks_parallel_scheme =
+      MatrixFree<dim,number>::AdditionalData::none;
+    data.tasks_block_size = 7;
+    mf_data->reinit (dof, constraints, quad, data);
+  }
+
+  MatrixFreeOperators::MassOperator<dim,fe_degree, fe_degree+2, 1, LinearAlgebra::distributed::Vector<number> > mf;
+  mf.initialize(mf_data);
+  mf.compute_diagonal();
+
+  LinearAlgebra::distributed::BlockVector<number> left(n_blocks), right(n_blocks);
+  for (unsigned int b = 0; b < n_blocks; ++b)
+    {
+      mf_data->initialize_dof_vector (left.block(b));
+      mf_data->initialize_dof_vector (right.block(b));
+      left.block(b) = 0.;
+      right.block(b) = 0.;
+      for (unsigned int i=0; i<right.block(b).local_size(); ++i)
+        {
+          const unsigned int glob_index =
+            owned_set.nth_index_in_set (i);
+          if (constraints.is_constrained(glob_index))
+            continue;
+          right.block(b).local_element(i) = random_value<double>();
+          left.block(b).local_element(i) = random_value<double>();
+        }
+    }
+
+  FullMatrix<number> metric(n_blocks,n_blocks);
+  metric = 0.;
+  for (unsigned int i = 0; i < n_blocks; ++i)
+    metric(i,i) = 1.;
+
+  const double res = left.multivector_inner_product_with_metric(metric, right);
+  const double res2 = left * right;
+
+  double res3 = 0.;
+  for (unsigned int i = 0; i < n_blocks; ++i)
+    res3 += left.block(i) * right.block(i);
+
+  const double diff_norm = std::abs(res-res2);
+  const double diff_norm2 = std::abs(res-res3);
+  deallog << "Norm of difference: " << diff_norm << " " << diff_norm2 << std::endl;
+}
+
+
+int main (int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, testing_max_num_threads());
+
+  unsigned int myid = Utilities::MPI::this_mpi_process (MPI_COMM_WORLD);
+  deallog.push(Utilities::int_to_string(myid));
+
+  if (myid == 0)
+    {
+      initlog();
+      deallog << std::setprecision(4);
+
+      test<2,1>();
+    }
+  else
+    {
+      test<2,1>();
+    }
+}
diff --git a/tests/mpi/parallel_block_vector_10.with_p4est=true.mpirun=1.output b/tests/mpi/parallel_block_vector_10.with_p4est=true.mpirun=1.output
new file mode 100644 (file)
index 0000000..9b6ca0b
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL:0::Norm of difference: 0.000 0.000
diff --git a/tests/mpi/parallel_block_vector_10.with_p4est=true.mpirun=4.output b/tests/mpi/parallel_block_vector_10.with_p4est=true.mpirun=4.output
new file mode 100644 (file)
index 0000000..9b6ca0b
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL:0::Norm of difference: 0.000 0.000
diff --git a/tests/mpi/parallel_block_vector_11.cc b/tests/mpi/parallel_block_vector_11.cc
new file mode 100644 (file)
index 0000000..3771204
--- /dev/null
@@ -0,0 +1,165 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2017 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 at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+
+// this BlockVector<Number>::multivector_inner_product_with_metric(symmetric=true).
+// Triangulation and Mass operator are the same as in matrix_free/mass_operator_01.cc
+
+#include "../tests.h"
+
+#include <deal.II/base/utilities.h>
+#include <deal.II/base/function.h>
+#include <deal.II/distributed/tria.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/manifold_lib.h>
+#include <deal.II/dofs/dof_tools.h>
+#include <deal.II/dofs/dof_handler.h>
+#include <deal.II/lac/constraint_matrix.h>
+#include <deal.II/matrix_free/operators.h>
+#include <deal.II/fe/fe_q.h>
+#include <deal.II/numerics/vector_tools.h>
+#include <deal.II/lac/la_parallel_block_vector.h>
+
+#include <iostream>
+
+
+
+
+template <int dim, int fe_degree>
+void test (const unsigned int n_blocks = 5)
+{
+  typedef double number;
+
+  parallel::distributed::Triangulation<dim> tria (MPI_COMM_WORLD);
+  GridGenerator::hyper_cube (tria);
+  tria.refine_global(1);
+  typename Triangulation<dim>::active_cell_iterator
+  cell = tria.begin_active (),
+  endc = tria.end();
+  cell = tria.begin_active ();
+  for (; cell!=endc; ++cell)
+    if (cell->is_locally_owned())
+      if (cell->center().norm()<0.2)
+        cell->set_refine_flag();
+  tria.execute_coarsening_and_refinement();
+  if (dim < 3 && fe_degree < 2)
+    tria.refine_global(2);
+  else
+    tria.refine_global(1);
+  if (tria.begin(tria.n_levels()-1)->is_locally_owned())
+    tria.begin(tria.n_levels()-1)->set_refine_flag();
+  if (tria.last()->is_locally_owned())
+    tria.last()->set_refine_flag();
+  tria.execute_coarsening_and_refinement();
+  cell = tria.begin_active ();
+  for (unsigned int i=0; i<10-3*dim; ++i)
+    {
+      cell = tria.begin_active ();
+      unsigned int counter = 0;
+      for (; cell!=endc; ++cell, ++counter)
+        if (cell->is_locally_owned())
+          if (counter % (7-i) == 0)
+            cell->set_refine_flag();
+      tria.execute_coarsening_and_refinement();
+    }
+
+  FE_Q<dim> fe (fe_degree);
+  DoFHandler<dim> dof (tria);
+  dof.distribute_dofs(fe);
+
+  IndexSet owned_set = dof.locally_owned_dofs();
+  IndexSet relevant_set;
+  DoFTools::extract_locally_relevant_dofs (dof, relevant_set);
+
+  ConstraintMatrix constraints (relevant_set);
+  DoFTools::make_hanging_node_constraints(dof, constraints);
+  VectorTools::interpolate_boundary_values (dof, 0, Functions::ZeroFunction<dim>(),
+                                            constraints);
+  constraints.close();
+
+  std::shared_ptr<MatrixFree<dim,number> > mf_data(new MatrixFree<dim,number> ());
+  {
+    const QGauss<1> quad (fe_degree+2);
+    typename MatrixFree<dim,number>::AdditionalData data;
+    data.tasks_parallel_scheme =
+      MatrixFree<dim,number>::AdditionalData::none;
+    data.tasks_block_size = 7;
+    mf_data->reinit (dof, constraints, quad, data);
+  }
+
+  MatrixFreeOperators::MassOperator<dim,fe_degree, fe_degree+2, 1, LinearAlgebra::distributed::Vector<number> > mf;
+  mf.initialize(mf_data);
+  mf.compute_diagonal();
+
+  LinearAlgebra::distributed::BlockVector<number> left(n_blocks), right(n_blocks);
+  for (unsigned int b = 0; b < n_blocks; ++b)
+    {
+      mf_data->initialize_dof_vector (left.block(b));
+      mf_data->initialize_dof_vector (right.block(b));
+      left.block(b) = 0.;
+      right.block(b) = 0.;
+      for (unsigned int i=0; i<right.block(b).local_size(); ++i)
+        {
+          const unsigned int glob_index =
+            owned_set.nth_index_in_set (i);
+          if (constraints.is_constrained(glob_index))
+            continue;
+          right.block(b).local_element(i) = random_value<double>();
+        }
+      right.block(b).update_ghost_values();
+      mf.vmult (left.block(b), right.block(b));
+    }
+
+  FullMatrix<number> metric(n_blocks,n_blocks);
+  for (unsigned int i = 0; i < n_blocks; ++i)
+    for (unsigned int j = i; j < n_blocks; ++j)
+      {
+        const double val = 1. + (i*3 + j*7);
+        metric(i,j) = val;
+        metric(j,i) = val;
+      }
+
+  const double res = left.multivector_inner_product_with_metric(metric, right, true);
+
+  double res2 = 0.;
+  for (unsigned int i = 0; i < n_blocks; ++i)
+    for (unsigned int j = 0; j < n_blocks; ++j)
+      res2 += metric(i,j) * (left.block(i) * right.block(j));
+
+  const double diff_norm = std::abs(res-res2);
+  deallog << "Norm of difference: " << diff_norm << std::endl;
+}
+
+
+int main (int argc, char **argv)
+{
+  Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, testing_max_num_threads());
+
+  unsigned int myid = Utilities::MPI::this_mpi_process (MPI_COMM_WORLD);
+  deallog.push(Utilities::int_to_string(myid));
+
+  if (myid == 0)
+    {
+      initlog();
+      deallog << std::setprecision(4);
+
+      test<2,1>();
+    }
+  else
+    {
+      test<2,1>();
+    }
+}
diff --git a/tests/mpi/parallel_block_vector_11.with_p4est=true.mpirun=4.output b/tests/mpi/parallel_block_vector_11.with_p4est=true.mpirun=4.output
new file mode 100644 (file)
index 0000000..b3f4ed9
--- /dev/null
@@ -0,0 +1,2 @@
+
+DEAL:0::Norm of difference: 0.000

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.