$extrastylesheet
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