我在C中有一个结构的动态数组。说:
int n=100;
struct particle{
double pos[3];
double force[3];
double mass;
int type;
};
struct particle *mypart;
mypart = (struct particle*) calloc(n,sizeof(struct particle));
在并行代码中,一些操作已完成,mypart[i].force[j]
最后我需要在此数组(maypart[i].force
)上执行MPI_Allreduce 。通过考虑MPI_Type_create_struct
以及其他data_type函数,我无法获得任何有效的解决方案,只能将结构内部的数组传递给其他内核。有人知道吗?
更新:有关代码的一些细节:这是分子动力学代码,其中作用在每个粒子上的力归因于与其他粒子的相互作用。目的是拆分每个核心上的力计算。可以同时在不同的核上计算第i个粒子上的力。力循环后,应将此粒子上的力求和,以使每个粒子具有单一值的力(3个分量)。这是通过MPI_Allreduce + MPI_SUM函数完成的。我希望这可以阐明我要做什么。
您想要实现的目标并非不可能,但也不是琐碎的。首先,您必须声明一个表示整个结构类型的数据类型,或者只声明一个力的数据类型。要构建后者,请以适当的位移从三个连续的双打开始:
MPI_Datatype type_force;
int blen = 3;
MPI_Aint displ = offsetof(struct particle, force);
MPI_Type types = MPI_DOUBLE;
MPI_Type_create_struct(1, &blen, &displ, &types, &type_force);
必须调整新数据类型的大小以匹配C结构的范围,因此我们可以直接访问多个数组元素:
MPI_Datatype type_force_resized;
MPI_Aint lb, extent;
MPI_Type_get_extent(type_force, &lb, &extent);
extent = sizeof(struct particle);
MPI_Type_create_resized(type_force, lb, extent, &type_force_resized);
MPI_Type_commit(&type_force_resized);
全局(清一色)减少,现在几乎可以归结为:
struct particle *particles = calloc(n, sizeof(struct particle));
MPI_Allreduce(mypart, particles, n, type_force_resized,
MPI_SUM, MPI_COMM_WORLD);
由于MPI_(All)Reduce
不允许将不同的MPI数据类型用于源缓冲区和接收缓冲区,因此必须使用数组struct particle
而不是简单数组double[n][3]
。结果将放置在forces[]
每个数组元素的字段中。
现在,问题在于MPI_SUM
无法对派生数据类型进行操作。解决方案是声明您自己的归约操作:
void force_sum(struct particle *in, struct particle *inout,
int *len, MPI_Datatype *dptr)
{
for (int i = 0; i < *len; i++)
{
inout[i].force[0] += in[i].force[0];
inout[i].force[1] += in[i].force[1];
inout[i].force[2] += in[i].force[2];
}
}
MPI_Op force_sum_op;
MPI_Op_create(force_sum, 1, &force_sum_op);
通过以上所有准备工作,减少量变为:
MPI_Allreduce(mypart, particles, n, type_force_resized,
force_sum_op, MPI_COMM_WORLD);
如果您首先将所有力集中在一个double forces[n][3]
阵列中,则将是一个更简单的变体。然后整个还原操作归结为:
double forces[n][3]; // Local forces
double total_forces[n][3]; // Total forces
... transfer mypart[i].force into forces[i] ...
MPI_Allreduce(forces, total_forces, 3*n, MPI_DOUBLE,
MPI_SUM, MPI_COMM_WORLD);
// Done
但是此方法需要额外的内存,并且需要进行内存复制操作。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句