libMesh
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 
38 namespace libMesh
39 {
40 //-----------------------------------------------------------------------
41 // PetscVector members
42 
43 template <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 
58 template <typename T>
59 template <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 }
73 template <typename T>
75 {
76  return PetscVector<T>::norm<NORM_1>();
77 }
78 template <typename T>
80 {
81  return PetscVector<T>::norm<NORM_2>();
82 }
83 template <typename T>
85 {
86  return PetscVector<T>::norm<NORM_INFINITY>();
87 }
88 
89 
90 
91 template <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 
107 template <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 
123 template <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);
131 
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 
140 template <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 
152 template <typename T>
154 {
155  parallel_object_only();
156 
157 
158  // We just call the PETSc VecConjugate
159  LibmeshPetscCall(VecConjugate(_vec));
160 }
161 
162 
163 
164 template <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 }
178 
179 
180 
181 template <typename T>
182 void PetscVector<T>::add_vector (const T * v,
183  const std::vector<numeric_index_type> & dof_indices)
184 {
185  // If we aren't adding anything just return
186  if (dof_indices.empty())
187  return;
188 
189  this->_restore_array();
190 
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 
203 template <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 
231 template <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 
242 
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 }
256 
257 
258 
259 template <typename T>
261  const SparseMatrix<T> & A_in)
262 {
263  parallel_object_only();
264 
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 
291 
292 
293 template <typename T>
294 void PetscVector<T>::add (const T v_in)
295 {
296  this->_get_array(false);
297 
298  for (numeric_index_type i=0; i<_local_size; i++)
299  _values[i] += PetscScalar(v_in);
300 }
301 
302 
303 
304 template <typename T>
306 {
307  parallel_object_only();
308 
309  this->add (1., v);
310 }
311 
312 
313 
314 template <typename T>
315 void PetscVector<T>::add (const T a_in, const NumericVector<T> & v_in)
316 {
317  parallel_object_only();
318 
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();
333 
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 
349 template <typename T>
350 void 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 
368 template <typename T>
369 void 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 
386 template <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 
399 template <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 
412 template <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 
428 template <typename T>
429 T PetscVector<T>::dot (const NumericVector<T> & v_in) const
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 
449 template <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 
471 template <typename T>
474 {
475  parallel_object_only();
476 
477  this->_restore_array();
478  libmesh_assert(this->closed());
479 
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 
498 template <typename 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 
514 template <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());
533  libmesh_assert (v.closed());
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);
552  WrappedPetsc<VecScatter> scatter;
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 
582 template <typename T>
584 PetscVector<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 
621 template <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 
636 template <typename T>
638  const std::vector<numeric_index_type> & /*send_list*/) const
639 {
640  this->localize(v_local_in);
641 }
642 
643 
644 
645 template <typename T>
646 void 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.
654  WrappedPetsc<Vec> dest;
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".
667  WrappedPetsc<VecScatter> scatter;
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 
694 template <typename T>
695 void PetscVector<T>::localize (const numeric_index_type first_local_idx,
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 
735  WrappedPetsc<VecScatter> scatter;
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 
752 template <typename T>
753 void 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 
786 template <>
787 void PetscVector<Real>::localize_to_one (std::vector<Real> & v_local,
788  const processor_id_type
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  {
817  WrappedPetsc<Vec> vout;
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 
869 template <>
870 void 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 
954 template <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 
978 template <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 
1002 template <typename T>
1003 void 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 
1051 template <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
1168  WrappedPetsc<VecScatter> scatter;
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 
1183 template <typename T>
1184 void 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 
1257 template <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 
1295 template <typename T>
1296 std::unique_ptr<NumericVector<T>>
1297 PetscVector<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 
1315 template <typename T>
1316 void
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
1341 template class LIBMESH_EXPORT PetscVector<Number>;
1342 
1343 } // namespace libMesh
1344 
1345 
1346 
1347 #endif // #ifdef LIBMESH_HAVE_PETSC
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
virtual Real l2_norm() const override
Definition: petsc_vector.C:79
bool closed()
Checks that the library has been closed.
Definition: libmesh.C:331
virtual void localize(std::vector< T > &v_local) const override
Creates a copy of the global vector in the local vector v_local.
Definition: petsc_vector.C:753
This class provides a nice interface to PETSc&#39;s Vec object.
Definition: petsc_vector.h:73
void add_vector_conjugate_transpose(const NumericVector< T > &v, const SparseMatrix< T > &A)
.
Definition: petsc_vector.C:260
virtual void add_vector_transpose(const NumericVector< T > &v, const SparseMatrix< T > &A) override
Computes , i.e.
Definition: petsc_vector.C:232
boost::multiprecision::float128 real(const boost::multiprecision::float128 in)
This class provides a nice interface to the PETSc C-based data structures for parallel, sparse matrices.
virtual numeric_index_type size() const override
virtual Real linfty_norm() const override
Definition: petsc_vector.C:84
void scale(MeshBase &mesh, const Real xs, const Real ys=0., const Real zs=0.)
Scales the mesh.
virtual bool initialized() const
void _get_array(bool read_only) const
Queries the array (and the local form if the vector is ghosted) from PETSc.
virtual numeric_index_type local_size() const override
virtual void add(const numeric_index_type i, const T value) override
Adds value to the vector entry specified by i.
Definition: petsc_vector.C:165
Vec _vec
Actual PETSc vector datatype to hold vector entries.
Definition: petsc_vector.h:364
Provides a uniform interface to vector storage schemes for different linear algebra libraries...
Definition: vector_fe_ex5.C:44
const Parallel::Communicator & comm() const
PetscScalar * pPS(T *ptr)
Definition: petsc_macro.h:174
bool is_effectively_ghosted() const
bool _is_initialized
true once init() has been called.
The libMesh namespace provides an interface to certain functionality in the library.
virtual void pointwise_divide(const NumericVector< T > &vec1, const NumericVector< T > &vec2) override
Computes (summation not implied) i.e.
Definition: petsc_vector.C:979
void _restore_array() const
Restores the array (and the local form if the vector is ghosted) to PETSc.
uint8_t processor_id_type
Definition: id_types.h:104
PetscInt * numeric_petsc_cast(const numeric_index_type *p)
Generic sparse matrix.
Definition: vector_fe_ex5.C:46
PetscScalar PS(T val)
Definition: petsc_macro.h:168
processor_id_type size() const
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.
Definition: petsc_vector.C:350
virtual void pointwise_mult(const NumericVector< T > &vec1, const NumericVector< T > &vec2) override
Computes (summation not implied) i.e.
Definition: petsc_vector.C:955
bool is_effectively_serial() const
virtual Real l1_norm() const override
Definition: petsc_vector.C:74
virtual void abs() override
Sets for each entry in the vector.
Definition: petsc_vector.C:413
dof_id_type numeric_index_type
Definition: id_types.h:99
virtual NumericVector< T > & operator+=(const NumericVector< T > &v) override
Adds v to *this, .
Definition: petsc_vector.C:93
virtual void conjugate() override
Negates the imaginary component of each entry in the vector.
Definition: petsc_vector.C:153
libmesh_assert(ctx)
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.
PetscErrorCode PetscInt const PetscInt IS * is
ParallelType _type
Type of vector.
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.
Real norm() const
Definition: petsc_vector.C:60
virtual bool closed() const
virtual T sum() const override
Definition: petsc_vector.C:44
std::complex< Real > Complex
ParallelType type() const
virtual void set(const numeric_index_type i, const T value) override
Sets v(i) = value.
Definition: petsc_vector.C:124
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
T indefinite_dot(const NumericVector< T > &v) const
Definition: petsc_vector.C:450
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.
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.
Definition: petsc_vector.h:721
static const bool value
Definition: xdr_io.C:55
bool initialized()
Checks that library initialization has been done.
Definition: libmesh.C:324
PetscVector< T > & operator=(const PetscVector< T > &v)
Copy assignment operator.
Definition: petsc_vector.C:516
void * ctx
virtual void reciprocal() override
Computes the component-wise reciprocal, .
Definition: petsc_vector.C:141
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]...
Definition: petsc_vector.C:182
virtual NumericVector< T > & operator*=(const NumericVector< T > &v) override
Computes the component-wise multiplication of this vector&#39;s entries by another&#39;s, ...
Definition: petsc_vector.C:387
boost::multiprecision::float128 imag(const boost::multiprecision::float128)
virtual void print_matlab(const std::string &name="") const override
Print the contents of the vector in Matlab&#39;s sparse matrix format.
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 void scale(const T factor) override
Scale each element of the vector by the given factor.
Definition: petsc_vector.C:369
bool _is_closed
Flag which tracks whether the vector&#39;s values are consistent on all processors after insertion or add...
virtual void close() override
Calls the NumericVector&#39;s internal assembly routines, ensuring that the values are consistent across ...
Definition: petsc_vector.h:911
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)
A useful inline function which replaces the macros used previously.
virtual NumericVector< T > & operator/=(const NumericVector< T > &v) override
Computes the component-wise division of this vector&#39;s entries by another&#39;s, .
Definition: petsc_vector.C:400
virtual NumericVector< T > & operator-=(const NumericVector< T > &v) override
Subtracts v from *this, .
Definition: petsc_vector.C:109
virtual T dot(const NumericVector< T > &v) const override
Definition: petsc_vector.C:429