$extrastylesheet
distributed_vector.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 
00020 #include "libmesh/libmesh_common.h"
00021 
00022 // C++ includes
00023 #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
00024 #include <cmath> // for std::abs
00025 #include <limits> // std::numeric_limits<T>::min()
00026 
00027 // Local Includes
00028 #include "libmesh/distributed_vector.h"
00029 #include "libmesh/dense_vector.h"
00030 #include "libmesh/dense_subvector.h"
00031 #include "libmesh/parallel.h"
00032 #include "libmesh/tensor_tools.h"
00033 
00034 namespace libMesh
00035 {
00036 
00037 
00038 
00039 //--------------------------------------------------------------------------
00040 // DistributedVector methods
00041 template <typename T>
00042 T DistributedVector<T>::sum () const
00043 {
00044   // This function must be run on all processors at once
00045   parallel_object_only();
00046 
00047   libmesh_assert (this->initialized());
00048   libmesh_assert_equal_to (_values.size(), _local_size);
00049   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00050 
00051   T local_sum = 0.;
00052 
00053   for (numeric_index_type i=0; i<local_size(); i++)
00054     local_sum += _values[i];
00055 
00056   this->comm().sum(local_sum);
00057 
00058   return local_sum;
00059 }
00060 
00061 
00062 
00063 template <typename T>
00064 Real DistributedVector<T>::l1_norm () const
00065 {
00066   // This function must be run on all processors at once
00067   parallel_object_only();
00068 
00069   libmesh_assert (this->initialized());
00070   libmesh_assert_equal_to (_values.size(), _local_size);
00071   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00072 
00073   double local_l1 = 0.;
00074 
00075   for (numeric_index_type i=0; i<local_size(); i++)
00076     local_l1 += std::abs(_values[i]);
00077 
00078   this->comm().sum(local_l1);
00079 
00080   return local_l1;
00081 }
00082 
00083 
00084 
00085 template <typename T>
00086 Real DistributedVector<T>::l2_norm () const
00087 {
00088   // This function must be run on all processors at once
00089   parallel_object_only();
00090 
00091   libmesh_assert (this->initialized());
00092   libmesh_assert_equal_to (_values.size(), _local_size);
00093   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00094 
00095   double local_l2 = 0.;
00096 
00097   for (numeric_index_type i=0; i<local_size(); i++)
00098     local_l2 += TensorTools::norm_sq(_values[i]);
00099 
00100   this->comm().sum(local_l2);
00101 
00102   return std::sqrt(local_l2);
00103 }
00104 
00105 
00106 
00107 template <typename T>
00108 Real DistributedVector<T>::linfty_norm () const
00109 {
00110   // This function must be run on all processors at once
00111   parallel_object_only();
00112 
00113   libmesh_assert (this->initialized());
00114   libmesh_assert_equal_to (_values.size(), _local_size);
00115   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00116 
00117   Real local_linfty = 0.;
00118 
00119   for (numeric_index_type i=0; i<local_size(); i++)
00120     local_linfty  = std::max(local_linfty,
00121                              static_cast<Real>(std::abs(_values[i]))
00122                              ); // Note we static_cast so that both
00123                                 // types are the same, as required
00124                                 // by std::max
00125 
00126   this->comm().max(local_linfty);
00127 
00128   return local_linfty;
00129 }
00130 
00131 
00132 
00133 template <typename T>
00134 NumericVector<T>& DistributedVector<T>::operator += (const NumericVector<T>& v)
00135 {
00136   libmesh_assert (this->closed());
00137   libmesh_assert (this->initialized());
00138   libmesh_assert_equal_to (_values.size(), _local_size);
00139   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00140 
00141   add(1., v);
00142 
00143   return *this;
00144 }
00145 
00146 
00147 
00148 template <typename T>
00149 NumericVector<T>& DistributedVector<T>::operator -= (const NumericVector<T>& v)
00150 {
00151   libmesh_assert (this->closed());
00152   libmesh_assert (this->initialized());
00153   libmesh_assert_equal_to (_values.size(), _local_size);
00154   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00155 
00156   add(-1., v);
00157 
00158   return *this;
00159 }
00160 
00161 
00162 
00163 template <typename T>
00164 NumericVector<T> & DistributedVector<T>::operator /= (NumericVector<T> & v)
00165 {
00166   libmesh_assert_equal_to(size(), v.size());
00167 
00168   DistributedVector<T> & v_vec = cast_ref<DistributedVector<T>&>(v);
00169 
00170   std::size_t val_size = _values.size();
00171 
00172   for(std::size_t i=0; i<val_size; i++)
00173     _values[i] = _values[i] / v_vec._values[i];
00174 
00175   return *this;
00176 }
00177 
00178 
00179 
00180 
00181 template <typename T>
00182 void DistributedVector<T>::reciprocal()
00183 {
00184   for (numeric_index_type i=0; i<local_size(); i++)
00185     {
00186       // Don't divide by zero
00187       libmesh_assert_not_equal_to (_values[i], T(0));
00188 
00189       _values[i] = 1. / _values[i];
00190     }
00191 }
00192 
00193 
00194 
00195 
00196 template <typename T>
00197 void DistributedVector<T>::conjugate()
00198 {
00199   for (numeric_index_type i=0; i<local_size(); i++)
00200     {
00201       // Replace values by complex conjugate
00202       _values[i] = libmesh_conj(_values[i]);
00203     }
00204 }
00205 
00206 
00207 
00208 
00209 
00210 template <typename T>
00211 void DistributedVector<T>::add (const T v)
00212 {
00213   libmesh_assert (this->initialized());
00214   libmesh_assert_equal_to (_values.size(), _local_size);
00215   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00216 
00217   for (numeric_index_type i=0; i<local_size(); i++)
00218     _values[i] += v;
00219 }
00220 
00221 
00222 
00223 template <typename T>
00224 void DistributedVector<T>::add (const NumericVector<T>& v)
00225 {
00226   libmesh_assert (this->initialized());
00227   libmesh_assert_equal_to (_values.size(), _local_size);
00228   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00229 
00230   add (1., v);
00231 }
00232 
00233 
00234 
00235 template <typename T>
00236 void DistributedVector<T>::add (const T a, const NumericVector<T>& v)
00237 {
00238   libmesh_assert (this->initialized());
00239   libmesh_assert_equal_to (_values.size(), _local_size);
00240   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00241 
00242   add(a, v);
00243 }
00244 
00245 
00246 
00247 template <typename T>
00248 void DistributedVector<T>::scale (const T factor)
00249 {
00250   libmesh_assert (this->initialized());
00251   libmesh_assert_equal_to (_values.size(), _local_size);
00252   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00253 
00254   for (std::size_t i=0; i<local_size(); i++)
00255     _values[i] *= factor;
00256 }
00257 
00258 template <typename T>
00259 void DistributedVector<T>::abs()
00260 {
00261   libmesh_assert (this->initialized());
00262   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00263 
00264   for (numeric_index_type i=0; i<local_size(); i++)
00265     this->set(i,std::abs(_values[i]));
00266 }
00267 
00268 
00269 
00270 
00271 
00272 template <typename T>
00273 T DistributedVector<T>::dot (const NumericVector<T>& V) const
00274 {
00275   // This function must be run on all processors at once
00276   parallel_object_only();
00277 
00278   // Make sure the NumericVector passed in is really a DistributedVector
00279   const DistributedVector<T>* v = cast_ptr<const DistributedVector<T>*>(&V);
00280 
00281   // Make sure that the two vectors are distributed in the same way.
00282   libmesh_assert_equal_to ( this->first_local_index(), v->first_local_index() );
00283   libmesh_assert_equal_to ( this->last_local_index(), v->last_local_index()  );
00284 
00285   // The result of dotting together the local parts of the vector.
00286   T local_dot = 0;
00287 
00288   for (std::size_t i=0; i<this->local_size(); i++)
00289     local_dot += this->_values[i] * v->_values[i];
00290 
00291   // The local dot products are now summed via MPI
00292   this->comm().sum(local_dot);
00293 
00294   return local_dot;
00295 }
00296 
00297 
00298 
00299 template <typename T>
00300 NumericVector<T>&
00301 DistributedVector<T>::operator = (const T s)
00302 {
00303   libmesh_assert (this->initialized());
00304   libmesh_assert_equal_to (_values.size(), _local_size);
00305   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00306 
00307   for (std::size_t i=0; i<local_size(); i++)
00308     _values[i] = s;
00309 
00310   return *this;
00311 }
00312 
00313 
00314 
00315 template <typename T>
00316 NumericVector<T>&
00317 DistributedVector<T>::operator = (const NumericVector<T>& v_in)
00318 {
00319   // Make sure the NumericVector passed in is really a DistributedVector
00320   const DistributedVector<T>* v = cast_ptr<const DistributedVector<T>*>(&v_in);
00321 
00322   *this = *v;
00323 
00324   return *this;
00325 }
00326 
00327 
00328 
00329 template <typename T>
00330 DistributedVector<T>&
00331 DistributedVector<T>::operator = (const DistributedVector<T>& v)
00332 {
00333   this->_is_initialized    = v._is_initialized;
00334   this->_is_closed         = v._is_closed;
00335 
00336   _global_size       = v._global_size;
00337   _local_size        = v._local_size;
00338   _first_local_index = v._first_local_index;
00339   _last_local_index  = v._last_local_index;
00340 
00341   if (v.local_size() == this->local_size())
00342     _values = v._values;
00343 
00344   else
00345     libmesh_error_msg("v.local_size() = " << v.local_size() << " must be equal to this->local_size() = " << this->local_size());
00346 
00347   return *this;
00348 }
00349 
00350 
00351 
00352 template <typename T>
00353 NumericVector<T>&
00354 DistributedVector<T>::operator = (const std::vector<T>& v)
00355 {
00356   libmesh_assert (this->initialized());
00357   libmesh_assert_equal_to (_values.size(), _local_size);
00358   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00359 
00360   if (v.size() == local_size())
00361     _values = v;
00362 
00363   else if (v.size() == size())
00364     for (std::size_t i=first_local_index(); i<last_local_index(); i++)
00365       _values[i-first_local_index()] = v[i];
00366 
00367   else
00368     libmesh_error_msg("Incompatible sizes in DistributedVector::operator=");
00369 
00370   return *this;
00371 }
00372 
00373 
00374 
00375 template <typename T>
00376 void DistributedVector<T>::localize (NumericVector<T>& v_local_in) const
00377 
00378 {
00379   libmesh_assert (this->initialized());
00380   libmesh_assert_equal_to (_values.size(), _local_size);
00381   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00382 
00383   DistributedVector<T>* v_local = cast_ptr<DistributedVector<T>*>(&v_local_in);
00384 
00385   v_local->_first_local_index = 0;
00386 
00387   v_local->_global_size =
00388     v_local->_local_size =
00389     v_local->_last_local_index = size();
00390 
00391   v_local->_is_initialized =
00392     v_local->_is_closed = true;
00393 
00394   // Call localize on the vector's values.  This will help
00395   // prevent code duplication
00396   localize (v_local->_values);
00397 
00398 #ifndef LIBMESH_HAVE_MPI
00399 
00400   libmesh_assert_equal_to (local_size(), size());
00401 
00402 #endif
00403 }
00404 
00405 
00406 
00407 template <typename T>
00408 void DistributedVector<T>::localize (NumericVector<T>& v_local_in,
00409                                      const std::vector<numeric_index_type>&) const
00410 {
00411   libmesh_assert (this->initialized());
00412   libmesh_assert_equal_to (_values.size(), _local_size);
00413   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00414 
00415   // TODO: We don't yet support the send list; this is inefficient:
00416   localize (v_local_in);
00417 }
00418 
00419 
00420 
00421 template <typename T>
00422 void DistributedVector<T>::localize (const numeric_index_type first_local_idx,
00423                                      const numeric_index_type last_local_idx,
00424                                      const std::vector<numeric_index_type>& send_list)
00425 {
00426   // Only good for serial vectors
00427   libmesh_assert_equal_to (this->size(), this->local_size());
00428   libmesh_assert_greater (last_local_idx, first_local_idx);
00429   libmesh_assert_less_equal (send_list.size(), this->size());
00430   libmesh_assert_less (last_local_idx, this->size());
00431 
00432   const numeric_index_type my_size       = this->size();
00433   const numeric_index_type my_local_size = (last_local_idx - first_local_idx + 1);
00434 
00435   // Don't bother for serial cases
00436   if ((first_local_idx == 0) &&
00437       (my_local_size == my_size))
00438     return;
00439 
00440 
00441   // Build a parallel vector, initialize it with the local
00442   // parts of (*this)
00443   DistributedVector<T> parallel_vec(this->comm());
00444 
00445   parallel_vec.init (my_size, my_local_size, true, PARALLEL);
00446 
00447   // Copy part of *this into the parallel_vec
00448   for (numeric_index_type i=first_local_idx; i<=last_local_idx; i++)
00449     parallel_vec._values[i-first_local_idx] = _values[i];
00450 
00451   // localize like normal
00452   parallel_vec.localize (*this, send_list);
00453 }
00454 
00455 
00456 
00457 template <typename T>
00458 void DistributedVector<T>::localize (std::vector<T>& v_local) const
00459 {
00460   // This function must be run on all processors at once
00461   parallel_object_only();
00462 
00463   libmesh_assert (this->initialized());
00464   libmesh_assert_equal_to (_values.size(), _local_size);
00465   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00466 
00467   v_local = this->_values;
00468 
00469   this->comm().allgather (v_local);
00470 
00471 #ifndef LIBMESH_HAVE_MPI
00472   libmesh_assert_equal_to (local_size(), size());
00473 #endif
00474 }
00475 
00476 
00477 
00478 template <typename T>
00479 void DistributedVector<T>::localize_to_one (std::vector<T>& v_local,
00480                                             const processor_id_type pid) const
00481 {
00482   // This function must be run on all processors at once
00483   parallel_object_only();
00484 
00485   libmesh_assert (this->initialized());
00486   libmesh_assert_equal_to (_values.size(), _local_size);
00487   libmesh_assert_equal_to ((_last_local_index - _first_local_index), _local_size);
00488 
00489   v_local = this->_values;
00490 
00491   this->comm().gather (pid, v_local);
00492 
00493 #ifndef LIBMESH_HAVE_MPI
00494   libmesh_assert_equal_to (local_size(), size());
00495 #endif
00496 }
00497 
00498 
00499 
00500 template <typename T>
00501 void DistributedVector<T>::pointwise_mult (const NumericVector<T>&,
00502                                            const NumericVector<T>&)
00503 //void DistributedVector<T>::pointwise_mult (const NumericVector<T>& vec1,
00504 //   const NumericVector<T>& vec2)
00505 {
00506   libmesh_not_implemented();
00507 }
00508 
00509 
00510 
00511 //--------------------------------------------------------------
00512 // Explicit instantiations
00513 template class DistributedVector<Number>;
00514 
00515 } // namespace libMesh