LCOV - code coverage report
Current view: top level - src/numerics - petsc_vector.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 399 474 84.2 %
Date: 2025-08-19 19:27:09 Functions: 50 55 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 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"
      32             : #include "timpi/parallel_implementation.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>
      44         140 : T PetscVector<T>::sum () const
      45             : {
      46         140 :   this->_restore_array();
      47           4 :   libmesh_assert(this->closed());
      48             : 
      49         140 :   PetscScalar value=0.;
      50             : 
      51         140 :   LibmeshPetscCall(VecSum (_vec, &value));
      52             : 
      53         140 :   return static_cast<T>(value);
      54             : }
      55             : 
      56             : 
      57             : 
      58             : template <typename T>
      59             : template <NormType N>
      60      233809 : Real PetscVector<T>::norm () const
      61             : {
      62        6862 :   parallel_object_only();
      63             : 
      64      233809 :   this->_restore_array();
      65        6862 :   libmesh_assert(this->closed());
      66             : 
      67      233809 :   PetscReal value=0.;
      68             : 
      69      233809 :   LibmeshPetscCall(VecNorm (_vec, N, &value));
      70             : 
      71      233809 :   return static_cast<Real>(value);
      72             : }
      73             : template <typename T>
      74        1540 : Real PetscVector<T>::l1_norm () const
      75             : {
      76        1540 :   return PetscVector<T>::norm<NORM_1>();
      77             : }
      78             : template <typename T>
      79      232059 : Real PetscVector<T>::l2_norm () const
      80             : {
      81      232059 :   return PetscVector<T>::norm<NORM_2>();
      82             : }
      83             : template <typename T>
      84         210 : Real PetscVector<T>::linfty_norm () const
      85             : {
      86         210 :   return PetscVector<T>::norm<NORM_INFINITY>();
      87             : }
      88             : 
      89             : 
      90             : 
      91             : template <typename T>
      92             : NumericVector<T> &
      93       32830 : PetscVector<T>::operator += (const NumericVector<T> & v)
      94             : {
      95         938 :   parallel_object_only();
      96             : 
      97       32830 :   this->_restore_array();
      98         938 :   libmesh_assert(this->closed());
      99             : 
     100       32830 :   this->add(1., v);
     101             : 
     102       32830 :   return *this;
     103             : }
     104             : 
     105             : 
     106             : 
     107             : template <typename T>
     108             : NumericVector<T> &
     109       80780 : PetscVector<T>::operator -= (const NumericVector<T> & v)
     110             : {
     111        2308 :   parallel_object_only();
     112             : 
     113       80780 :   this->_restore_array();
     114        2308 :   libmesh_assert(this->closed());
     115             : 
     116       80780 :   this->add(-1., v);
     117             : 
     118       80780 :   return *this;
     119             : }
     120             : 
     121             : 
     122             : 
     123             : template <typename T>
     124    39082656 : void PetscVector<T>::set (const numeric_index_type i, const T value)
     125             : {
     126    39082656 :   this->_restore_array();
     127     3671333 :   libmesh_assert_less (i, size());
     128             : 
     129    39082656 :   PetscInt i_val = static_cast<PetscInt>(i);
     130    39082656 :   PetscScalar petsc_value = PS(value);
     131             : 
     132    39082656 :   std::scoped_lock lock(this->_numeric_vector_mutex);
     133    39082656 :   LibmeshPetscCall(VecSetValues (_vec, 1, &i_val, &petsc_value, INSERT_VALUES));
     134             : 
     135    39082656 :   this->_is_closed = false;
     136    39082656 : }
     137             : 
     138             : 
     139             : 
     140             : template <typename T>
     141         140 : void PetscVector<T>::reciprocal()
     142             : {
     143           4 :   parallel_object_only();
     144             : 
     145             : 
     146             :   // VecReciprocal has been in PETSc since at least 2.3.3 days
     147         140 :   LibmeshPetscCall(VecReciprocal(_vec));
     148         140 : }
     149             : 
     150             : 
     151             : 
     152             : template <typename T>
     153           0 : void PetscVector<T>::conjugate()
     154             : {
     155           0 :   parallel_object_only();
     156             : 
     157             : 
     158             :   // We just call the PETSc VecConjugate
     159           0 :   LibmeshPetscCall(VecConjugate(_vec));
     160           0 : }
     161             : 
     162             : 
     163             : 
     164             : template <typename T>
     165   190919454 : void PetscVector<T>::add (const numeric_index_type i, const T value)
     166             : {
     167   190919454 :   this->_restore_array();
     168    17728297 :   libmesh_assert_less (i, size());
     169             : 
     170   190919454 :   PetscInt i_val = static_cast<PetscInt>(i);
     171   190919454 :   PetscScalar petsc_value = PS(value);
     172             : 
     173   190919454 :   std::scoped_lock lock(this->_numeric_vector_mutex);
     174   190919454 :   LibmeshPetscCall(VecSetValues (_vec, 1, &i_val, &petsc_value, ADD_VALUES));
     175             : 
     176   190919454 :   this->_is_closed = false;
     177   190919454 : }
     178             : 
     179             : 
     180             : 
     181             : template <typename T>
     182    73914189 : 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    73914189 :   if (dof_indices.empty())
     187           0 :     return;
     188             : 
     189    73914189 :   this->_restore_array();
     190             : 
     191    11234253 :   const PetscInt * i_val = reinterpret_cast<const PetscInt *>(dof_indices.data());
     192     5721574 :   const PetscScalar * petsc_value = pPS(v);
     193             : 
     194    73914189 :   std::scoped_lock lock(this->_numeric_vector_mutex);
     195    79426868 :   LibmeshPetscCall(VecSetValues (_vec, cast_int<PetscInt>(dof_indices.size()),
     196             :                                  i_val, petsc_value, ADD_VALUES));
     197             : 
     198    73914189 :   this->_is_closed = false;
     199             : }
     200             : 
     201             : 
     202             : 
     203             : template <typename T>
     204     2978796 : void PetscVector<T>::add_vector (const NumericVector<T> & v_in,
     205             :                                  const SparseMatrix<T> & A_in)
     206             : {
     207       85138 :   parallel_object_only();
     208             : 
     209     2978796 :   this->_restore_array();
     210             :   // Make sure the data passed in are really of Petsc types
     211       85138 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     212       85138 :   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     2978796 :   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           0 :       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     2978796 :   LibmeshPetscCall(MatMultAdd(const_cast<PetscMatrixBase<T> *>(A)->mat(), v->_vec, _vec, _vec));
     227     2978796 : }
     228             : 
     229             : 
     230             : 
     231             : template <typename T>
     232           0 : void PetscVector<T>::add_vector_transpose (const NumericVector<T> & v_in,
     233             :                                            const SparseMatrix<T> & A_in)
     234             : {
     235           0 :   parallel_object_only();
     236             : 
     237           0 :   this->_restore_array();
     238             :   // Make sure the data passed in are really of Petsc types
     239           0 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     240           0 :   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           0 :   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           0 :       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           0 :   LibmeshPetscCall(MatMultTransposeAdd(const_cast<PetscMatrixBase<T> *>(A)->mat(), v->_vec, _vec, _vec));
     255           0 : }
     256             : 
     257             : 
     258             : 
     259             : template <typename T>
     260           0 : void PetscVector<T>::add_vector_conjugate_transpose (const NumericVector<T> & v_in,
     261             :                                                      const SparseMatrix<T> & A_in)
     262             : {
     263           0 :   parallel_object_only();
     264             : 
     265           0 :   this->_restore_array();
     266             :   // Make sure the data passed in are really of Petsc types
     267           0 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     268           0 :   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           0 :   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           0 :       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           0 :   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           0 :   LibmeshPetscCall(MatMultHermitianTranspose(const_cast<PetscMatrixBase<T> *>(A)->mat(), v->_vec, _vec));
     286             : 
     287             :   // Add the temporary copy to the matvec result
     288           0 :   this->add(1., *this_clone);
     289           0 : }
     290             : 
     291             : 
     292             : 
     293             : template <typename T>
     294         346 : void PetscVector<T>::add (const T v_in)
     295             : {
     296         346 :   this->_get_array(false);
     297             : 
     298       17382 :   for (numeric_index_type i=0; i<_local_size; i++)
     299       17036 :     _values[i] += PetscScalar(v_in);
     300         346 : }
     301             : 
     302             : 
     303             : 
     304             : template <typename T>
     305      603238 : void PetscVector<T>::add (const NumericVector<T> & v)
     306             : {
     307       17288 :   parallel_object_only();
     308             : 
     309      603238 :   this->add (1., v);
     310      603238 : }
     311             : 
     312             : 
     313             : 
     314             : template <typename T>
     315     4361153 : void PetscVector<T>::add (const T a_in, const NumericVector<T> & v_in)
     316             : {
     317      124770 :   parallel_object_only();
     318             : 
     319     4361153 :   this->_restore_array();
     320             : 
     321             :   // VecAXPY doesn't support &x==&y
     322     4361153 :   if (this == &v_in)
     323             :     {
     324         140 :       this->scale(a_in+1);
     325         140 :       return;
     326             :     }
     327             : 
     328      124766 :   PetscScalar a = PS(a_in);
     329             : 
     330             :   // Make sure the NumericVector passed in is really a PetscVector
     331      124766 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     332     4361013 :   v->_restore_array();
     333             : 
     334      124766 :   libmesh_assert_equal_to (this->size(), v->size());
     335             : 
     336     4361013 :   LibmeshPetscCall(VecAXPY(_vec, a, v->vec()));
     337             : 
     338      124766 :   libmesh_assert(this->comm().verify(int(this->type())));
     339             : 
     340     4361013 :   if (this->type() == GHOSTED)
     341       97440 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     342             : 
     343     4361013 :   this->_is_closed = true;
     344             : }
     345             : 
     346             : 
     347             : 
     348             : template <typename T>
     349     4764364 : void PetscVector<T>::insert (const T * v,
     350             :                              const std::vector<numeric_index_type> & dof_indices)
     351             : {
     352     4764364 :   if (dof_indices.empty())
     353           0 :     return;
     354             : 
     355     4764364 :   this->_restore_array();
     356             : 
     357      865384 :   PetscInt * idx_values = numeric_petsc_cast(dof_indices.data());
     358     4764364 :   std::scoped_lock lock(this->_numeric_vector_mutex);
     359     5197056 :   LibmeshPetscCall(VecSetValues (_vec, cast_int<PetscInt>(dof_indices.size()),
     360             :                                  idx_values, pPS(v), INSERT_VALUES));
     361             : 
     362     4764364 :   this->_is_closed = false;
     363             : }
     364             : 
     365             : 
     366             : 
     367             : template <typename T>
     368      628490 : void PetscVector<T>::scale (const T factor_in)
     369             : {
     370       17956 :   parallel_object_only();
     371             : 
     372      628490 :   this->_restore_array();
     373             : 
     374       17956 :   PetscScalar factor = PS(factor_in);
     375             : 
     376      628490 :   LibmeshPetscCall(VecScale(_vec, factor));
     377             : 
     378       17956 :   libmesh_assert(this->comm().verify(int(this->type())));
     379             : 
     380      628490 :   if (this->type() == GHOSTED)
     381           0 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     382      628490 : }
     383             : 
     384             : template <typename T>
     385         140 : NumericVector<T> & PetscVector<T>::operator *= (const NumericVector<T> & v)
     386             : {
     387           4 :   parallel_object_only();
     388             : 
     389             : 
     390           4 :   const PetscVector<T> * v_vec = cast_ptr<const PetscVector<T> *>(&v);
     391             : 
     392         140 :   LibmeshPetscCall(VecPointwiseMult(_vec, _vec, v_vec->_vec));
     393             : 
     394         140 :   return *this;
     395             : }
     396             : 
     397             : template <typename T>
     398       78870 : NumericVector<T> & PetscVector<T>::operator /= (const NumericVector<T> & v)
     399             : {
     400        2454 :   parallel_object_only();
     401             : 
     402             : 
     403        2454 :   const PetscVector<T> * v_vec = cast_ptr<const PetscVector<T> *>(&v);
     404             : 
     405       78870 :   LibmeshPetscCall(VecPointwiseDivide(_vec, _vec, v_vec->_vec));
     406             : 
     407       78870 :   return *this;
     408             : }
     409             : 
     410             : template <typename T>
     411           0 : void PetscVector<T>::abs()
     412             : {
     413           0 :   parallel_object_only();
     414             : 
     415           0 :   this->_restore_array();
     416             : 
     417           0 :   LibmeshPetscCall(VecAbs(_vec));
     418             : 
     419           0 :   libmesh_assert(this->comm().verify(int(this->type())));
     420             : 
     421           0 :   if (this->type() == GHOSTED)
     422           0 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     423           0 : }
     424             : 
     425             : template <typename T>
     426    10363074 : T PetscVector<T>::dot (const NumericVector<T> & v_in) const
     427             : {
     428      296116 :   parallel_object_only();
     429             : 
     430    10363074 :   this->_restore_array();
     431             : 
     432             :   // Error flag
     433             : 
     434             :   // Return value
     435    10363074 :   PetscScalar value=0.;
     436             : 
     437             :   // Make sure the NumericVector passed in is really a PetscVector
     438      296116 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     439             : 
     440             :   // 2.3.x (at least) style.  Untested for previous versions.
     441    10363074 :   LibmeshPetscCall(VecDot(this->_vec, v->_vec, &value));
     442             : 
     443    10363074 :   return static_cast<T>(value);
     444             : }
     445             : 
     446             : template <typename T>
     447           0 : T PetscVector<T>::indefinite_dot (const NumericVector<T> & v_in) const
     448             : {
     449           0 :   parallel_object_only();
     450             : 
     451           0 :   this->_restore_array();
     452             : 
     453             :   // Error flag
     454             : 
     455             :   // Return value
     456           0 :   PetscScalar value=0.;
     457             : 
     458             :   // Make sure the NumericVector passed in is really a PetscVector
     459           0 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     460             : 
     461             :   // 2.3.x (at least) style.  Untested for previous versions.
     462           0 :   LibmeshPetscCall(VecTDot(this->_vec, v->_vec, &value));
     463             : 
     464           0 :   return static_cast<T>(value);
     465             : }
     466             : 
     467             : 
     468             : template <typename T>
     469             : NumericVector<T> &
     470         140 : PetscVector<T>::operator = (const T s_in)
     471             : {
     472           4 :   parallel_object_only();
     473             : 
     474         140 :   this->_restore_array();
     475           4 :   libmesh_assert(this->closed());
     476             : 
     477           4 :   PetscScalar s = PS(s_in);
     478             : 
     479         140 :   if (this->size() != 0)
     480             :     {
     481         140 :       LibmeshPetscCall(VecSet(_vec, s));
     482             : 
     483           4 :       libmesh_assert(this->comm().verify(int(this->type())));
     484             : 
     485         140 :       if (this->type() == GHOSTED)
     486           0 :         VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     487             :     }
     488             : 
     489         140 :   return *this;
     490             : }
     491             : 
     492             : 
     493             : 
     494             : template <typename T>
     495             : NumericVector<T> &
     496     3689309 : PetscVector<T>::operator = (const NumericVector<T> & v_in)
     497             : {
     498      103198 :   parallel_object_only();
     499             : 
     500             :   // Make sure the NumericVector passed in is really a PetscVector
     501      103198 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     502             : 
     503     3689309 :   *this = *v;
     504             : 
     505     3689309 :   return *this;
     506             : }
     507             : 
     508             : 
     509             : 
     510             : template <typename T>
     511             : PetscVector<T> &
     512     3689379 : PetscVector<T>::operator = (const PetscVector<T> & v)
     513             : {
     514      103200 :   parallel_object_only();
     515             : 
     516     3689379 :   this->_restore_array();
     517     3689379 :   v._restore_array();
     518             : 
     519      103200 :   libmesh_assert_equal_to (this->size(), v.size());
     520      103200 :   libmesh_assert_equal_to (this->local_size(), v.local_size());
     521      103200 :   libmesh_assert (v.closed());
     522             : 
     523             : 
     524     3689379 :   LibmeshPetscCall(VecCopy (v._vec, this->_vec));
     525             : 
     526      103200 :   libmesh_assert(this->comm().verify(int(this->type())));
     527             : 
     528     3689379 :   if (this->type() == GHOSTED)
     529     2684711 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     530             : 
     531     3689379 :   this->_is_closed = true;
     532             : 
     533     3689379 :   return *this;
     534             : }
     535             : 
     536             : 
     537             : 
     538             : template <typename T>
     539             : NumericVector<T> &
     540          70 : PetscVector<T>::operator = (const std::vector<T> & v)
     541             : {
     542           2 :   parallel_object_only();
     543             : 
     544          70 :   this->_get_array(false);
     545             : 
     546             :   /**
     547             :    * Case 1:  The vector is the same size of
     548             :    * The global vector.  Only add the local components.
     549             :    */
     550          70 :   if (this->size() == v.size())
     551             :     {
     552          70 :       numeric_index_type first = first_local_index();
     553          70 :       numeric_index_type last = last_local_index();
     554      300860 :       for (numeric_index_type i=0; i<last-first; i++)
     555      309384 :         _values[i] = PS(v[first + i]);
     556             :     }
     557             : 
     558             :   /**
     559             :    * Case 2: The vector is the same size as our local
     560             :    * piece.  Insert directly to the local piece.
     561             :    */
     562             :   else
     563             :     {
     564           0 :       for (numeric_index_type i=0; i<_local_size; i++)
     565           0 :         _values[i] = PS(v[i]);
     566             :     }
     567             : 
     568             :   // Make sure ghost dofs are up to date
     569          70 :   if (this->type() == GHOSTED)
     570           0 :     this->close();
     571             : 
     572          70 :   return *this;
     573             : }
     574             : 
     575             : 
     576             : 
     577             : template <typename T>
     578        2137 : void PetscVector<T>::localize (NumericVector<T> & v_local_in) const
     579             : {
     580          50 :   parallel_object_only();
     581             : 
     582        2137 :   this->_restore_array();
     583             : 
     584             :   // Make sure the NumericVector passed in is really a PetscVector
     585          50 :   PetscVector<T> * v_local = cast_ptr<PetscVector<T> *>(&v_local_in);
     586             : 
     587          50 :   libmesh_assert(v_local);
     588             :   // v_local_in should be closed
     589          50 :   libmesh_assert(v_local->closed());
     590          50 :   libmesh_assert_equal_to (v_local->size(), this->size());
     591             :   // 1) v_local_in is a large vector to hold the whole world
     592             :   // 2) v_local_in is a ghosted vector
     593             :   // 3) v_local_in is a parallel vector
     594             :   // Cases 2) and 3) should be scalable
     595          50 :   libmesh_assert(this->size()==v_local->local_size() || this->local_size()==v_local->local_size());
     596             : 
     597             : 
     598        2137 :   if (v_local->type() == SERIAL && this->size() == v_local->local_size())
     599             :   {
     600          48 :     WrappedPetsc<VecScatter> scatter;
     601        2067 :     LibmeshPetscCall(VecScatterCreateToAll(_vec, scatter.get(), nullptr));
     602        2067 :     VecScatterBeginEnd(this->comm(), scatter, _vec, v_local->_vec, INSERT_VALUES, SCATTER_FORWARD);
     603             :   }
     604             :   // Two vectors have the same size, and we should just do a simple copy.
     605             :   // v_local could be either a parallel or ghosted vector
     606          70 :   else if (this->local_size() == v_local->local_size())
     607          70 :     LibmeshPetscCall(VecCopy(_vec,v_local->_vec));
     608             :   else
     609           0 :     libmesh_error_msg("Vectors are inconsistent");
     610             : 
     611             :   // Make sure ghost dofs are up to date
     612             :   // We do not call "close" here to save a global reduction
     613        2137 :   if (v_local->type() == GHOSTED)
     614          70 :     VecGhostUpdateBeginEnd(this->comm(), v_local->_vec, INSERT_VALUES, SCATTER_FORWARD);
     615        2137 : }
     616             : 
     617             : 
     618             : 
     619             : template <typename T>
     620     2207330 : void PetscVector<T>::localize (NumericVector<T> & v_local_in,
     621             :                                const std::vector<numeric_index_type> & send_list) const
     622             : {
     623       60542 :   parallel_object_only();
     624             : 
     625       60542 :   libmesh_assert(this->comm().verify(int(this->type())));
     626       60542 :   libmesh_assert(this->comm().verify(int(v_local_in.type())));
     627             : 
     628             :   // FIXME: Workaround for a strange bug at large-scale.
     629             :   // If we have ghosting, PETSc lets us just copy the solution, and
     630             :   // doing so avoids a segfault?
     631     2267872 :   if (v_local_in.type() == GHOSTED &&
     632      120080 :       this->type() == PARALLEL)
     633             :     {
     634     2075994 :       v_local_in = *this;
     635     2075994 :       return;
     636             :     }
     637             : 
     638             :   // Normal code path begins here
     639             : 
     640      131336 :   this->_restore_array();
     641             : 
     642             :   // Make sure the NumericVector passed in is really a PetscVector
     643        3860 :   PetscVector<T> * v_local = cast_ptr<PetscVector<T> *>(&v_local_in);
     644             : 
     645        3860 :   libmesh_assert(v_local);
     646        3860 :   libmesh_assert_equal_to (v_local->size(), this->size());
     647        3860 :   libmesh_assert_less_equal (send_list.size(), v_local->size());
     648             : 
     649             :   const numeric_index_type n_sl =
     650        7532 :     cast_int<numeric_index_type>(send_list.size());
     651             : 
     652      135196 :   std::vector<PetscInt> idx(n_sl + this->local_size());
     653     2982828 :   for (numeric_index_type i=0; i<n_sl; i++)
     654     3176636 :     idx[i] = static_cast<PetscInt>(send_list[i]);
     655    26086052 :   for (auto i : make_range(this->local_size()))
     656    25954716 :     idx[n_sl+i] = i + this->first_local_index();
     657             : 
     658             :   // Create the index set & scatter objects
     659        7720 :   WrappedPetsc<IS> is;
     660      131336 :   PetscInt * idxptr = idx.empty() ? nullptr : idx.data();
     661      131336 :   LibmeshPetscCall(ISCreateGeneral(this->comm().get(), n_sl+this->local_size(),
     662             :                                    idxptr, PETSC_USE_POINTER, is.get()));
     663             : 
     664        7720 :   WrappedPetsc<VecScatter> scatter;
     665      131336 :   LibmeshPetscCall(VecScatterCreate(_vec,          is,
     666             :                                     v_local->_vec, is,
     667             :                                     scatter.get()));
     668             : 
     669             :   // Perform the scatter
     670      131336 :   VecScatterBeginEnd(this->comm(), scatter, _vec, v_local->_vec, INSERT_VALUES, SCATTER_FORWARD);
     671             : 
     672             :   // Make sure ghost dofs are up to date
     673      131336 :   if (v_local->type() == GHOSTED)
     674      131336 :     v_local->close();
     675             : }
     676             : 
     677             : 
     678             : 
     679             : template <typename T>
     680         140 : void PetscVector<T>::localize (std::vector<T> & v_local,
     681             :                                const std::vector<numeric_index_type> & indices) const
     682             : {
     683           4 :   parallel_object_only();
     684             : 
     685             :   // Error code used to check the status of all PETSc function calls.
     686             : 
     687             :   // Create a sequential destination Vec with the right number of entries on each proc.
     688           8 :   WrappedPetsc<Vec> dest;
     689         144 :   LibmeshPetscCall(VecCreateSeq(PETSC_COMM_SELF, cast_int<PetscInt>(indices.size()), dest.get()));
     690             : 
     691             :   // Create an IS using the libmesh routine.  PETSc does not own the
     692             :   // IS memory in this case, it is automatically cleaned up by the
     693             :   // std::vector destructor.
     694           8 :   PetscInt * idxptr =
     695         140 :     indices.empty() ? nullptr : numeric_petsc_cast(indices.data());
     696           8 :   WrappedPetsc<IS> is;
     697         140 :   LibmeshPetscCall(ISCreateGeneral(this->comm().get(), cast_int<PetscInt>(indices.size()), idxptr,
     698             :                                    PETSC_USE_POINTER, is.get()));
     699             : 
     700             :   // Create the VecScatter object. "PETSC_NULL" means "use the identity IS".
     701           8 :   WrappedPetsc<VecScatter> scatter;
     702         140 :   LibmeshPetscCall(VecScatterCreate(_vec,
     703             :                                     /*src is=*/is,
     704             :                                     /*dest vec=*/dest,
     705             :                                     /*dest is=*/LIBMESH_PETSC_NULLPTR,
     706             :                                     scatter.get()));
     707             : 
     708             :   // Do the scatter
     709         140 :   VecScatterBeginEnd(this->comm(), scatter, _vec, dest, INSERT_VALUES, SCATTER_FORWARD);
     710             : 
     711             :   // Get access to the values stored in dest.
     712             :   PetscScalar * values;
     713         140 :   LibmeshPetscCall(VecGetArray (dest, &values));
     714             : 
     715             :   // Store values into the provided v_local. Make sure there is enough
     716             :   // space reserved and then clear out any existing entries before
     717             :   // inserting.
     718         144 :   v_local.reserve(indices.size());
     719           4 :   v_local.clear();
     720         144 :   v_local.insert(v_local.begin(), values, values+indices.size());
     721             : 
     722             :   // We are done using it, so restore the array.
     723         140 :   LibmeshPetscCall(VecRestoreArray (dest, &values));
     724         140 : }
     725             : 
     726             : 
     727             : 
     728             : template <typename T>
     729       10428 : void PetscVector<T>::localize (const numeric_index_type first_local_idx,
     730             :                                const numeric_index_type last_local_idx,
     731             :                                const std::vector<numeric_index_type> & send_list)
     732             : {
     733         472 :   parallel_object_only();
     734             : 
     735       10428 :   this->_restore_array();
     736             : 
     737         472 :   libmesh_assert_less_equal (send_list.size(), this->size());
     738         472 :   libmesh_assert_less_equal (last_local_idx+1, this->size());
     739             : 
     740       10428 :   const numeric_index_type my_size       = this->size();
     741       10428 :   const numeric_index_type my_local_size = (last_local_idx + 1 - first_local_idx);
     742             : 
     743             :   // Don't bother for serial cases
     744             :   //  if ((first_local_idx == 0) &&
     745             :   //      (my_local_size == my_size))
     746             :   // But we do need to stay in sync for degenerate cases
     747       10900 :   if (this->n_processors() == 1)
     748         144 :     return;
     749             : 
     750             : 
     751             :   // Build a parallel vector, initialize it with the local
     752             :   // parts of (*this)
     753       11228 :   PetscVector<T> parallel_vec(this->comm(), PARALLEL);
     754             : 
     755       10284 :   parallel_vec.init (my_size, my_local_size, true, PARALLEL);
     756             : 
     757             : 
     758             :   // Copy part of *this into the parallel_vec
     759             :   {
     760             :     // Create idx, idx[i] = i+first_local_idx;
     761       10756 :     std::vector<PetscInt> idx(my_local_size);
     762         472 :     std::iota (idx.begin(), idx.end(), first_local_idx);
     763             : 
     764             :     // Create the index set & scatter objects
     765         944 :     WrappedPetsc<IS> is;
     766       18870 :     LibmeshPetscCall(ISCreateGeneral(this->comm().get(), my_local_size,
     767             :                                      my_local_size ? idx.data() : nullptr, PETSC_USE_POINTER, is.get()));
     768             : 
     769         472 :     WrappedPetsc<VecScatter> scatter;
     770       10284 :     LibmeshPetscCall(VecScatterCreate(_vec,              is,
     771             :                                       parallel_vec._vec, is,
     772             :                                       scatter.get()));
     773             : 
     774             :     // Perform the scatter
     775       10284 :     VecScatterBeginEnd(this->comm(), scatter, _vec, parallel_vec._vec, INSERT_VALUES, SCATTER_FORWARD);
     776             :   }
     777             : 
     778             :   // localize like normal
     779       10284 :   parallel_vec.close();
     780       10284 :   parallel_vec.localize (*this, send_list);
     781       10284 :   this->close();
     782        9340 : }
     783             : 
     784             : 
     785             : 
     786             : template <typename T>
     787       21350 : void PetscVector<T>::localize (std::vector<T> & v_local) const
     788             : {
     789         610 :   parallel_object_only();
     790             : 
     791       21350 :   this->_restore_array();
     792             : 
     793             :   // This function must be run on all processors at once
     794         610 :   parallel_object_only();
     795             : 
     796       21350 :   const PetscInt n = this->size();
     797       21350 :   const PetscInt nl = this->local_size();
     798             :   PetscScalar * values;
     799             : 
     800         610 :   v_local.clear();
     801       21350 :   v_local.resize(n, 0.);
     802             : 
     803       21350 :   LibmeshPetscCall(VecGetArray (_vec, &values));
     804             : 
     805       21350 :   numeric_index_type ioff = first_local_index();
     806             : 
     807    13196761 :   for (PetscInt i=0; i<nl; i++)
     808    14372892 :     v_local[i+ioff] = static_cast<T>(values[i]);
     809             : 
     810       21350 :   LibmeshPetscCall(VecRestoreArray (_vec, &values));
     811             : 
     812       21350 :   this->comm().sum(v_local);
     813       21350 : }
     814             : 
     815             : 
     816             : 
     817             : // Full specialization for Real datatypes
     818             : #ifdef LIBMESH_USE_REAL_NUMBERS
     819             : 
     820             : template <>
     821       84872 : void PetscVector<Real>::localize_to_one (std::vector<Real> & v_local,
     822             :                                          const processor_id_type
     823             :                                          timpi_mpi_var(pid)) const
     824             : {
     825        2700 :   parallel_object_only();
     826             : 
     827       84872 :   this->_restore_array();
     828             : 
     829       84872 :   const PetscInt n  = size();
     830             :   PetscScalar * values;
     831             : 
     832             :   // only one processor
     833       87572 :   if (n_processors() == 1)
     834             :     {
     835        1204 :       v_local.resize(n);
     836             : 
     837        1204 :       LibmeshPetscCall(VecGetArray (_vec, &values));
     838             : 
     839     2689350 :       for (PetscInt i=0; i<n; i++)
     840     2688146 :         v_local[i] = static_cast<Real>(values[i]);
     841             : 
     842        1204 :       LibmeshPetscCall(VecRestoreArray (_vec, &values));
     843             :     }
     844             : 
     845             :   // otherwise multiple processors
     846             : #ifdef LIBMESH_HAVE_MPI
     847             :   else
     848             :     {
     849       83668 :       if (pid == 0) // optimized version for localizing to 0
     850             :         {
     851        5400 :           WrappedPetsc<Vec> vout;
     852        5400 :           WrappedPetsc<VecScatter> ctx;
     853             : 
     854       83668 :           LibmeshPetscCall(VecScatterCreateToZero(_vec, ctx.get(), vout.get()));
     855             : 
     856       83668 :           VecScatterBeginEnd(this->comm(), ctx, _vec, vout, INSERT_VALUES, SCATTER_FORWARD);
     857             : 
     858       86368 :           if (processor_id() == 0)
     859             :             {
     860       12385 :               v_local.resize(n);
     861             : 
     862       12385 :               LibmeshPetscCall(VecGetArray (vout, &values));
     863             : 
     864    27338900 :               for (PetscInt i=0; i<n; i++)
     865    30179110 :                 v_local[i] = static_cast<Real>(values[i]);
     866             : 
     867       12385 :               LibmeshPetscCall(VecRestoreArray (vout, &values));
     868             :             }
     869             :         }
     870             :       else
     871             :         {
     872           0 :           v_local.resize(n);
     873             : 
     874           0 :           numeric_index_type ioff = this->first_local_index();
     875           0 :           std::vector<Real> local_values (n, 0.);
     876             : 
     877             :           {
     878           0 :             LibmeshPetscCall(VecGetArray (_vec, &values));
     879             : 
     880           0 :             const PetscInt nl = local_size();
     881           0 :             for (PetscInt i=0; i<nl; i++)
     882           0 :               local_values[i+ioff] = static_cast<Real>(values[i]);
     883             : 
     884           0 :             LibmeshPetscCall(VecRestoreArray (_vec, &values));
     885             :           }
     886             : 
     887             : 
     888           0 :           MPI_Reduce (local_values.data(), v_local.data(), n,
     889           0 :                       Parallel::StandardType<Real>(),
     890             :                       Parallel::OpFunction<Real>::sum(), pid,
     891           0 :                       this->comm().get());
     892             :         }
     893             :     }
     894             : #endif // LIBMESH_HAVE_MPI
     895       84872 : }
     896             : 
     897             : #endif
     898             : 
     899             : 
     900             : // Full specialization for Complex datatypes
     901             : #ifdef LIBMESH_USE_COMPLEX_NUMBERS
     902             : 
     903             : template <>
     904             : void PetscVector<Complex>::localize_to_one (std::vector<Complex> & v_local,
     905             :                                             const processor_id_type pid) const
     906             : {
     907             :   parallel_object_only();
     908             : 
     909             :   this->_restore_array();
     910             : 
     911             :   const PetscInt n  = size();
     912             :   const PetscInt nl = local_size();
     913             :   PetscScalar * values;
     914             : 
     915             : 
     916             :   v_local.resize(n);
     917             : 
     918             : 
     919             :   for (PetscInt i=0; i<n; i++)
     920             :     v_local[i] = 0.;
     921             : 
     922             :   // only one processor
     923             :   if (n_processors() == 1)
     924             :     {
     925             :       LibmeshPetscCall(VecGetArray (_vec, &values));
     926             : 
     927             :       for (PetscInt i=0; i<n; i++)
     928             :         v_local[i] = static_cast<Complex>(values[i]);
     929             : 
     930             :       LibmeshPetscCall(VecRestoreArray (_vec, &values));
     931             :     }
     932             : 
     933             :   // otherwise multiple processors
     934             :   else
     935             :     {
     936             :       numeric_index_type ioff = this->first_local_index();
     937             : 
     938             :       /* in here the local values are stored, acting as send buffer for MPI
     939             :        * initialize to zero, since we collect using MPI_SUM
     940             :        */
     941             :       std::vector<Real> real_local_values(n, 0.);
     942             :       std::vector<Real> imag_local_values(n, 0.);
     943             : 
     944             :       {
     945             :         LibmeshPetscCall(VecGetArray (_vec, &values));
     946             : 
     947             :         // provide my local share to the real and imag buffers
     948             :         for (PetscInt i=0; i<nl; i++)
     949             :           {
     950             :             real_local_values[i+ioff] = static_cast<Complex>(values[i]).real();
     951             :             imag_local_values[i+ioff] = static_cast<Complex>(values[i]).imag();
     952             :           }
     953             : 
     954             :         LibmeshPetscCall(VecRestoreArray (_vec, &values));
     955             :       }
     956             : 
     957             :       /* have buffers of the real and imaginary part of v_local.
     958             :        * Once MPI_Reduce() collected all the real and imaginary
     959             :        * parts in these std::vector<Real>, the values can be
     960             :        * copied to v_local
     961             :        */
     962             :       std::vector<Real> real_v_local(n);
     963             :       std::vector<Real> imag_v_local(n);
     964             : 
     965             :       // collect entries from other proc's in real_v_local, imag_v_local
     966             :       MPI_Reduce (real_local_values.data(),
     967             :                   real_v_local.data(), n,
     968             :                   Parallel::StandardType<Real>(),
     969             :                   Parallel::OpFunction<Real>::sum(),
     970             :                   pid, this->comm().get());
     971             : 
     972             :       MPI_Reduce (imag_local_values.data(),
     973             :                   imag_v_local.data(), n,
     974             :                   Parallel::StandardType<Real>(),
     975             :                   Parallel::OpFunction<Real>::sum(),
     976             :                   pid, this->comm().get());
     977             : 
     978             :       // copy real_v_local and imag_v_local to v_local
     979             :       for (PetscInt i=0; i<n; i++)
     980             :         v_local[i] = Complex(real_v_local[i], imag_v_local[i]);
     981             :     }
     982             : }
     983             : 
     984             : #endif
     985             : 
     986             : 
     987             : 
     988             : template <typename T>
     989          70 : void PetscVector<T>::pointwise_mult (const NumericVector<T> & vec1,
     990             :                                      const NumericVector<T> & vec2)
     991             : {
     992           2 :   parallel_object_only();
     993             : 
     994          70 :   this->_restore_array();
     995             : 
     996             :   // Convert arguments to PetscVector*.
     997           2 :   const PetscVector<T> * vec1_petsc = cast_ptr<const PetscVector<T> *>(&vec1);
     998           2 :   const PetscVector<T> * vec2_petsc = cast_ptr<const PetscVector<T> *>(&vec2);
     999             : 
    1000             :   // Call PETSc function.
    1001          70 :   LibmeshPetscCall(VecPointwiseMult(_vec, vec1_petsc->vec(), vec2_petsc->vec()));
    1002             : 
    1003           2 :   libmesh_assert(this->comm().verify(int(this->type())));
    1004             : 
    1005          70 :   if (this->type() == GHOSTED)
    1006           0 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
    1007             : 
    1008          70 :   this->_is_closed = true;
    1009          70 : }
    1010             : 
    1011             : template <typename T>
    1012          70 : void PetscVector<T>::pointwise_divide (const NumericVector<T> & vec1,
    1013             :                                        const NumericVector<T> & vec2)
    1014             : {
    1015           2 :   parallel_object_only();
    1016             : 
    1017          70 :   this->_restore_array();
    1018             : 
    1019             :   // Convert arguments to PetscVector*.
    1020           2 :   const PetscVector<T> * const vec1_petsc = cast_ptr<const PetscVector<T> *>(&vec1);
    1021           2 :   const PetscVector<T> * const vec2_petsc = cast_ptr<const PetscVector<T> *>(&vec2);
    1022             : 
    1023             :   // Call PETSc function.
    1024          70 :   LibmeshPetscCall(VecPointwiseDivide(_vec, vec1_petsc->vec(), vec2_petsc->vec()));
    1025             : 
    1026           2 :   libmesh_assert(this->comm().verify(int(this->type())));
    1027             : 
    1028          70 :   if (this->type() == GHOSTED)
    1029           0 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
    1030             : 
    1031          70 :   this->_is_closed = true;
    1032          70 : }
    1033             : 
    1034             : template <typename T>
    1035         140 : void PetscVector<T>::print_matlab (const std::string & name) const
    1036             : {
    1037           4 :   parallel_object_only();
    1038             : 
    1039         140 :   this->_restore_array();
    1040           4 :   libmesh_assert (this->closed());
    1041             : 
    1042             : 
    1043           8 :   WrappedPetsc<PetscViewer> petsc_viewer;
    1044         140 :   LibmeshPetscCall(PetscViewerCreate (this->comm().get(), petsc_viewer.get()));
    1045             : 
    1046             :   // Create an ASCII file containing the matrix
    1047             :   // if a filename was provided.
    1048         140 :   if (name != "")
    1049             :     {
    1050         140 :       LibmeshPetscCall(PetscViewerASCIIOpen(this->comm().get(),
    1051             :                                             name.c_str(),
    1052             :                                             petsc_viewer.get()));
    1053             : 
    1054             : #if PETSC_VERSION_LESS_THAN(3,7,0)
    1055             :       LibmeshPetscCall(PetscViewerSetFormat (petsc_viewer,
    1056             :                                              PETSC_VIEWER_ASCII_MATLAB));
    1057             : #else
    1058         140 :       LibmeshPetscCall(PetscViewerPushFormat (petsc_viewer,
    1059             :                                               PETSC_VIEWER_ASCII_MATLAB));
    1060             : #endif
    1061             : 
    1062         140 :       LibmeshPetscCall(VecView (_vec, petsc_viewer));
    1063             :     }
    1064             : 
    1065             :   // Otherwise the matrix will be dumped to the screen.
    1066             :   else
    1067             :     {
    1068             : 
    1069             : #if PETSC_VERSION_LESS_THAN(3,7,0)
    1070             :       LibmeshPetscCall(PetscViewerSetFormat (PETSC_VIEWER_STDOUT_WORLD,
    1071             :                                              PETSC_VIEWER_ASCII_MATLAB));
    1072             : #else
    1073           0 :       LibmeshPetscCall(PetscViewerPushFormat (PETSC_VIEWER_STDOUT_WORLD,
    1074             :                                               PETSC_VIEWER_ASCII_MATLAB));
    1075             : #endif
    1076             : 
    1077           0 :       LibmeshPetscCall(VecView (_vec, PETSC_VIEWER_STDOUT_WORLD));
    1078             :     }
    1079         140 : }
    1080             : 
    1081             : 
    1082             : 
    1083             : 
    1084             : 
    1085             : template <typename T>
    1086        1330 : void PetscVector<T>::create_subvector(NumericVector<T> & subvector,
    1087             :                                       const std::vector<numeric_index_type> & rows,
    1088             :                                       const bool supplying_global_rows) const
    1089             : {
    1090          38 :   parallel_object_only();
    1091             : 
    1092        1330 :   libmesh_error_msg_if(
    1093             :       subvector.type() == GHOSTED,
    1094             :       "We do not support scattering parallel information to ghosts for subvectors");
    1095             : 
    1096        1330 :   this->_restore_array();
    1097             : 
    1098             :   // PETSc data structures
    1099             : 
    1100             :   // Make sure the passed in subvector is really a PetscVector
    1101          38 :   PetscVector<T> * petsc_subvector = cast_ptr<PetscVector<T> *>(&subvector);
    1102             : 
    1103             :   // If the petsc_subvector is already initialized, we assume that the
    1104             :   // user has already allocated the *correct* amount of space for it.
    1105             :   // If not, we use the appropriate PETSc routines to initialize it.
    1106        1330 :   if (!petsc_subvector->initialized())
    1107             :     {
    1108           0 :       libmesh_assert(petsc_subvector->_type == AUTOMATIC || petsc_subvector->_type == PARALLEL);
    1109             : 
    1110           0 :       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           0 :         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           0 :         LibmeshPetscCall(VecCreateMPI(this->comm().get(),
    1123             :                                       cast_int<PetscInt>(rows.size()),
    1124             :                                       PETSC_DETERMINE,
    1125             :                                       &(petsc_subvector->_vec)));
    1126             : 
    1127           0 :       LibmeshPetscCall(VecSetFromOptions (petsc_subvector->_vec));
    1128             : 
    1129             :       // We created a parallel vector
    1130           0 :       petsc_subvector->_type = PARALLEL;
    1131             : 
    1132             :       // Mark the subvector as initialized
    1133           0 :       petsc_subvector->_is_initialized = true;
    1134             :     }
    1135             :   else
    1136             :     {
    1137        1330 :       petsc_subvector->_restore_array();
    1138             :     }
    1139             : 
    1140        1406 :   std::vector<PetscInt> idx(rows.size());
    1141        1330 :   if (supplying_global_rows)
    1142           0 :     std::iota (idx.begin(), idx.end(), 0);
    1143             :   else
    1144             :     {
    1145             :       PetscInt start;
    1146        1330 :       LibmeshPetscCall(VecGetOwnershipRange(petsc_subvector->_vec, &start, nullptr));
    1147        1330 :       std::iota (idx.begin(), idx.end(), start);
    1148             :     }
    1149             : 
    1150             :   // Construct index sets
    1151          76 :   WrappedPetsc<IS> parent_is;
    1152        1368 :   LibmeshPetscCall(ISCreateGeneral(this->comm().get(),
    1153             :                                    cast_int<PetscInt>(rows.size()),
    1154             :                                    numeric_petsc_cast(rows.data()),
    1155             :                                    PETSC_USE_POINTER,
    1156             :                                    parent_is.get()));
    1157             : 
    1158          76 :   WrappedPetsc<IS> subvector_is;
    1159        1368 :   LibmeshPetscCall(ISCreateGeneral(this->comm().get(),
    1160             :                                    cast_int<PetscInt>(rows.size()),
    1161             :                                    idx.data(),
    1162             :                                    PETSC_USE_POINTER,
    1163             :                                    subvector_is.get()));
    1164             : 
    1165             :   // Construct the scatter object
    1166          38 :   WrappedPetsc<VecScatter> scatter;
    1167        1330 :   LibmeshPetscCall(VecScatterCreate(this->_vec,
    1168             :                                     parent_is,
    1169             :                                     petsc_subvector->_vec,
    1170             :                                     subvector_is,
    1171             :                                     scatter.get()));
    1172             : 
    1173             :   // Actually perform the scatter
    1174        1330 :   VecScatterBeginEnd(this->comm(), scatter, this->_vec, petsc_subvector->_vec, INSERT_VALUES, SCATTER_FORWARD);
    1175             : 
    1176        1330 :   petsc_subvector->_is_closed = true;
    1177        1330 : }
    1178             : 
    1179             : 
    1180             : 
    1181             : template <typename T>
    1182  7175880747 : void PetscVector<T>::_get_array(bool read_only) const
    1183             : {
    1184   570195256 :   libmesh_assert (this->initialized());
    1185             : 
    1186   570195256 :   bool initially_array_is_present = _array_is_present.load(std::memory_order_acquire);
    1187             : 
    1188             :   // If we already have a read/write array - and we're trying
    1189             :   // to get a read only array - let's just use the read write
    1190  7175880747 :   if (initially_array_is_present && read_only && !_values_read_only)
    1191    24807602 :     _read_only_values = _values;
    1192             : 
    1193             :   // If the values have already been retrieved and we're currently
    1194             :   // trying to get a non-read only view (ie read/write) and the
    1195             :   // values are currently read only... then we need to restore
    1196             :   // the array first... and then retrieve it again.
    1197  7175880747 :   if (initially_array_is_present && !read_only && _values_read_only)
    1198             :     {
    1199         210 :       _restore_array();
    1200           6 :       initially_array_is_present = false;
    1201             :     }
    1202             : 
    1203  7175880543 :   if (!initially_array_is_present)
    1204             :     {
    1205     1399973 :       std::scoped_lock lock(_petsc_get_restore_array_mutex);
    1206     1324405 :       if (!_array_is_present.load(std::memory_order_relaxed))
    1207             :         {
    1208     1319352 :                   if (this->type() != GHOSTED)
    1209             :             {
    1210       32748 :               if (read_only)
    1211             :                 {
    1212       32122 :                   LibmeshPetscCall(VecGetArrayRead(_vec, &_read_only_values));
    1213       32122 :                   _values_read_only = true;
    1214             :                 }
    1215             :               else
    1216             :                 {
    1217         626 :                   LibmeshPetscCall(VecGetArray(_vec, &_values));
    1218         626 :                   _values_read_only = false;
    1219             :                 }
    1220       32748 :               _local_size = this->local_size();
    1221             :             }
    1222             :           else
    1223             :             {
    1224     1286604 :               LibmeshPetscCall(VecGhostGetLocalForm (_vec,&_local_form));
    1225             : 
    1226     1286604 :               if (read_only)
    1227             :                 {
    1228     1286604 :                   LibmeshPetscCall(VecGetArrayRead(_local_form, &_read_only_values));
    1229     1286604 :                   _values_read_only = true;
    1230             :                 }
    1231             :               else
    1232             :                 {
    1233           0 :                   LibmeshPetscCall(VecGetArray(_local_form, &_values));
    1234           0 :                   _values_read_only = false;
    1235             :                 }
    1236             : 
    1237     1286604 :               PetscInt my_local_size = 0;
    1238     1286604 :               LibmeshPetscCall(VecGetLocalSize(_local_form, &my_local_size));
    1239     1286604 :               _local_size = static_cast<numeric_index_type>(my_local_size);
    1240             :             }
    1241             : 
    1242             :           { // cache ownership range
    1243     1319352 :             PetscInt petsc_first=0, petsc_last=0;
    1244     1319352 :             LibmeshPetscCall(VecGetOwnershipRange (_vec, &petsc_first, &petsc_last));
    1245     1319352 :             _first = static_cast<numeric_index_type>(petsc_first);
    1246     1319352 :             _last = static_cast<numeric_index_type>(petsc_last);
    1247             :           }
    1248       73910 :           _array_is_present.store(true, std::memory_order_release);
    1249             :         }
    1250             :     }
    1251  7175880747 : }
    1252             : 
    1253             : 
    1254             : 
    1255             : template <typename T>
    1256   353609484 : void PetscVector<T>::_restore_array() const
    1257             : {
    1258   353609484 :   libmesh_error_msg_if(_values_manually_retrieved,
    1259             :                        "PetscVector values were manually retrieved but are being automatically restored!");
    1260             : 
    1261    28826540 :   libmesh_assert (this->initialized());
    1262   353609484 :   if (_array_is_present.load(std::memory_order_acquire))
    1263             :     {
    1264     1393262 :       std::scoped_lock lock(_petsc_get_restore_array_mutex);
    1265     1319352 :       if (_array_is_present.load(std::memory_order_relaxed))
    1266             :         {
    1267     1319352 :                   if (this->type() != GHOSTED)
    1268             :             {
    1269       32748 :               if (_values_read_only)
    1270       32122 :                 LibmeshPetscCall(VecRestoreArrayRead (_vec, &_read_only_values));
    1271             :               else
    1272         626 :                 LibmeshPetscCall(VecRestoreArray (_vec, &_values));
    1273             : 
    1274       32748 :               _values = nullptr;
    1275             :             }
    1276             :           else
    1277             :             {
    1278     1286604 :               if (_values_read_only)
    1279     1286604 :                 LibmeshPetscCall(VecRestoreArrayRead (_local_form, &_read_only_values));
    1280             :               else
    1281           0 :                 LibmeshPetscCall(VecRestoreArray (_local_form, &_values));
    1282             : 
    1283     1286604 :               _values = nullptr;
    1284     1286604 :               LibmeshPetscCall(VecGhostRestoreLocalForm (_vec,&_local_form));
    1285     1286604 :               _local_form = nullptr;
    1286     1286604 :               _local_size = 0;
    1287             :             }
    1288       73910 :           _array_is_present.store(false, std::memory_order_release);
    1289             :         }
    1290             :     }
    1291   353609484 : }
    1292             : 
    1293             : template <typename T>
    1294             : std::unique_ptr<NumericVector<T>>
    1295        8590 : PetscVector<T>::get_subvector(const std::vector<numeric_index_type> & rows)
    1296             : {
    1297             :   // Construct index set
    1298          38 :   WrappedPetsc<IS> parent_is;
    1299        8628 :   LibmeshPetscCall(ISCreateGeneral(this->comm().get(),
    1300             :                                    cast_int<PetscInt>(rows.size()),
    1301             :                                    numeric_petsc_cast(rows.data()),
    1302             :                                    PETSC_USE_POINTER,
    1303             :                                    parent_is.get()));
    1304             : 
    1305             :   Vec subvec;
    1306        8590 :   LibmeshPetscCall(VecGetSubVector(_vec, parent_is, &subvec));
    1307             : 
    1308        8590 :   this->_is_closed = false;
    1309             : 
    1310        8628 :   return std::make_unique<PetscVector<T>>(subvec, this->comm());
    1311             : }
    1312             : 
    1313             : template <typename T>
    1314             : void
    1315        8590 : PetscVector<T>::restore_subvector(std::unique_ptr<NumericVector<T>> subvector,
    1316             :                                   const std::vector<numeric_index_type> & rows)
    1317             : {
    1318          38 :   auto * const petsc_subvector = cast_ptr<PetscVector<T> *>(subvector.get());
    1319             : 
    1320             :   // Construct index set
    1321          38 :   WrappedPetsc<IS> parent_is;
    1322        8628 :   LibmeshPetscCall(ISCreateGeneral(this->comm().get(),
    1323             :                                    cast_int<PetscInt>(rows.size()),
    1324             :                                    numeric_petsc_cast(rows.data()),
    1325             :                                    PETSC_USE_POINTER,
    1326             :                                    parent_is.get()));
    1327             : 
    1328        8590 :   Vec subvec = petsc_subvector->vec();
    1329        8590 :   LibmeshPetscCall(VecRestoreSubVector(_vec, parent_is, &subvec));
    1330             : 
    1331        8590 :   if (this->type() == GHOSTED)
    1332           0 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
    1333             : 
    1334        8590 :   this->_is_closed = true;
    1335        8590 : }
    1336             : 
    1337             : //------------------------------------------------------------------
    1338             : // Explicit instantiations
    1339             : template class LIBMESH_EXPORT PetscVector<Number>;
    1340             : 
    1341             : } // namespace libMesh
    1342             : 
    1343             : 
    1344             : 
    1345             : #endif // #ifdef LIBMESH_HAVE_PETSC

Generated by: LCOV version 1.14