libMesh
Loading...
Searching...
No Matches
petsc_vector.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18#include "libmesh/petsc_vector.h"
19
20#ifdef LIBMESH_HAVE_PETSC
21
22// libMesh includes
23#include "libmesh/petsc_matrix_base.h"
24#include "libmesh/dense_subvector.h"
25#include "libmesh/dense_vector.h"
26#include "libmesh/int_range.h"
27#include "libmesh/petsc_macro.h"
28#include "libmesh/wrapped_petsc.h"
29
30// TIMPI includes
31#include "timpi/op_function.h"
33#include "timpi/standard_type.h"
34
35// C++ includes
36#include <numeric> // std::iota
37
38namespace libMesh
39{
40//-----------------------------------------------------------------------
41// PetscVector members
42
43template <typename T>
45{
46 this->_restore_array();
47 libmesh_assert(this->closed());
48
49 PetscScalar value=0.;
50
51 LibmeshPetscCall(VecSum (_vec, &value));
52
53 return static_cast<T>(value);
54}
55
56
57
58template <typename T>
59template <NormType N>
61{
62 parallel_object_only();
63
64 this->_restore_array();
65 libmesh_assert(this->closed());
66
67 PetscReal value=0.;
68
69 LibmeshPetscCall(VecNorm (_vec, N, &value));
70
71 return static_cast<Real>(value);
72}
73template <typename T>
78template <typename T>
83template <typename T>
88
89
90
91template <typename T>
94{
95 parallel_object_only();
96
97 this->_restore_array();
98 libmesh_assert(this->closed());
99
100 this->add(1., v);
101
102 return *this;
103}
104
105
106
107template <typename T>
110{
111 parallel_object_only();
112
113 this->_restore_array();
114 libmesh_assert(this->closed());
115
116 this->add(-1., v);
117
118 return *this;
119}
120
121
122
123template <typename T>
125{
126 this->_restore_array();
127 libmesh_assert_less (i, size());
128
129 PetscInt i_val = static_cast<PetscInt>(i);
130 PetscScalar petsc_value = PS(value);
132 std::scoped_lock lock(this->_numeric_vector_mutex);
133 LibmeshPetscCall(VecSetValues (_vec, 1, &i_val, &petsc_value, INSERT_VALUES));
134
135 this->_is_closed = false;
136}
137
138
139
140template <typename T>
142{
143 parallel_object_only();
144
145
146 // VecReciprocal has been in PETSc since at least 2.3.3 days
147 LibmeshPetscCall(VecReciprocal(_vec));
148}
149
150
151
152template <typename T>
154{
155 parallel_object_only();
156
157
158 // We just call the PETSc VecConjugate
159 LibmeshPetscCall(VecConjugate(_vec));
160}
161
162
163
164template <typename T>
166{
167 this->_restore_array();
168 libmesh_assert_less (i, size());
169
170 PetscInt i_val = static_cast<PetscInt>(i);
171 PetscScalar petsc_value = PS(value);
172
173 std::scoped_lock lock(this->_numeric_vector_mutex);
174 LibmeshPetscCall(VecSetValues (_vec, 1, &i_val, &petsc_value, ADD_VALUES));
175
176 this->_is_closed = false;
177}
179
180
181template <typename T>
183 const std::vector<numeric_index_type> & dof_indices)
185 // If we aren't adding anything just return
186 if (dof_indices.empty())
187 return;
189 this->_restore_array();
191 const PetscInt * i_val = reinterpret_cast<const PetscInt *>(dof_indices.data());
192 const PetscScalar * petsc_value = pPS(v);
193
194 std::scoped_lock lock(this->_numeric_vector_mutex);
195 LibmeshPetscCall(VecSetValues (_vec, cast_int<PetscInt>(dof_indices.size()),
196 i_val, petsc_value, ADD_VALUES));
197
198 this->_is_closed = false;
199}
200
201
202
203template <typename T>
205 const SparseMatrix<T> & A_in)
206{
207 parallel_object_only();
208
209 this->_restore_array();
210 // Make sure the data passed in are really of Petsc types
211 const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
212 const PetscMatrixBase<T> * A = cast_ptr<const PetscMatrixBase<T> *>(&A_in);
213
214
215 // We shouldn't close() the matrix for you, as that would potentially modify the state of a const object.
216 if (!A->closed())
217 {
218 libmesh_warning("Matrix A must be assembled before calling PetscVector::add_vector(v, A).\n"
219 "Please update your code, as this warning will become an error in a future release.");
220 libmesh_deprecated();
221 const_cast<PetscMatrixBase<T> *>(A)->close();
222 }
223
224 // The const_cast<> is not elegant, but it is required since PETSc
225 // expects a non-const Mat.
226 LibmeshPetscCall(MatMultAdd(const_cast<PetscMatrixBase<T> *>(A)->mat(), v->_vec, _vec, _vec));
227}
228
229
230
231template <typename T>
233 const SparseMatrix<T> & A_in)
234{
235 parallel_object_only();
236
237 this->_restore_array();
238 // Make sure the data passed in are really of Petsc types
239 const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
240 const PetscMatrixBase<T> * A = cast_ptr<const PetscMatrixBase<T> *>(&A_in);
241
243 // We shouldn't close() the matrix for you, as that would potentially modify the state of a const object.
244 if (!A->closed())
245 {
246 libmesh_warning("Matrix A must be assembled before calling PetscVector::add_vector_transpose(v, A).\n"
247 "Please update your code, as this warning will become an error in a future release.");
248 libmesh_deprecated();
249 const_cast<PetscMatrixBase<T> *>(A)->close();
250 }
251
252 // The const_cast<> is not elegant, but it is required since PETSc
253 // expects a non-const Mat.
254 LibmeshPetscCall(MatMultTransposeAdd(const_cast<PetscMatrixBase<T> *>(A)->mat(), v->_vec, _vec, _vec));
255}
257
258
259template <typename T>
261 const SparseMatrix<T> & A_in)
262{
263 parallel_object_only();
265 this->_restore_array();
266 // Make sure the data passed in are really of Petsc types
267 const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
268 const PetscMatrixBase<T> * A = cast_ptr<const PetscMatrixBase<T> *>(&A_in);
269
270 // We shouldn't close() the matrix for you, as that would potentially modify the state of a const object.
271 if (!A->closed())
272 {
273 libmesh_warning("Matrix A must be assembled before calling PetscVector::add_vector_conjugate_transpose(v, A).\n"
274 "Please update your code, as this warning will become an error in a future release.");
275 libmesh_deprecated();
276 const_cast<PetscMatrixBase<T> *>(A)->close();
277 }
278
279 // Store a temporary copy since MatMultHermitianTransposeAdd doesn't seem to work
280 // TODO: Find out why MatMultHermitianTransposeAdd doesn't work, might be a PETSc bug?
281 std::unique_ptr<NumericVector<Number>> this_clone = this->clone();
282
283 // The const_cast<> is not elegant, but it is required since PETSc
284 // expects a non-const Mat.
285 LibmeshPetscCall(MatMultHermitianTranspose(const_cast<PetscMatrixBase<T> *>(A)->mat(), v->_vec, _vec));
286
287 // Add the temporary copy to the matvec result
288 this->add(1., *this_clone);
289}
290
292
293template <typename T>
294void PetscVector<T>::add (const T v_in)
296 this->_get_array(false);
298 for (numeric_index_type i=0; i<_local_size; i++)
299 _values[i] += PetscScalar(v_in);
300}
301
302
303
304template <typename T>
307 parallel_object_only();
309 this->add (1., v);
311
313
314template <typename T>
315void PetscVector<T>::add (const T a_in, const NumericVector<T> & v_in)
316{
317 parallel_object_only();
319 this->_restore_array();
320
321 // VecAXPY doesn't support &x==&y
322 if (this == &v_in)
323 {
324 this->scale(a_in+1);
325 return;
326 }
327
328 PetscScalar a = PS(a_in);
329
330 // Make sure the NumericVector passed in is really a PetscVector
331 const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
332 v->_restore_array();
334 libmesh_assert_equal_to (this->size(), v->size());
335
336 LibmeshPetscCall(VecAXPY(_vec, a, v->vec()));
337
338 libmesh_assert(this->comm().verify(
339 static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
340
341 if (this->is_effectively_ghosted())
342 VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
343
344 this->_is_closed = true;
345}
346
347
348
349template <typename T>
350void PetscVector<T>::insert (const T * v,
351 const std::vector<numeric_index_type> & dof_indices)
352{
353 if (dof_indices.empty())
354 return;
355
356 this->_restore_array();
357
358 PetscInt * idx_values = numeric_petsc_cast(dof_indices.data());
359 std::scoped_lock lock(this->_numeric_vector_mutex);
360 LibmeshPetscCall(VecSetValues (_vec, cast_int<PetscInt>(dof_indices.size()),
361 idx_values, pPS(v), INSERT_VALUES));
362
363 this->_is_closed = false;
364}
365
366
367
368template <typename T>
369void PetscVector<T>::scale (const T factor_in)
370{
371 parallel_object_only();
372
373 this->_restore_array();
374
375 PetscScalar factor = PS(factor_in);
376
377 LibmeshPetscCall(VecScale(_vec, factor));
378
379 libmesh_assert(this->comm().verify(
380 static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
381
382 if (this->is_effectively_ghosted())
383 VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
384}
385
386template <typename T>
388{
389 parallel_object_only();
390
391
392 const PetscVector<T> * v_vec = cast_ptr<const PetscVector<T> *>(&v);
393
394 LibmeshPetscCall(VecPointwiseMult(_vec, _vec, v_vec->_vec));
395
396 return *this;
397}
398
399template <typename T>
401{
402 parallel_object_only();
403
404
405 const PetscVector<T> * v_vec = cast_ptr<const PetscVector<T> *>(&v);
406
407 LibmeshPetscCall(VecPointwiseDivide(_vec, _vec, v_vec->_vec));
408
409 return *this;
410}
411
412template <typename T>
414{
415 parallel_object_only();
416
417 this->_restore_array();
418
419 LibmeshPetscCall(VecAbs(_vec));
420
421 libmesh_assert(this->comm().verify(
422 static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
423
424 if (this->is_effectively_ghosted())
425 VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
426}
427
428template <typename T>
430{
431 parallel_object_only();
432
433 this->_restore_array();
434
435 // Error flag
436
437 // Return value
438 PetscScalar value=0.;
439
440 // Make sure the NumericVector passed in is really a PetscVector
441 const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
442
443 // 2.3.x (at least) style. Untested for previous versions.
444 LibmeshPetscCall(VecDot(this->_vec, v->_vec, &value));
445
446 return static_cast<T>(value);
447}
448
449template <typename T>
451{
452 parallel_object_only();
453
454 this->_restore_array();
455
456 // Error flag
457
458 // Return value
459 PetscScalar value=0.;
460
461 // Make sure the NumericVector passed in is really a PetscVector
462 const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
463
464 // 2.3.x (at least) style. Untested for previous versions.
465 LibmeshPetscCall(VecTDot(this->_vec, v->_vec, &value));
466
467 return static_cast<T>(value);
468}
469
470
471template <typename T>
474{
475 parallel_object_only();
476
477 this->_restore_array();
478 libmesh_assert(this->closed());
480 PetscScalar s = PS(s_in);
481
482 if (this->size() != 0)
483 {
484 LibmeshPetscCall(VecSet(_vec, s));
485
486 libmesh_assert(this->comm().verify(
487 static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
488
489 if (this->is_effectively_ghosted())
490 VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
491 }
492
493 return *this;
494}
495
496
497
498template <typename T>
499NumericVector<T> &
501{
502 parallel_object_only();
503
504 // Make sure the NumericVector passed in is really a PetscVector
505 const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
506
507 *this = *v;
508
509 return *this;
510}
511
512
513
514template <typename T>
517{
518 enum AssignmentType { ParallelToSerial, SerialToParallel, SameToSame, Error };
519
520 parallel_object_only();
521 libmesh_assert(this->comm().verify(
522 static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
523 libmesh_assert(this->comm().verify(
524 static_cast<typename std::underlying_type<ParallelType>::type>(v.type())));
525
526 if (this == &v)
527 return *this;
528
529 this->_restore_array();
530 v._restore_array();
531
532 libmesh_assert_equal_to (this->size(), v.size());
534
535 AssignmentType assign_type = Error;
536 if (this->is_effectively_serial() && !v.is_effectively_serial())
537 assign_type = ParallelToSerial;
538 else if (!this->is_effectively_serial() && v.is_effectively_serial())
539 assign_type = SerialToParallel;
540 else if (this->local_size() == v.local_size())
541 assign_type = SameToSame;
542
543 libmesh_assert(this->comm().verify(
544 static_cast<typename std::underlying_type<AssignmentType>::type>(assign_type)));
545
546 switch (assign_type)
547 {
548 case ParallelToSerial:
549 {
550 // scatter from parallel to serial
551 libmesh_assert(v.comm().size() > 1);
553 LibmeshPetscCall(VecScatterCreateToAll(v._vec, scatter.get(), nullptr));
554 VecScatterBeginEnd(v.comm(), scatter, v._vec, _vec, INSERT_VALUES, SCATTER_FORWARD);
555 break;
556 }
557 case SameToSame:
558 // serial to serial or parallel to parallel
559 LibmeshPetscCall(VecCopy(v._vec, _vec));
560 break;
561 case SerialToParallel:
562 libmesh_not_implemented_msg(
563 "Scattering from a serial vector on every rank to a parallel vector is not behavior we "
564 "define because we do not verify the serial vector is the same on each rank");
565 default:
566 libmesh_error_msg("Unhandled vector combination");
567 }
568
569 libmesh_assert(this->comm().verify(
570 static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
571
572 if (this->is_effectively_ghosted())
573 VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
574
575 this->_is_closed = true;
576
577 return *this;
578}
579
580
581
582template <typename T>
584PetscVector<T>::operator = (const std::vector<T> & v)
585{
586 parallel_object_only();
587
588 this->_get_array(false);
589
594 if (this->size() == v.size())
595 {
596 numeric_index_type first = first_local_index();
597 numeric_index_type last = last_local_index();
598 for (numeric_index_type i=0; i<last-first; i++)
599 _values[i] = PS(v[first + i]);
600 }
601
606 else
607 {
608 for (numeric_index_type i=0; i<_local_size; i++)
609 _values[i] = PS(v[i]);
610 }
611
612 // Make sure ghost dofs are up to date
613 if (this->is_effectively_ghosted())
614 this->close();
615
616 return *this;
617}
618
619
620
621template <typename T>
623{
624 parallel_object_only();
625
626 libmesh_assert(this->comm().verify(
627 static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
628 libmesh_assert(this->comm().verify(
629 static_cast<typename std::underlying_type<ParallelType>::type>(v_local_in.type())));
630
631 v_local_in = *this;
632}
633
634
635
636template <typename T>
638 const std::vector<numeric_index_type> & /*send_list*/) const
639{
640 this->localize(v_local_in);
641}
642
643
644
645template <typename T>
646void PetscVector<T>::localize (std::vector<T> & v_local,
647 const std::vector<numeric_index_type> & indices) const
648{
649 parallel_object_only();
650
651 // Error code used to check the status of all PETSc function calls.
652
653 // Create a sequential destination Vec with the right number of entries on each proc.
655 LibmeshPetscCall(VecCreateSeq(PETSC_COMM_SELF, cast_int<PetscInt>(indices.size()), dest.get()));
656
657 // Create an IS using the libmesh routine. PETSc does not own the
658 // IS memory in this case, it is automatically cleaned up by the
659 // std::vector destructor.
660 PetscInt * idxptr =
661 indices.empty() ? nullptr : numeric_petsc_cast(indices.data());
663 LibmeshPetscCall(ISCreateGeneral(this->comm().get(), cast_int<PetscInt>(indices.size()), idxptr,
664 PETSC_USE_POINTER, is.get()));
665
666 // Create the VecScatter object. "PETSC_NULL" means "use the identity IS".
668 LibmeshPetscCall(VecScatterCreate(_vec,
669 /*src is=*/is,
670 /*dest vec=*/dest,
671 /*dest is=*/LIBMESH_PETSC_NULLPTR,
672 scatter.get()));
673
674 // Do the scatter
675 VecScatterBeginEnd(this->comm(), scatter, _vec, dest, INSERT_VALUES, SCATTER_FORWARD);
676
677 // Get access to the values stored in dest.
678 PetscScalar * values;
679 LibmeshPetscCall(VecGetArray (dest, &values));
680
681 // Store values into the provided v_local. Make sure there is enough
682 // space reserved and then clear out any existing entries before
683 // inserting.
684 v_local.reserve(indices.size());
685 v_local.clear();
686 v_local.insert(v_local.begin(), values, values+indices.size());
687
688 // We are done using it, so restore the array.
689 LibmeshPetscCall(VecRestoreArray (dest, &values));
690}
691
692
693
694template <typename T>
696 const numeric_index_type last_local_idx,
697 const std::vector<numeric_index_type> & send_list)
698{
699 parallel_object_only();
700
701 this->_restore_array();
702
703 libmesh_assert_less_equal (send_list.size(), this->size());
704 libmesh_assert_less_equal (last_local_idx+1, this->size());
705
706 const numeric_index_type my_size = this->size();
707 const numeric_index_type my_local_size = (last_local_idx + 1 - first_local_idx);
708
709 // Don't bother for serial cases
710 // if ((first_local_idx == 0) &&
711 // (my_local_size == my_size))
712 // But we do need to stay in sync for degenerate cases
713 if (this->n_processors() == 1)
714 return;
715
716
717 // Build a parallel vector, initialize it with the local
718 // parts of (*this)
719 PetscVector<T> parallel_vec(this->comm(), PARALLEL);
720
721 parallel_vec.init (my_size, my_local_size, true, PARALLEL);
722
723
724 // Copy part of *this into the parallel_vec
725 {
726 // Create idx, idx[i] = i+first_local_idx;
727 std::vector<PetscInt> idx(my_local_size);
728 std::iota (idx.begin(), idx.end(), first_local_idx);
729
730 // Create the index set & scatter objects
732 LibmeshPetscCall(ISCreateGeneral(this->comm().get(), my_local_size,
733 my_local_size ? idx.data() : nullptr, PETSC_USE_POINTER, is.get()));
734
736 LibmeshPetscCall(VecScatterCreate(_vec, is,
737 parallel_vec._vec, is,
738 scatter.get()));
739
740 // Perform the scatter
741 VecScatterBeginEnd(this->comm(), scatter, _vec, parallel_vec._vec, INSERT_VALUES, SCATTER_FORWARD);
742 }
743
744 // localize like normal
745 parallel_vec.close();
746 parallel_vec.localize (*this, send_list);
747 this->close();
748}
749
750
751
752template <typename T>
753void PetscVector<T>::localize (std::vector<T> & v_local) const
754{
755 parallel_object_only();
756
757 this->_restore_array();
758
759 // This function must be run on all processors at once
760 parallel_object_only();
761
762 const PetscInt n = this->size();
763 const PetscInt nl = this->local_size();
764 PetscScalar * values;
765
766 v_local.clear();
767 v_local.resize(n, 0.);
768
769 LibmeshPetscCall(VecGetArray (_vec, &values));
770
771 numeric_index_type ioff = first_local_index();
772
773 for (PetscInt i=0; i<nl; i++)
774 v_local[i+ioff] = static_cast<T>(values[i]);
775
776 LibmeshPetscCall(VecRestoreArray (_vec, &values));
777
778 this->comm().sum(v_local);
779}
780
781
782
783// Full specialization for Real datatypes
784#ifdef LIBMESH_USE_REAL_NUMBERS
785
786template <>
787void PetscVector<Real>::localize_to_one (std::vector<Real> & v_local,
789 timpi_mpi_var(pid)) const
790{
791 parallel_object_only();
792
793 this->_restore_array();
794
795 const PetscInt n = size();
796 PetscScalar * values;
797
798 // only one processor
799 if (n_processors() == 1)
800 {
801 v_local.resize(n);
802
803 LibmeshPetscCall(VecGetArray (_vec, &values));
804
805 for (PetscInt i=0; i<n; i++)
806 v_local[i] = static_cast<Real>(values[i]);
807
808 LibmeshPetscCall(VecRestoreArray (_vec, &values));
809 }
810
811 // otherwise multiple processors
812#ifdef LIBMESH_HAVE_MPI
813 else
814 {
815 if (pid == 0) // optimized version for localizing to 0
816 {
819
820 LibmeshPetscCall(VecScatterCreateToZero(_vec, ctx.get(), vout.get()));
821
822 VecScatterBeginEnd(this->comm(), ctx, _vec, vout, INSERT_VALUES, SCATTER_FORWARD);
823
824 if (processor_id() == 0)
825 {
826 v_local.resize(n);
827
828 LibmeshPetscCall(VecGetArray (vout, &values));
829
830 for (PetscInt i=0; i<n; i++)
831 v_local[i] = static_cast<Real>(values[i]);
832
833 LibmeshPetscCall(VecRestoreArray (vout, &values));
834 }
835 }
836 else
837 {
838 v_local.resize(n);
839
840 numeric_index_type ioff = this->first_local_index();
841 std::vector<Real> local_values (n, 0.);
842
843 {
844 LibmeshPetscCall(VecGetArray (_vec, &values));
845
846 const PetscInt nl = local_size();
847 for (PetscInt i=0; i<nl; i++)
848 local_values[i+ioff] = static_cast<Real>(values[i]);
849
850 LibmeshPetscCall(VecRestoreArray (_vec, &values));
851 }
852
853
854 MPI_Reduce (local_values.data(), v_local.data(), n,
857 this->comm().get());
858 }
859 }
860#endif // LIBMESH_HAVE_MPI
861}
862
863#endif
864
865
866// Full specialization for Complex datatypes
867#ifdef LIBMESH_USE_COMPLEX_NUMBERS
868
869template <>
870void PetscVector<Complex>::localize_to_one (std::vector<Complex> & v_local,
871 const processor_id_type pid) const
872{
873 parallel_object_only();
874
875 this->_restore_array();
876
877 const PetscInt n = size();
878 const PetscInt nl = local_size();
879 PetscScalar * values;
880
881
882 v_local.resize(n);
883
884
885 for (PetscInt i=0; i<n; i++)
886 v_local[i] = 0.;
887
888 // only one processor
889 if (n_processors() == 1)
890 {
891 LibmeshPetscCall(VecGetArray (_vec, &values));
892
893 for (PetscInt i=0; i<n; i++)
894 v_local[i] = static_cast<Complex>(values[i]);
895
896 LibmeshPetscCall(VecRestoreArray (_vec, &values));
897 }
898
899 // otherwise multiple processors
900 else
901 {
902 numeric_index_type ioff = this->first_local_index();
903
904 /* in here the local values are stored, acting as send buffer for MPI
905 * initialize to zero, since we collect using MPI_SUM
906 */
907 std::vector<Real> real_local_values(n, 0.);
908 std::vector<Real> imag_local_values(n, 0.);
909
910 {
911 LibmeshPetscCall(VecGetArray (_vec, &values));
912
913 // provide my local share to the real and imag buffers
914 for (PetscInt i=0; i<nl; i++)
915 {
916 real_local_values[i+ioff] = static_cast<Complex>(values[i]).real();
917 imag_local_values[i+ioff] = static_cast<Complex>(values[i]).imag();
918 }
919
920 LibmeshPetscCall(VecRestoreArray (_vec, &values));
921 }
922
923 /* have buffers of the real and imaginary part of v_local.
924 * Once MPI_Reduce() collected all the real and imaginary
925 * parts in these std::vector<Real>, the values can be
926 * copied to v_local
927 */
928 std::vector<Real> real_v_local(n);
929 std::vector<Real> imag_v_local(n);
930
931 // collect entries from other proc's in real_v_local, imag_v_local
932 MPI_Reduce (real_local_values.data(),
933 real_v_local.data(), n,
936 pid, this->comm().get());
937
938 MPI_Reduce (imag_local_values.data(),
939 imag_v_local.data(), n,
942 pid, this->comm().get());
943
944 // copy real_v_local and imag_v_local to v_local
945 for (PetscInt i=0; i<n; i++)
946 v_local[i] = Complex(real_v_local[i], imag_v_local[i]);
947 }
948}
949
950#endif
951
952
953
954template <typename T>
956 const NumericVector<T> & vec2)
957{
958 parallel_object_only();
959
960 this->_restore_array();
961
962 // Convert arguments to PetscVector*.
963 const PetscVector<T> * vec1_petsc = cast_ptr<const PetscVector<T> *>(&vec1);
964 const PetscVector<T> * vec2_petsc = cast_ptr<const PetscVector<T> *>(&vec2);
965
966 // Call PETSc function.
967 LibmeshPetscCall(VecPointwiseMult(_vec, vec1_petsc->vec(), vec2_petsc->vec()));
968
969 libmesh_assert(this->comm().verify(
970 static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
971
972 if (this->is_effectively_ghosted())
973 VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
974
975 this->_is_closed = true;
976}
977
978template <typename T>
980 const NumericVector<T> & vec2)
981{
982 parallel_object_only();
983
984 this->_restore_array();
985
986 // Convert arguments to PetscVector*.
987 const PetscVector<T> * const vec1_petsc = cast_ptr<const PetscVector<T> *>(&vec1);
988 const PetscVector<T> * const vec2_petsc = cast_ptr<const PetscVector<T> *>(&vec2);
989
990 // Call PETSc function.
991 LibmeshPetscCall(VecPointwiseDivide(_vec, vec1_petsc->vec(), vec2_petsc->vec()));
992
993 libmesh_assert(this->comm().verify(
994 static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
995
996 if (this->is_effectively_ghosted())
997 VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
998
999 this->_is_closed = true;
1000}
1001
1002template <typename T>
1003void PetscVector<T>::print_matlab (const std::string & name) const
1004{
1005 parallel_object_only();
1006
1007 this->_restore_array();
1008 libmesh_assert (this->closed());
1009
1010 // Create an ASCII file containing the matrix
1011 // if a filename was provided.
1012 if (name != "")
1013 {
1014 WrappedPetsc<PetscViewer> petsc_viewer;
1015
1016 LibmeshPetscCall(PetscViewerASCIIOpen(this->comm().get(),
1017 name.c_str(),
1018 petsc_viewer.get()));
1019
1020#if PETSC_VERSION_LESS_THAN(3,7,0)
1021 LibmeshPetscCall(PetscViewerSetFormat (petsc_viewer,
1022 PETSC_VIEWER_ASCII_MATLAB));
1023#else
1024 LibmeshPetscCall(PetscViewerPushFormat (petsc_viewer,
1025 PETSC_VIEWER_ASCII_MATLAB));
1026#endif
1027
1028 LibmeshPetscCall(VecView (_vec, petsc_viewer));
1029 }
1030
1031 // Otherwise the matrix will be dumped to the screen.
1032 else
1033 {
1034
1035#if PETSC_VERSION_LESS_THAN(3,7,0)
1036 LibmeshPetscCall(PetscViewerSetFormat (PETSC_VIEWER_STDOUT_WORLD,
1037 PETSC_VIEWER_ASCII_MATLAB));
1038#else
1039 LibmeshPetscCall(PetscViewerPushFormat (PETSC_VIEWER_STDOUT_WORLD,
1040 PETSC_VIEWER_ASCII_MATLAB));
1041#endif
1042
1043 LibmeshPetscCall(VecView (_vec, PETSC_VIEWER_STDOUT_WORLD));
1044 }
1045}
1046
1047
1048
1049
1050
1051template <typename T>
1053 const std::vector<numeric_index_type> & rows,
1054 const bool supplying_global_rows) const
1055{
1056 parallel_object_only();
1057
1058 libmesh_error_msg_if(
1059 subvector.is_effectively_ghosted(),
1060 "We do not support scattering parallel information to ghosts for subvectors");
1061
1062 this->_restore_array();
1063
1064 // PETSc data structures
1065
1066 // Make sure the passed in subvector is really a PetscVector
1067 PetscVector<T> * petsc_subvector = cast_ptr<PetscVector<T> *>(&subvector);
1068
1069 // If the petsc_subvector is already initialized, we assume that the
1070 // user has already allocated the *correct* amount of space for it.
1071 // If not, we use the appropriate PETSc routines to initialize it.
1072 if (!petsc_subvector->initialized())
1073 {
1074 if (this->is_effectively_serial())
1075 {
1076 libmesh_assert(this->comm().verify(rows.size()));
1077 LibmeshPetscCall(VecCreateSeq(this->comm().get(), rows.size(), &(petsc_subvector->_vec)));
1078
1079#ifdef LIBMESH_ENABLE_DEPRECATED
1080 // In the past we always created PARALLEL subvectors from
1081 // GHOSTED vectors, but this behavior must now be specified
1082 // downstream when it's desired, by setting the subvector
1083 // type in advance.
1084 petsc_subvector->_type = (this->type() == SERIAL) ? SERIAL : PARALLEL;
1085
1086 if (petsc_subvector->type() == AUTOMATIC &&
1087 this->type() != petsc_subvector->type())
1088 libmesh_deprecated();
1089#else
1090 // If the subvector already had a type, let's not change it.
1091 // If it was just at the default AUTOMATIC, let's pick the
1092 // true type from the supervector.
1093 if (petsc_subvector->type() == AUTOMATIC)
1094 petsc_subvector->_type = this->type();
1095#endif
1096 }
1097 else
1098 {
1099#ifndef LIBMESH_ENABLE_DEPRECATED
1100 // We're only supporting PARALLEL subvectors in parallel
1101 // so far, but we want to leave other possible API inputs
1102 // marked as invalid so we can add support for other
1103 // subvector types later.
1104 if (petsc_subvector->type() != PARALLEL &&
1105 (petsc_subvector->type() != AUTOMATIC ||
1106 this->type() != PARALLEL))
1107 libmesh_not_implemented_msg("Cannot yet create non-PARALLEL subvectors in parallel");
1108#endif
1109
1110 if (supplying_global_rows)
1111 // Initialize the petsc_subvector to have enough space to hold
1112 // the entries which will be scattered into it. Note: such an
1113 // init() function (where we let PETSc decide the number of local
1114 // entries) is not currently offered by the PetscVector
1115 // class. Should we differentiate here between sequential and
1116 // parallel vector creation based on this->n_processors() ?
1117 LibmeshPetscCall(VecCreateMPI(this->comm().get(),
1118 PETSC_DECIDE, // n_local
1119 cast_int<PetscInt>(rows.size()), // n_global
1120 &(petsc_subvector->_vec)));
1121 else
1122 LibmeshPetscCall(VecCreateMPI(this->comm().get(),
1123 cast_int<PetscInt>(rows.size()),
1124 PETSC_DETERMINE,
1125 &(petsc_subvector->_vec)));
1126
1127 // We created a parallel vector
1128 petsc_subvector->_type = PARALLEL;
1129 }
1130
1131 LibmeshPetscCall(VecSetFromOptions (petsc_subvector->_vec));
1132
1133
1134 // Mark the subvector as initialized
1135 petsc_subvector->_is_initialized = true;
1136 }
1137 else
1138 {
1139 petsc_subvector->_restore_array();
1140 }
1141
1142 std::vector<PetscInt> idx(rows.size());
1143 if (supplying_global_rows)
1144 std::iota (idx.begin(), idx.end(), 0);
1145 else
1146 {
1147 PetscInt start;
1148 LibmeshPetscCall(VecGetOwnershipRange(petsc_subvector->_vec, &start, nullptr));
1149 std::iota (idx.begin(), idx.end(), start);
1150 }
1151
1152 // Construct index sets
1153 WrappedPetsc<IS> parent_is;
1154 LibmeshPetscCall(ISCreateGeneral(this->comm().get(),
1155 cast_int<PetscInt>(rows.size()),
1156 numeric_petsc_cast(rows.data()),
1157 PETSC_USE_POINTER,
1158 parent_is.get()));
1159
1160 WrappedPetsc<IS> subvector_is;
1161 LibmeshPetscCall(ISCreateGeneral(this->comm().get(),
1162 cast_int<PetscInt>(rows.size()),
1163 idx.data(),
1164 PETSC_USE_POINTER,
1165 subvector_is.get()));
1166
1167 // Construct the scatter object
1169 LibmeshPetscCall(VecScatterCreate(this->_vec,
1170 parent_is,
1171 petsc_subvector->_vec,
1172 subvector_is,
1173 scatter.get()));
1174
1175 // Actually perform the scatter
1176 VecScatterBeginEnd(this->comm(), scatter, this->_vec, petsc_subvector->_vec, INSERT_VALUES, SCATTER_FORWARD);
1177
1178 petsc_subvector->_is_closed = true;
1179}
1180
1181
1182
1183template <typename T>
1184void PetscVector<T>::_get_array(bool read_only) const
1185{
1186 libmesh_assert (this->initialized());
1187
1188 bool initially_array_is_present = _array_is_present.load(std::memory_order_acquire);
1189
1190 // If we already have a read/write array - and we're trying
1191 // to get a read only array - let's just use the read write
1192 if (initially_array_is_present && read_only && !_values_read_only)
1193 _read_only_values = _values;
1194
1195 // If the values have already been retrieved and we're currently
1196 // trying to get a non-read only view (ie read/write) and the
1197 // values are currently read only... then we need to restore
1198 // the array first... and then retrieve it again.
1199 if (initially_array_is_present && !read_only && _values_read_only)
1200 {
1201 _restore_array();
1202 initially_array_is_present = false;
1203 }
1204
1205 if (!initially_array_is_present)
1206 {
1207 std::scoped_lock lock(_petsc_get_restore_array_mutex);
1208 if (!_array_is_present.load(std::memory_order_relaxed))
1209 {
1210 if (!this->is_effectively_ghosted())
1211 {
1212 if (read_only)
1213 {
1214 LibmeshPetscCall(VecGetArrayRead(_vec, &_read_only_values));
1215 _values_read_only = true;
1216 }
1217 else
1218 {
1219 LibmeshPetscCall(VecGetArray(_vec, &_values));
1220 _values_read_only = false;
1221 }
1222 _local_size = this->local_size();
1223 }
1224 else
1225 {
1226 LibmeshPetscCall(VecGhostGetLocalForm (_vec,&_local_form));
1227
1228 if (read_only)
1229 {
1230 LibmeshPetscCall(VecGetArrayRead(_local_form, &_read_only_values));
1231 _values_read_only = true;
1232 }
1233 else
1234 {
1235 LibmeshPetscCall(VecGetArray(_local_form, &_values));
1236 _values_read_only = false;
1237 }
1238
1239 PetscInt my_local_size = 0;
1240 LibmeshPetscCall(VecGetLocalSize(_local_form, &my_local_size));
1241 _local_size = static_cast<numeric_index_type>(my_local_size);
1242 }
1243
1244 { // cache ownership range
1245 PetscInt petsc_first=0, petsc_last=0;
1246 LibmeshPetscCall(VecGetOwnershipRange (_vec, &petsc_first, &petsc_last));
1247 _first = static_cast<numeric_index_type>(petsc_first);
1248 _last = static_cast<numeric_index_type>(petsc_last);
1249 }
1250 _array_is_present.store(true, std::memory_order_release);
1251 }
1252 }
1253}
1254
1255
1256
1257template <typename T>
1259{
1260 libmesh_error_msg_if(_values_manually_retrieved,
1261 "PetscVector values were manually retrieved but are being automatically restored!");
1262
1263 libmesh_assert (this->initialized());
1264 if (_array_is_present.load(std::memory_order_acquire))
1265 {
1266 std::scoped_lock lock(_petsc_get_restore_array_mutex);
1267 if (_array_is_present.load(std::memory_order_relaxed))
1268 {
1269 if (!this->is_effectively_ghosted())
1270 {
1271 if (_values_read_only)
1272 LibmeshPetscCall(VecRestoreArrayRead (_vec, &_read_only_values));
1273 else
1274 LibmeshPetscCall(VecRestoreArray (_vec, &_values));
1275
1276 _values = nullptr;
1277 }
1278 else
1279 {
1280 if (_values_read_only)
1281 LibmeshPetscCall(VecRestoreArrayRead (_local_form, &_read_only_values));
1282 else
1283 LibmeshPetscCall(VecRestoreArray (_local_form, &_values));
1284
1285 _values = nullptr;
1286 LibmeshPetscCall(VecGhostRestoreLocalForm (_vec,&_local_form));
1287 _local_form = nullptr;
1288 _local_size = 0;
1289 }
1290 _array_is_present.store(false, std::memory_order_release);
1291 }
1292 }
1293}
1294
1295template <typename T>
1296std::unique_ptr<NumericVector<T>>
1297PetscVector<T>::get_subvector(const std::vector<numeric_index_type> & rows)
1298{
1299 // Construct index set
1300 WrappedPetsc<IS> parent_is;
1301 LibmeshPetscCall(ISCreateGeneral(this->comm().get(),
1302 cast_int<PetscInt>(rows.size()),
1303 numeric_petsc_cast(rows.data()),
1304 PETSC_USE_POINTER,
1305 parent_is.get()));
1306
1307 Vec subvec;
1308 LibmeshPetscCall(VecGetSubVector(_vec, parent_is, &subvec));
1309
1310 this->_is_closed = false;
1311
1312 return std::make_unique<PetscVector<T>>(subvec, this->comm());
1313}
1314
1315template <typename T>
1316void
1318 const std::vector<numeric_index_type> & rows)
1319{
1320 auto * const petsc_subvector = cast_ptr<PetscVector<T> *>(subvector.get());
1321
1322 // Construct index set
1323 WrappedPetsc<IS> parent_is;
1324 LibmeshPetscCall(ISCreateGeneral(this->comm().get(),
1325 cast_int<PetscInt>(rows.size()),
1326 numeric_petsc_cast(rows.data()),
1327 PETSC_USE_POINTER,
1328 parent_is.get()));
1329
1330 Vec subvec = petsc_subvector->vec();
1331 LibmeshPetscCall(VecRestoreSubVector(_vec, parent_is, &subvec));
1332
1333 if (this->is_effectively_ghosted())
1334 VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
1335
1336 this->_is_closed = true;
1337}
1338
1339//------------------------------------------------------------------
1340// Explicit instantiations
1341template class LIBMESH_EXPORT PetscVector<Number>;
1342
1343} // namespace libMesh
1344
1345
1346
1347#endif // #ifdef LIBMESH_HAVE_PETSC
processor_id_type size() const
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
bool is_effectively_serial() const
ParallelType type() const
bool is_effectively_ghosted() const
ParallelType _type
Type of vector.
virtual bool initialized() const
bool _is_initialized
true once init() has been called.
bool _is_closed
Flag which tracks whether the vector's values are consistent on all processors after insertion or add...
virtual bool closed() const
const Parallel::Communicator & comm() const
This class provides a nice interface to the PETSc C-based data structures for parallel,...
virtual bool closed() const override
This class provides a nice interface to PETSc's Vec object.
virtual NumericVector< T > & operator*=(const NumericVector< T > &v) override
Computes the component-wise multiplication of this vector's entries by another's, .
virtual void insert(const T *v, const std::vector< numeric_index_type > &dof_indices) override
Inserts the entries of v in *this at the locations specified by v.
virtual NumericVector< T > & operator-=(const NumericVector< T > &v) override
Subtracts v from *this, .
virtual std::unique_ptr< NumericVector< T > > get_subvector(const std::vector< numeric_index_type > &rows) override
Creates a view into this vector using the indices in rows.
virtual Real linfty_norm() const override
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices) override
Computes , where v is a pointer and each dof_indices[i] specifies where to add value v[i].
virtual void set(const numeric_index_type i, const T value) override
Sets v(i) = value.
virtual numeric_index_type size() const override
virtual void close() override
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
virtual NumericVector< T > & operator/=(const NumericVector< T > &v) override
Computes the component-wise division of this vector's entries by another's, .
virtual void add_vector_transpose(const NumericVector< T > &v, const SparseMatrix< T > &A) override
Computes , i.e.
virtual NumericVector< T > & operator+=(const NumericVector< T > &v) override
Adds v to *this, .
virtual void restore_subvector(std::unique_ptr< NumericVector< T > > subvector, const std::vector< numeric_index_type > &rows) override
Restores a view into this vector using the indices in rows.
void _get_array(bool read_only) const
Queries the array (and the local form if the vector is ghosted) from PETSc.
virtual void localize_to_one(std::vector< T > &v_local, const processor_id_type proc_id=0) const override
Creates a local copy of the global vector in v_local only on processor proc_id.
virtual void conjugate() override
Negates the imaginary component of each entry in the vector.
void _restore_array() const
Restores the array (and the local form if the vector is ghosted) to PETSc.
virtual void print_matlab(const std::string &name="") const override
Print the contents of the vector in Matlab's sparse matrix format.
virtual void pointwise_mult(const NumericVector< T > &vec1, const NumericVector< T > &vec2) override
Computes (summation not implied) i.e.
virtual void scale(const T factor) override
Scale each element of the vector by the given factor.
virtual void pointwise_divide(const NumericVector< T > &vec1, const NumericVector< T > &vec2) override
Computes (summation not implied) i.e.
virtual Real l2_norm() const override
virtual void create_subvector(NumericVector< T > &subvector, const std::vector< numeric_index_type > &rows, bool supplying_global_rows=true) const override
Fills in subvector from this vector using the indices in rows.
virtual numeric_index_type local_size() const override
virtual void localize(std::vector< T > &v_local) const override
Creates a copy of the global vector in the local vector v_local.
virtual Real l1_norm() const override
T indefinite_dot(const NumericVector< T > &v) const
PetscVector< T > & operator=(const PetscVector< T > &v)
Copy assignment operator.
virtual void add(const numeric_index_type i, const T value) override
Adds value to the vector entry specified by i.
virtual void reciprocal() override
Computes the component-wise reciprocal, .
virtual T dot(const NumericVector< T > &v) const override
Vec _vec
Actual PETSc vector datatype to hold vector entries.
void add_vector_conjugate_transpose(const NumericVector< T > &v, const SparseMatrix< T > &A)
.
virtual T sum() const override
virtual void abs() override
Sets for each entry in the vector.
virtual void init(const numeric_index_type N, const numeric_index_type n_local, const bool fast=false, const ParallelType type=AUTOMATIC) override
Change the dimension of the vector to n.
Generic sparse matrix.
The libMesh namespace provides an interface to certain functionality in the library.
bool closed()
Checks that the library has been closed.
Definition libmesh.C:331
std::complex< Real > Complex
libmesh_assert(ctx)
PetscScalar * pPS(T *ptr)
dof_id_type numeric_index_type
Definition id_types.h:99
PetscInt * numeric_petsc_cast(const numeric_index_type *p)
PetscErrorCode PetscInt const PetscInt IS * is
bool initialized()
Checks that library initialization has been done.
Definition libmesh.C:324
PetscScalar PS(T val)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
Definition id_types.h:104
static const bool value
Definition xdr_io.C:55