libMesh
Loading...
Searching...
No Matches
laspack_matrix.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
20// Local includes
21#include "libmesh/libmesh_config.h"
22
23#ifdef LIBMESH_HAVE_LASPACK
24
25#include "libmesh/laspack_matrix.h"
26#include "libmesh/dense_matrix.h"
27#include "libmesh/dof_map.h"
28#include "libmesh/numeric_vector.h"
29#include "libmesh/sparsity_pattern.h"
30
31
32// C++ Includes
33#include <memory>
34
35
36namespace libMesh
37{
38
39
40//-----------------------------------------------------------------------
41// LaspackMatrix members
42template <typename T>
44{
45 // clear data, start over
46 this->clear ();
47
48 // big trouble if this fails!
49 libmesh_assert(this->_dof_map);
50
51 const numeric_index_type n_rows = sparsity_pattern.size();
52
53 // Initialize the _row_start data structure,
54 // allocate storage for the _csr array
55 {
56 std::size_t size = 0;
57
58 for (numeric_index_type row=0; row<n_rows; row++)
59 size += sparsity_pattern[row].size();
60
61 _csr.resize (size);
62 _row_start.reserve(n_rows + 1);
63 }
64
65
66 // Initialize the _csr data structure.
67 {
68 std::vector<numeric_index_type>::iterator position = _csr.begin();
69
70 _row_start.push_back (position);
71
72 for (numeric_index_type row=0; row<n_rows; row++)
73 {
74 // insert the row indices
75 for (const auto & col : sparsity_pattern[row])
76 {
77 libmesh_assert (position != _csr.end());
78 *position = col;
79 ++position;
80 }
81
82 _row_start.push_back (position);
83 }
84 }
85
86
87 // Initialize the matrix
88 libmesh_assert (!this->initialized());
89 this->init ();
91 //libMesh::out << "n_rows=" << n_rows << std::endl;
92 //libMesh::out << "m()=" << m() << std::endl;
93 libmesh_assert_equal_to (n_rows, this->m());
94
95 // Tell the matrix about its structure. Initialize it
96 // to zero.
97 for (numeric_index_type i=0; i<n_rows; i++)
98 {
99 auto rs = _row_start[i];
100
101 const numeric_index_type length = _row_start[i+1] - rs;
102
103 Q_SetLen (&_QMat, i+1, length);
104
105 for (numeric_index_type l=0; l<length; l++)
106 {
107 const numeric_index_type j = *(rs+l);
108
109 // sanity check
110 //libMesh::out << "m()=" << m() << std::endl;
111 //libMesh::out << "(i,j,l) = (" << i
112 // << "," << j
113 // << "," << l
114 // << ")" << std::endl;
115 //libMesh::out << "pos(i,j)=" << pos(i,j)
116 // << std::endl;
117 libmesh_assert_equal_to (this->pos(i,j), l);
118 Q_SetEntry (&_QMat, i+1, l, j+1, 0.);
119 }
120 }
121
122 // That's it!
123 //libmesh_here();
124}
125
126
127
128template <typename T>
130 const numeric_index_type n_in,
131 const numeric_index_type m_l,
132 const numeric_index_type n_l,
133 const numeric_index_type nnz,
134 const numeric_index_type,
135 const numeric_index_type)
136{
137 // noz ignored... only used for multiple processors!
138 libmesh_assert_equal_to (m_in, m_l);
139 libmesh_assert_equal_to (n_in, n_l);
140 libmesh_assert_equal_to (m_in, n_in);
141 libmesh_assert_greater (nnz, 0);
142
143 if ((m_in != m_l) ||
144 (n_in != n_l))
145 libmesh_not_implemented_msg("Laspack does not support distributed matrices");
146
147 if (m_in != n_in)
148 libmesh_not_implemented_msg("Laspack does not support rectangular matrices");
149
150 if (nnz < n_in)
151 libmesh_warning("Using inefficient LaspackMatrix allocation via this init() method");
152
153 const dof_id_type n_rows = m_in;
154
155 // Laspack doesn't let us assign sparse indices on the fly, so
156 // without a sparsity pattern we're stuck allocating a dense matrix
157 {
158 _csr.resize (m_in * m_in);
159 _row_start.reserve(m_in + 1);
160 }
161
162 // Initialize the _csr data structure.
163 {
164 std::vector<numeric_index_type>::iterator position = _csr.begin();
165
166 _row_start.push_back (position);
167
168 for (numeric_index_type row=0; row<n_rows; row++)
169 {
170 // insert the row indices
171 for (const auto & col : make_range(n_rows))
172 {
173 libmesh_assert (position != _csr.end());
174 *position = col;
175 ++position;
176 }
177
178 _row_start.push_back (position);
179 }
180 }
181
182 Q_Constr(&_QMat, const_cast<char *>("Mat"), m_in, _LPFalse, Rowws, Normal, _LPTrue);
183
184 this->_is_initialized = true;
185
186 // Tell the matrix about its structure. Initialize it
187 // to zero.
188 for (numeric_index_type i=0; i<n_rows; i++)
189 {
190 auto rs = _row_start[i];
191
192 const numeric_index_type length = _row_start[i+1] - rs;
193
194 Q_SetLen (&_QMat, i+1, length);
195
196 for (numeric_index_type l=0; l<length; l++)
197 {
198 const numeric_index_type j = *(rs+l);
199
200 libmesh_assert_equal_to (this->pos(i,j), l);
201 Q_SetEntry (&_QMat, i+1, l, j+1, 0.);
202 }
203 }
204}
205
206
207
208template <typename T>
210{
211 // Ignore calls on initialized objects
212 if (this->initialized())
213 return;
214
215 // We need a sparsity pattern for this!
216 libmesh_assert(this->_sp);
217
218 // Clear initialized matrices
219 if (this->initialized())
220 this->clear();
221
222 const numeric_index_type n_rows = this->_dof_map->n_dofs();
223#ifndef NDEBUG
224 // The following variables are only used for assertions,
225 // so avoid declaring them when asserts are inactive.
226 const numeric_index_type n_cols = n_rows;
227 const numeric_index_type n_l = this->_dof_map->n_dofs_on_processor(0);
228 const numeric_index_type m_l = n_l;
229#endif
230
231 // Laspack Matrices only work for uniprocessor cases
232 libmesh_assert_equal_to (n_rows, n_cols);
233 libmesh_assert_equal_to (m_l, n_rows);
234 libmesh_assert_equal_to (n_l, n_cols);
235
236#ifndef NDEBUG
237 // The following variables are only used for assertions,
238 // so avoid declaring them when asserts are inactive.
239 const std::vector<numeric_index_type> & n_nz = this->_sp->get_n_nz();
240 const std::vector<numeric_index_type> & n_oz = this->_sp->get_n_oz();
241#endif
242
243 // Make sure the sparsity pattern isn't empty
244 libmesh_assert_equal_to (n_nz.size(), n_l);
245 libmesh_assert_equal_to (n_oz.size(), n_l);
246
247 if (n_rows==0)
248 return;
249
250 Q_Constr(&_QMat, const_cast<char *>("Mat"), n_rows, _LPFalse, Rowws, Normal, _LPTrue);
251
252 this->_is_initialized = true;
253
254 libmesh_assert_equal_to (n_rows, this->m());
255}
256
257
258
259template <typename T>
261 const std::vector<numeric_index_type> & rows,
262 const std::vector<numeric_index_type> & cols)
263
264{
265 libmesh_assert (this->initialized());
266 unsigned int n_rows = cast_int<unsigned int>(rows.size());
267 unsigned int n_cols = cast_int<unsigned int>(cols.size());
268 libmesh_assert_equal_to (dm.m(), n_rows);
269 libmesh_assert_equal_to (dm.n(), n_cols);
270
271
272 for (unsigned int i=0; i<n_rows; i++)
273 for (unsigned int j=0; j<n_cols; j++)
274 this->add(rows[i],cols[j],dm(i,j));
275}
276
277
278
279template <typename T>
281{
282 // There does not seem to be a straightforward way to iterate over
283 // the columns of a LaspackMatrix. So we use some extra storage and
284 // keep track of the column sums while going over the row entries...
285 std::vector<Real> abs_col_sums(this->n());
286
287 const numeric_index_type n_rows = this->m();
288
289 for (numeric_index_type row : make_range(n_rows))
290 {
291 auto r_start = _row_start[row];
292
293 const numeric_index_type len = (_row_start[row+1] - _row_start[row]);
294
295 // Make sure we agree on the row length
296 libmesh_assert_equal_to (len, Q_GetLen(&_QMat, row+1));
297
298 for (numeric_index_type l=0; l<len; l++)
299 {
300 const numeric_index_type j = *(r_start + l);
301
302 // Make sure the data structures are working
303 libmesh_assert_equal_to ((j+1), Q_GetPos (&_QMat, row+1, l));
304
305 abs_col_sums[j] += std::abs(Q_GetVal (&_QMat, row+1, l));
306 }
307 }
308
309 return *(std::max_element(abs_col_sums.begin(), abs_col_sums.end()));
310}
311
312
313
314template <typename T>
316{
317 const numeric_index_type n_rows = this->m();
318
319 Real max_row_sum = 0;
320
321 for (numeric_index_type row : make_range(n_rows))
322 {
323 Real row_sum = 0;
324
325 const numeric_index_type len = (_row_start[row+1] - _row_start[row]);
326
327 // Make sure we agree on the row length
328 libmesh_assert_equal_to (len, Q_GetLen(&_QMat, row+1));
329
330 for (numeric_index_type l=0; l<len; l++)
331 {
332 // Make sure the data structures are working
333 libmesh_assert_equal_to ((*(_row_start[row] + l)+1), Q_GetPos
334 (&_QMat, row+1, l));
335
336 row_sum += std::abs(Q_GetVal (&_QMat, row+1, l));
337 }
338
339 max_row_sum = std::max(max_row_sum, row_sum);
340 }
341
342 return max_row_sum;
343}
344
345
346
347template <typename T>
349{
350 const numeric_index_type n_rows = this->m();
351
352 dest.init(n_rows, n_rows);
353
354 for (numeric_index_type i : make_range(n_rows))
355 dest.set(i, Q_GetEl (const_cast<QMatrix*>(&_QMat), i+1, i+1));
356}
357
358
359
360template <typename T>
362{
363 LaspackMatrix<T> & target = cast_ref<LaspackMatrix<T> &>(dest);
364 target.clear();
365
366 const numeric_index_type N = this->n();
367 libmesh_assert_equal_to(N, this->m());
368
369 std::vector<numeric_index_type> col_sizes(N);
370 for (numeric_index_type row : make_range(N))
371 {
372 const numeric_index_type len = (_row_start[row+1] - _row_start[row]);
373 auto r_start = _row_start[row];
374 for (numeric_index_type l=0; l<len; l++)
375 {
376 const numeric_index_type col = *(r_start + l);
377 ++col_sizes[col];
378 }
379 }
380
381 target._csr.resize(_csr.size());
382 target._row_start.resize(N+1);
383 std::vector<std::vector<numeric_index_type>::iterator> writeable_row_start(N+1);
384 writeable_row_start[0] = target._csr.begin();
385 target._row_start[0] = target._csr.begin();
386 for (numeric_index_type col: make_range(N))
387 {
388 writeable_row_start[col+1] = writeable_row_start[col] + col_sizes[col];
389 target._row_start[col+1] = target._row_start[col] + col_sizes[col];
390 }
391
392 std::vector<numeric_index_type> col_offsets;
393 // Reuse memory
394 col_offsets.swap(col_sizes);
395 std::fill(col_offsets.begin(), col_offsets.end(), 0);
396
397 Q_Constr(&target._QMat, const_cast<char *>("Mat"), N, _LPFalse, Rowws, Normal, _LPTrue);
398 target._is_initialized = true;
399
400 for (numeric_index_type row : make_range(N))
401 {
402 const numeric_index_type len = (_row_start[row+1] - _row_start[row]);
403 auto r_start = _row_start[row];
404 for (numeric_index_type l=0; l<len; l++)
405 {
406 const numeric_index_type col = *(r_start + l);
407 *(writeable_row_start[col]+col_offsets[col]) = row;
408 ++col_offsets[col];
409 }
410 }
411
412 for (numeric_index_type col : make_range(N))
413 {
414 auto len = col_offsets[col];
415 libmesh_assert(target._row_start[col] + len ==
416 target._row_start[col+1]);
417 Q_SetLen(&target._QMat, col+1, len);
418
419 auto rs = target._row_start[col];
420 for (numeric_index_type l : make_range(len))
421 {
422 const numeric_index_type j = *(rs+l);
423 const auto value = Q_GetEl(const_cast<QMatrix*>(&_QMat), j+1, col+1);
424 Q_SetEntry (&target._QMat, col+1, l, j+1, value);
425 }
426 }
427}
428
429
430
431template <typename T>
433 std::vector<numeric_index_type> & indices,
434 std::vector<T> & values) const
435{
436 indices.clear();
437 values.clear();
438
439 const numeric_index_type len = (_row_start[i+1] - _row_start[i]);
440
441 // Make sure we agree on the row length
442 libmesh_assert_equal_to (len, Q_GetLen(&_QMat, i+1));
443
444 auto r_start = _row_start[i];
445
446 for (numeric_index_type l=0; l<len; l++)
447 {
448 const numeric_index_type j = *(r_start + l);
449
450 // Make sure the data structures are working
451 libmesh_assert_equal_to ((j+1), Q_GetPos (&_QMat, i+1, l));
452
453 indices.push_back(j);
454
455 values.push_back(Q_GetVal (&_QMat, i+1, l));
456 }
457}
458
459
460
461template <typename T>
463 SparseMatrix<T>(comm),
464 _closed (false)
465{
466}
467
468
469
470template <typename T>
472{
473 this->clear ();
474}
475
476
477
478template <typename T>
480{
481 if (this->initialized())
482 {
483 Q_Destr(&_QMat);
484 }
485
486 _csr.clear();
487 _row_start.clear();
488 _closed = false;
489 this->_is_initialized = false;
490}
491
492
493
494template <typename T>
496{
497 const numeric_index_type n_rows = this->m();
498
499 for (numeric_index_type row=0; row<n_rows; row++)
500 {
501 auto r_start = _row_start[row];
502
503 const numeric_index_type len = (_row_start[row+1] - _row_start[row]);
504
505 // Make sure we agree on the row length
506 libmesh_assert_equal_to (len, Q_GetLen(&_QMat, row+1));
507
508 for (numeric_index_type l=0; l<len; l++)
509 {
510 const numeric_index_type j = *(r_start + l);
511
512 // Make sure the data structures are working
513 libmesh_assert_equal_to ((j+1), Q_GetPos (&_QMat, row+1, l));
514
515 Q_SetEntry (&_QMat, row+1, l, j+1, 0.);
516 }
517 }
518
519 this->close();
520}
521
522
523
524template <typename T>
525std::unique_ptr<SparseMatrix<T>> LaspackMatrix<T>::zero_clone () const
526{
527 // Make empty copy with matching comm, initialize, zero, and return.
528 auto mat_copy = std::make_unique<LaspackMatrix<T>>(this->comm());
529 if (this->_dof_map)
530 mat_copy->attach_dof_map(*this->_dof_map);
531 else
532 mat_copy->init(this->m(), this->n(), this->local_m(),
533 this->local_n(), this->local_n());
534
535 mat_copy->zero();
536
537 return mat_copy;
538}
539
540
541
542template <typename T>
543std::unique_ptr<SparseMatrix<T>> LaspackMatrix<T>::clone () const
544{
545 // We don't currently have a faster implementation than making a
546 // zero clone and then filling in the values.
547 auto mat_copy = this->zero_clone();
548 mat_copy->add(1., *this);
549
550 return mat_copy;
551}
552
553template <typename T>
555{
556 libmesh_assert (this->initialized());
557
558 return static_cast<numeric_index_type>(Q_GetDim(const_cast<QMatrix*>(&_QMat)));
559}
560
561
562
563template <typename T>
565{
566 libmesh_assert (this->initialized());
567
568 return static_cast<numeric_index_type>(Q_GetDim(const_cast<QMatrix*>(&_QMat)));
569}
570
571
572
573template <typename T>
575{
576 return 0;
577}
578
579
580
581template <typename T>
583{
584 return this->m();
585}
586
587
588
589template <typename T>
591{
592 return 0;
593}
594
595
596
597template <typename T>
599{
600 return this->n();
601}
602
603
604
605template <typename T>
607 const numeric_index_type j,
608 const T value)
609{
610 libmesh_assert (this->initialized());
611 libmesh_assert_less (i, this->m());
612 libmesh_assert_less (j, this->n());
613
614 const numeric_index_type position = this->pos(i,j);
615
616 // Sanity check
617 libmesh_assert_equal_to (*(_row_start[i]+position), j);
618 libmesh_assert_equal_to ((j+1), Q_GetPos (&_QMat, i+1, position));
619
620 Q_SetEntry (&_QMat, i+1, position, j+1, value);
621}
622
623
624
625template <typename T>
627 const numeric_index_type j,
628 const T value)
629{
630 libmesh_assert (this->initialized());
631 libmesh_assert_less (i, this->m());
632 libmesh_assert_less (j, this->n());
633
634 const numeric_index_type position = this->pos(i,j);
635
636 // Sanity check
637 libmesh_assert_equal_to (*(_row_start[i]+position), j);
638
639 Q_AddVal (&_QMat, i+1, position, value);
640}
641
642
643
644template <typename T>
646 const std::vector<numeric_index_type> & dof_indices)
647{
648 this->add_matrix (dm, dof_indices, dof_indices);
649}
650
651
652
653template <typename T>
654void LaspackMatrix<T>::add (const T a_in, const SparseMatrix<T> & X_in)
655{
656 libmesh_assert (this->initialized());
657 libmesh_assert_equal_to (this->m(), X_in.m());
658 libmesh_assert_equal_to (this->n(), X_in.n());
659
660 const LaspackMatrix<T> * X =
661 cast_ptr<const LaspackMatrix<T> *> (&X_in);
662
663 _LPNumber a = static_cast<_LPNumber> (a_in);
664
666
667 // loops taken from LaspackMatrix<T>::zero ()
668
669 const numeric_index_type n_rows = this->m();
670
671 for (numeric_index_type row=0; row<n_rows; row++)
672 {
673 auto r_start = _row_start[row];
674
675 const numeric_index_type len = (_row_start[row+1] - _row_start[row]);
676
677 // Make sure we agree on the row length
678 libmesh_assert_equal_to (len, Q_GetLen(&_QMat, row+1));
679 // compare matrix sparsity structures
680 libmesh_assert_equal_to (len, Q_GetLen(&(X->_QMat), row+1));
681
682
683 for (numeric_index_type l=0; l<len; l++)
684 {
685 const numeric_index_type j = *(r_start + l);
686
687 // Make sure the data structures are working
688 libmesh_assert_equal_to ((j+1), Q_GetPos (&_QMat, row+1, l));
689
690 const _LPNumber value = a * Q_GetEl(const_cast<QMatrix*>(&(X->_QMat)), row+1, j+1);
691 Q_AddVal (&_QMat, row+1, l, value);
692 }
693 }
694}
695
696
697
698
699template <typename T>
701 const numeric_index_type j) const
702{
703 libmesh_assert (this->initialized());
704 libmesh_assert_less (i, this->m());
705 libmesh_assert_less (j, this->n());
706
707 return Q_GetEl (const_cast<QMatrix*>(&_QMat), i+1, j+1);
708}
709
710
711
712template <typename T>
714 const numeric_index_type j) const
715{
716 libmesh_assert_less (i, this->m());
717 libmesh_assert_less (j, this->n());
718 libmesh_assert_less (i+1, _row_start.size());
719 libmesh_assert (_row_start.back() == _csr.end());
720
721 // note this requires the _csr to be sorted
722 auto p = std::equal_range (_row_start[i], _row_start[i+1], j);
723
724 // Make sure the row contains the element j
725 libmesh_assert (p.first != p.second);
726
727 // Make sure the values match
728 libmesh_assert (*p.first == j);
729
730 // Return the position in the compressed row
731 return std::distance (_row_start[i], p.first);
732}
733
734
735
736template <typename T>
738{
740
741 this->_closed = true;
742
743 // We've probably changed some entries so we need to tell LASPACK
744 // that cached data is now invalid.
745 *_QMat.DiagElAlloc = _LPFalse;
746 *_QMat.ElSorted = _LPFalse;
747 if (*_QMat.ILUExists)
748 {
749 *_QMat.ILUExists = _LPFalse;
750 Q_Destr(_QMat.ILU);
751 }
752}
753
754
755
756//------------------------------------------------------------------
757// Explicit instantiations
758template class LIBMESH_EXPORT LaspackMatrix<Number>;
759
760} // namespace libMesh
761
762
763#endif // #ifdef LIBMESH_HAVE_LASPACK
Defines a dense matrix for use in Finite Element-type computations.
The LaspackMatrix class wraps a QMatrix object from the Laspack library.
virtual void init(const numeric_index_type m, const numeric_index_type n, const numeric_index_type m_l, const numeric_index_type n_l, const numeric_index_type nnz=30, const numeric_index_type noz=10, const numeric_index_type blocksize=1) override
Initialize SparseMatrix with the specified sizes.
virtual void clear() override
Restores the SparseMatrix<T> to a pristine state.
LaspackMatrix(const Parallel::Communicator &comm)
Constructor; initializes the matrix to be empty, without any structure, i.e.
virtual void set(const numeric_index_type i, const numeric_index_type j, const T value) override
Set the element (i,j) to value.
virtual void zero() override
Set all entries to 0.
std::vector< numeric_index_type > _csr
The compressed row indices.
QMatrix _QMat
The Laspack sparse matrix pointer.
virtual numeric_index_type col_start() const override
virtual void close() override
Calls the SparseMatrix's internal assembly routines, ensuring that the values are consistent across p...
numeric_index_type pos(const numeric_index_type i, const numeric_index_type j) const
virtual void get_row(numeric_index_type i, std::vector< numeric_index_type > &indices, std::vector< T > &values) const override
Get a row from the matrix.
virtual void add_matrix(const DenseMatrix< T > &dm, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols) override
Add the full matrix dm to the SparseMatrix.
std::vector< std::vector< numeric_index_type >::const_iterator > _row_start
The start of each row in the compressed row index data structure.
virtual numeric_index_type col_stop() const override
virtual std::unique_ptr< SparseMatrix< T > > clone() const override
virtual std::unique_ptr< SparseMatrix< T > > zero_clone() const override
virtual numeric_index_type row_stop() const override
virtual T operator()(const numeric_index_type i, const numeric_index_type j) const override
virtual void add(const numeric_index_type i, const numeric_index_type j, const T value) override
Add value to the element (i,j).
virtual void get_transpose(SparseMatrix< T > &dest) const override
Copies the transpose of the matrix into dest, which may be *this.
virtual numeric_index_type n() const override
virtual Real l1_norm() const override
virtual void update_sparsity_pattern(const SparsityPattern::Graph &) override
Updates the matrix sparsity pattern.
virtual numeric_index_type m() const override
virtual Real linfty_norm() const override
virtual numeric_index_type row_start() const override
virtual void get_diagonal(NumericVector< T > &dest) const override
Copies the diagonal part of the matrix into dest.
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual void set(const numeric_index_type i, const T value)=0
Sets v(i) = value.
virtual void init(const numeric_index_type n, const numeric_index_type n_local, const bool fast=false, const ParallelType ptype=AUTOMATIC)=0
Change the dimension of the vector to n.
Generic sparse matrix.
virtual numeric_index_type n() const =0
virtual numeric_index_type m() const =0
bool _is_initialized
Flag indicating whether or not the matrix has been initialized.
The libMesh namespace provides an interface to certain functionality in the library.
ParallelType
Defines an enum for parallel data structure types.
libmesh_assert(ctx)
dof_id_type numeric_index_type
Definition id_types.h:99
bool initialized()
Checks that library initialization has been done.
Definition libmesh.C:324
uint8_t dof_id_type
Definition id_types.h:67
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