deal.II version GIT relicensing-6842-g793a97d2aa 2026-10-02 14:00:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
psblas_vector.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2019 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13
15#include <deal.II/base/mpi.h>
16
18
19#ifdef DEAL_II_WITH_PSBLAS
20# include <psb_base_cbind.h>
21# include <psb_c_base.h>
22# include <psb_c_dbase.h>
23
25
26namespace PSCToolkitWrappers
27{
28
30 : psblas_vector(nullptr)
31 , psblas_context(InitFinalize::get_psblas_context())
32 , psblas_descriptor(nullptr)
33 , communicator(MPI_COMM_NULL)
34 , ghosted(false)
35 , state(internal::State::Default)
36 , last_action(VectorOperation::unknown)
37 , remote_entries_pending(false)
38 {}
39
40
41 Vector::Vector(const Vector &v)
42 : Vector::Vector()
43 {
44 if (v.has_ghost_elements())
45 reinit(v.owned_elements, v.ghost_indices, v.communicator);
46 else
47 reinit(v.owned_elements, v.communicator);
48
49 this->operator=(v);
50 }
51
52
54 {
55 if (state != internal::State::Default)
56 {
57 int ierr;
58 ierr = psb_c_dgefree(psblas_vector, psblas_descriptor.get());
59 AssertNothrow(ierr == 0, ExcFreePSBLASVector(ierr));
60 }
61 }
62
63
64
65 Vector::Vector(const IndexSet &local_partitioning, const MPI_Comm comm)
66 {
67 communicator = comm;
68 psblas_vector = nullptr;
69 ghosted = false;
70 // forward the call to reinit function below.
71 reinit(local_partitioning, communicator);
72 }
73
74
75
76 Vector::Vector(const IndexSet &local_partitioning,
77 const IndexSet &ghost_indices,
78 const MPI_Comm comm)
79 {
80 communicator = comm;
81 psblas_vector = nullptr;
82 ghosted = true;
83 // forward the call to reinit function taking ghost indices.
84 reinit(local_partitioning, ghost_indices, communicator);
85 }
86
87
88
89 void
90 Vector::reinit(const IndexSet &local_partitioning,
91 const MPI_Comm comm,
92 const bool omit_zeroing_entries)
93 {
94 Assert(comm != MPI_COMM_NULL,
95 ExcMessage("MPI_COMM_NULL passed to Vector::reinit()."));
96
97 // A PSBLAS descriptor describes the parallel partitioning, so it can only
98 // be recycled if that partitioning stays the same. Note: comparing global
99 // sizes is not enough because two **different** partitionings can have the
100 // same global size.
101 const bool partitioning_changes_locally =
102 (psblas_descriptor.get() == nullptr) || (ghosted == true) ||
103 (communicator != comm) ||
104 (owned_elements.size() != local_partitioning.size()) ||
105 (owned_elements != local_partitioning);
106
107 // Creating a descriptor is a collective operation, so the processes have to
108 // agree on whether one is built. If changes are only on some
109 // of the processes, we must therefore trigger the rebuild everywhere.
110 const bool partitioning_will_change =
111 Utilities::MPI::logical_or(partitioning_changes_locally, comm);
112
113 communicator = comm;
114 ghosted = false;
115 owned_elements = local_partitioning;
116 // index_within_set() requires a compressed index set
117 owned_elements.compress();
118
119 int ierr;
120 if (partitioning_will_change == true)
121 {
122 psblas_descriptor.reset(psb_c_new_descriptor(),
123 internal::DescriptorDeleter());
124
125 // Use get_index_vector() from IndexSet to get the indexes
126 const std::vector<types::global_dof_index> &indexes =
127 local_partitioning.get_index_vector();
128
129 const auto number_of_local_indexes =
130 indexes.size(); // Number of local indexes
131
132 std::vector<psb_l_t> vl(number_of_local_indexes);
133 for (std::size_t i = 0; i < number_of_local_indexes; ++i)
134 {
135 const auto psblas_index = static_cast<psb_l_t>(indexes[i]);
136 AssertIntegerConversion(psblas_index, indexes[i]);
137 vl[i] = psblas_index;
138 }
139
140 // Insert the indexes into the descriptor
141 psblas_context = InitFinalize::get_psblas_context();
142 ierr = psb_c_cdall_vl(number_of_local_indexes,
143 vl.data(),
144 *psblas_context,
145 psblas_descriptor.get());
146
147 // Free the vl array
148 Assert(ierr == 0, ExcInitializePSBLASDescriptor(ierr));
149 }
150
151 // Create a new PSBLAS vector and allocate mem space for vector
152 psblas_vector = psb_c_new_dvector();
153
154 ierr = psb_c_dgeall_remote_options(psblas_vector,
155 psblas_descriptor.get(),
156 PSB_MATBLD_REMOTE,
157 PSB_DUPL_DEF);
158 Assert(ierr == 0, ExcInitializePSBLASVector(ierr));
159
160 if (omit_zeroing_entries == false)
161 {
162 ierr = psb_c_dvect_set_scal(psblas_vector, 0.0);
163 Assert(ierr == 0,
164 ExcCallingPSBLASFunction(ierr, "psb_c_dvect_set_scal"));
165 }
166
167 state = internal::State::Assembled;
168 last_action = VectorOperation::unknown;
169 remote_entries_pending = false;
170 }
171
172
173
174 void
175 Vector::reinit(const IndexSet &local_partitioning,
176 const IndexSet &ghosts,
177 const MPI_Comm comm)
178 {
179 Assert(comm != MPI_COMM_NULL,
180 ExcMessage("MPI_COMM_NULL passed to Vector::reinit()."));
181
182 IndexSet new_ghost_indices = ghosts;
183 new_ghost_indices.subtract_set(local_partitioning);
184
185 // A descriptor describes the parallel partitioning including the halo, so
186 // it can only be recycled if both stay the same. Note: comparing global
187 // sizes is not enough because two **different** partitionings can have the
188 // same global size.
189 const bool partitioning_changes_locally =
190 (psblas_descriptor.get() == nullptr) || (ghosted == false) ||
191 (communicator != comm) ||
192 (owned_elements.size() != local_partitioning.size()) ||
193 (owned_elements != local_partitioning) ||
194 (ghost_indices.size() != new_ghost_indices.size()) ||
195 (ghost_indices != new_ghost_indices);
196
197 // Creating a descriptor is a collective operation, so the processes have to
198 // agree on whether one is built.
199 const bool partitioning_will_change =
200 Utilities::MPI::logical_or(partitioning_changes_locally, comm);
201
202 communicator = comm;
203 ghosted = true;
204 owned_elements = local_partitioning;
205 ghost_indices = std::move(new_ghost_indices);
206 // index_within_set() requires a compressed index set
207 owned_elements.compress();
208
209 int ierr;
210 if (partitioning_will_change == true)
211 {
212 psblas_descriptor.reset(psb_c_new_descriptor(),
213 internal::DescriptorDeleter());
214
215 // Use get_index_vector() from IndexSet to get the indexes
216 const std::vector<types::global_dof_index> &indexes =
217 local_partitioning.get_index_vector();
218
219 const auto number_of_local_indexes =
220 indexes.size(); // Number of local indexes
221
222 std::vector<psb_l_t> vl(number_of_local_indexes);
223 std::vector<psb_i_t> lidx(number_of_local_indexes);
224 for (std::size_t i = 0; i < number_of_local_indexes; ++i)
225 {
226 const auto psblas_index = static_cast<psb_l_t>(indexes[i]);
227 const auto idx = static_cast<psb_i_t>(i);
228 AssertIntegerConversion(psblas_index, indexes[i]);
230 vl[i] = psblas_index;
231 lidx[i] = idx;
232 }
233
234 // Ghost case. From the manual:
235 // 1) psb_cdall() with vl (global) and lidx (local)
236 // 2) psb_cdins(nz,ja,desc,info,lidx=lidx), where:
237 // - ja contains halo indices
238 // - lidx: corresponding local indices
239
240 // Insert the indexes into the descriptor
241 psblas_context = InitFinalize::get_psblas_context();
242 ierr = psb_c_cdall_vl_lidx(number_of_local_indexes,
243 vl.data(),
244 lidx.data(),
245 *psblas_context,
246 psblas_descriptor.get());
247
248 Assert(ierr == 0, ExcInitializePSBLASDescriptor(ierr));
249
250 // ... insert the ghost indices ...
251 const std::vector<types::global_dof_index> &ghost_indexes =
252 ghost_indices.get_index_vector();
253 const auto number_of_ghost_indices = ghost_indexes.size();
254
255 std::vector<psb_l_t> global_ghost_indices(number_of_ghost_indices);
256 std::vector<psb_i_t> local_ghost_indices(number_of_ghost_indices);
257
258 psb_i_t extended_idx_counter = number_of_local_indexes;
259 for (std::size_t i = 0; i < number_of_ghost_indices; ++i)
260 {
261 const auto psblas_index = static_cast<psb_l_t>(ghost_indexes[i]);
262 AssertIntegerConversion(psblas_index, ghost_indexes[i]);
263 global_ghost_indices[i] = psblas_index;
264 const auto idx = static_cast<psb_i_t>(extended_idx_counter);
265 AssertIntegerConversion(idx, extended_idx_counter);
266 local_ghost_indices[i] = extended_idx_counter++;
267 }
268
269
270 ierr = psb_c_cdins_lidx(number_of_ghost_indices,
271 global_ghost_indices.data(),
272 local_ghost_indices.data(),
273 psblas_descriptor.get());
274
275 Assert(ierr == 0, ExcCallingPSBLASFunction(ierr, "psb_c_cdins_lidx"));
276 }
277
278 // Assemble the descriptor first so that the halo (ghost) information is
279 // known before the vector is allocated and assembled.
280 if (!psb_c_cd_is_asb(psblas_descriptor.get()))
281 {
282 ierr = psb_c_cdasb(psblas_descriptor.get());
283 Assert(ierr == 0, ExcAssemblePSBLASDescriptor(ierr));
284 }
285
286 // Create a new PSBLAS vector and allocate mem space for it
287 psblas_vector = psb_c_new_dvector();
288
289 ierr = psb_c_dgeall_remote_options(psblas_vector,
290 psblas_descriptor.get(),
291 PSB_MATBLD_REMOTE,
292 PSB_DUPL_DEF);
293 Assert(ierr == 0, ExcInitializePSBLASVector(ierr));
294
295 // Assemble the vector so that storage for the ghost (halo) elements is
296 // allocated. This is required for update_ghost_values() (psb_c_dhalo) to
297 // work correctly.
298 ierr = psb_c_dgeasb_options(psblas_vector,
299 psblas_descriptor.get(),
300 PSB_DUPL_DEF);
301 Assert(ierr == 0, ExcAssemblePSBLASVector(ierr));
302
303 state = internal::State::Assembled;
304 last_action = VectorOperation::unknown;
305 remote_entries_pending = false;
306 }
307
308
309
310 void
311 Vector::reinit(const Vector &v, const bool omit_zeroing_entries)
312 {
313 psblas_descriptor = v.psblas_descriptor;
314 if (v.has_ghost_elements())
315 {
317 v.ghost_indices,
319 if (!omit_zeroing_entries)
320 {
321 int ierr = psb_c_dvect_set_scal(psblas_vector, 0.0);
322 Assert(ierr == 0,
323 ExcCallingPSBLASFunction(ierr, "psb_c_dvect_set_scal"));
324 }
325 }
326 else
327 {
328 reinit(v.owned_elements,
330 omit_zeroing_entries);
331
332 int ierr;
333 if (!psb_c_cd_is_asb(psblas_descriptor.get()))
334 {
335 ierr = psb_c_cdasb(psblas_descriptor.get());
336 Assert(ierr == 0, ExcAssemblePSBLASDescriptor(ierr));
337 }
338 ierr = psb_c_dgeasb_options(psblas_vector,
339 psblas_descriptor.get(),
340 PSB_DUPL_DEF);
341 Assert(ierr == 0, ExcAssemblePSBLASVector(ierr));
342 }
343 }
344
345
346
347 Vector &
348 Vector::operator=(const Vector &v)
349 {
350 Assert(v.last_action == VectorOperation::unknown,
351 ExcWrongMode(VectorOperation::unknown, v.last_action));
352 Assert(last_action == VectorOperation::unknown,
353 ExcWrongMode(VectorOperation::unknown, last_action));
354 Assert(v.state == internal::State::Assembled,
355 ExcInvalidStateAssembled(v.state));
356
357 // Vectors can have different sizes. If so, we first resize the vector
358 if (size() != v.size())
359 {
360 // since v has been assembled, we can recycle its descriptor
361 psblas_descriptor = v.psblas_descriptor;
362 if (v.has_ghost_elements())
364 v.ghost_indices,
366 else
367 reinit(v.owned_elements, v.get_mpi_communicator(), true);
368 }
369
370 // Copy only the locally owned entries from v into this vector. We use
371 // psb_c_dgeaxpby (this = 1.0 * v + 0.0 * this)
372 int ierr = psb_c_dgeaxpby(value_type(1.0),
373 v.psblas_vector,
374 value_type(0.0),
375 psblas_vector,
376 psblas_descriptor.get());
377 AssertThrow(ierr == 0, ExcAXPBY(ierr));
378
379 // If current vector has ghost elements, update them
380 if (has_ghost_elements())
382
383 state = internal::State::Assembled;
384 remote_entries_pending = false;
385
386 return *this;
387 }
388
389
390
391 Vector &
393 {
395 Assert(state != internal::State::Default, ExcInvalidState(state));
396 int ierr = psb_c_dvect_set_scal(psblas_vector, s);
397 Assert(ierr == 0, ExcCallingPSBLASFunction(ierr, "psb_c_dvect_set_scal"));
398 return *this;
399 }
400
401
402
405 {
406 return communicator;
407 }
408
409
410
411 psb_c_descriptor *
412 Vector::get_psblas_descriptor() const
413 {
414 return psblas_descriptor.get();
415 }
416
417
418
419 psb_c_dvector *
420 Vector::get_psblas_vector() const
421 {
422 return psblas_vector;
423 }
424
425
426
427 void
428 Vector::clear()
429 {
430 if (state != internal::State::Default)
431 {
432 int ierr = psb_c_dgefree(psblas_vector, psblas_descriptor.get());
433 Assert(ierr == 0, ExcFreePSBLASVector(ierr));
434
435 // Reset the vector
436 psblas_vector = nullptr;
437 owned_elements.clear();
438 owned_elements.set_size(0);
439 ghost_indices.clear();
440 owned_elements.set_size(0);
441 state = internal::State::Default;
442 last_action = VectorOperation::unknown;
443 remote_entries_pending = false;
444 }
445 }
446
447
448
450 Vector::linfty_norm() const
451 {
452 Assert(state == internal::State::Assembled,
453 ExcInvalidStateAssembled(state));
454 return psb_c_dgenrmi(psblas_vector, psblas_descriptor.get());
455 }
456
457
458
460 Vector::l1_norm() const
461 {
462 Assert(state == internal::State::Assembled,
463 ExcInvalidStateAssembled(state));
464 return psb_c_dgeasum(psblas_vector, psblas_descriptor.get());
465 }
466
467
468
470 Vector::l2_norm() const
471 {
472 Assert(state == internal::State::Assembled,
473 ExcInvalidStateAssembled(state));
474 return psb_c_dgenrm2(psblas_vector, psblas_descriptor.get());
475 }
476
477
478
480 Vector::mean_value() const
481 {
482 const value_type *start_ptr = psb_c_dvect_f_get_pnt(psblas_vector);
483 const value_type *end_ptr = start_ptr + locally_owned_size();
484
485 value_type local_sum_of_values = 0.0;
486 for (const value_type *ptr = start_ptr; ptr != end_ptr; ++ptr)
487 local_sum_of_values += *ptr;
488
489 return Utilities::MPI::sum(local_sum_of_values, communicator) / size();
490 }
491
492
493
494 bool
495 Vector::all_zero() const
496 {
497 // we get a pointer to the underlying vector and check if all
498 // entries are zero.
499 const value_type *start_ptr = psb_c_dvect_f_get_pnt(psblas_vector);
500 Assert(start_ptr != nullptr,
501 ExcMessage("Error getting underlying PSBLAS vector."));
502
503 const bool has_nonzero_local =
504 std::any_of(start_ptr,
505 start_ptr + locally_owned_size(),
506 [](const value_type &val) { return val != value_type(); });
507
508 unsigned int num_nonzero =
509 Utilities::MPI::sum(has_nonzero_local ? 1 : 0, communicator);
510 return num_nonzero == 0;
511 }
512
513
514
515 void
516 Vector::equ(const value_type a, const Vector &v)
517 {
518 AssertDimension(size(), v.size());
521
522 // do the analogous to VecAXPBY(vector, a, 0.0, v.vector) in PETSc
523 int ierr = psb_c_dgeaxpby(
524 a, v.psblas_vector, 0.0, psblas_vector, psblas_descriptor.get());
525 AssertThrow(ierr == 0, ExcAXPBY(ierr));
526 }
527
528
529
532 {
533 return owned_elements.n_elements();
534 }
535
536
537
539 Vector::operator*(const Vector &v) const
540 {
541 AssertDimension(size(), v.size());
542 return psb_c_dgedot(psblas_vector,
543 v.psblas_vector,
544 psblas_descriptor.get());
545 }
546
547
548
549 Vector &
550 Vector::operator+=(const Vector &v)
551 {
552 AssertDimension(size(), v.size());
554 int ierr = psb_c_dgeaxpby(value_type(1.0),
555 v.psblas_vector,
556 1.0,
557 psblas_vector,
558 psblas_descriptor.get());
559 AssertThrow(ierr == 0, ExcAXPBY(ierr));
560 return *this;
561 }
562
563
564 Vector &
565 Vector::operator-=(const Vector &v)
566 {
567 AssertDimension(size(), v.size());
569 int ierr = psb_c_dgeaxpby(value_type(-1.0),
570 v.psblas_vector,
571 1.0,
572 psblas_vector,
573 psblas_descriptor.get());
574 AssertThrow(ierr == 0, ExcAXPBY(ierr));
575 return *this;
576 }
577
578
579 void
580 Vector::set(const std::vector<Vector::size_type> &indices,
581 const std::vector<Vector::value_type> &values)
582 {
584 Assert(state != internal::State::Default, ExcInvalidState(state));
585 AssertDimension(indices.size(), values.size());
586
587 value_type *const local_values = psb_c_dvect_f_get_pnt(psblas_vector);
588
589 for (std::size_t i = 0; i < indices.size(); ++i)
590 {
591 Assert(owned_elements.is_element(indices[i]),
592 ExcMessage("You are trying to write to an element of the vector "
593 "that is not locally owned. This is not allowed for "
594 "the current interface to PSBLAS vectors."));
595 local_values[owned_elements.index_within_set(indices[i])] = values[i];
596 }
597 }
598
599
600
601 void
602 Vector::add(const std::vector<Vector::size_type> &indices,
603 const std::vector<Vector::value_type> &values)
604 {
606 Assert(state != internal::State::Default, ExcInvalidState(state));
607 Assert(indices.size() == values.size(),
608 ExcMessage("Indices and values size mismatch."));
609
610 value_type *const local_values = psb_c_dvect_f_get_pnt(psblas_vector);
611
612 // Contributions to entries owned by another process cannot be applied
613 // locally; hand them to PSBLAS, which exchanges them in compress().
614 std::vector<psb_l_t> irw;
615 std::vector<psb_d_t> val;
616
617 for (std::size_t i = 0; i < indices.size(); ++i)
618 if (owned_elements.is_element(indices[i]))
619 local_values[owned_elements.index_within_set(indices[i])] += values[i];
620 else
621 {
622 const auto psblas_index = static_cast<psb_l_t>(indices[i]);
623 AssertIntegerConversion(psblas_index, indices[i]);
624 irw.push_back(psblas_index);
625 val.push_back(values[i]);
626 }
627
628 if (irw.empty() == false)
629 {
630 const auto nz = static_cast<psb_i_t>(irw.size());
631 AssertIntegerConversion(nz, irw.size());
632
633 const int ierr = psb_c_dgeins(
634 nz, irw.data(), val.data(), psblas_vector, psblas_descriptor.get());
635 Assert(ierr == 0, ExcInsertionInPSBLASVector(ierr));
636
637 remote_entries_pending = true;
638 }
639 }
640
641
642
643 void
644 Vector::add(const value_type s, const Vector &V)
645 {
648 int ierr = psb_c_dgeaxpby(s,
649 V.psblas_vector,
650 value_type(1.0),
651 psblas_vector,
652 psblas_descriptor.get());
653 Assert(ierr == 0, ExcAXPBY(ierr));
654 }
655
656
657
658 void
659 Vector::add(const value_type s)
660 {
663 value_type *start_ptr = psb_c_dvect_f_get_pnt(psblas_vector);
664 value_type *end_ptr = start_ptr + locally_owned_size();
665 while (start_ptr != end_ptr)
666 {
667 *start_ptr += s;
668 ++start_ptr;
669 }
670 }
671
672
673
674 void
675 Vector::sadd(const value_type s, const Vector &V)
676 {
679 int ierr = psb_c_dgeaxpby(value_type(1.0),
680 V.psblas_vector,
681 s,
682 psblas_vector,
683 psblas_descriptor.get());
684 Assert(ierr == 0, ExcAXPBY(ierr));
685 }
686
687
688 void
689 Vector::sadd(const value_type s, const value_type a, const Vector &V)
690 {
693 int ierr = psb_c_dgeaxpby(
694 a, V.psblas_vector, s, psblas_vector, psblas_descriptor.get());
695 Assert(ierr == 0, ExcAXPBY(ierr));
696 }
697
698
699 void
700 Vector::scale(const Vector &v)
701 {
703 AssertDimension(size(), v.size());
704 value_type *start_ptr = psb_c_dvect_f_get_pnt(psblas_vector);
705 value_type *start_ptr_v = psb_c_dvect_f_get_pnt(v.psblas_vector);
706 value_type *end_ptr = start_ptr + locally_owned_size();
707 while (start_ptr != end_ptr)
708 {
709 *start_ptr *= (*start_ptr_v);
710 ++start_ptr;
711 ++start_ptr_v;
712 }
713 }
714
715
716
718 Vector::add_and_dot(const value_type a, const Vector &V, const Vector &W)
719 {
720 // forward the call to add()...
721 add(a, V);
722 // ... and then do the dot product
723 return psb_c_dgedot(psblas_vector,
724 W.psblas_vector,
725 psblas_descriptor.get());
726 }
727
728
729
730 void
732 {
733 // simply swap pointers
734 std::swap(psblas_vector, v.psblas_vector);
735 std::swap(psblas_descriptor, v.psblas_descriptor);
736 std::swap(ghosted, v.ghosted);
737 std::swap(this->last_action, v.last_action);
738 std::swap(communicator, v.communicator);
739 std::swap(state, v.state);
740 std::swap(remote_entries_pending, v.remote_entries_pending);
741 std::swap(owned_elements, v.owned_elements);
742 // We use a temp variable to swap the IndexSets
743 IndexSet temp(ghost_indices);
744 ghost_indices = v.ghost_indices;
745 v.ghost_indices = temp;
746 }
747
748
749
750 void
752 {
753 Assert(has_ghost_elements() == false,
754 ExcMessage("Calling compress() is only useful if a vector "
755 "has been written into, but this is a vector with ghost "
756 "elements and consequently is read-only. It does "
757 "not make sense to call compress() for such "
758 "vectors."));
759
760 // We check the state of the vector...
761 Assert(state != internal::State::Default, ExcInvalidDefault());
762 // ... and if the last action was compatible with what we want to do
764 last_action == VectorOperation::unknown || last_action == operation,
766 "Missing compress() or calling with wrong VectorOperation argument."));
767
768 // We check if the descriptor has already been assembled somewhere
769 int ierr;
770 if (!psb_c_cd_is_asb(psblas_descriptor.get()))
771 {
772 ierr = psb_c_cdasb(psblas_descriptor.get());
773 Assert(ierr == 0, ExcAssemblePSBLASDescriptor(ierr));
774 }
775
776 // Entries belonging to this process have already been written into the
777 // local storage, so only contributions destined for other processes
778 // require an assembly step. Since the assembly is a collective, all
779 // processes must agree on whether it is performed.
780 if (Utilities::MPI::logical_or(remote_entries_pending, communicator))
781 {
782 Assert(operation == VectorOperation::add ||
783 operation == VectorOperation::insert,
785
786# ifdef FALSE
787 // Uncomment this path when psb_c_dgereinit() is available in the PSBLAS
788
789 // Move the vector into update state, in which psb_geasb() only
790 // exchanges the pending remote contributions and leaves the entries
791 // we already hold alone.
792 ierr = psb_c_dgereinit(psblas_vector, psblas_descriptor.get(), false);
793 Assert(ierr == 0, ExcCallingPSBLASFunction(ierr, "psb_c_dgereinit"));
794# else
795 // Without psb_c_dgereinit() the vector stays in build state, where
796 // psb_geasb() rebuilds it from the list of inserted coefficients. The
797 // entries we already hold therefore have to be put onto that list in
798 // order to survive.
799 const std::vector<types::global_dof_index> &indices =
800 owned_elements.get_index_vector();
801 const value_type *const local_values =
802 psb_c_dvect_f_get_pnt(psblas_vector);
803
804 std::vector<psb_l_t> irw(indices.size());
805 std::vector<psb_d_t> val(indices.size());
806 for (std::size_t i = 0; i < indices.size(); ++i)
807 {
808 const auto psblas_index = static_cast<psb_l_t>(indices[i]);
809 AssertIntegerConversion(psblas_index, indices[i]);
810 irw[i] = psblas_index;
811 val[i] = local_values[i];
812 }
813
814 const auto nz = static_cast<psb_i_t>(irw.size());
815 AssertIntegerConversion(nz, irw.size());
816
817 ierr = psb_c_dgeins(
818 nz, irw.data(), val.data(), psblas_vector, psblas_descriptor.get());
819 Assert(ierr == 0, ExcInsertionInPSBLASVector(ierr));
820# endif
821
822 ierr = psb_c_dgeasb_options(psblas_vector,
823 psblas_descriptor.get(),
824 operation == VectorOperation::add ?
825 PSB_DUPL_ADD :
826 PSB_DUPL_DEF);
827 Assert(ierr == 0, ExcAssemblePSBLASVector(ierr));
828
829 remote_entries_pending = false;
830 }
831
832 state = internal::State::Assembled;
833 last_action = VectorOperation::unknown;
834 }
835
836
837
838 void
840 {
841 if (ghosted)
842 {
843 int ierr = psb_c_dhalo(psblas_vector, psblas_descriptor.get());
844 Assert(ierr == 0, ExcMessage("Error while updating ghost values."));
845 }
846 }
847
848
849 std::size_t
851 {
852 std::size_t mem = MemoryConsumption::memory_consumption(ghosted) +
854
855 // mem += psb_c_sizeof(psblas_vector); TODO[MF]: missing from PSBLAS's
856 // interface
857 return mem;
858 }
859
860
861} // namespace PSCToolkitWrappers
862
864#endif
size_type size() const
size_type size() const
Definition index_set.h:1759
void subtract_set(const IndexSet &other)
Definition index_set.cc:496
void compress() const
Definition index_set.h:1767
std::vector< size_type > get_index_vector() const
Definition index_set.cc:911
bool has_ghost_elements() const
void add(const std::vector< size_type > &indices, const std::vector< OtherNumber > &values)
Vector< Number > & operator=(const Number s)
Number operator*(const Vector< Number2 > &V) const
Number mean_value() const
Number add_and_dot(const Number a, const Vector< Number > &V, const Vector< Number > &W)
MPI_Comm get_mpi_communicator() const
virtual size_type size() const override
void equ(const Number a, const Vector< Number > &u)
void sadd(const Number s, const Vector< Number > &V)
friend class Vector
Definition vector.h:1102
real_type l2_norm() const
virtual ~Vector() override=default
real_type linfty_norm() const
Vector< Number > & operator+=(const Vector< Number > &V)
void scale(const Vector< Number > &scaling_factors)
IndexSet locally_owned_elements() const
AlignedVector< Number > values
Definition vector.h:1075
virtual void reinit(const size_type N, const bool omit_zeroing_entries=false)
size_type locally_owned_size() const
virtual void swap(Vector< Number > &v) noexcept
void compress(VectorOperation::values operation=VectorOperation::unknown) const
Vector< Number > & operator-=(const Vector< Number > &V)
void update_ghost_values() const
bool all_zero() const
std::size_t memory_consumption() const
real_type l1_norm() const
Number value_type
Definition vector.h:115
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define AssertIntegerConversion(index1, index2)
static ::ExceptionBase & ExcGhostsPresent()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertIsFinite(number)
#define AssertDimension(dim1, dim2)
#define AssertNothrow(cond, exc)
static ::ExceptionBase & ExcInvalidState()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
const MPI_Comm comm
Definition mpi.cc:912
constexpr char V
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
T sum(const T &t, const MPI_Comm mpi_communicator)
T logical_or(const T &t, const MPI_Comm mpi_communicator)
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)