21 #include "libmesh/sparse_matrix.h" 24 #include "libmesh/dof_map.h" 25 #include "libmesh/dense_matrix.h" 26 #include "libmesh/diagonal_matrix.h" 27 #include "libmesh/laspack_matrix.h" 28 #include "libmesh/libmesh_logging.h" 29 #include "libmesh/eigen_sparse_matrix.h" 30 #include "libmesh/parallel.h" 31 #include "libmesh/petsc_matrix.h" 32 #include "libmesh/trilinos_epetra_matrix.h" 33 #include "libmesh/numeric_vector.h" 34 #include "libmesh/enum_solver_package.h" 38 #ifdef LIBMESH_HAVE_GZSTREAM 39 # include "gzstream.h" 42 #ifdef LIBMESH_HAVE_HDF5 51 #ifdef LIBMESH_HAVE_CXX11_REGEX 71 _use_hash_table(false)
97 const std::vector<numeric_index_type> & brows,
98 const std::vector<numeric_index_type> & bcols)
100 libmesh_assert_equal_to (dm.
m() / brows.size(), dm.
n() / bcols.size());
103 (dm.
m() / brows.size());
105 libmesh_assert_equal_to (dm.
m()%blocksize, 0);
106 libmesh_assert_equal_to (dm.
n()%blocksize, 0);
108 std::vector<numeric_index_type> rows, cols;
110 rows.reserve(blocksize*brows.size());
111 cols.reserve(blocksize*bcols.size());
113 for (
auto & row : brows)
117 for (
unsigned int v=0; v<blocksize; v++)
121 for (
auto & col : bcols)
125 for (
unsigned int v=0; v<blocksize; v++)
129 this->add_matrix (dm, rows, cols);
142 libmesh_not_implemented();
145 os <<
"Real part:" << std::endl;
149 os << std::setw(8) << (*this)(i,j).
real() <<
" ";
153 os << std::endl <<
"Imaginary part:" << std::endl;
157 os << std::setw(8) << (*this)(i,j).
imag() <<
" ";
168 template <
typename T>
169 std::unique_ptr<SparseMatrix<T>>
178 return std::make_unique<DiagonalMatrix<T>>(comm);
181 switch (solver_package)
184 #ifdef LIBMESH_HAVE_LASPACK 186 return std::make_unique<LaspackMatrix<T>>(comm);
190 #ifdef LIBMESH_HAVE_PETSC 192 return std::make_unique<PetscMatrix<T>>(comm);
196 #ifdef LIBMESH_TRILINOS_HAVE_EPETRA 198 return std::make_unique<EpetraMatrix<T>>(comm);
202 #ifdef LIBMESH_HAVE_EIGEN 204 return std::make_unique<EigenSparseMatrix<T>>(comm);
208 libmesh_error_msg(
"ERROR: Unrecognized solver package: " << solver_package);
213 template <
typename T>
218 this->vector_mult_add(dest,arg);
223 template <
typename T>
234 template <
typename T>
238 libmesh_not_implemented();
242 template <
typename T>
251 template <
typename T>
254 parallel_object_only();
259 end_dof = this->row_stop();
263 if (this->processor_id() == 0)
265 libmesh_assert_equal_to (first_dof, 0);
273 if (c != static_cast<T>(0.0))
275 os << i <<
" " << j <<
" " << c << std::endl;
282 os << (*
this)(i,j) <<
" ";
287 std::vector<numeric_index_type> ibuf, jbuf;
292 this->comm().receive(p, ibuf);
293 this->comm().receive(p, jbuf);
294 this->comm().receive(p, cbuf);
295 libmesh_assert_equal_to (ibuf.size(), jbuf.size());
296 libmesh_assert_equal_to (ibuf.size(), cbuf.size());
300 libmesh_assert_greater_equal (ibuf.front(), currenti);
301 libmesh_assert_greater_equal (ibuf.back(), ibuf.front());
303 std::size_t currentb = 0;
304 for (;currenti <= ibuf.back(); ++currenti)
310 if (currentb < ibuf.size() &&
311 ibuf[currentb] == currenti &&
314 os << currenti <<
" " << j <<
" " << cbuf[currentb] << std::endl;
323 if (currentb < ibuf.size() &&
324 ibuf[currentb] == currenti &&
327 os << cbuf[currentb] <<
" ";
331 os << static_cast<T>(0.0) <<
" ";
339 for (; currenti != this->m(); ++currenti)
342 os << static_cast<T>(0.0) <<
" ";
349 std::vector<numeric_index_type> ibuf, jbuf;
359 if (c != static_cast<T>(0.0))
367 this->comm().send(0,ibuf);
368 this->comm().send(0,jbuf);
369 this->comm().send(0,cbuf);
374 template <
typename T>
377 parallel_object_only();
382 end_dof = this->row_stop();
386 if (this->processor_id() == 0)
388 std::unique_ptr<std::ofstream> file;
391 file = std::make_unique<std::ofstream>(
name.c_str());
395 std::size_t sparsity_nonzeros = this->n_nonzeros();
397 std::size_t real_nonzeros = 0;
399 libmesh_assert_equal_to(first_dof, 0);
405 if (c != static_cast<T>(0.0))
413 std::size_t nonzeros_on_p = 0;
414 this->comm().receive(p, nonzeros_on_p);
415 real_nonzeros += nonzeros_on_p;
418 if (sparsity_nonzeros &&
419 sparsity_nonzeros != real_nonzeros)
420 libmesh_warning(sparsity_nonzeros <<
421 " nonzeros allocated, but " <<
422 real_nonzeros <<
" used.");
428 os <<
"%Mat Object: () " << this->n_processors() <<
" MPI processes\n" 429 <<
"% type: " << (this->n_processors() > 1 ?
"mpi" :
"seq") <<
"aij\n" 430 <<
"% Size = " << this->m() <<
' ' << this->n() <<
'\n' 431 <<
"% Nonzeros = " << real_nonzeros <<
'\n' 432 <<
"zzz = zeros(" << real_nonzeros <<
",3);\n" 442 if (c != static_cast<T>(0.0))
445 os << (i+1) <<
' ' << (j+1) <<
" " << c <<
'\n';
450 std::vector<numeric_index_type> ibuf, jbuf;
454 this->comm().receive(p, ibuf);
455 this->comm().receive(p, jbuf);
456 this->comm().receive(p, cbuf);
457 libmesh_assert_equal_to (ibuf.size(), jbuf.size());
458 libmesh_assert_equal_to (ibuf.size(), cbuf.size());
461 os << ibuf[n] <<
' ' << jbuf[n] <<
" " << cbuf[n] <<
'\n';
464 os <<
"];\n" <<
"Mat_sparse = spconvert(zzz);" << std::endl;
468 std::vector<numeric_index_type> ibuf, jbuf;
470 std::size_t my_nonzeros = 0;
479 if (c != static_cast<T>(0.0))
488 this->comm().send(0,my_nonzeros);
489 this->comm().send(0,ibuf);
490 this->comm().send(0,jbuf);
491 this->comm().send(0,cbuf);
497 template <
typename T>
500 libmesh_not_implemented_msg
501 (
"libMesh cannot write PETSc binary-format files from non-PETSc matrices");
506 template <
typename T>
509 libmesh_not_implemented_msg
510 (
"libMesh cannot write PETSc HDF5-format files from non-PETSc matrices");
515 template <
typename T>
519 std::ifstream in (filename.c_str());
521 (!in.good(),
"ERROR: cannot read file:\n\t" <<
530 basename.remove_suffix(3);
534 this->read_matlab(filename);
537 #ifndef LIBMESH_HAVE_PETSC 538 libmesh_error_msg(
"Cannot load PETSc matrix file " <<
539 filename <<
" without PETSc-enabled libMesh.");
541 #if LIBMESH_DOF_ID_BYTES != 8 542 libmesh_error_msg(
"Cannot load 64-bit PETSc matrix file " <<
543 filename <<
" with non-64-bit libMesh.");
545 this->read_petsc_binary(filename);
549 #ifndef LIBMESH_HAVE_PETSC 550 libmesh_error_msg(
"Cannot load PETSc matrix file " <<
551 filename <<
" without PETSc-enabled libMesh.");
553 #if LIBMESH_DOF_ID_BYTES != 4 554 libmesh_error_msg(
"Cannot load 32-bit PETSc matrix file " <<
555 filename <<
" with non-32-bit libMesh.");
557 this->read_petsc_binary(filename);
561 this->read_coreform_hdf5(filename);
564 libmesh_error_msg(
" ERROR: Unrecognized matrix file extension on: " 566 <<
"\n I understand the following:\n\n" 567 <<
" *.h5 -- CoreForm HDF5 sparse matrix format\n" 568 <<
" *.matlab -- Matlab sparse matrix format\n" 569 <<
" *.m -- Matlab sparse matrix format\n" 570 <<
" *.petsc32 -- PETSc binary format, 32-bit\n" 571 <<
" *.petsc64 -- PETSc binary format, 64-bit\n" 577 template <
typename T>
579 const std::string & groupname)
581 #ifndef LIBMESH_HAVE_HDF5 583 libmesh_error_msg(
"ERROR: need HDF5 support to handle .h5 files!!!");
585 LOG_SCOPE(
"read_coreform_hdf5()",
"SparseMatrix");
587 std::size_t num_rows, num_cols;
591 auto check_open = [&filename](hid_t id,
const std::string & objname)
593 if (
id == H5I_INVALID_HID)
594 libmesh_error_msg(
"Couldn't open " + objname +
" in " + filename);
597 auto check_hdf5 = [&filename](
auto hdf5val,
const std::string & objname)
600 libmesh_error_msg(
"HDF5 error from " + objname +
" in " + filename);
604 if (this->processor_id() == 0)
606 const hid_t file = H5Fopen(filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
608 if (file == H5I_INVALID_HID)
609 libmesh_file_error(filename);
611 group = H5Gopen(file, groupname.c_str(), H5P_DEFAULT);
612 check_open(group, groupname);
614 auto read_size_attribute = [&filename, &group, &check_open, &check_hdf5]
615 (
const std::string & attribute_name)
617 unsigned long long returnval = 0;
619 const hid_t attr = H5Aopen(group, attribute_name.c_str(), H5P_DEFAULT);
620 check_open(attr, attribute_name);
622 const hid_t attr_type = H5Aget_type(attr);
623 check_hdf5(attr_type, attribute_name +
" type");
627 if (H5Tget_class(attr_type) != H5T_INTEGER)
628 libmesh_error_msg(
"Non-integer type for " + attribute_name +
" in " + filename);
634 herr_t errval = H5Aread(attr, H5T_NATIVE_ULLONG, &returnval);
635 check_hdf5(errval, attribute_name +
" read");
642 num_cols = read_size_attribute(
"num_cols");
643 num_rows = read_size_attribute(
"num_rows");
645 this->comm().broadcast(num_cols);
646 this->comm().broadcast(num_rows);
650 this->comm().broadcast(num_cols);
651 this->comm().broadcast(num_rows);
655 new_col_start, new_col_stop;
659 std::vector<numeric_index_type> new_row_starts, new_row_stops,
660 new_col_starts, new_col_stops;
663 num_cols == this->m() &&
664 num_rows == this->n())
666 new_row_start = this->row_start(),
667 new_row_stop = this->row_stop();
669 new_col_start = this->col_start(),
670 new_col_stop = this->col_stop();
675 new_row_start = this->processor_id() * num_rows / this->n_processors(),
676 new_row_stop = (this->processor_id()+1) * num_rows / this->n_processors();
678 new_col_start = this->processor_id() * num_cols / this->n_processors(),
679 new_col_stop = (this->processor_id()+1) * num_cols / this->n_processors();
682 this->comm().gather(0, new_row_start, new_row_starts);
683 this->comm().gather(0, new_row_stop, new_row_stops);
684 this->comm().gather(0, new_col_start, new_col_starts);
685 this->comm().gather(0, new_col_stop, new_col_stops);
688 off_diagonal_nonzeros = 0;
690 std::vector<std::size_t> cols, row_offsets;
691 std::vector<double> vals;
693 if (this->processor_id() == 0)
695 auto read_vector = [&filename, &group, &check_open, &check_hdf5]
696 (
const std::string & dataname,
auto hdf5_class,
697 auto hdf5_type,
auto & datavec)
699 const hid_t data = H5Dopen1(group, dataname.c_str());
700 check_open(data, dataname.c_str());
702 const hid_t
data_type = H5Dget_type(data);
703 check_hdf5(
data_type, dataname +
" type");
707 if (H5Tget_class(
data_type) != hdf5_class)
708 libmesh_error_msg(
"Unexpected type for " + dataname +
" in " + filename);
712 const hid_t dataspace = H5Dget_space(data);
713 check_hdf5(dataspace, dataname +
" space");
715 int ndims = H5Sget_simple_extent_ndims(dataspace);
717 libmesh_error_msg(
"Non-vector space for " + dataname +
" in " + filename);
720 herr_t errval = H5Sget_simple_extent_dims(dataspace, &len, &maxlen);
721 check_hdf5(errval, dataname +
" dims");
725 errval = H5Dread(data, hdf5_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, datavec.data());
726 check_hdf5(errval, dataname +
" read");
729 read_vector(
"cols", H5T_INTEGER, H5T_NATIVE_ULLONG, cols);
730 read_vector(
"row_offsets", H5T_INTEGER, H5T_NATIVE_ULLONG, row_offsets);
731 read_vector(
"vals", H5T_FLOAT, H5T_NATIVE_DOUBLE, vals);
733 if (cols.size() != vals.size())
734 libmesh_error_msg(
"Inconsistent cols/vals sizes in " + filename);
736 if (row_offsets.size() != num_rows + 1)
737 libmesh_error_msg(
"Inconsistent row_offsets size in " + filename);
744 if (row_offsets[0] != 0)
745 libmesh_error_msg(
"Unexpected row_offsets[0] in " + filename);
749 while (row_offsets[current_row+1] <= i)
752 if (row_offsets[current_row] < row_offsets[current_row-1])
753 libmesh_error_msg(
"Non-monotonic row_offsets in " + filename);
754 current_on_diagonal_nonzeros = 0;
755 current_off_diagonal_nonzeros = 0;
758 while (current_row >= (new_row_stops[current_proc]+1))
762 if (cols[i] >= new_col_starts[current_proc] &&
763 cols[i] < new_col_stops[current_proc])
765 ++current_on_diagonal_nonzeros;
766 on_diagonal_nonzeros =
767 std::max(on_diagonal_nonzeros,
768 current_on_diagonal_nonzeros);
772 ++current_off_diagonal_nonzeros;
773 off_diagonal_nonzeros =
774 std::max(off_diagonal_nonzeros,
775 current_off_diagonal_nonzeros);
780 this->comm().broadcast(on_diagonal_nonzeros);
781 this->comm().broadcast(off_diagonal_nonzeros);
783 this->
init(num_rows, num_cols,
784 new_row_stop-new_row_start,
785 new_col_stop-new_col_start,
786 on_diagonal_nonzeros,
787 off_diagonal_nonzeros);
790 if (this->processor_id() == 0)
795 while (row_offsets[current_row+1] <= i)
798 libmesh_assert_greater_equal (row_offsets[current_row],
799 row_offsets[current_row-1]);
801 this->
set(current_row, cols[i], vals[i]);
806 #endif // LIBMESH_HAVE_HDF5 811 template <
typename T>
814 LOG_SCOPE(
"read_matlab()",
"SparseMatrix");
816 #ifndef LIBMESH_HAVE_CXX11_REGEX 817 libmesh_not_implemented();
820 parallel_object_only();
830 std::vector<numeric_index_type> new_row_starts, new_row_stops,
831 new_col_starts, new_col_stops;
834 new_col_start, new_col_stop;
845 std::unique_ptr<std::istream> file;
854 std::vector<std::tuple<numeric_index_type, numeric_index_type, T>> entries;
860 if (this->processor_id() == 0)
864 const std::regex start_regex
865 (
"\\s*\\w+\\s*=\\s*\\[");
866 const std::regex end_regex
871 #ifdef LIBMESH_HAVE_GZSTREAM 872 auto inf = std::make_unique<igzstream>();
874 inf->open(filename.c_str(), std::ios::in);
875 file = std::move(inf);
877 libmesh_error_msg(
"ERROR: need gzstream to handle .gz files!!!");
882 auto inf = std::make_unique<std::ifstream>();
887 inf->open(new_name.c_str(), std::ios::in);
888 file = std::move(inf);
893 const std::regex size_regex
894 (
"%\\s*[Ss][Ii][Zz][Ee]\\s*=\\s*(\\d+)\\s+(\\d+)");
895 const std::string whitespace =
" \t";
897 bool have_started =
false;
898 bool have_ended =
false;
899 std::size_t largest_i_seen = 0, largest_j_seen = 0;
903 std::size_t current_row = 1;
905 for (std::string line; std::getline(*file, line);)
915 std::istringstream l(line);
920 l >> i >> j >>
value;
925 (!have_started,
"Confused by premature entries in matrix file " << filename);
927 entries.emplace_back(cast_int<numeric_index_type>(i),
928 cast_int<numeric_index_type>(j),
932 (!i || !j,
"Expected 1-based indexing in matrix file " 935 current_row = std::max(current_row, i);
939 "Can't handle out-of-order entries in matrix file " 942 largest_i_seen = std::max(i, largest_i_seen);
943 largest_j_seen = std::max(j, largest_j_seen);
946 else if (std::regex_search(line, sm, size_regex))
948 const std::string msize = sm[1];
949 const std::string nsize = sm[2];
950 m = std::stoull(msize);
951 n = std::stoull(nsize);
954 else if (std::regex_search(line, start_regex))
957 else if (std::regex_search(line, end_regex))
965 (!have_started,
"Confused by missing assignment beginning in matrix file " << filename);
968 (!have_ended,
"Confused by missing assignment ending in matrix file " << filename);
971 (m > largest_i_seen,
"Confused by missing final row(s) in matrix file " << filename);
974 (m > 0 && m < largest_i_seen,
"Confused by extra final row(s) in matrix file " << filename);
980 (n > largest_j_seen,
"Confused by missing final column(s) in matrix file " << filename);
983 (n > 0 && n < largest_j_seen,
"Confused by extra final column(s) in matrix file " << filename);
988 this->comm().broadcast(m);
989 this->comm().broadcast(n);
993 this->comm().broadcast(m);
994 this->comm().broadcast(n);
1001 new_row_start = this->row_start(),
1002 new_row_stop = this->row_stop();
1004 new_col_start = this->col_start(),
1005 new_col_stop = this->col_stop();
1010 new_row_start = this->processor_id() * m / this->n_processors(),
1011 new_row_stop = (this->processor_id()+1) * m / this->n_processors();
1013 new_col_start = this->processor_id() * n / this->n_processors(),
1014 new_col_stop = (this->processor_id()+1) * n / this->n_processors();
1017 this->comm().gather(0, new_row_start, new_row_starts);
1018 this->comm().gather(0, new_row_stop, new_row_stops);
1019 this->comm().gather(0, new_col_start, new_col_starts);
1020 this->comm().gather(0, new_col_stop, new_col_stops);
1029 off_diagonal_nonzeros =0;
1031 if (this->processor_id() == 0)
1040 for (
auto [i, j,
value] : entries)
1042 if (i > current_row)
1046 while (current_row >= (new_row_stops[current_proc]+1))
1048 current_on_diagonal_nonzeros = 0;
1049 current_off_diagonal_nonzeros = 0;
1053 if (j >= (new_col_starts[current_proc]+1) &&
1054 j < (new_col_stops[current_proc]+1))
1056 ++current_on_diagonal_nonzeros;
1057 on_diagonal_nonzeros =
1058 std::max(on_diagonal_nonzeros,
1059 current_on_diagonal_nonzeros);
1063 ++current_off_diagonal_nonzeros;
1064 off_diagonal_nonzeros =
1065 std::max(off_diagonal_nonzeros,
1066 current_off_diagonal_nonzeros);
1071 this->comm().broadcast(on_diagonal_nonzeros);
1072 this->comm().broadcast(off_diagonal_nonzeros);
1075 new_row_stop-new_row_start,
1076 new_col_stop-new_col_start,
1077 on_diagonal_nonzeros,
1078 off_diagonal_nonzeros);
1083 if (this->processor_id() == 0)
1084 for (
auto [i, j,
value] : entries)
1085 this->
set(i-1, j-1,
value);
1093 template <
typename T>
1096 libmesh_not_implemented_msg
1097 (
"libMesh cannot read PETSc binary-format files into non-PETSc matrices");
1102 template <
typename T>
1105 libmesh_not_implemented_msg
1106 (
"libMesh cannot read PETSc HDF5-format files into non-PETSc matrices");
1111 template <
typename T>
1116 for (
const auto i :
make_range(this->row_start(), this->row_stop()))
1117 for (
const auto j :
make_range(this->col_start(), this->col_stop()))
1118 this->
set(i, j, (*this)(i, j) *
scale);
1123 template <
typename T>
1126 auto diff_mat = this->clone();
1127 diff_mat->add(-1.0, other_mat);
1128 return diff_mat->l1_norm();
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
bool closed()
Checks that the library has been closed.
virtual std::size_t n_nonzeros() const
SparseMatrix(const Parallel::Communicator &comm)
Constructor; initializes the matrix to be empty, without any structure, i.e.
This helper class can be called on multiple threads to compute the sparsity pattern (or graph) of the...
boost::multiprecision::float128 real(const boost::multiprecision::float128 in)
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
bool ends_with(std::string_view superstring, std::string_view suffix)
Look for a substring at the very end of a string.
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]...
Provides a uniform interface to vector storage schemes for different linear algebra libraries...
The libMesh namespace provides an interface to certain functionality in the library.
const SparsityPattern::Build * get_sparsity_pattern() const
uint8_t processor_id_type
virtual void zero()=0
Set all entries to zero.
This class handles the numbering of degrees of freedom on a mesh.
void libmesh_ignore(const Args &...)
dof_id_type numeric_index_type
bool _is_initialized
Flag that tells if init() has been called.
auto l1_norm_diff(const NumericVector< T > &vec1, const NumericVector< T > &vec2)
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
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 ...
An object whose state is distributed along a set of processors.
std::string_view basename_of(const std::string &fullname)
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...
bool initialized()
Checks that library initialization has been done.
boost::multiprecision::float128 imag(const boost::multiprecision::float128)
SolverPackage
Defines an enum for various linear solver packages.
MatrixBuildType
Defines an enum for matrix build types.
Defines a dense matrix for use in Finite Element-type computations.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...