1 // --------------------------------------------------------------------- 2 // 3 // Copyright (C) 1999 - 2020 by the deal.II authors 4 // 5 // This file is part of the deal.II library. 6 // 7 // The deal.II library is free software; you can use it, redistribute 8 // it, and/or modify it under the terms of the GNU Lesser General 9 // Public License as published by the Free Software Foundation; either 10 // version 2.1 of the License, or (at your option) any later version. 11 // The full text of the license can be found in the file LICENSE.md at 12 // the top level directory of deal.II. 13 // 14 // --------------------------------------------------------------------- 15 16 #ifndef dealii_parallel_block_vector_templates_h 17 #define dealii_parallel_block_vector_templates_h 18 19 20 #include <deal.II/base/config.h> 21 22 #include <deal.II/lac/la_parallel_block_vector.h> 23 #include <deal.II/lac/lapack_support.h> 24 #include <deal.II/lac/petsc_block_vector.h> 25 #include <deal.II/lac/read_write_vector.h> 26 #include <deal.II/lac/trilinos_parallel_block_vector.h> 27 #include <deal.II/lac/vector.h> 28 29 30 DEAL_II_NAMESPACE_OPEN 31 32 // Forward type declaration to have special treatment of 33 // LAPACKFullMatrix<number> 34 // in multivector_inner_product() 35 #ifndef DOXYGEN 36 template <typename Number> 37 class LAPACKFullMatrix; 38 #endif 39 40 namespace LinearAlgebra 41 { 42 namespace distributed 43 { 44 template <typename Number> BlockVector(const size_type n_blocks,const size_type block_size)45 BlockVector<Number>::BlockVector(const size_type n_blocks, 46 const size_type block_size) 47 { 48 reinit(n_blocks, block_size); 49 } 50 51 52 53 template <typename Number> BlockVector(const std::vector<size_type> & n)54 BlockVector<Number>::BlockVector(const std::vector<size_type> &n) 55 { 56 reinit(n, false); 57 } 58 59 60 template <typename Number> BlockVector(const std::vector<IndexSet> & local_ranges,const std::vector<IndexSet> & ghost_indices,const MPI_Comm communicator)61 BlockVector<Number>::BlockVector(const std::vector<IndexSet> &local_ranges, 62 const std::vector<IndexSet> &ghost_indices, 63 const MPI_Comm communicator) 64 { 65 std::vector<size_type> sizes(local_ranges.size()); 66 for (unsigned int i = 0; i < local_ranges.size(); ++i) 67 sizes[i] = local_ranges[i].size(); 68 69 this->block_indices.reinit(sizes); 70 this->components.resize(this->n_blocks()); 71 72 for (unsigned int i = 0; i < this->n_blocks(); ++i) 73 this->block(i).reinit(local_ranges[i], ghost_indices[i], communicator); 74 } 75 76 77 template <typename Number> BlockVector(const std::vector<IndexSet> & local_ranges,const MPI_Comm communicator)78 BlockVector<Number>::BlockVector(const std::vector<IndexSet> &local_ranges, 79 const MPI_Comm communicator) 80 { 81 std::vector<size_type> sizes(local_ranges.size()); 82 for (unsigned int i = 0; i < local_ranges.size(); ++i) 83 sizes[i] = local_ranges[i].size(); 84 85 this->block_indices.reinit(sizes); 86 this->components.resize(this->n_blocks()); 87 88 for (unsigned int i = 0; i < this->n_blocks(); ++i) 89 this->block(i).reinit(local_ranges[i], communicator); 90 } 91 92 93 94 template <typename Number> BlockVector(const BlockVector<Number> & v)95 BlockVector<Number>::BlockVector(const BlockVector<Number> &v) 96 : BlockVectorBase<Vector<Number>>() 97 { 98 this->components.resize(v.n_blocks()); 99 this->block_indices = v.block_indices; 100 101 for (size_type i = 0; i < this->n_blocks(); ++i) 102 this->components[i] = v.components[i]; 103 } 104 105 106 107 template <typename Number> 108 template <typename OtherNumber> BlockVector(const BlockVector<OtherNumber> & v)109 BlockVector<Number>::BlockVector(const BlockVector<OtherNumber> &v) 110 { 111 reinit(v, true); 112 *this = v; 113 } 114 115 116 117 template <typename Number> 118 void reinit(const size_type n_bl,const size_type bl_sz,const bool omit_zeroing_entries)119 BlockVector<Number>::reinit(const size_type n_bl, 120 const size_type bl_sz, 121 const bool omit_zeroing_entries) 122 { 123 std::vector<size_type> n(n_bl, bl_sz); 124 reinit(n, omit_zeroing_entries); 125 } 126 127 128 template <typename Number> 129 void reinit(const std::vector<size_type> & n,const bool omit_zeroing_entries)130 BlockVector<Number>::reinit(const std::vector<size_type> &n, 131 const bool omit_zeroing_entries) 132 { 133 this->block_indices.reinit(n); 134 if (this->components.size() != this->n_blocks()) 135 this->components.resize(this->n_blocks()); 136 137 for (size_type i = 0; i < this->n_blocks(); ++i) 138 this->components[i].reinit(n[i], omit_zeroing_entries); 139 } 140 141 142 143 template <typename Number> 144 template <typename Number2> 145 void reinit(const BlockVector<Number2> & v,const bool omit_zeroing_entries)146 BlockVector<Number>::reinit(const BlockVector<Number2> &v, 147 const bool omit_zeroing_entries) 148 { 149 this->block_indices = v.get_block_indices(); 150 if (this->components.size() != this->n_blocks()) 151 this->components.resize(this->n_blocks()); 152 153 for (unsigned int i = 0; i < this->n_blocks(); ++i) 154 this->block(i).reinit(v.block(i), omit_zeroing_entries); 155 } 156 157 158 159 template <typename Number> 160 BlockVector<Number> & 161 BlockVector<Number>::operator=(const value_type s) 162 { 163 AssertIsFinite(s); 164 165 BaseClass::operator=(s); 166 return *this; 167 } 168 169 170 171 template <typename Number> 172 BlockVector<Number> & 173 BlockVector<Number>::operator=(const BlockVector &v) 174 { 175 // we only allow assignment to vectors with the same number of blocks 176 // or to an empty BlockVector 177 Assert(this->n_blocks() == 0 || this->n_blocks() == v.n_blocks(), 178 ExcDimensionMismatch(this->n_blocks(), v.n_blocks())); 179 180 if (this->n_blocks() != v.n_blocks()) 181 reinit(v.n_blocks(), true); 182 183 for (size_type i = 0; i < this->n_blocks(); ++i) 184 this->components[i] = v.block(i); 185 186 this->collect_sizes(); 187 return *this; 188 } 189 190 191 192 template <typename Number> 193 BlockVector<Number> & 194 BlockVector<Number>::operator=(const Vector<Number> &v) 195 { 196 BaseClass::operator=(v); 197 return *this; 198 } 199 200 201 202 template <typename Number> 203 template <typename Number2> 204 BlockVector<Number> & 205 BlockVector<Number>::operator=(const BlockVector<Number2> &v) 206 { 207 reinit(v, true); 208 BaseClass::operator=(v); 209 return *this; 210 } 211 212 213 214 #ifdef DEAL_II_WITH_PETSC 215 216 namespace petsc_helpers 217 { 218 template <typename PETSC_Number, typename Number> 219 void copy_petsc_vector(const PETSC_Number * petsc_start_ptr,const PETSC_Number * petsc_end_ptr,Number * ptr)220 copy_petsc_vector(const PETSC_Number *petsc_start_ptr, 221 const PETSC_Number *petsc_end_ptr, 222 Number * ptr) 223 { 224 std::copy(petsc_start_ptr, petsc_end_ptr, ptr); 225 } 226 227 template <typename PETSC_Number, typename Number> 228 void copy_petsc_vector(const std::complex<PETSC_Number> * petsc_start_ptr,const std::complex<PETSC_Number> * petsc_end_ptr,std::complex<Number> * ptr)229 copy_petsc_vector(const std::complex<PETSC_Number> *petsc_start_ptr, 230 const std::complex<PETSC_Number> *petsc_end_ptr, 231 std::complex<Number> * ptr) 232 { 233 std::copy(petsc_start_ptr, petsc_end_ptr, ptr); 234 } 235 236 template <typename PETSC_Number, typename Number> 237 void copy_petsc_vector(const std::complex<PETSC_Number> *,const std::complex<PETSC_Number> *,Number *)238 copy_petsc_vector(const std::complex<PETSC_Number> * /*petsc_start_ptr*/, 239 const std::complex<PETSC_Number> * /*petsc_end_ptr*/, 240 Number * /*ptr*/) 241 { 242 AssertThrow(false, ExcMessage("Tried to copy complex -> real")); 243 } 244 } // namespace petsc_helpers 245 246 247 248 template <typename Number> 249 BlockVector<Number> & 250 BlockVector<Number>:: 251 operator=(const PETScWrappers::MPI::BlockVector &petsc_vec) 252 { 253 AssertDimension(this->n_blocks(), petsc_vec.n_blocks()); 254 for (unsigned int i = 0; i < this->n_blocks(); ++i) 255 { 256 // We would like to use the same compact infrastructure as for the 257 // Trilinos vector below, but the interface through ReadWriteVector 258 // does not support overlapping (ghosted) PETSc vectors, which we need 259 // for backward compatibility. 260 261 Assert(petsc_vec.block(i).locally_owned_elements() == 262 this->block(i).locally_owned_elements(), 263 StandardExceptions::ExcInvalidState()); 264 265 // get a representation of the vector and copy it 266 PetscScalar * start_ptr; 267 PetscErrorCode ierr = 268 VecGetArray(static_cast<const Vec &>(petsc_vec.block(i)), 269 &start_ptr); 270 AssertThrow(ierr == 0, ExcPETScError(ierr)); 271 272 const size_type vec_size = this->block(i).local_size(); 273 petsc_helpers::copy_petsc_vector(start_ptr, 274 start_ptr + vec_size, 275 this->block(i).begin()); 276 277 // restore the representation of the vector 278 ierr = VecRestoreArray(static_cast<const Vec &>(petsc_vec.block(i)), 279 &start_ptr); 280 AssertThrow(ierr == 0, ExcPETScError(ierr)); 281 282 // spread ghost values between processes? 283 if (this->block(i).vector_is_ghosted || 284 petsc_vec.block(i).has_ghost_elements()) 285 this->block(i).update_ghost_values(); 286 } 287 288 return *this; 289 } 290 291 #endif 292 293 294 295 #ifdef DEAL_II_WITH_TRILINOS 296 297 template <typename Number> 298 BlockVector<Number> & 299 BlockVector<Number>:: 300 operator=(const TrilinosWrappers::MPI::BlockVector &trilinos_vec) 301 { 302 AssertDimension(this->n_blocks(), trilinos_vec.n_blocks()); 303 for (unsigned int i = 0; i < this->n_blocks(); ++i) 304 { 305 const auto &partitioner = this->block(i).get_partitioner(); 306 IndexSet combined_set = partitioner->locally_owned_range(); 307 combined_set.add_indices(partitioner->ghost_indices()); 308 ReadWriteVector<Number> rw_vector(combined_set); 309 rw_vector.import(trilinos_vec.block(i), VectorOperation::insert); 310 this->block(i).import(rw_vector, VectorOperation::insert); 311 312 if (this->block(i).has_ghost_elements() || 313 trilinos_vec.block(i).has_ghost_elements()) 314 this->block(i).update_ghost_values(); 315 } 316 317 return *this; 318 } 319 320 #endif 321 322 323 324 template <typename Number> 325 void compress(::dealii::VectorOperation::values operation)326 BlockVector<Number>::compress(::dealii::VectorOperation::values operation) 327 { 328 const unsigned int n_chunks = 329 (this->n_blocks() + communication_block_size - 1) / 330 communication_block_size; 331 for (unsigned int c = 0; c < n_chunks; ++c) 332 { 333 const unsigned int start = c * communication_block_size; 334 const unsigned int end = 335 std::min(start + communication_block_size, this->n_blocks()); 336 337 // start all requests for all blocks before finishing the transfers as 338 // this saves repeated synchronizations. In order to avoid conflict 339 // with possible other ongoing communication requests (from 340 // LA::distributed::Vector that supports unfinished requests), add 341 // 100 to the communication tag (the first 100 can be used by normal 342 // vectors). 343 for (unsigned int block = start; block < end; ++block) 344 this->block(block).compress_start(block - start + 100, operation); 345 for (unsigned int block = start; block < end; ++block) 346 this->block(block).compress_finish(operation); 347 } 348 } 349 350 351 352 template <typename Number> 353 void update_ghost_values()354 BlockVector<Number>::update_ghost_values() const 355 { 356 const unsigned int n_chunks = 357 (this->n_blocks() + communication_block_size - 1) / 358 communication_block_size; 359 for (unsigned int c = 0; c < n_chunks; ++c) 360 { 361 const unsigned int start = c * communication_block_size; 362 const unsigned int end = 363 std::min(start + communication_block_size, this->n_blocks()); 364 365 // In order to avoid conflict with possible other ongoing 366 // communication requests (from LA::distributed::Vector that supports 367 // unfinished requests), add 100 to the communication tag (the first 368 // 100 can be used by normal vectors) 369 for (unsigned int block = start; block < end; ++block) 370 this->block(block).update_ghost_values_start(block - start + 100); 371 for (unsigned int block = start; block < end; ++block) 372 this->block(block).update_ghost_values_finish(); 373 } 374 } 375 376 377 378 template <typename Number> 379 void zero_out_ghosts()380 BlockVector<Number>::zero_out_ghosts() const 381 { 382 for (unsigned int block = 0; block < this->n_blocks(); ++block) 383 this->block(block).zero_out_ghosts(); 384 } 385 386 387 388 template <typename Number> 389 bool has_ghost_elements()390 BlockVector<Number>::has_ghost_elements() const 391 { 392 bool has_ghost_elements = false; 393 for (unsigned int block = 0; block < this->n_blocks(); ++block) 394 if (this->block(block).has_ghost_elements() == true) 395 has_ghost_elements = true; 396 return has_ghost_elements; 397 } 398 399 400 401 template <typename Number> 402 void reinit(const VectorSpaceVector<Number> & V,const bool omit_zeroing_entries)403 BlockVector<Number>::reinit(const VectorSpaceVector<Number> &V, 404 const bool omit_zeroing_entries) 405 { 406 Assert(dynamic_cast<const BlockVector<Number> *>(&V) != nullptr, 407 ExcVectorTypeNotCompatible()); 408 const BlockVector<Number> &down_V = 409 dynamic_cast<const BlockVector<Number> &>(V); 410 reinit(down_V, omit_zeroing_entries); 411 } 412 413 414 template <typename Number> 415 BlockVector<Number> & 416 BlockVector<Number>::operator*=(const Number factor) 417 { 418 for (unsigned int block = 0; block < this->n_blocks(); ++block) 419 this->block(block) *= factor; 420 return *this; 421 } 422 423 424 425 template <typename Number> 426 BlockVector<Number> & 427 BlockVector<Number>::operator/=(const Number factor) 428 { 429 operator*=(static_cast<Number>(1.) / factor); 430 return *this; 431 } 432 433 434 435 template <typename Number> 436 void scale(const VectorSpaceVector<Number> & vv)437 BlockVector<Number>::scale(const VectorSpaceVector<Number> &vv) 438 { 439 // Downcast. Throws an exception if invalid. 440 Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr, 441 ExcVectorTypeNotCompatible()); 442 const BlockVector<Number> &v = 443 dynamic_cast<const BlockVector<Number> &>(vv); 444 AssertDimension(this->n_blocks(), v.n_blocks()); 445 for (unsigned int block = 0; block < this->n_blocks(); ++block) 446 this->block(block).scale(v.block(block)); 447 } 448 449 450 451 template <typename Number> 452 void equ(const Number a,const VectorSpaceVector<Number> & vv)453 BlockVector<Number>::equ(const Number a, 454 const VectorSpaceVector<Number> &vv) 455 { 456 // Downcast. Throws an exception if invalid. 457 Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr, 458 ExcVectorTypeNotCompatible()); 459 const BlockVector<Number> &v = 460 dynamic_cast<const BlockVector<Number> &>(vv); 461 AssertDimension(this->n_blocks(), v.n_blocks()); 462 for (unsigned int block = 0; block < this->n_blocks(); ++block) 463 this->block(block).equ(a, v.block(block)); 464 } 465 466 467 468 template <typename Number> 469 BlockVector<Number> & 470 BlockVector<Number>::operator+=(const VectorSpaceVector<Number> &vv) 471 { 472 // Downcast. Throws an exception if invalid. 473 Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr, 474 ExcVectorTypeNotCompatible()); 475 const BlockVector<Number> &v = 476 dynamic_cast<const BlockVector<Number> &>(vv); 477 AssertDimension(this->n_blocks(), v.n_blocks()); 478 for (unsigned int block = 0; block < this->n_blocks(); ++block) 479 this->block(block) += v.block(block); 480 481 return *this; 482 } 483 484 485 486 template <typename Number> 487 BlockVector<Number> & 488 BlockVector<Number>::operator-=(const VectorSpaceVector<Number> &vv) 489 { 490 // Downcast. Throws an exception if invalid. 491 Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr, 492 ExcVectorTypeNotCompatible()); 493 const BlockVector<Number> &v = 494 dynamic_cast<const BlockVector<Number> &>(vv); 495 AssertDimension(this->n_blocks(), v.n_blocks()); 496 for (unsigned int block = 0; block < this->n_blocks(); ++block) 497 this->block(block) -= v.block(block); 498 499 return *this; 500 } 501 502 503 504 template <typename Number> 505 void add(const Number a)506 BlockVector<Number>::add(const Number a) 507 { 508 for (unsigned int block = 0; block < this->n_blocks(); ++block) 509 this->block(block).add(a); 510 } 511 512 513 514 template <typename Number> 515 void add(const Number a,const VectorSpaceVector<Number> & vv)516 BlockVector<Number>::add(const Number a, 517 const VectorSpaceVector<Number> &vv) 518 { 519 // Downcast. Throws an exception if invalid. 520 Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr, 521 ExcVectorTypeNotCompatible()); 522 const BlockVector<Number> &v = 523 dynamic_cast<const BlockVector<Number> &>(vv); 524 AssertDimension(this->n_blocks(), v.n_blocks()); 525 for (unsigned int block = 0; block < this->n_blocks(); ++block) 526 this->block(block).add(a, v.block(block)); 527 } 528 529 530 531 template <typename Number> 532 void add(const Number a,const VectorSpaceVector<Number> & vv,const Number b,const VectorSpaceVector<Number> & ww)533 BlockVector<Number>::add(const Number a, 534 const VectorSpaceVector<Number> &vv, 535 const Number b, 536 const VectorSpaceVector<Number> &ww) 537 { 538 // Downcast. Throws an exception if invalid. 539 Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr, 540 ExcVectorTypeNotCompatible()); 541 const BlockVector<Number> &v = 542 dynamic_cast<const BlockVector<Number> &>(vv); 543 AssertDimension(this->n_blocks(), v.n_blocks()); 544 Assert(dynamic_cast<const BlockVector<Number> *>(&ww) != nullptr, 545 ExcVectorTypeNotCompatible()); 546 const BlockVector<Number> &w = 547 dynamic_cast<const BlockVector<Number> &>(ww); 548 AssertDimension(this->n_blocks(), v.n_blocks()); 549 550 for (unsigned int block = 0; block < this->n_blocks(); ++block) 551 this->block(block).add(a, v.block(block), b, w.block(block)); 552 } 553 554 555 556 template <typename Number> 557 void sadd(const Number x,const Number a,const VectorSpaceVector<Number> & vv)558 BlockVector<Number>::sadd(const Number x, 559 const Number a, 560 const VectorSpaceVector<Number> &vv) 561 { 562 // Downcast. Throws an exception if invalid. 563 Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr, 564 ExcVectorTypeNotCompatible()); 565 const BlockVector<Number> &v = 566 dynamic_cast<const BlockVector<Number> &>(vv); 567 AssertDimension(this->n_blocks(), v.n_blocks()); 568 for (unsigned int block = 0; block < this->n_blocks(); ++block) 569 this->block(block).sadd(x, a, v.block(block)); 570 } 571 572 573 574 template <typename Number> 575 void sadd(const Number x,const BlockVector<Number> & v)576 BlockVector<Number>::sadd(const Number x, const BlockVector<Number> &v) 577 { 578 AssertDimension(this->n_blocks(), v.n_blocks()); 579 for (unsigned int block = 0; block < this->n_blocks(); ++block) 580 this->block(block).sadd(x, v.block(block)); 581 } 582 583 584 585 template <typename Number> 586 template <typename OtherNumber> 587 void add(const std::vector<size_type> & indices,const::dealii::Vector<OtherNumber> & values)588 BlockVector<Number>::add(const std::vector<size_type> & indices, 589 const ::dealii::Vector<OtherNumber> &values) 590 { 591 for (size_type i = 0; i < indices.size(); ++i) 592 (*this)(indices[i]) += values[i]; 593 } 594 595 596 597 template <typename Number> 598 void add(const std::vector<size_type> & indices,const std::vector<Number> & values)599 BlockVector<Number>::add(const std::vector<size_type> &indices, 600 const std::vector<Number> & values) 601 { 602 for (size_type i = 0; i < indices.size(); ++i) 603 (*this)(indices[i]) += values[i]; 604 } 605 606 607 608 template <typename Number> 609 bool all_zero()610 BlockVector<Number>::all_zero() const 611 { 612 Assert(this->n_blocks() > 0, ExcEmptyObject()); 613 614 // use int instead of bool. in order to make global reduction operations 615 // work also when MPI_Init was not called, only call MPI_Allreduce 616 // commands when there is more than one processor (note that reinit() 617 // functions handle this case correctly through the job_supports_mpi() 618 // query). this is the same in all the functions below 619 int local_result = -1; 620 for (unsigned int i = 0; i < this->n_blocks(); ++i) 621 local_result = 622 std::max(local_result, 623 (this->block(i).linfty_norm_local() == 0) ? -1 : 0); 624 625 if (this->block(0).partitioner->n_mpi_processes() > 1) 626 return -Utilities::MPI::max( 627 local_result, this->block(0).partitioner->get_mpi_communicator()); 628 else 629 return local_result; 630 } 631 632 633 634 template <typename Number> 635 Number BlockVector<Number>:: 636 operator*(const VectorSpaceVector<Number> &vv) const 637 { 638 Assert(this->n_blocks() > 0, ExcEmptyObject()); 639 640 // Downcast. Throws an exception if invalid. 641 Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr, 642 ExcVectorTypeNotCompatible()); 643 const BlockVector<Number> &v = 644 dynamic_cast<const BlockVector<Number> &>(vv); 645 AssertDimension(this->n_blocks(), v.n_blocks()); 646 647 Number local_result = Number(); 648 for (unsigned int i = 0; i < this->n_blocks(); ++i) 649 local_result += this->block(i).inner_product_local(v.block(i)); 650 651 if (this->block(0).partitioner->n_mpi_processes() > 1) 652 return Utilities::MPI::sum( 653 local_result, this->block(0).partitioner->get_mpi_communicator()); 654 else 655 return local_result; 656 } 657 658 659 660 template <typename Number> 661 inline Number mean_value()662 BlockVector<Number>::mean_value() const 663 { 664 Assert(this->n_blocks() > 0, ExcEmptyObject()); 665 666 Number local_result = Number(); 667 for (unsigned int i = 0; i < this->n_blocks(); ++i) 668 local_result += 669 this->block(i).mean_value_local() * 670 static_cast<real_type>(this->block(i).partitioner->local_size()); 671 672 if (this->block(0).partitioner->n_mpi_processes() > 1) 673 return Utilities::MPI::sum( 674 local_result, 675 this->block(0).partitioner->get_mpi_communicator()) / 676 static_cast<real_type>(this->size()); 677 else 678 return local_result / static_cast<real_type>(this->size()); 679 } 680 681 682 683 template <typename Number> 684 inline typename BlockVector<Number>::real_type l1_norm()685 BlockVector<Number>::l1_norm() const 686 { 687 Assert(this->n_blocks() > 0, ExcEmptyObject()); 688 689 real_type local_result = real_type(); 690 for (unsigned int i = 0; i < this->n_blocks(); ++i) 691 local_result += this->block(i).l1_norm_local(); 692 693 if (this->block(0).partitioner->n_mpi_processes() > 1) 694 return Utilities::MPI::sum( 695 local_result, this->block(0).partitioner->get_mpi_communicator()); 696 else 697 return local_result; 698 } 699 700 701 702 template <typename Number> 703 inline typename BlockVector<Number>::real_type norm_sqr()704 BlockVector<Number>::norm_sqr() const 705 { 706 Assert(this->n_blocks() > 0, ExcEmptyObject()); 707 708 real_type local_result = real_type(); 709 for (unsigned int i = 0; i < this->n_blocks(); ++i) 710 local_result += this->block(i).norm_sqr_local(); 711 712 if (this->block(0).partitioner->n_mpi_processes() > 1) 713 return Utilities::MPI::sum( 714 local_result, this->block(0).partitioner->get_mpi_communicator()); 715 else 716 return local_result; 717 } 718 719 720 721 template <typename Number> 722 inline typename BlockVector<Number>::real_type l2_norm()723 BlockVector<Number>::l2_norm() const 724 { 725 return std::sqrt(norm_sqr()); 726 } 727 728 729 730 template <typename Number> 731 inline typename BlockVector<Number>::real_type lp_norm(const real_type p)732 BlockVector<Number>::lp_norm(const real_type p) const 733 { 734 Assert(this->n_blocks() > 0, ExcEmptyObject()); 735 736 real_type local_result = real_type(); 737 for (unsigned int i = 0; i < this->n_blocks(); ++i) 738 local_result += std::pow(this->block(i).lp_norm_local(p), p); 739 740 if (this->block(0).partitioner->n_mpi_processes() > 1) 741 return std::pow(Utilities::MPI::sum( 742 local_result, 743 this->block(0).partitioner->get_mpi_communicator()), 744 static_cast<real_type>(1.0 / p)); 745 else 746 return std::pow(local_result, static_cast<real_type>(1.0 / p)); 747 } 748 749 750 751 template <typename Number> 752 inline typename BlockVector<Number>::real_type linfty_norm()753 BlockVector<Number>::linfty_norm() const 754 { 755 Assert(this->n_blocks() > 0, ExcEmptyObject()); 756 757 real_type local_result = real_type(); 758 for (unsigned int i = 0; i < this->n_blocks(); ++i) 759 local_result = 760 std::max(local_result, this->block(i).linfty_norm_local()); 761 762 if (this->block(0).partitioner->n_mpi_processes() > 1) 763 return Utilities::MPI::max( 764 local_result, this->block(0).partitioner->get_mpi_communicator()); 765 else 766 return local_result; 767 } 768 769 770 771 template <typename Number> 772 inline Number add_and_dot(const Number a,const VectorSpaceVector<Number> & vv,const VectorSpaceVector<Number> & ww)773 BlockVector<Number>::add_and_dot(const Number a, 774 const VectorSpaceVector<Number> &vv, 775 const VectorSpaceVector<Number> &ww) 776 { 777 // Downcast. Throws an exception if invalid. 778 Assert(dynamic_cast<const BlockVector<Number> *>(&vv) != nullptr, 779 ExcVectorTypeNotCompatible()); 780 const BlockVector<Number> &v = 781 dynamic_cast<const BlockVector<Number> &>(vv); 782 AssertDimension(this->n_blocks(), v.n_blocks()); 783 784 // Downcast. Throws an exception if invalid. 785 Assert(dynamic_cast<const BlockVector<Number> *>(&ww) != nullptr, 786 ExcVectorTypeNotCompatible()); 787 const BlockVector<Number> &w = 788 dynamic_cast<const BlockVector<Number> &>(ww); 789 AssertDimension(this->n_blocks(), w.n_blocks()); 790 791 Number local_result = Number(); 792 for (unsigned int i = 0; i < this->n_blocks(); ++i) 793 local_result += 794 this->block(i).add_and_dot_local(a, v.block(i), w.block(i)); 795 796 if (this->block(0).partitioner->n_mpi_processes() > 1) 797 return Utilities::MPI::sum( 798 local_result, this->block(0).partitioner->get_mpi_communicator()); 799 else 800 return local_result; 801 } 802 803 804 805 template <typename Number> 806 inline void swap(BlockVector<Number> & v)807 BlockVector<Number>::swap(BlockVector<Number> &v) 808 { 809 Assert(this->n_blocks() == v.n_blocks(), 810 ExcDimensionMismatch(this->n_blocks(), v.n_blocks())); 811 812 for (size_type i = 0; i < this->n_blocks(); ++i) 813 dealii::swap(this->components[i], v.components[i]); 814 dealii::swap(this->block_indices, v.block_indices); 815 } 816 817 818 819 template <typename Number> 820 typename BlockVector<Number>::size_type size()821 BlockVector<Number>::size() const 822 { 823 return this->block_indices.total_size(); 824 } 825 826 827 828 template <typename Number> 829 inline void import(const LinearAlgebra::ReadWriteVector<Number> &,VectorOperation::values,std::shared_ptr<const CommunicationPatternBase>)830 BlockVector<Number>::import(const LinearAlgebra::ReadWriteVector<Number> &, 831 VectorOperation::values, 832 std::shared_ptr<const CommunicationPatternBase>) 833 { 834 AssertThrow(false, ExcNotImplemented()); 835 } 836 837 838 839 template <typename Number> 840 IndexSet locally_owned_elements()841 BlockVector<Number>::locally_owned_elements() const 842 { 843 IndexSet is(size()); 844 845 // copy index sets from blocks into the global one, shifted by the 846 // appropriate amount for each block 847 for (unsigned int b = 0; b < this->n_blocks(); ++b) 848 { 849 IndexSet x = this->block(b).locally_owned_elements(); 850 is.add_indices(x, this->block_indices.block_start(b)); 851 } 852 853 is.compress(); 854 855 return is; 856 } 857 858 template <typename Number> 859 void print(std::ostream & out,const unsigned int precision,const bool scientific,const bool across)860 BlockVector<Number>::print(std::ostream & out, 861 const unsigned int precision, 862 const bool scientific, 863 const bool across) const 864 { 865 for (unsigned int b = 0; b < this->n_blocks(); ++b) 866 this->block(b).print(out, precision, scientific, across); 867 } 868 869 870 871 template <typename Number> 872 std::size_t memory_consumption()873 BlockVector<Number>::memory_consumption() const 874 { 875 return (MemoryConsumption::memory_consumption(this->block_indices) + 876 MemoryConsumption::memory_consumption(this->components)); 877 } 878 879 880 881 namespace internal 882 { 883 template <typename FullMatrixType> 884 inline void set_symmetric(FullMatrixType &,const bool)885 set_symmetric(FullMatrixType &, const bool) 886 {} 887 888 template <typename NumberType> 889 inline void set_symmetric(LAPACKFullMatrix<NumberType> & matrix,const bool symmetric)890 set_symmetric(LAPACKFullMatrix<NumberType> &matrix, const bool symmetric) 891 { 892 if (symmetric) 893 matrix.set_property(LAPACKSupport::symmetric); 894 else 895 matrix.set_property(LAPACKSupport::general); 896 } 897 } // namespace internal 898 899 900 901 template <typename Number> 902 template <typename FullMatrixType> 903 void multivector_inner_product(FullMatrixType & matrix,const BlockVector<Number> & V,const bool symmetric)904 BlockVector<Number>::multivector_inner_product(FullMatrixType &matrix, 905 const BlockVector<Number> &V, 906 const bool symmetric) const 907 { 908 const unsigned int m = this->n_blocks(); 909 const unsigned int n = V.n_blocks(); 910 911 // in case one vector is empty and the second one is not, the 912 // FullMatrix resized to (m,n) will have 0 both in m() and n() 913 // which is how TableBase<N,T>::reinit() works as of deal.ii@8.5.0. 914 // Since in this case there is nothing to do anyway -- return immediately. 915 if (n == 0 || m == 0) 916 return; 917 918 Assert(matrix.m() == m, ExcDimensionMismatch(matrix.m(), m)); 919 Assert(matrix.n() == n, ExcDimensionMismatch(matrix.n(), n)); 920 921 // reset the matrix 922 matrix = typename FullMatrixType::value_type(0.0); 923 924 internal::set_symmetric(matrix, symmetric); 925 if (symmetric) 926 { 927 Assert(m == n, ExcDimensionMismatch(m, n)); 928 929 for (unsigned int i = 0; i < m; i++) 930 for (unsigned int j = i; j < n; j++) 931 matrix(i, j) = this->block(i).inner_product_local(V.block(j)); 932 933 for (unsigned int i = 0; i < m; i++) 934 for (unsigned int j = i + 1; j < n; j++) 935 matrix(j, i) = matrix(i, j); 936 } 937 else 938 { 939 for (unsigned int i = 0; i < m; ++i) 940 for (unsigned int j = 0; j < n; ++j) 941 matrix(i, j) = this->block(i).inner_product_local(V.block(j)); 942 } 943 944 Utilities::MPI::sum(matrix, 945 this->block(0).get_mpi_communicator(), 946 matrix); 947 } 948 949 950 951 template <typename Number> 952 template <typename FullMatrixType> 953 Number multivector_inner_product_with_metric(const FullMatrixType & matrix,const BlockVector<Number> & V,const bool symmetric)954 BlockVector<Number>::multivector_inner_product_with_metric( 955 const FullMatrixType & matrix, 956 const BlockVector<Number> &V, 957 const bool symmetric) const 958 { 959 Number res = Number(0.); 960 961 const unsigned int m = this->n_blocks(); 962 const unsigned int n = V.n_blocks(); 963 964 // in case one vector is empty and the second one is not, the 965 // FullMatrix resized to (m,n) will have 0 both in m() and n() 966 // which is how TableBase<N,T>::reinit() works. 967 // Since in this case there is nothing to do anyway -- return immediately. 968 if (n == 0 || m == 0) 969 return res; 970 971 Assert(matrix.m() == m, ExcDimensionMismatch(matrix.m(), m)); 972 Assert(matrix.n() == n, ExcDimensionMismatch(matrix.n(), n)); 973 974 if (symmetric) 975 { 976 Assert(m == n, ExcDimensionMismatch(m, n)); 977 978 for (unsigned int i = 0; i < m; i++) 979 { 980 res += 981 matrix(i, i) * this->block(i).inner_product_local(V.block(i)); 982 for (unsigned int j = i + 1; j < n; j++) 983 res += 2. * matrix(i, j) * 984 this->block(i).inner_product_local(V.block(j)); 985 } 986 } 987 else 988 { 989 for (unsigned int i = 0; i < m; i++) 990 for (unsigned int j = 0; j < n; j++) 991 res += 992 matrix(i, j) * this->block(i).inner_product_local(V.block(j)); 993 } 994 995 return Utilities::MPI::sum(res, this->block(0).get_mpi_communicator()); 996 } 997 998 999 1000 template <typename Number> 1001 template <typename FullMatrixType> 1002 void mmult(BlockVector<Number> & V,const FullMatrixType & matrix,const Number s,const Number b)1003 BlockVector<Number>::mmult(BlockVector<Number> & V, 1004 const FullMatrixType &matrix, 1005 const Number s, 1006 const Number b) const 1007 { 1008 const unsigned int m = this->n_blocks(); 1009 const unsigned int n = V.n_blocks(); 1010 1011 // in case one vector is empty and the second one is not, the 1012 // FullMatrix resized to (m,n) will have 0 both in m() and n() 1013 // which is how TableBase<N,T>::reinit() works. 1014 // Since in this case there is nothing to do anyway -- return immediately. 1015 if (n == 0 || m == 0) 1016 return; 1017 1018 Assert(matrix.m() == m, ExcDimensionMismatch(matrix.m(), m)); 1019 Assert(matrix.n() == n, ExcDimensionMismatch(matrix.n(), n)); 1020 1021 for (unsigned int i = 0; i < n; i++) 1022 { 1023 // below we make this work gracefully for identity-like matrices in 1024 // which case the two loops over j won't do any work as A(j,i)==0 1025 const unsigned int k = std::min(i, m - 1); 1026 V.block(i).sadd_local(s, matrix(k, i) * b, this->block(k)); 1027 for (unsigned int j = 0; j < k; j++) 1028 V.block(i).add_local(matrix(j, i) * b, this->block(j)); 1029 for (unsigned int j = k + 1; j < m; j++) 1030 V.block(i).add_local(matrix(j, i) * b, this->block(j)); 1031 } 1032 1033 if (V.block(0).vector_is_ghosted) 1034 { 1035 for (unsigned int i = 0; i < n; i++) 1036 Assert(V.block(i).vector_is_ghosted, 1037 ExcMessage( 1038 "All blocks should be either in ghosted state or not.")); 1039 1040 V.update_ghost_values(); 1041 } 1042 } 1043 1044 1045 1046 } // end of namespace distributed 1047 1048 } // namespace LinearAlgebra 1049 1050 DEAL_II_NAMESPACE_CLOSE 1051 1052 #endif 1053