return;
Assert (matrix.m() == m,
- dealii::ExcDimensionMismatch(matrix.m(),m));
+ ExcDimensionMismatch(matrix.m(),m));
Assert (matrix.n() == n,
- dealii::ExcDimensionMismatch(matrix.n(),n));
+ ExcDimensionMismatch(matrix.n(),n));
// reset the matrix
matrix = typename FullMatrixType::value_type(0.0);
if (symmetric)
{
Assert (m == n,
- dealii::ExcDimensionMismatch(m,n));
+ ExcDimensionMismatch(m,n));
for (unsigned int i = 0; i < m; i++)
for (unsigned int j = i; j < n; j++)
return res;
Assert (matrix.m() == m,
- dealii::ExcDimensionMismatch(matrix.m(),m));
+ ExcDimensionMismatch(matrix.m(),m));
Assert (matrix.n() == n,
- dealii::ExcDimensionMismatch(matrix.n(),n));
+ ExcDimensionMismatch(matrix.n(),n));
if (symmetric)
{
Assert (m == n,
- dealii::ExcDimensionMismatch(m,n));
+ ExcDimensionMismatch(m,n));
for (unsigned int i = 0; i < m; i++)
{
template <typename Number>
template <typename FullMatrixType>
void
- BlockVector<Number>::mmult(const BlockVector<Number> &V,
- const FullMatrixType &matrix)
+ BlockVector<Number>::mmult(BlockVector<Number> &V,
+ const FullMatrixType &matrix,
+ const Number s,
+ const Number b) const
{
- const unsigned int n = this->n_blocks();
- const unsigned int m = V.n_blocks();
+ 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()
return;
Assert (matrix.m() == m,
- dealii::ExcDimensionMismatch(matrix.m(),m));
+ ExcDimensionMismatch(matrix.m(),m));
Assert (matrix.n() == n,
- dealii::ExcDimensionMismatch(matrix.n(),n));
+ 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));
+ {
+ // below we make this work gracefully for identity-like matrices in
+ // which case the two loops over j won't do any work as A(j,i)==0
+ const unsigned int k = std::min(i,m-1);
+ V.block(i).sadd(s,matrix(k,i)*b, this->block(k));
+ for (unsigned int j = 0 ; j < k; j++)
+ V.block(i).add (matrix(j,i)*b, this->block(j));
+ for (unsigned int j = k+1; j < m; j++)
+ V.block(i).add (matrix(j,i)*b, this->block(j));
+ }
}
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// 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, s,b)
+// also for vectors of different number of blocks.
+// 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 = 5, const unsigned int m = 3)
+{
+ 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), right(m), left2(n);
+ for (unsigned int b = 0; b < n; ++b)
+ {
+ mf_data->initialize_dof_vector (left.block(b));
+ mf_data->initialize_dof_vector (left2.block(b));
+ left.block(b) = 0.;
+ left2.block(b) = 0.;
+ for (unsigned int i=0; i<left.block(b).local_size(); ++i)
+ {
+ const unsigned int glob_index =
+ owned_set.nth_index_in_set (i);
+ if (constraints.is_constrained(glob_index))
+ continue;
+ left.block(b).local_element(i) = random_value<double>();
+ }
+ }
+
+ for (unsigned int b = 0; b < m; ++b)
+ {
+ mf_data->initialize_dof_vector (right.block(b));
+ 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>();
+ }
+ }
+
+
+ FullMatrix<number> metric(m,n);
+ for (unsigned int i = 0; i < m; ++i)
+ for (unsigned int j = 0; j < n; ++j)
+ metric(i,j) = 0.3 + (i*3 + j*7);
+
+ right.mmult(left,metric); // L = RM
+ right.mmult(left,metric,2.,3.); // L = 2L + 3 RM = 5RM
+
+ for (unsigned int i = 0; i < n; ++i)
+ for (unsigned int j = 0; j < m; ++j)
+ left2.block(i).add(5.*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>(5,3);
+ test<2,1>(3,3);
+ test<2,1>(3,5);
+ }
+ else
+ {
+ test<2,1>(5,3);
+ test<2,1>(3,3);
+ test<2,1>(3,5);
+ }
+}