LCOV - code coverage report
Current view: top level - src/numerics - petsc_vector.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4476 (4beb67) with base a68cc6 Lines: 383 466 82.2 %
Date: 2026-06-03 20:22:46 Functions: 50 55 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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"
      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      263751 : Real PetscVector<T>::norm () const
      61             : {
      62        7654 :   parallel_object_only();
      63             : 
      64      263751 :   this->_restore_array();
      65        7654 :   libmesh_assert(this->closed());
      66             : 
      67      263751 :   PetscReal value=0.;
      68             : 
      69      263751 :   LibmeshPetscCall(VecNorm (_vec, N, &value));
      70             : 
      71      263751 :   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      262001 : Real PetscVector<T>::l2_norm () const
      80             : {
      81      262001 :   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    44138174 : void PetscVector<T>::set (const numeric_index_type i, const T value)
     125             : {
     126    44138174 :   this->_restore_array();
     127     4052344 :   libmesh_assert_less (i, size());
     128             : 
     129    44138174 :   PetscInt i_val = static_cast<PetscInt>(i);
     130    44138174 :   PetscScalar petsc_value = PS(value);
     131             : 
     132    44138174 :   std::scoped_lock lock(this->_numeric_vector_mutex);
     133    44138174 :   LibmeshPetscCall(VecSetValues (_vec, 1, &i_val, &petsc_value, INSERT_VALUES));
     134             : 
     135    44138174 :   this->_is_closed = false;
     136    44138174 : }
     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   190413154 : void PetscVector<T>::add (const numeric_index_type i, const T value)
     166             : {
     167   190413154 :   this->_restore_array();
     168    16671969 :   libmesh_assert_less (i, size());
     169             : 
     170   190413154 :   PetscInt i_val = static_cast<PetscInt>(i);
     171   190413154 :   PetscScalar petsc_value = PS(value);
     172             : 
     173   190413154 :   std::scoped_lock lock(this->_numeric_vector_mutex);
     174   190413154 :   LibmeshPetscCall(VecSetValues (_vec, 1, &i_val, &petsc_value, ADD_VALUES));
     175             : 
     176   190413154 :   this->_is_closed = false;
     177   190413154 : }
     178             : 
     179             : 
     180             : 
     181             : template <typename T>
     182    74796616 : 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    74796616 :   if (dof_indices.empty())
     187           0 :     return;
     188             : 
     189    74796616 :   this->_restore_array();
     190             : 
     191    11356020 :   const PetscInt * i_val = reinterpret_cast<const PetscInt *>(dof_indices.data());
     192     5782458 :   const PetscScalar * petsc_value = pPS(v);
     193             : 
     194    74796616 :   std::scoped_lock lock(this->_numeric_vector_mutex);
     195    80370178 :   LibmeshPetscCall(VecSetValues (_vec, cast_int<PetscInt>(dof_indices.size()),
     196             :                                  i_val, petsc_value, ADD_VALUES));
     197             : 
     198    74796616 :   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     4369171 : void PetscVector<T>::add (const T a_in, const NumericVector<T> & v_in)
     316             : {
     317      124982 :   parallel_object_only();
     318             : 
     319     4369171 :   this->_restore_array();
     320             : 
     321             :   // VecAXPY doesn't support &x==&y
     322     4369171 :   if (this == &v_in)
     323             :     {
     324         140 :       this->scale(a_in+1);
     325         140 :       return;
     326             :     }
     327             : 
     328      124978 :   PetscScalar a = PS(a_in);
     329             : 
     330             :   // Make sure the NumericVector passed in is really a PetscVector
     331      124978 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     332     4369031 :   v->_restore_array();
     333             : 
     334      124978 :   libmesh_assert_equal_to (this->size(), v->size());
     335             : 
     336     4369031 :   LibmeshPetscCall(VecAXPY(_vec, a, v->vec()));
     337             : 
     338      124978 :   libmesh_assert(this->comm().verify(
     339             :       static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
     340             : 
     341      124978 :   if (this->is_effectively_ghosted())
     342       96048 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     343             : 
     344     4369031 :   this->_is_closed = true;
     345             : }
     346             : 
     347             : 
     348             : 
     349             : template <typename T>
     350     5109831 : void PetscVector<T>::insert (const T * v,
     351             :                              const std::vector<numeric_index_type> & dof_indices)
     352             : {
     353     5109831 :   if (dof_indices.empty())
     354           0 :     return;
     355             : 
     356     5109831 :   this->_restore_array();
     357             : 
     358      923670 :   PetscInt * idx_values = numeric_petsc_cast(dof_indices.data());
     359     5109831 :   std::scoped_lock lock(this->_numeric_vector_mutex);
     360     5571666 :   LibmeshPetscCall(VecSetValues (_vec, cast_int<PetscInt>(dof_indices.size()),
     361             :                                  idx_values, pPS(v), INSERT_VALUES));
     362             : 
     363     5109831 :   this->_is_closed = false;
     364             : }
     365             : 
     366             : 
     367             : 
     368             : template <typename T>
     369      632902 : void PetscVector<T>::scale (const T factor_in)
     370             : {
     371       18076 :   parallel_object_only();
     372             : 
     373      632902 :   this->_restore_array();
     374             : 
     375       18076 :   PetscScalar factor = PS(factor_in);
     376             : 
     377      632902 :   LibmeshPetscCall(VecScale(_vec, factor));
     378             : 
     379       18076 :   libmesh_assert(this->comm().verify(
     380             :       static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
     381             : 
     382       18076 :   if (this->is_effectively_ghosted())
     383           0 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     384      632902 : }
     385             : 
     386             : template <typename T>
     387         140 : NumericVector<T> & PetscVector<T>::operator *= (const NumericVector<T> & v)
     388             : {
     389           4 :   parallel_object_only();
     390             : 
     391             : 
     392           4 :   const PetscVector<T> * v_vec = cast_ptr<const PetscVector<T> *>(&v);
     393             : 
     394         140 :   LibmeshPetscCall(VecPointwiseMult(_vec, _vec, v_vec->_vec));
     395             : 
     396         140 :   return *this;
     397             : }
     398             : 
     399             : template <typename T>
     400       79452 : NumericVector<T> & PetscVector<T>::operator /= (const NumericVector<T> & v)
     401             : {
     402        2448 :   parallel_object_only();
     403             : 
     404             : 
     405        2448 :   const PetscVector<T> * v_vec = cast_ptr<const PetscVector<T> *>(&v);
     406             : 
     407       79452 :   LibmeshPetscCall(VecPointwiseDivide(_vec, _vec, v_vec->_vec));
     408             : 
     409       79452 :   return *this;
     410             : }
     411             : 
     412             : template <typename T>
     413           0 : void PetscVector<T>::abs()
     414             : {
     415           0 :   parallel_object_only();
     416             : 
     417           0 :   this->_restore_array();
     418             : 
     419           0 :   LibmeshPetscCall(VecAbs(_vec));
     420             : 
     421           0 :   libmesh_assert(this->comm().verify(
     422             :       static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
     423             : 
     424           0 :   if (this->is_effectively_ghosted())
     425           0 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     426           0 : }
     427             : 
     428             : template <typename T>
     429    10363074 : T PetscVector<T>::dot (const NumericVector<T> & v_in) const
     430             : {
     431      296116 :   parallel_object_only();
     432             : 
     433    10363074 :   this->_restore_array();
     434             : 
     435             :   // Error flag
     436             : 
     437             :   // Return value
     438    10363074 :   PetscScalar value=0.;
     439             : 
     440             :   // Make sure the NumericVector passed in is really a PetscVector
     441      296116 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     442             : 
     443             :   // 2.3.x (at least) style.  Untested for previous versions.
     444    10363074 :   LibmeshPetscCall(VecDot(this->_vec, v->_vec, &value));
     445             : 
     446    10363074 :   return static_cast<T>(value);
     447             : }
     448             : 
     449             : template <typename T>
     450           0 : T PetscVector<T>::indefinite_dot (const NumericVector<T> & v_in) const
     451             : {
     452           0 :   parallel_object_only();
     453             : 
     454           0 :   this->_restore_array();
     455             : 
     456             :   // Error flag
     457             : 
     458             :   // Return value
     459           0 :   PetscScalar value=0.;
     460             : 
     461             :   // Make sure the NumericVector passed in is really a PetscVector
     462           0 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     463             : 
     464             :   // 2.3.x (at least) style.  Untested for previous versions.
     465           0 :   LibmeshPetscCall(VecTDot(this->_vec, v->_vec, &value));
     466             : 
     467           0 :   return static_cast<T>(value);
     468             : }
     469             : 
     470             : 
     471             : template <typename T>
     472             : NumericVector<T> &
     473         140 : PetscVector<T>::operator = (const T s_in)
     474             : {
     475           4 :   parallel_object_only();
     476             : 
     477         140 :   this->_restore_array();
     478           4 :   libmesh_assert(this->closed());
     479             : 
     480           4 :   PetscScalar s = PS(s_in);
     481             : 
     482         140 :   if (this->size() != 0)
     483             :     {
     484         140 :       LibmeshPetscCall(VecSet(_vec, s));
     485             : 
     486           4 :       libmesh_assert(this->comm().verify(
     487             :           static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
     488             : 
     489           4 :       if (this->is_effectively_ghosted())
     490           0 :         VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     491             :     }
     492             : 
     493         140 :   return *this;
     494             : }
     495             : 
     496             : 
     497             : 
     498             : template <typename T>
     499             : NumericVector<T> &
     500     3940565 : PetscVector<T>::operator = (const NumericVector<T> & v_in)
     501             : {
     502      110384 :   parallel_object_only();
     503             : 
     504             :   // Make sure the NumericVector passed in is really a PetscVector
     505      110384 :   const PetscVector<T> * v = cast_ptr<const PetscVector<T> *>(&v_in);
     506             : 
     507     3940565 :   *this = *v;
     508             : 
     509     3940565 :   return *this;
     510             : }
     511             : 
     512             : 
     513             : 
     514             : template <typename T>
     515             : PetscVector<T> &
     516     3940635 : PetscVector<T>::operator = (const PetscVector<T> & v)
     517             : {
     518             :   enum AssignmentType { ParallelToSerial, SerialToParallel, SameToSame, Error };
     519             : 
     520      110386 :   parallel_object_only();
     521      110386 :   libmesh_assert(this->comm().verify(
     522             :       static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
     523      110386 :   libmesh_assert(this->comm().verify(
     524             :       static_cast<typename std::underlying_type<ParallelType>::type>(v.type())));
     525             : 
     526     3940635 :   if (this == &v)
     527         480 :     return *this;
     528             : 
     529     3923835 :   this->_restore_array();
     530     3923835 :   v._restore_array();
     531             : 
     532      109906 :   libmesh_assert_equal_to (this->size(), v.size());
     533      109906 :   libmesh_assert (v.closed());
     534             : 
     535      109906 :   AssignmentType assign_type = Error;
     536      109906 :   if (this->is_effectively_serial() && !v.is_effectively_serial())
     537          48 :     assign_type = ParallelToSerial;
     538      109858 :   else if (!this->is_effectively_serial() && v.is_effectively_serial())
     539           0 :     assign_type = SerialToParallel;
     540     3922179 :   else if (this->local_size() == v.local_size())
     541      109858 :     assign_type = SameToSame;
     542             : 
     543      109906 :   libmesh_assert(this->comm().verify(
     544             :       static_cast<typename std::underlying_type<AssignmentType>::type>(assign_type)));
     545             : 
     546      109906 :   switch (assign_type)
     547             :     {
     548          48 :       case ParallelToSerial:
     549             :       {
     550             :           // scatter from parallel to serial
     551          48 :           libmesh_assert(v.comm().size() > 1);
     552          96 :           WrappedPetsc<VecScatter> scatter;
     553        1656 :           LibmeshPetscCall(VecScatterCreateToAll(v._vec, scatter.get(), nullptr));
     554        1656 :           VecScatterBeginEnd(v.comm(), scatter, v._vec, _vec, INSERT_VALUES, SCATTER_FORWARD);
     555          48 :           break;
     556             :       }
     557      109858 :       case SameToSame:
     558             :         // serial to serial or parallel to parallel
     559     3922179 :         LibmeshPetscCall(VecCopy(v._vec, _vec));
     560      109858 :         break;
     561           0 :       case SerialToParallel:
     562           0 :         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           0 :       default:
     566           0 :         libmesh_error_msg("Unhandled vector combination");
     567             :     }
     568             : 
     569      109906 :   libmesh_assert(this->comm().verify(
     570             :       static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
     571             : 
     572      109906 :   if (this->is_effectively_ghosted())
     573     2867104 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     574             : 
     575     3923835 :   this->_is_closed = true;
     576             : 
     577     3923835 :   return *this;
     578             : }
     579             : 
     580             : 
     581             : 
     582             : template <typename T>
     583             : NumericVector<T> &
     584          70 : PetscVector<T>::operator = (const std::vector<T> & v)
     585             : {
     586           2 :   parallel_object_only();
     587             : 
     588          70 :   this->_get_array(false);
     589             : 
     590             :   /**
     591             :    * Case 1:  The vector is the same size of
     592             :    * The global vector.  Only add the local components.
     593             :    */
     594          70 :   if (this->size() == v.size())
     595             :     {
     596          70 :       numeric_index_type first = first_local_index();
     597          70 :       numeric_index_type last = last_local_index();
     598      300860 :       for (numeric_index_type i=0; i<last-first; i++)
     599      309384 :         _values[i] = PS(v[first + i]);
     600             :     }
     601             : 
     602             :   /**
     603             :    * Case 2: The vector is the same size as our local
     604             :    * piece.  Insert directly to the local piece.
     605             :    */
     606             :   else
     607             :     {
     608           0 :       for (numeric_index_type i=0; i<_local_size; i++)
     609           0 :         _values[i] = PS(v[i]);
     610             :     }
     611             : 
     612             :   // Make sure ghost dofs are up to date
     613           2 :   if (this->is_effectively_ghosted())
     614           0 :     this->close();
     615             : 
     616          70 :   return *this;
     617             : }
     618             : 
     619             : 
     620             : 
     621             : template <typename T>
     622      126761 : void PetscVector<T>::localize (NumericVector<T> & v_local_in) const
     623             : {
     624       62864 :   parallel_object_only();
     625             : 
     626       62864 :   libmesh_assert(this->comm().verify(
     627             :       static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
     628       62864 :   libmesh_assert(this->comm().verify(
     629             :       static_cast<typename std::underlying_type<ParallelType>::type>(v_local_in.type())));
     630             : 
     631      126761 :   v_local_in = *this;
     632      126761 : }
     633             : 
     634             : 
     635             : 
     636             : template <typename T>
     637     2274133 : void PetscVector<T>::localize (NumericVector<T> & v_local_in,
     638             :                                const std::vector<numeric_index_type> & /*send_list*/) const
     639             : {
     640      124624 :   this->localize(v_local_in);
     641      140464 : }
     642             : 
     643             : 
     644             : 
     645             : template <typename T>
     646         140 : void PetscVector<T>::localize (std::vector<T> & v_local,
     647             :                                const std::vector<numeric_index_type> & indices) const
     648             : {
     649           4 :   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           8 :   WrappedPetsc<Vec> dest;
     655         144 :   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           8 :   PetscInt * idxptr =
     661         140 :     indices.empty() ? nullptr : numeric_petsc_cast(indices.data());
     662           8 :   WrappedPetsc<IS> is;
     663         140 :   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           8 :   WrappedPetsc<VecScatter> scatter;
     668         140 :   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         140 :   VecScatterBeginEnd(this->comm(), scatter, _vec, dest, INSERT_VALUES, SCATTER_FORWARD);
     676             : 
     677             :   // Get access to the values stored in dest.
     678             :   PetscScalar * values;
     679         140 :   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         144 :   v_local.reserve(indices.size());
     685           4 :   v_local.clear();
     686         144 :   v_local.insert(v_local.begin(), values, values+indices.size());
     687             : 
     688             :   // We are done using it, so restore the array.
     689         140 :   LibmeshPetscCall(VecRestoreArray (dest, &values));
     690         140 : }
     691             : 
     692             : 
     693             : 
     694             : template <typename T>
     695       17428 : 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         672 :   parallel_object_only();
     700             : 
     701       17428 :   this->_restore_array();
     702             : 
     703         672 :   libmesh_assert_less_equal (send_list.size(), this->size());
     704         672 :   libmesh_assert_less_equal (last_local_idx+1, this->size());
     705             : 
     706       17428 :   const numeric_index_type my_size       = this->size();
     707       17428 :   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       18100 :   if (this->n_processors() == 1)
     714         244 :     return;
     715             : 
     716             : 
     717             :   // Build a parallel vector, initialize it with the local
     718             :   // parts of (*this)
     719       18528 :   PetscVector<T> parallel_vec(this->comm(), PARALLEL);
     720             : 
     721       17184 :   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       17856 :     std::vector<PetscInt> idx(my_local_size);
     728         672 :     std::iota (idx.begin(), idx.end(), first_local_idx);
     729             : 
     730             :     // Create the index set & scatter objects
     731        1344 :     WrappedPetsc<IS> is;
     732       32470 :     LibmeshPetscCall(ISCreateGeneral(this->comm().get(), my_local_size,
     733             :                                      my_local_size ? idx.data() : nullptr, PETSC_USE_POINTER, is.get()));
     734             : 
     735         672 :     WrappedPetsc<VecScatter> scatter;
     736       17184 :     LibmeshPetscCall(VecScatterCreate(_vec,              is,
     737             :                                       parallel_vec._vec, is,
     738             :                                       scatter.get()));
     739             : 
     740             :     // Perform the scatter
     741       17184 :     VecScatterBeginEnd(this->comm(), scatter, _vec, parallel_vec._vec, INSERT_VALUES, SCATTER_FORWARD);
     742             :   }
     743             : 
     744             :   // localize like normal
     745       17184 :   parallel_vec.close();
     746       17184 :   parallel_vec.localize (*this, send_list);
     747       17184 :   this->close();
     748       15840 : }
     749             : 
     750             : 
     751             : 
     752             : template <typename T>
     753       21350 : void PetscVector<T>::localize (std::vector<T> & v_local) const
     754             : {
     755         610 :   parallel_object_only();
     756             : 
     757       21350 :   this->_restore_array();
     758             : 
     759             :   // This function must be run on all processors at once
     760         610 :   parallel_object_only();
     761             : 
     762       21350 :   const PetscInt n = this->size();
     763       21350 :   const PetscInt nl = this->local_size();
     764             :   PetscScalar * values;
     765             : 
     766         610 :   v_local.clear();
     767       21350 :   v_local.resize(n, 0.);
     768             : 
     769       21350 :   LibmeshPetscCall(VecGetArray (_vec, &values));
     770             : 
     771       21350 :   numeric_index_type ioff = first_local_index();
     772             : 
     773    13196761 :   for (PetscInt i=0; i<nl; i++)
     774    14372892 :     v_local[i+ioff] = static_cast<T>(values[i]);
     775             : 
     776       21350 :   LibmeshPetscCall(VecRestoreArray (_vec, &values));
     777             : 
     778       21350 :   this->comm().sum(v_local);
     779       21350 : }
     780             : 
     781             : 
     782             : 
     783             : // Full specialization for Real datatypes
     784             : #ifdef LIBMESH_USE_REAL_NUMBERS
     785             : 
     786             : template <>
     787       85454 : void PetscVector<Real>::localize_to_one (std::vector<Real> & v_local,
     788             :                                          const processor_id_type
     789             :                                          timpi_mpi_var(pid)) const
     790             : {
     791        2694 :   parallel_object_only();
     792             : 
     793       85454 :   this->_restore_array();
     794             : 
     795       85454 :   const PetscInt n  = size();
     796             :   PetscScalar * values;
     797             : 
     798             :   // only one processor
     799       88148 :   if (n_processors() == 1)
     800             :     {
     801        1213 :       v_local.resize(n);
     802             : 
     803        1213 :       LibmeshPetscCall(VecGetArray (_vec, &values));
     804             : 
     805     2717154 :       for (PetscInt i=0; i<n; i++)
     806     2715941 :         v_local[i] = static_cast<Real>(values[i]);
     807             : 
     808        1213 :       LibmeshPetscCall(VecRestoreArray (_vec, &values));
     809             :     }
     810             : 
     811             :   // otherwise multiple processors
     812             : #ifdef LIBMESH_HAVE_MPI
     813             :   else
     814             :     {
     815       84241 :       if (pid == 0) // optimized version for localizing to 0
     816             :         {
     817        5388 :           WrappedPetsc<Vec> vout;
     818        5388 :           WrappedPetsc<VecScatter> ctx;
     819             : 
     820       84241 :           LibmeshPetscCall(VecScatterCreateToZero(_vec, ctx.get(), vout.get()));
     821             : 
     822       84241 :           VecScatterBeginEnd(this->comm(), ctx, _vec, vout, INSERT_VALUES, SCATTER_FORWARD);
     823             : 
     824       86935 :           if (processor_id() == 0)
     825             :             {
     826       12451 :               v_local.resize(n);
     827             : 
     828       12451 :               LibmeshPetscCall(VecGetArray (vout, &values));
     829             : 
     830    27244108 :               for (PetscInt i=0; i<n; i++)
     831    29922653 :                 v_local[i] = static_cast<Real>(values[i]);
     832             : 
     833       12451 :               LibmeshPetscCall(VecRestoreArray (vout, &values));
     834             :             }
     835             :         }
     836             :       else
     837             :         {
     838           0 :           v_local.resize(n);
     839             : 
     840           0 :           numeric_index_type ioff = this->first_local_index();
     841           0 :           std::vector<Real> local_values (n, 0.);
     842             : 
     843             :           {
     844           0 :             LibmeshPetscCall(VecGetArray (_vec, &values));
     845             : 
     846           0 :             const PetscInt nl = local_size();
     847           0 :             for (PetscInt i=0; i<nl; i++)
     848           0 :               local_values[i+ioff] = static_cast<Real>(values[i]);
     849             : 
     850           0 :             LibmeshPetscCall(VecRestoreArray (_vec, &values));
     851             :           }
     852             : 
     853             : 
     854           0 :           MPI_Reduce (local_values.data(), v_local.data(), n,
     855           0 :                       Parallel::StandardType<Real>(),
     856             :                       Parallel::OpFunction<Real>::sum(), pid,
     857           0 :                       this->comm().get());
     858             :         }
     859             :     }
     860             : #endif // LIBMESH_HAVE_MPI
     861       85454 : }
     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,
     934             :                   Parallel::StandardType<Real>(),
     935             :                   Parallel::OpFunction<Real>::sum(),
     936             :                   pid, this->comm().get());
     937             : 
     938             :       MPI_Reduce (imag_local_values.data(),
     939             :                   imag_v_local.data(), n,
     940             :                   Parallel::StandardType<Real>(),
     941             :                   Parallel::OpFunction<Real>::sum(),
     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>
     955          70 : void PetscVector<T>::pointwise_mult (const NumericVector<T> & vec1,
     956             :                                      const NumericVector<T> & vec2)
     957             : {
     958           2 :   parallel_object_only();
     959             : 
     960          70 :   this->_restore_array();
     961             : 
     962             :   // Convert arguments to PetscVector*.
     963           2 :   const PetscVector<T> * vec1_petsc = cast_ptr<const PetscVector<T> *>(&vec1);
     964           2 :   const PetscVector<T> * vec2_petsc = cast_ptr<const PetscVector<T> *>(&vec2);
     965             : 
     966             :   // Call PETSc function.
     967          70 :   LibmeshPetscCall(VecPointwiseMult(_vec, vec1_petsc->vec(), vec2_petsc->vec()));
     968             : 
     969           2 :   libmesh_assert(this->comm().verify(
     970             :       static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
     971             : 
     972           2 :   if (this->is_effectively_ghosted())
     973           0 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     974             : 
     975          70 :   this->_is_closed = true;
     976          70 : }
     977             : 
     978             : template <typename T>
     979          70 : void PetscVector<T>::pointwise_divide (const NumericVector<T> & vec1,
     980             :                                        const NumericVector<T> & vec2)
     981             : {
     982           2 :   parallel_object_only();
     983             : 
     984          70 :   this->_restore_array();
     985             : 
     986             :   // Convert arguments to PetscVector*.
     987           2 :   const PetscVector<T> * const vec1_petsc = cast_ptr<const PetscVector<T> *>(&vec1);
     988           2 :   const PetscVector<T> * const vec2_petsc = cast_ptr<const PetscVector<T> *>(&vec2);
     989             : 
     990             :   // Call PETSc function.
     991          70 :   LibmeshPetscCall(VecPointwiseDivide(_vec, vec1_petsc->vec(), vec2_petsc->vec()));
     992             : 
     993           2 :   libmesh_assert(this->comm().verify(
     994             :       static_cast<typename std::underlying_type<ParallelType>::type>(this->type())));
     995             : 
     996           2 :   if (this->is_effectively_ghosted())
     997           0 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
     998             : 
     999          70 :   this->_is_closed = true;
    1000          70 : }
    1001             : 
    1002             : template <typename T>
    1003         140 : void PetscVector<T>::print_matlab (const std::string & name) const
    1004             : {
    1005           4 :   parallel_object_only();
    1006             : 
    1007         140 :   this->_restore_array();
    1008           4 :   libmesh_assert (this->closed());
    1009             : 
    1010             :   // Create an ASCII file containing the matrix
    1011             :   // if a filename was provided.
    1012         140 :   if (name != "")
    1013             :     {
    1014           8 :       WrappedPetsc<PetscViewer> petsc_viewer;
    1015             : 
    1016         140 :       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         140 :       LibmeshPetscCall(PetscViewerPushFormat (petsc_viewer,
    1025             :                                               PETSC_VIEWER_ASCII_MATLAB));
    1026             : #endif
    1027             : 
    1028         140 :       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           0 :       LibmeshPetscCall(PetscViewerPushFormat (PETSC_VIEWER_STDOUT_WORLD,
    1040             :                                               PETSC_VIEWER_ASCII_MATLAB));
    1041             : #endif
    1042             : 
    1043           0 :       LibmeshPetscCall(VecView (_vec, PETSC_VIEWER_STDOUT_WORLD));
    1044             :     }
    1045         140 : }
    1046             : 
    1047             : 
    1048             : 
    1049             : 
    1050             : 
    1051             : template <typename T>
    1052        8610 : void PetscVector<T>::create_subvector(NumericVector<T> & subvector,
    1053             :                                       const std::vector<numeric_index_type> & rows,
    1054             :                                       const bool supplying_global_rows) const
    1055             : {
    1056         246 :   parallel_object_only();
    1057             : 
    1058         246 :   libmesh_error_msg_if(
    1059             :       subvector.is_effectively_ghosted(),
    1060             :       "We do not support scattering parallel information to ghosts for subvectors");
    1061             : 
    1062        8610 :   this->_restore_array();
    1063             : 
    1064             :   // PETSc data structures
    1065             : 
    1066             :   // Make sure the passed in subvector is really a PetscVector
    1067         246 :   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        8610 :   if (!petsc_subvector->initialized())
    1073             :     {
    1074           0 :       if (this->is_effectively_serial())
    1075             :         {
    1076           0 :           libmesh_assert(this->comm().verify(rows.size()));
    1077           0 :           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           0 :           petsc_subvector->_type = (this->type() == SERIAL) ? SERIAL : PARALLEL;
    1085             : 
    1086           0 :           if (petsc_subvector->type() == AUTOMATIC &&
    1087           0 :               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           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             :           // We created a parallel vector
    1128           0 :           petsc_subvector->_type = PARALLEL;
    1129             :         }
    1130             : 
    1131           0 :       LibmeshPetscCall(VecSetFromOptions (petsc_subvector->_vec));
    1132             : 
    1133             : 
    1134             :       // Mark the subvector as initialized
    1135           0 :       petsc_subvector->_is_initialized = true;
    1136             :     }
    1137             :   else
    1138             :     {
    1139        8610 :       petsc_subvector->_restore_array();
    1140             :     }
    1141             : 
    1142        9102 :   std::vector<PetscInt> idx(rows.size());
    1143        8610 :   if (supplying_global_rows)
    1144           4 :     std::iota (idx.begin(), idx.end(), 0);
    1145             :   else
    1146             :     {
    1147             :       PetscInt start;
    1148        8470 :       LibmeshPetscCall(VecGetOwnershipRange(petsc_subvector->_vec, &start, nullptr));
    1149        8470 :       std::iota (idx.begin(), idx.end(), start);
    1150             :     }
    1151             : 
    1152             :   // Construct index sets
    1153         492 :   WrappedPetsc<IS> parent_is;
    1154        8856 :   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         492 :   WrappedPetsc<IS> subvector_is;
    1161        8856 :   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         246 :   WrappedPetsc<VecScatter> scatter;
    1169        8610 :   LibmeshPetscCall(VecScatterCreate(this->_vec,
    1170             :                                     parent_is,
    1171             :                                     petsc_subvector->_vec,
    1172             :                                     subvector_is,
    1173             :                                     scatter.get()));
    1174             : 
    1175             :   // Actually perform the scatter
    1176        8610 :   VecScatterBeginEnd(this->comm(), scatter, this->_vec, petsc_subvector->_vec, INSERT_VALUES, SCATTER_FORWARD);
    1177             : 
    1178        8610 :   petsc_subvector->_is_closed = true;
    1179        8610 : }
    1180             : 
    1181             : 
    1182             : 
    1183             : template <typename T>
    1184  7454797555 : void PetscVector<T>::_get_array(bool read_only) const
    1185             : {
    1186   589768282 :   libmesh_assert (this->initialized());
    1187             : 
    1188   589768282 :   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  7454797555 :   if (initially_array_is_present && read_only && !_values_read_only)
    1193    24807602 :     _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  7454797555 :   if (initially_array_is_present && !read_only && _values_read_only)
    1200             :     {
    1201         210 :       _restore_array();
    1202           6 :       initially_array_is_present = false;
    1203             :     }
    1204             : 
    1205  7454797351 :   if (!initially_array_is_present)
    1206             :     {
    1207     1956665 :       std::scoped_lock lock(_petsc_get_restore_array_mutex);
    1208     1841419 :       if (!_array_is_present.load(std::memory_order_relaxed))
    1209             :         {
    1210      115099 :           if (!this->is_effectively_ghosted())
    1211             :             {
    1212      124789 :               if (read_only)
    1213             :                 {
    1214      124163 :                   LibmeshPetscCall(VecGetArrayRead(_vec, &_read_only_values));
    1215      124163 :                   _values_read_only = true;
    1216             :                 }
    1217             :               else
    1218             :                 {
    1219         626 :                   LibmeshPetscCall(VecGetArray(_vec, &_values));
    1220         626 :                   _values_read_only = false;
    1221             :                 }
    1222      124789 :               _local_size = this->local_size();
    1223             :             }
    1224             :           else
    1225             :             {
    1226     1716247 :               LibmeshPetscCall(VecGhostGetLocalForm (_vec,&_local_form));
    1227             : 
    1228     1716247 :               if (read_only)
    1229             :                 {
    1230     1716247 :                   LibmeshPetscCall(VecGetArrayRead(_local_form, &_read_only_values));
    1231     1716247 :                   _values_read_only = true;
    1232             :                 }
    1233             :               else
    1234             :                 {
    1235           0 :                   LibmeshPetscCall(VecGetArray(_local_form, &_values));
    1236           0 :                   _values_read_only = false;
    1237             :                 }
    1238             : 
    1239     1716247 :               PetscInt my_local_size = 0;
    1240     1716247 :               LibmeshPetscCall(VecGetLocalSize(_local_form, &my_local_size));
    1241     1716247 :               _local_size = static_cast<numeric_index_type>(my_local_size);
    1242             :             }
    1243             : 
    1244             :           { // cache ownership range
    1245     1841036 :             PetscInt petsc_first=0, petsc_last=0;
    1246     1841036 :             LibmeshPetscCall(VecGetOwnershipRange (_vec, &petsc_first, &petsc_last));
    1247     1841036 :             _first = static_cast<numeric_index_type>(petsc_first);
    1248     1841036 :             _last = static_cast<numeric_index_type>(petsc_last);
    1249             :           }
    1250      115099 :           _array_is_present.store(true, std::memory_order_release);
    1251             :         }
    1252             :     }
    1253  7454797555 : }
    1254             : 
    1255             : 
    1256             : 
    1257             : template <typename T>
    1258   360100611 : void PetscVector<T>::_restore_array() const
    1259             : {
    1260   360100611 :   libmesh_error_msg_if(_values_manually_retrieved,
    1261             :                        "PetscVector values were manually retrieved but are being automatically restored!");
    1262             : 
    1263    28260730 :   libmesh_assert (this->initialized());
    1264   360100611 :   if (_array_is_present.load(std::memory_order_acquire))
    1265             :     {
    1266     1956135 :       std::scoped_lock lock(_petsc_get_restore_array_mutex);
    1267     1841036 :       if (_array_is_present.load(std::memory_order_relaxed))
    1268             :         {
    1269      115099 :           if (!this->is_effectively_ghosted())
    1270             :             {
    1271      124789 :               if (_values_read_only)
    1272      124163 :                 LibmeshPetscCall(VecRestoreArrayRead (_vec, &_read_only_values));
    1273             :               else
    1274         626 :                 LibmeshPetscCall(VecRestoreArray (_vec, &_values));
    1275             : 
    1276      124789 :               _values = nullptr;
    1277             :             }
    1278             :           else
    1279             :             {
    1280     1716247 :               if (_values_read_only)
    1281     1716247 :                 LibmeshPetscCall(VecRestoreArrayRead (_local_form, &_read_only_values));
    1282             :               else
    1283           0 :                 LibmeshPetscCall(VecRestoreArray (_local_form, &_values));
    1284             : 
    1285     1716247 :               _values = nullptr;
    1286     1716247 :               LibmeshPetscCall(VecGhostRestoreLocalForm (_vec,&_local_form));
    1287     1716247 :               _local_form = nullptr;
    1288     1716247 :               _local_size = 0;
    1289             :             }
    1290      115099 :           _array_is_present.store(false, std::memory_order_release);
    1291             :         }
    1292             :     }
    1293   360100611 : }
    1294             : 
    1295             : template <typename T>
    1296             : std::unique_ptr<NumericVector<T>>
    1297       15730 : PetscVector<T>::get_subvector(const std::vector<numeric_index_type> & rows)
    1298             : {
    1299             :   // Construct index set
    1300         242 :   WrappedPetsc<IS> parent_is;
    1301       15972 :   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       15730 :   LibmeshPetscCall(VecGetSubVector(_vec, parent_is, &subvec));
    1309             : 
    1310       15730 :   this->_is_closed = false;
    1311             : 
    1312       15972 :   return std::make_unique<PetscVector<T>>(subvec, this->comm());
    1313             : }
    1314             : 
    1315             : template <typename T>
    1316             : void
    1317       15730 : PetscVector<T>::restore_subvector(std::unique_ptr<NumericVector<T>> subvector,
    1318             :                                   const std::vector<numeric_index_type> & rows)
    1319             : {
    1320         242 :   auto * const petsc_subvector = cast_ptr<PetscVector<T> *>(subvector.get());
    1321             : 
    1322             :   // Construct index set
    1323         242 :   WrappedPetsc<IS> parent_is;
    1324       15972 :   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       15730 :   Vec subvec = petsc_subvector->vec();
    1331       15730 :   LibmeshPetscCall(VecRestoreSubVector(_vec, parent_is, &subvec));
    1332             : 
    1333         242 :   if (this->is_effectively_ghosted())
    1334           0 :     VecGhostUpdateBeginEnd(this->comm(), _vec, INSERT_VALUES, SCATTER_FORWARD);
    1335             : 
    1336       15730 :   this->_is_closed = true;
    1337       15730 : }
    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

Generated by: LCOV version 1.14