libmesh解析
本工作只是尝试解析原libmesh的代码,供学习使用
全部  命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 
coupling_matrix.h
浏览该文件的文档.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2023 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 #ifndef LIBMESH_COUPLING_MATRIX_H
21 #define LIBMESH_COUPLING_MATRIX_H
22 
23 // Local Includes
24 #include "libmesh/libmesh_common.h"
25 
26 // C++ includes
27 #include <algorithm>
28 #include <limits>
29 #include <utility> // std::pair
30 #include <vector>
31 
32 namespace libMesh
33 {
34 
35 // Forward declarations
36 class ConstCouplingAccessor;
37 class CouplingAccessor;
38 
39 class ConstCouplingRow;
40 
41 class ConstCouplingRowConstIterator;
42 
51 class CouplingMatrix
52 {
53 public:
58  explicit
59  CouplingMatrix (const std::size_t n=0);
60 
67  bool operator() (const std::size_t i,
68  const std::size_t j) const;
69 
76  CouplingAccessor operator() (const std::size_t i,
77  const std::size_t j);
78 
83  std::size_t size() const;
84 
89  void resize(const std::size_t n);
90 
94  void clear();
95 
100  bool empty() const;
101 
107  CouplingMatrix & operator&= (const CouplingMatrix & other);
108 
109 private:
110  friend class ConstCouplingAccessor;
111  friend class CouplingAccessor;
112  friend class ConstCouplingRow;
113  friend class ConstCouplingRowConstIterator;
114 
123  typedef std::pair<std::size_t, std::size_t> range_type;
124  typedef std::vector<range_type> rc_type;
125  rc_type _ranges; // 存储非零元素的范围
126 
130  std::size_t _size;
131 };
132 
133 
134 
138 class ConstCouplingAccessor
139 {
140 public:
146  ConstCouplingAccessor(std::size_t loc_in,
147  const CouplingMatrix & mat_in) :
148  _location(loc_in), _mat(mat_in)
149  {
150  libmesh_assert_less(_location, _mat.size() * _mat.size());
151  }
152 
157  operator bool() const
158  {
159  const std::size_t max_size = std::numeric_limits<std::size_t>::max();
160 
161  // 寻找可能包含i,j的范围
162  CouplingMatrix::rc_type::const_iterator lb = std::upper_bound
163  (_mat._ranges.begin(), _mat._ranges.end(),
164  std::make_pair(_location, max_size));
165  if (lb!=_mat._ranges.begin())
166  --lb;
167  else
168  lb=_mat._ranges.end();
169 
170  // 如果没有范围可能包含i,j,则为0
171  if (lb == _mat._ranges.end())
172  return false;
173 
174  const std::size_t lastloc = lb->second;
175 
176 #ifdef DEBUG
177  const std::size_t firstloc = lb->first;
178  libmesh_assert_less_equal(firstloc, lastloc);
179  libmesh_assert_less_equal(firstloc, _location);
180 
181  CouplingMatrix::rc_type::const_iterator next = lb;
182  next++;
183  if (next != _mat._ranges.end())
184  {
185  // 范围应该是排序的,不应该接触
186  libmesh_assert_greater(next->first, lastloc+1);
187  }
188 #endif
189 
190  return (lastloc >= _location);
191  }
192 
193 protected:
197  std::size_t _location;
201  const CouplingMatrix & _mat;
202 };
203 
204 
208 class CouplingAccessor : public ConstCouplingAccessor
209 {
210 public:
216  CouplingAccessor(std::size_t loc_in,
217  CouplingMatrix & mat_in) :
218  ConstCouplingAccessor(loc_in, mat_in), _my_mat(mat_in) {}
219 
225  template <typename T>
226  CouplingAccessor & operator = (T new_value)
227  {
228  // 为了向后兼容,我们接受整数参数,但耦合矩阵条目实际上都是零或一。
229  const bool as_bool = new_value;
230  libmesh_assert_equal_to(new_value, as_bool);
231 
232  *this = as_bool;
233  return *this;
234  }
235 
241  CouplingAccessor & operator = (bool new_value)
242  {
243  const std::size_t max_size = std::numeric_limits<std::size_t>::max();
244 
245  // 寻找可能包含i,j的范围
246  CouplingMatrix::rc_type::iterator lb =
247  std::upper_bound (_my_mat._ranges.begin(), _my_mat._ranges.end(),
248  std::make_pair(_location, max_size));
249  if (lb!=_my_mat._ranges.begin())
250  --lb;
251  else
252  lb=_my_mat._ranges.end();
253 
254  // 如果没有范围可能包含i,j,则可能需要创建一个新的范围。
255  if (lb == _my_mat._ranges.end())
256  {
257  if (new_value == true)
258  _my_mat._ranges.emplace
259  (_my_mat._ranges.begin(), _location, _location);
260  }
261  else
262  {
263  const std::size_t firstloc = lb->first;
264  const std::size_t lastloc = lb->second;
265  libmesh_assert_less_equal(firstloc, lastloc);
266  libmesh_assert_less_equal(firstloc, _location);
267 
268 #ifdef DEBUG
269  {
270  CouplingMatrix::rc_type::const_iterator next = lb;
271  next++;
272  if (next != _my_mat._ranges.end())
273  {
274  // 范围应该是排序的,不应该接触
275  libmesh_assert_greater(next->first, lastloc+1);
276  }
277  }
278 #endif
279 
280  // 如果在此范围内,可能需要缩短、移除或拆分它
281  if (new_value == false)
282  {
283  // 如果位置在范围的起始位置,且为唯一元素,则移除整个范围
284  if (_location == firstloc)
285  {
286  if (_location == lastloc)
287  {
288  _my_mat._ranges.erase(lb);
289  }
290  else
291  {
292  libmesh_assert_less(lb->first, lastloc);
293  lb->first++;
294  }
295  }
296  // 如果位置在范围的结束位置,则减小范围的结束位置
297  else if (_location == lastloc)
298  {
299  libmesh_assert_less(firstloc, lb->second);
300  lb->second--;
301  }
302  // 如果位置在范围内部,则调整范围的起始位置和添加新的范围
303  else if (_location < lastloc)
304  {
305  libmesh_assert_less_equal(_location + 1, lastloc);
306 
307  lb->first = _location + 1;
308 
309  libmesh_assert_less_equal(firstloc, _location - 1);
310 
311  _my_mat._ranges.emplace(lb, firstloc, _location - 1);
312  }
313  }
314  // 如果不在范围内,可能需要扩展范围、与相邻范围连接或添加新范围
315  else // new_value == true
316  {
317  CouplingMatrix::rc_type::iterator next = lb;
318  next++;
319  const std::size_t nextloc =
320  (next == _my_mat._ranges.end()) ?
321  std::numeric_limits<std::size_t>::max() :
322  next->first;
323 
324  // 范围应该是排序的,不应该相邻
325  libmesh_assert_greater(nextloc, lastloc + 1);
326 
327  // 如果位置在范围之外,可能需要扩展范围或与下一个相邻范围连接
328  if (_location > lastloc)
329  {
330  // 如果位置在当前范围的结束位置之后,且与下一个范围的开始位置相邻,则将其与下一个范围合并
331  if (_location == lastloc + 1)
332  {
333  if (_location == nextloc - 1)
334  {
335  next->first = firstloc;
336  _my_mat._ranges.erase(lb);
337  }
338  else
339  lb->second++;
340  }
341  // 如果位置在下一个范围的开始位置之前,则将其作为新范围插入
342  else
343  {
344  // 如果位置刚好在下一个范围的开始位置之前,则减小下一个范围的开始位置
345  if (_location == nextloc - 1)
346  next->first--;
347  else
348  _my_mat._ranges.emplace(next, _location, _location);
349  }
350  }
351  }
352 
353  return *this;
354 }
355 
356 private:
357 
361 CouplingMatrix & _my_mat;
362 };
363 
364 
365 
369 class ConstCouplingRow
370 {
371 public:
378  ConstCouplingRow(std::size_t row_in,
379  const CouplingMatrix & mat_in) :
380  _row_i(row_in), _mat(mat_in),
381  _end_location(_row_i * _mat.size() + _mat.size() - 1)
382  {
383  libmesh_assert_less(_row_i, _mat.size());
384 
385  // 为 i,N 查找开始范围的位置
386  _begin_location = _end_location;
387 
388  const std::size_t max_size = std::numeric_limits<std::size_t>::max();
389 
390  // 查找可能包含 i,N 的范围,使用 upper_bound 不完全符合需求
391  _begin_it = std::upper_bound
392  (_mat._ranges.begin(), _mat._ranges.end(),
393  std::make_pair(_begin_location, max_size));
394  if (_begin_it != _mat._ranges.begin())
395  --_begin_it;
396  else
397  _begin_it = _mat._ranges.end();
398 
399  // 如果范围不存在,则表示为空行
400  if (_begin_it == _mat._ranges.end())
401  _begin_location = max_size;
402  else
403  {
404  const std::size_t lastloc = _begin_it->second;
405  // 如果范围在 i,0 之前结束,则为空行
406  std::size_t zero_location = _row_i * _mat.size();
407  if (zero_location > lastloc)
408  {
409  _begin_location = max_size;
410  _begin_it = _mat._ranges.end();
411  }
412  else
413  {
414  while (_begin_it != _mat._ranges.begin())
415  {
416  CouplingMatrix::rc_type::const_iterator prev =
417  _begin_it;
418  --prev;
419 
420  if (prev->second < zero_location)
421  break;
422 
423  _begin_it = prev;
424  }
425  if (_begin_it->first < zero_location)
426  _begin_location = zero_location;
427  else
428  _begin_location = _begin_it->first;
429  }
430  }
431  }
432 
433  /*
434  * \brief 用于在此行中循环遍历索引的前向迭代器类型。
435  */
436  typedef ConstCouplingRowConstIterator const_iterator;
437 
438  /*
439  * \brief 返回此行中第一个索引的迭代器,对于空行则返回 end()。
440  */
441  const_iterator begin() const;
442 
443  /*
444  * \brief 表示行末尾的迭代器。
445  */
446  const_iterator end() const;
447 
455  bool operator== (const ConstCouplingRow & other) const
456  {
457  // 考虑到来自不同矩阵对象的行是相等的是不正确的
458  libmesh_assert(&_mat == &other._mat);
459 
460  return ((_begin_location == other._begin_location) &&
461  (_begin_it == other._begin_it));
462  }
463 
471  bool operator!= (const ConstCouplingRow & other) const
472  {
473  return !(*this == other);
474  }
475 protected:
476 
477  friend class ConstCouplingRowConstIterator;
478 
479  std::size_t _row_i;
480  const CouplingMatrix & _mat;
481 
482  // 对应于此行第一个条目的位置 (i*size+j),对于空行则为 std::numeric_limits<size_t>::max()
483  std::size_t _begin_location;
484 
485  // 对应于此行结束的位置 (i*size+j)(不考虑该结束位置是否在范围内)。缓存位置,因为每次 ++iterator 调用都需要使用它
486  const std::size_t _end_location;
487 
488  // 包含第一个行元素的范围的迭代器,如果对于此行不存在 CouplingMatrix 值,则为 _mat._ranges.end()
489  CouplingMatrix::rc_type::const_iterator _begin_it;
490 };
491 
492 
493 
497 class ConstCouplingRowConstIterator
498 {
499 public:
507  ConstCouplingRowConstIterator(const ConstCouplingRow & row_in,
508  std::size_t loc_in,
509  CouplingMatrix::rc_type::const_iterator it_in) :
510  _location(loc_in),
511  _row(row_in),
512  _it(it_in)
513  {
514 #ifndef NDEBUG
515  if (_it != _row._mat._ranges.end())
516  {
517  libmesh_assert_less_equal(_it->first, _location);
518  libmesh_assert_less_equal(_location, _it->second);
519  }
520  else
521  {
522  libmesh_assert_equal_to
523  (_location, std::numeric_limits<size_t>::max());
524  }
525 #endif
526  }
527 
533  std::size_t operator* ()
534  {
535  libmesh_assert_not_equal_to
536  (_location, std::numeric_limits<std::size_t>::max());
537  return _location % _row._mat.size();
538  }
539 
545  ConstCouplingRowConstIterator & operator++ ()
546  {
547  libmesh_assert_not_equal_to
548  (_location, std::numeric_limits<std::size_t>::max());
549  libmesh_assert
550  (_it != _row._mat._ranges.end());
551 
552  if (_location >= _it->second)
553  {
554  ++_it;
555 
556  // 是否超出矩阵的末尾?
557  if (_it == _row._mat._ranges.end())
558  _location = std::numeric_limits<std::size_t>::max();
559  else
560  {
561  _location = _it->first;
562  // 新范围是否超出行的末尾?
563  if (_location > _row._end_location)
564  _location = std::numeric_limits<std::size_t>::max();
565  }
566  }
567  // 递增后是否超出行的末尾?
568  else if (_location >= _row._end_location)
569  _location = std::numeric_limits<std::size_t>::max();
570  else
571  ++_location;
572 
573  return *this;
574  }
575 
583  bool operator== (const ConstCouplingRowConstIterator & other) const
584  {
585  // 考虑到来自不同行对象的迭代器是相等的是不正确的
586  libmesh_assert(_row == other._row);
587 
588  return (_location == other._location);
589  }
590 
598  bool operator!= (const ConstCouplingRowConstIterator & other) const
599  {
600  return !(*this == other);
601  }
602 
603 private:
604  // 对应于此迭代器位置的位置 (i*size+j),或 std::numeric_limits<size_t>::max() 表示 end()
605  std::size_t _location;
606  const ConstCouplingRow & _row;
607  // 包含此迭代器位置的范围,或 _row._mat._ranges.end() 表示此位置不在任何范围内
608  CouplingMatrix::rc_type::const_iterator _it;
609 };
610 
611 
612 
613 //--------------------------------------------------
614 // ConstCouplingRow inline methods
615 inline
616 ConstCouplingRow::const_iterator ConstCouplingRow::begin() const
617 {
618  return const_iterator (*this, _begin_location, _begin_it);
619 }
620 
621 inline
622 ConstCouplingRow::const_iterator ConstCouplingRow::end() const
623 {
624  return const_iterator
625  (*this, std::numeric_limits<std::size_t>::max(),
626  _mat._ranges.end());
627 }
628 
629 
630 
631 //--------------------------------------------------
632 // CouplingMatrix inline methods
633 inline
634 CouplingMatrix::CouplingMatrix (const std::size_t n) :
635  _ranges(), _size(n)
636 {
637  this->resize(n);
638 }
639 
640 
641 
642 inline
643 bool CouplingMatrix::operator() (const std::size_t i,
644  const std::size_t j) const
645 {
646  libmesh_assert_less (i, _size);
647  libmesh_assert_less (j, _size);
648 
649  const std::size_t location = std::size_t(i)*_size + j;
650 
651  return bool(ConstCouplingAccessor(location, *this));
652 }
653 
654 
655 
656 
657 inline
658 CouplingAccessor CouplingMatrix::operator() (const std::size_t i,
659  const std::size_t j)
660 {
661  const std::size_t location = std::size_t(i)*_size + j;
662 
663  return CouplingAccessor(location, *this);
664 }
665 
666 
667 
668 inline
669 std::size_t CouplingMatrix::size() const
670 {
671  return _size;
672 }
673 
674 
675 
676 inline
677 void CouplingMatrix::resize(const std::size_t n)
678 {
679  _size = n;
680 
681  _ranges.clear();
682 }
683 
684 
685 
686 inline
687 void CouplingMatrix::clear()
688 {
689  this->resize(0);
690 }
691 
692 
693 
694 inline
695 bool CouplingMatrix::empty() const
696 {
697  return (_size == 0);
698 }
699 
700 
701 } // namespace libMesh
702 
703 
704 #endif // LIBMESH_COUPLING_MATRIX_H
bool operator==(const variant_filter_iterator< Predicate, Type, ReferenceType, PointerType, OtherConstType, OtherConstReferenceType, OtherConstPointerType > &x, const variant_filter_iterator< Predicate, Type, ReferenceType, PointerType, OtherConstType, OtherConstReferenceType, OtherConstPointerType > &y)
boostcopy::enable_if_c< ScalarTraits< Scalar >::value, TypeNTensor< N, typename CompareTypes< Scalar, T >::supertype > >::type operator*(const Scalar &, const TypeNTensor< N, T > &)
bool operator!=(const variant_filter_iterator< Predicate, Type, ReferenceType, PointerType, OtherConstType, OtherConstReferenceType, OtherConstPointerType > &x, const variant_filter_iterator< Predicate, Type, ReferenceType, PointerType, OtherConstType, OtherConstReferenceType, OtherConstPointerType > &y)