libmesh
迭代器的实现和方法(1)
在阅读
libmesh
源码的过程中,会接触到两个类:DistributedMesh
和ReplicatedMesh
,它们都是用来存放有限元问题的模型数据(主要包括问题离散后的节点Node
和单元Elem
数据)。两个类主要的不同在于它们存放节点Node
和单元Elem
数据方式不同。由于libmesh
主要面向的高性能计算的用户,其主要的用户计算的模型主要是大规模的实际工程问题,所以实际在程序计算过程中,需要多个CPU核同时进行计算。ReplicatedMesh
类主要在存放Node
和Elem
的过程中,每个CPUprocesser
都会存放完整的一套Node
和Elem
数据,但是每个CPUprocesser
参与处理和计算的Node
和Elem
都是整套数据的部分,因此存在大量的数据存储浪费.而DistributedMesh
在存放Node
和Elem
过程中,采用分布式存放的方式进行数据的存放,每个CPUProcesser
仅仅存放跟本Processer
计算相关的Node
和Elem
的数据,这样能保证程序在计算内存中大大的减少.
在阅读libmesh
代码的mesh
对象时,其定义了一个抽象基类MesBbase
,该类中主要是定义了mesh
类大概需要的一些函数接口(API).然后通过使用UnstructuredMesh
对象主要是声明了mesh
对象的基础功能,读写入文件等。
mesh对象的继承关系如下:
DistributedMesh --
|-- > UnstructuredMesh -> MeshBase
ReplicatedMesh --
libmesh
中mesh
对象的迭代器使用
在
DistributedMesh
类中存放Elem
数据使用的是自定义的mapvector
进行存放,其底层使用的是std::map<Elem *,Dof_id_type>
进行数据存放(此处不知道为何分布式存放的方式需要使用Key-value
的模式)。与之对应的是ReplicatedMesh
类在存放Elem
数据使用的是std::vector<Elem *>
,由于针对该类型每个Processer
都存放了完整的Elem
数据,因此只要保证每个processer
对应Elem
数据都相同即可(包括单元序号,顺序,大小完全一模一样).使用std::vector<Elem *>
存放完全可以理解。但是DistributedMesh
使用std::map
方式存放的原因暂时不太清楚。说明:
elem
数据和Node
数据都是类似的,所以清楚了Elem
等于清楚了Node
的迭代模式。
由于在两个类都是继承自最基础的MeshBase
类,而该类定义了大量的迭代器函数,包括单元迭代器和节点迭代器。根据不同的实现功能不同进行区分:
// 正常的单元迭代器
virtual element_iterator elements_begin () = 0;
virtual element_iterator elements_end () = 0;
virtual const_element_iterator elements_begin () const = 0;
virtual const_element_iterator elements_end () const = 0;
// 遍历所有elem->ancestor() 为true的单元 (具体功能不太清楚)
virtual element_iterator ancestor_elements_begin () = 0;
virtual element_iterator ancestor_elements_end () = 0;
virtual const_element_iterator ancestor_elements_begin () const = 0;
virtual const_element_iterator ancestor_elements_end () const = 0;
// ...
由于上面定义都是抽象类,所以在DistributedMesh
和ReplicatedMesh
类的定义中都已经override
覆盖了原始的定义(在对应类的声明定义中,只有对应迭代器的声明,没有函数定义和实现,一直很奇怪,通过生成的可执行程序
进行debug调试,终于找到两个类所有迭代器的实现,在mesh_iterator.C
文件).
libmesh
中迭代器的定义
Libmesh
中MeshBase
类迭代器的定义和实现是在mesh_iterator.C
文件中实现的,而且其应用了C语言中宏的方式实现的。
其中宏的定义如下:
// 单元 (同理节点也是一样的)
#define INSTANTIATE_ELEM_ACCESSORS(FUNC_PREFIX, PRED, FUNC_ARG, ...) \
ReplicatedMesh::element_iterator \
ReplicatedMesh::FUNC_PREFIX##_begin (FUNC_ARG) \
{ \
return element_iterator(_elements.begin(), _elements.end(), Predicates::PRED<elem_iterator_imp>(__VA_ARGS__)); \
} \
ReplicatedMesh::const_element_iterator \
ReplicatedMesh::FUNC_PREFIX##_begin (FUNC_ARG) const \
{ \
return const_element_iterator(_elements.begin(), _elements.end(), Predicates::PRED<const_elem_iterator_imp>(__VA_ARGS__)); \
} \
ReplicatedMesh::element_iterator \
ReplicatedMesh::FUNC_PREFIX##_end (FUNC_ARG) \
{ \
return element_iterator(_elements.end(), _elements.end(), Predicates::PRED<elem_iterator_imp>(__VA_ARGS__)); \
} \
ReplicatedMesh::const_element_iterator \
ReplicatedMesh::FUNC_PREFIX##_end (FUNC_ARG) const \
{ \
return const_element_iterator(_elements.end(), _elements.end(), Predicates::PRED<const_elem_iterator_imp>(__VA_ARGS__)); \
} \
DistributedMesh::element_iterator \
DistributedMesh::FUNC_PREFIX##_begin (FUNC_ARG) \
{ \
return element_iterator(_elements.begin(), _elements.end(), Predicates::PRED<elem_iterator_imp>(__VA_ARGS__)); \
} \
DistributedMesh::const_element_iterator \
DistributedMesh::FUNC_PREFIX##_begin (FUNC_ARG) const \
{ \
return const_element_iterator(_elements.begin(), _elements.end(), Predicates::PRED<const_elem_iterator_imp>(__VA_ARGS__)); \
} \
DistributedMesh::element_iterator \
DistributedMesh::FUNC_PREFIX##_end (FUNC_ARG) \
{ \
return element_iterator(_elements.end(), _elements.end(), Predicates::PRED<elem_iterator_imp>(__VA_ARGS__)); \
} \
DistributedMesh::const_element_iterator \
DistributedMesh::FUNC_PREFIX##_end (FUNC_ARG) const \
{ \
return const_element_iterator(_elements.end(), _elements.end(), Predicates::PRED<const_elem_iterator_imp>(__VA_ARGS__)); \
}
针对两种类(DistributedMesh
和ReplicatedMesh
)的函数接口都有四种实现,都是分别于类的声明的中的实现是一致的(包括begin
和end
两种迭代器,同时两种迭代器的分别有const
返回和non-const
返回值的区别)。
virtual element_iterator elements_begin () = 0;
virtual element_iterator elements_end () = 0;
virtual const_element_iterator elements_begin () const = 0;
virtual const_element_iterator elements_end () const = 0;
其中Elem
的各种迭代器函数的实现(根据宏的定义):elem
,active_elements
,ancestor_elements
...等等.代码实现如下:
INSTANTIATE_ELEM_ACCESSORS(elements, NotNull, EMPTY, EMPTY)
INSTANTIATE_ELEM_ACCESSORS(active_elements, Active, EMPTY, EMPTY)
INSTANTIATE_ELEM_ACCESSORS(not_active_elements, NotActive, EMPTY, EMPTY)
INSTANTIATE_ELEM_ACCESSORS(ancestor_elements, Ancestor, EMPTY, EMPTY)
INSTANTIATE_ELEM_ACCESSORS(not_ancestor_elements, NotAncestor, EMPTY, EMPTY)
INSTANTIATE_ELEM_ACCESSORS(subactive_elements, SubActive, EMPTY, EMPTY)
INSTANTIATE_ELEM_ACCESSORS(not_subactive_elements, NotSubActive, EMPTY, EMPTY)
INSTANTIATE_ELEM_ACCESSORS(local_elements, Local, EMPTY, this->processor_id())
INSTANTIATE_ELEM_ACCESSORS(semilocal_elements, ActiveSemiLocal, EMPTY, this->processor_id())
INSTANTIATE_ELEM_ACCESSORS(active_semilocal_elements, ActiveSemiLocal, EMPTY, this->processor_id())
INSTANTIATE_ELEM_ACCESSORS(facelocal_elements, FaceLocal, EMPTY, this->processor_id())
INSTANTIATE_ELEM_ACCESSORS(not_local_elements, NotLocal, EMPTY, this->processor_id())
INSTANTIATE_ELEM_ACCESSORS(active_local_elements, ActiveLocal, EMPTY, this->processor_id())
INSTANTIATE_ELEM_ACCESSORS(active_not_local_elements, ActiveNotLocal, EMPTY, this->processor_id())
根据宏的展开,分别实现了对应类函数接口的实现功能.
网友评论