libMesh
Loading...
Searching...
No Matches
numeric_vector.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19// Local Includes
20#include "libmesh/numeric_vector.h"
21#include "libmesh/distributed_vector.h"
22#include "libmesh/laspack_vector.h"
23#include "libmesh/eigen_sparse_vector.h"
24#include "libmesh/petsc_vector.h"
25#include "libmesh/trilinos_epetra_vector.h"
26#include "libmesh/shell_matrix.h"
27#include "libmesh/tensor_tools.h"
28#include "libmesh/enum_solver_package.h"
29#include "libmesh/int_range.h"
30
31// gzstream for reading/writing compressed files as a stream
32#ifdef LIBMESH_HAVE_GZSTREAM
33# include "gzstream.h"
34#endif
35
36// C++ includes
37#include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
38#include <cmath> // for std::abs
39#include <fstream>
40#include <iostream>
41#include <sstream>
42#include <limits>
43#include <memory>
44
45#ifdef LIBMESH_HAVE_CXX11_REGEX
46#include <regex>
47#endif
48
49
50namespace libMesh
51{
52
53
54
55//------------------------------------------------------------------
56// NumericVector methods
57
58// Full specialization for Real datatypes
59template <typename T>
60std::unique_ptr<NumericVector<T>>
62 SolverPackage solver_package,
63 ParallelType parallel_type)
64{
65 // Build the appropriate vector
66 switch (solver_package)
67 {
68
69#ifdef LIBMESH_HAVE_LASPACK
70 case LASPACK_SOLVERS:
71 return std::make_unique<LaspackVector<T>>(comm, parallel_type);
72#endif
73
74#ifdef LIBMESH_HAVE_PETSC
75 case PETSC_SOLVERS:
76 return std::make_unique<PetscVector<T>>(comm, parallel_type);
77#endif
78
79#ifdef LIBMESH_TRILINOS_HAVE_EPETRA
81 return std::make_unique<EpetraVector<T>>(comm, parallel_type);
82#endif
83
84#ifdef LIBMESH_HAVE_EIGEN
85 case EIGEN_SOLVERS:
86 return std::make_unique<EigenSparseVector<T>>(comm, parallel_type);
87#endif
88
89 default:
90 return std::make_unique<DistributedVector<T>>(comm, parallel_type);
91 }
92}
93
94
95
96template <typename T>
98{
99 // Check for no-op
100 if (_type == t)
101 return;
102
103 // If the NumericVector is not yet initialized, then it is generally
104 // safe to change the ParallelType, with minor restrictions.
105 if (!this->initialized())
106 {
107 // If ghosted vectors are not enabled and the user requested a
108 // GHOSTED vector, fall back on SERIAL.
109#ifndef LIBMESH_ENABLE_GHOSTED
110 if (t == GHOSTED)
111 {
112 _type = SERIAL;
113 return;
114 }
115#endif
116
117 _type = t;
118 return;
119 }
120
121 // If we made it here, then the NumericVector was already
122 // initialized and we don't currently allow the ParallelType to be
123 // changed, although this could potentially be added later.
124 libmesh_not_implemented();
125}
126
127template <typename T>
128void NumericVector<T>::insert (const T * v,
129 const std::vector<numeric_index_type> & dof_indices)
130{
131 libmesh_assert (v);
132
133 for (auto i : index_range(dof_indices))
134 this->set (dof_indices[i], v[i]);
135}
136
137
138
139template <typename T>
141 const std::vector<numeric_index_type> & dof_indices)
142{
143 libmesh_assert_equal_to (V.size(), dof_indices.size());
145
146 for (auto i : index_range(dof_indices))
147 this->set (dof_indices[i], V(i));
148}
149
150
151
152template <typename T>
154 const Real threshold) const
155{
156 libmesh_assert(this->compatible(other_vector));
157
158 int first_different_i = std::numeric_limits<int>::max();
159 numeric_index_type i = first_local_index();
160
161 while (first_different_i==std::numeric_limits<int>::max()
162 && i<last_local_index())
163 {
164 if (std::abs((*this)(i) - other_vector(i)) > threshold)
165 first_different_i = i;
166 else
167 i++;
168 }
169
170 // Find the correct first differing index in parallel
171 this->comm().min(first_different_i);
172
173 if (first_different_i == std::numeric_limits<int>::max())
174 return -1;
175
176 return first_different_i;
177}
178
179
180template <typename T>
182 const Real threshold) const
183{
184 libmesh_assert(this->compatible(other_vector));
185
186 int first_different_i = std::numeric_limits<int>::max();
187 numeric_index_type i = first_local_index();
188
189 do
190 {
191 if (std::abs((*this)(i) - other_vector(i)) > threshold *
192 std::max(std::abs((*this)(i)), std::abs(other_vector(i))))
193 first_different_i = i;
194 else
195 i++;
196 }
197 while (first_different_i==std::numeric_limits<int>::max()
198 && i<last_local_index());
199
200 // Find the correct first differing index in parallel
201 this->comm().min(first_different_i);
202
203 if (first_different_i == std::numeric_limits<int>::max())
204 return -1;
205
206 return first_different_i;
207}
208
209
210template <typename T>
212 const Real threshold) const
213{
214 libmesh_assert(this->compatible(other_vector));
215
216 int first_different_i = std::numeric_limits<int>::max();
217 numeric_index_type i = first_local_index();
218
219 const Real my_norm = this->linfty_norm();
220 const Real other_norm = other_vector.linfty_norm();
221 const Real abs_threshold = std::max(my_norm, other_norm) * threshold;
222
223 do
224 {
225 if (std::abs((*this)(i) - other_vector(i) ) > abs_threshold)
226 first_different_i = i;
227 else
228 i++;
229 }
230 while (first_different_i==std::numeric_limits<int>::max()
231 && i<last_local_index());
232
233 // Find the correct first differing index in parallel
234 this->comm().min(first_different_i);
235
236 if (first_different_i == std::numeric_limits<int>::max())
237 return -1;
238
239 return first_different_i;
240}
241
242
243
244template <typename T>
245void NumericVector<T>::print_matlab(const std::string & filename) const
246{
247 parallel_object_only();
248
249 libmesh_assert (this->initialized());
250
251 const numeric_index_type first_dof = this->first_local_index(),
252 end_dof = this->last_local_index();
253
254 // We'll print the vector from processor 0 to make sure
255 // it's serialized properly
256 if (this->processor_id() == 0)
257 {
258 std::unique_ptr<std::ofstream> file;
259
260 if (filename != "")
261 file = std::make_unique<std::ofstream>(filename.c_str());
262
263 std::ostream & os = (filename == "") ? libMesh::out : *file;
264
265 // Print a header similar to PETSC_VIEWER_ASCII_MATLAB
266 os << "%Vec Object: () " << this->n_processors() << " MPI processes\n"
267 << "% type: " << (this->n_processors() > 1 ? "mpi" : "seq") << "\n"
268 << "Vec = [\n";
269
270 for (numeric_index_type i : make_range(end_dof))
271 os << (*this)(i) << '\n';
272
273 std::vector<T> cbuf;
274 for (auto p : IntRange<processor_id_type>(1, this->n_processors()))
275 {
276 this->comm().receive(p, cbuf);
277
278 for (auto c : cbuf)
279 os << c << '\n';
280 }
281
282 os << "];\n" << std::endl;
283 }
284 else
285 {
286 std::vector<T> cbuf(end_dof - first_dof);
287
288 for (numeric_index_type i : make_range(end_dof - first_dof))
289 cbuf[i] = (*this)(first_dof+i);
290 this->comm().send(0,cbuf);
291 }
292}
293
294
295
296template <typename T>
297void NumericVector<T>::read_matlab(const std::string & filename)
298{
299 LOG_SCOPE("read_matlab()", "NumericVector");
300
301#ifndef LIBMESH_HAVE_CXX11_REGEX
302 libmesh_not_implemented(); // What is your compiler?!? Email us!
303 libmesh_ignore(filename);
304#else
305 parallel_object_only();
306
307 const bool gzipped_file = Utility::ends_with(filename, ".gz");
308
309 // If we don't already have this size, we'll need to reinit, and
310 // determine which entries each processor is in charge of.
311 std::vector<numeric_index_type> first_entries, end_entries;
312
313 numeric_index_type first_entry = 0,
314 end_entry = 0,
315 n = 0;
316
317 // We'll use an istream here; it might be an ifstream if we're
318 // opening a raw ASCII file or a gzstream if we're opening a
319 // compressed one.
320 std::unique_ptr<std::istream> file;
321
322 // First read through the file, saving size and entry data
323 std::vector<T> entries;
324
325 {
326 // We'll read the vector on processor 0 rather than try to juggle
327 // parallel I/O.
328 if (this->processor_id() == 0)
329 {
330 // We'll be using regular expressions to make ourselves slightly
331 // more robust to formatting.
332 const std::regex start_regex // assignment like "Vec_0x84000002_1 = ["
333 ("\\s*\\w+\\s*=\\s*\\[");
334 const std::regex end_regex // end of assignment
335 ("^[^%]*\\]");
336
337 if (gzipped_file)
339#ifdef LIBMESH_HAVE_GZSTREAM
340 auto inf = std::make_unique<igzstream>();
341 libmesh_assert(inf);
342 inf->open(filename.c_str(), std::ios::in);
343 file = std::move(inf);
344#else
345 libmesh_error_msg("ERROR: need gzstream to handle .gz files!!!");
346#endif
348 else
349 {
350 auto inf = std::make_unique<std::ifstream>();
351 libmesh_assert(inf);
352
353 std::string new_name = Utility::unzip_file(filename);
354
355 inf->open(new_name.c_str(), std::ios::in);
356 file = std::move(inf);
357 }
358
359 const std::string whitespace = " \t";
360
361 bool have_started = false;
362 bool have_ended = false;
363
364 for (std::string line; std::getline(*file, line);)
365 {
366 std::smatch sm;
368 // First, try to match an entry. This is the most common
369 // case so we won't rely on slow std::regex for it.
370 // stringstream is at least an improvement over that.
371 std::istringstream l(line);
372 T value;
373 l >> value;
374
375 if (!l.fail())
376 {
377 libmesh_error_msg_if
378 (!have_started, "Confused by premature entries in vector file " << filename);
379
380 entries.push_back(value);
381 ++n;
382 }
383
384 else if (std::regex_search(line, start_regex))
385 have_started = true;
386
387 else if (std::regex_search(line, end_regex))
388 {
389 have_ended = true;
390 break;
391 }
392 }
393
394 libmesh_error_msg_if
395 (!have_started, "Confused by missing assignment-beginning in vector file " << filename);
396
397 libmesh_error_msg_if
398 (!have_ended, "Confused by missing assignment-ending in vector file " << filename);
399 }
400
401 this->comm().broadcast(n);
402
403 if (this->initialized() &&
404 n == this->size())
405 {
406 first_entry = this->first_local_index(),
407 end_entry = this->last_local_index();
408 }
409 else
410 {
411 // Determine which rows/columns each processor will be in charge of
412 first_entry = this->processor_id() * n / this->n_processors(),
413 end_entry = (this->processor_id()+1) * n / this->n_processors();
414 }
415
416 this->comm().gather(0, first_entry, first_entries);
417 this->comm().gather(0, end_entry, end_entries);
418
419 } // Done reading entry data and broadcasting vector size
420
421 // If we're not already initialized compatibly with the file then
422 // we'll initialize here
423 bool need_init = !this->initialized() ||
424 (this->size() != n) ||
425 (this->local_size() != end_entry - first_entry);
426
427 this->comm().max(need_init);
428
429 if (need_init)
430 this->init(n, end_entry - first_entry);
431
432 // Set the vector values last. The iota call here is inefficient
433 // but it's probably better than calling a single virtual function
434 // per index.
435 if (this->processor_id() == 0)
436 for (auto p : make_range(this->n_processors()))
437 {
438 const numeric_index_type first_entry_p = first_entries[p];
439 const numeric_index_type n_local = end_entries[p] - first_entry_p;
440 std::vector<numeric_index_type> indices(n_local);
441 std::iota(indices.begin(), indices.end(), first_entry_p);
442 this->insert(entries.data() + first_entries[p],
443 indices);
444 }
445
446 this->close();
447#endif
448}
449
450
451/*
452// Full specialization for float datatypes (DistributedVector wants this)
453
454template <>
455int NumericVector<float>::compare (const NumericVector<float> & other_vector,
456const Real threshold) const
457{
458libmesh_assert (this->initialized());
459libmesh_assert (other_vector.initialized());
460libmesh_assert_equal_to (this->first_local_index(), other_vector.first_local_index());
461libmesh_assert_equal_to (this->last_local_index(), other_vector.last_local_index());
462
463int rvalue = -1;
464numeric_index_type i = first_local_index();
465
466do
467{
468if (std::abs((*this)(i) - other_vector(i) ) > threshold)
469rvalue = i;
470else
471i++;
472}
473while (rvalue==-1 && i<last_local_index());
474
475return rvalue;
476}
477
478// Full specialization for double datatypes
479template <>
480int NumericVector<double>::compare (const NumericVector<double> & other_vector,
481const Real threshold) const
482{
483libmesh_assert (this->initialized());
484libmesh_assert (other_vector.initialized());
485libmesh_assert_equal_to (this->first_local_index(), other_vector.first_local_index());
486libmesh_assert_equal_to (this->last_local_index(), other_vector.last_local_index());
487
488int rvalue = -1;
489numeric_index_type i = first_local_index();
490
491do
492{
493if (std::abs((*this)(i) - other_vector(i) ) > threshold)
494rvalue = i;
495else
496i++;
497}
498while (rvalue==-1 && i<last_local_index());
499
500return rvalue;
501}
502
503#ifdef LIBMESH_DEFAULT_TRIPLE_PRECISION
504// Full specialization for long double datatypes
505template <>
506int NumericVector<long double>::compare (const NumericVector<long double> & other_vector,
507const Real threshold) const
508{
509libmesh_assert (this->initialized());
510libmesh_assert (other_vector.initialized());
511libmesh_assert_equal_to (this->first_local_index(), other_vector.first_local_index());
512libmesh_assert_equal_to (this->last_local_index(), other_vector.last_local_index());
513
514int rvalue = -1;
515numeric_index_type i = first_local_index();
516
517do
518{
519if (std::abs((*this)(i) - other_vector(i) ) > threshold)
520rvalue = i;
521else
522i++;
523}
524while (rvalue==-1 && i<last_local_index());
525
526return rvalue;
527}
528#endif
529
530
531// Full specialization for Complex datatypes
532template <>
533int NumericVector<Complex>::compare (const NumericVector<Complex> & other_vector,
534const Real threshold) const
535{
536libmesh_assert (this->initialized());
537libmesh_assert (other_vector.initialized());
538libmesh_assert_equal_to (this->first_local_index(), other_vector.first_local_index());
539libmesh_assert_equal_to (this->last_local_index(), other_vector.last_local_index());
540
541int rvalue = -1;
542numeric_index_type i = first_local_index();
543
545{
546if ((std::abs((*this)(i).real() - other_vector(i).real()) > threshold) || (std::abs((*this)(i).imag() - other_vector(i).imag()) > threshold))
547rvalue = i;
548else
549i++;
550}
551while (rvalue==-1 && i<this->last_local_index());
552
553return rvalue;
554}
555*/
556
557
558template <class T>
559Real NumericVector<T>::subset_l1_norm (const std::set<numeric_index_type> & indices) const
560{
561 libmesh_assert (this->readable());
562
563 const NumericVector<T> & v = *this;
564
565 Real norm = 0;
566
567 for (const auto & index : indices)
568 norm += std::abs(v(index));
570 this->comm().sum(norm);
571
572 return norm;
573}
574
575template <class T>
576Real NumericVector<T>::subset_l2_norm (const std::set<numeric_index_type> & indices) const
577{
578 libmesh_assert (this->readable());
579
580 const NumericVector<T> & v = *this;
581
582 Real norm = 0;
583
584 for (const auto & index : indices)
585 norm += TensorTools::norm_sq(v(index));
586
587 this->comm().sum(norm);
588
589 return std::sqrt(norm);
590}
591
592template <class T>
593Real NumericVector<T>::subset_linfty_norm (const std::set<numeric_index_type> & indices) const
594{
595 libmesh_assert (this->readable());
596
597 const NumericVector<T> & v = *this;
599 Real norm = 0;
600
601 for (const auto & index : indices)
602 {
603 Real value = std::abs(v(index));
604 if (value > norm)
605 norm = value;
606 }
607
608 this->comm().max(norm);
609
610 return norm;
611}
612
613
614
615template <class T>
617{
618 libmesh_assert(this->compatible(v));
619
620 struct L2Differ {
621 const NumericVector<T> & v1, & v2;
622 Real norm_sq;
623
624 L2Differ (const NumericVector<T> & v1in,
625 const NumericVector<T> & v2in) :
626 v1(v1in), v2(v2in), norm_sq(0) {}
627
628 L2Differ (L2Differ & other, Threads::split) :
629 v1(other.v1), v2(other.v2), norm_sq(0) {}
630
631 void operator()(const IntRange<numeric_index_type> & index_range) {
632 for (const auto i : index_range)
633 norm_sq += TensorTools::norm_sq(v1(i) - v2(i));
634 }
635
636 void join(const L2Differ & other) {
637 norm_sq += other.norm_sq;
638 }
639 };
640
641 L2Differ differ(*this, v);
642
643 Threads::parallel_reduce(make_range(this->first_local_index(), this->last_local_index()), differ);
644
645 this->comm().sum(differ.norm_sq);
646
647 return std::sqrt(differ.norm_sq);
648}
649
650
651
652template <class T>
654{
655 libmesh_assert(this->compatible(v));
656
657 struct L1Differ {
658 const NumericVector<T> & v1, & v2;
659 Real norm;
660
661 L1Differ (const NumericVector<T> & v1in,
662 const NumericVector<T> & v2in) :
663 v1(v1in), v2(v2in), norm(0) {}
664
665 L1Differ (L1Differ & other, Threads::split) :
666 v1(other.v1), v2(other.v2), norm(0) {}
667
668 void operator()(const IntRange<numeric_index_type> & index_range) {
669 for (const auto i : index_range)
670 norm += libMesh::l1_norm_diff(v1(i), v2(i));
671 }
672
673 void join(const L1Differ & other) {
674 norm += other.norm;
675 }
676 };
677
678 L1Differ differ(*this, v);
679
680 Threads::parallel_reduce(make_range(this->first_local_index(), this->last_local_index()), differ);
681
682 this->comm().sum(differ.norm);
683
684 return differ.norm;
685}
686
687
688
689template <typename T>
691 const std::vector<numeric_index_type> & dof_indices)
692{
694
695 for (auto i : index_range(dof_indices))
696 this->add (dof_indices[i], v[i]);
697}
698
699
700
701template <typename T>
703 const std::vector<numeric_index_type> & dof_indices)
704{
706
707 const std::size_t n = dof_indices.size();
708 libmesh_assert_equal_to(v.size(), n);
709 for (numeric_index_type i=0; i != n; i++)
710 this->add (dof_indices[i], v(i));
711}
712
714
715template <typename T>
717 const ShellMatrix<T> & a)
718{
719 libmesh_assert(this->compatible(v));
720
721 a.vector_mult_add(*this,v);
722}
723
724
725
726template <typename T>
728{
729 return this->initialized() && this->closed();
730}
731
732
733template <typename T>
735{
736 return this->readable() && v.readable() &&
737 this->size() == v.size() &&
738 this->local_size() == v.local_size() &&
739 this->first_local_index() == v.first_local_index() &&
740 this->last_local_index() == v.last_local_index();
741}
742
743
744//------------------------------------------------------------------
745// Explicit instantiations
746template class LIBMESH_EXPORT NumericVector<Number>;
747
748} // namespace libMesh
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
Definition int_range.h:54
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
Real l1_norm_diff(const NumericVector< T > &other_vec) const
virtual numeric_index_type last_local_index() const =0
void set_type(ParallelType t)
Allow the user to change the ParallelType of the NumericVector under some circumstances.
Real l2_norm_diff(const NumericVector< T > &other_vec) const
virtual void read_matlab(const std::string &filename)
Read the contents of the vector from the Matlab-script format used by PETSc.
virtual void print_matlab(const std::string &filename="") const
Print the contents of the vector in Matlab's sparse matrix format.
virtual void insert(const T *v, const std::vector< numeric_index_type > &dof_indices)
Inserts the entries of v in *this at the locations specified by v.
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices)
Computes , where v is a pointer and each dof_indices[i] specifies where to add value v[i].
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, SolverPackage solver_package=libMesh::default_solver_package(), ParallelType parallel_type=AUTOMATIC)
Builds a NumericVector on the processors in communicator comm using the linear solver package specifi...
virtual numeric_index_type size() const =0
virtual Real linfty_norm() const =0
bool compatible(const NumericVector< T > &v) const
virtual Real subset_l1_norm(const std::set< numeric_index_type > &indices) const
virtual numeric_index_type local_size() const =0
virtual Real subset_l2_norm(const std::set< numeric_index_type > &indices) const
virtual int compare(const NumericVector< T > &other_vector, const Real threshold=TOLERANCE) const
virtual numeric_index_type first_local_index() const =0
virtual int local_relative_compare(const NumericVector< T > &other_vector, const Real threshold=TOLERANCE) const
virtual int global_relative_compare(const NumericVector< T > &other_vector, const Real threshold=TOLERANCE) const
virtual Real subset_linfty_norm(const std::set< numeric_index_type > &indices) const
Generic shell matrix, i.e.
virtual void vector_mult_add(NumericVector< T > &dest, const NumericVector< T > &arg) const =0
Multiplies the matrix with arg and adds the result to dest.
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
void parallel_reduce(const Range &range, Body &body, unsigned int n_threads=libMesh::n_threads())
Execute the provided reduction operation in parallel on the specified range.
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
bool ends_with(std::string_view superstring, std::string_view suffix)
Look for a substring at the very end of a string.
Definition utility.C:213
std::string unzip_file(std::string_view name)
Create an unzipped copy of a bz2 or xz file, returning the name of the now-unzipped file that can be ...
Definition utility.C:164
The libMesh namespace provides an interface to certain functionality in the library.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
ParallelType
Defines an enum for parallel data structure types.
bool closed()
Checks that the library has been closed.
Definition libmesh.C:331
void libmesh_ignore(const Args &...)
libmesh_assert(ctx)
OStreamProxy out
dof_id_type numeric_index_type
Definition id_types.h:99
SolverPackage
Defines an enum for various linear solver packages.
bool initialized()
Checks that library initialization has been done.
Definition libmesh.C:324
auto l1_norm_diff(const NumericVector< T > &vec1, const NumericVector< T > &vec2)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition int_range.h:176
static const bool value
Definition xdr_io.C:55