libmesh
迭代器的实现和方法(2)
由于两个类不同的迭代器都是存在四个函数的实现,主要包括
begin
和end
的两种结果实现(non-const
和const
)。由于两种实现方法都是一样的,只是解决的返回值不同,所以只针对non-const
结果进行分析。
libmesh
中具体某个迭代器的实现
主要是查看
elements
和active_local_elements
这两个迭代器结构的实现,他们分别代表了所有单元的迭代器begin-end
和本地processer单元begin-end
。应该在针对DistributedMesh
类中,Elem
对象都是使用mapvector<Elem *, dof_id_type> _elements;
的方式进行存储的,所以需要知道如何实现两个问题的。
查看mesh_iterator.C
中的实现,对宏进行提取出来,得到如下代码(针对DistributedMesh
类展开):
// 宏的定义(只有non-const返回值的定义)
#define INSTANTIATE_ELEM_ACCESSORS(FUNC_PREFIX, PRED, FUNC_ARG, ...) \
DistributedMesh::element_iterator \
DistributedMesh::FUNC_PREFIX##_begin (FUNC_ARG) \
{ \
return element_iterator(_elements.begin(), _elements.end(), Predicates::PRED<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__)); \
} \
// 实例化
INSTANTIATE_ELEM_ACCESSORS(elements, NotNull, EMPTY, EMPTY)
INSTANTIATE_ELEM_ACCESSORS(active_local_elements, ActiveLocal, EMPTY, this->processor_id())
// 其中 定义了如下宏(说明EMPTY 为空)
# define EMPTY
对INSTANTIATE_ELEM_ACCESSORS
宏进行解析
根据宏调用的参数INSTANTIATE_ELEM_ACCESSORS(FUNC_PREFIX, PRED, FUNC_ARG, ...)
其中FUNC_PREFIX
为实例化方法的前缀(elements
或者active_local_elements
)。根据宏中##
的符号可以连接成字符的特性,与FUNC_PREFIX##_begin
和FUNC_PREFIX_end
通过宏的展开形成elements_begin
和elements_end
两个对应类的方法。宏中具体内容就是方法的实现。
而宏中还有三个其他参数PRED
,FUNC_ARG
,...
;其中PRED
表示Predicates
命名空间的对应的类用来实现不同要求迭代器的实现,FUNC_ARG
则表示FUNC_PREFIX##_begin
方法对应参数列表,而...
表示是宏中表示的可变参数,在宏内部使用__VA_ARGS__
变量表示使用该可变参数(在activate_local_elements
的实现中有用到这个特性,this->processor_id()
)。通过引入##
和...
能将宏应用的特别强大,适应能力特别强。
针对elements
和activate_local_elements
迭代器实现
elements
是针对本模型所有单元的单元迭代器,而activate_local_elements
是针对模型中当前的CPUprocesser
中的单元迭代器,由于DistributedMesh
对象是分布式存储信息存储的,所以上述两个迭代器的返回结果肯定不一样的。
对elements
和activate_local_elements
迭代器的代码进行展开如下:
// elements迭代器(返回模型中所有迭代器)
DistributedMesh::element_iterator
DistributedMesh::elements_begin ()
{
return element_iterator(_elements.begin(), _elements.end(), Predicates::NotNull<elem_iterator_imp>());
}
DistributedMesh::element_iterator
DistributedMesh::elements_end ()
{
return element_iterator(_elements.end(), _elements.end(), Predicates::NotNull<elem_iterator_imp>());
}
// activate迭代器 (返回模型中当前进程下的单元)
DistributedMesh::element_iterator
DistributedMesh::activate_local_elements_begin ()
{
return element_iterator(_elements.begin(), _elements.end(), Predicates::ActiveLocal<elem_iterator_imp>(this->processor_id()));
}
DistributedMesh::element_iterator
DistributedMesh::activate_local_elements_end ()
{
return element_iterator(_elements.end(), _elements.end(), Predicates::ActiveLocal<elem_iterator_imp>(this->processor_id()));
}
根据宏进行展开后,可以看出elements
和activate_local_elements
对应的两个迭代器begin
,end
的返回值类型都是DistributedMesh
类中定义的单元迭代器element_iterator
。
同时两种不同功能(遍历本地,遍历全局)的迭代器的参数都是_elements
对象(该参数在DistributedMesh
中使用mapvector
进行存放的数据),此时是否能够说明_elements
是否存放的是完整的数据对象呢?还是在遍历全局的过程中,存在MPI
广播或者同步呢?
根据两种功能宏展开的函数内容上看,要实现两种功能主要是根据Predicates::NotNull
和Predicates::ActiveLocal
两者实现的,与_elements
数据存放无关,但是此时暂时无法知道mapvector<Elem*,Dof_id_type> _elements
数据存放的形式,是在本地仅存放所有单元的信息,还是局部?
进一步了解:
-
elements_iterator
的实现和作用 -
Predicates
命名空间的作用(其中主要包括单元迭代器不同功能的实现)
网友评论