如何在MPI中定义一个用户定义的函数,该函数需要几个输入缓冲区



我需要在MPI中定义一个用户定义的约简。在每个处理器中,我有3个向量,其中一个是双向量,另两个是整数。我无法将这些向量展平为一维数据并通过我的用户定义函数。此外,我不能使用MPI_create_struct和用户定义的数据类型,因为这些向量的大小在不同的处理器中不同。我知道用户定义的函数应该像一样

void my_sum_function(void* inputBuffer, void* outputBuffer, int* len, MPI_Datatype* datatype)
{
int*input = (int*)inputBuffer;
int* output = (int*)outputBuffer;
for (int i = 0; i < *len; i++) {
output[i] += input[i];
}
} 

但我正在寻找一种方法,让我的用户定义函数占用几个输入缓冲区,我想知道这是否可能,如果可能,怎么做?如果我可以使用struct,它应该是类似的东西

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <vector>
#include <iostream>
typedef std::vector<int>  VecInt_t;
typedef std::vector<double>  VecDbl_t;
typedef std::vector<VecInt_t>  VecVecInt_t;

struct vecs
{
VecDbl_t val_;
VecInt_t L2G_;
VecInt_t G2L_;
};
void my_sum_function(void* inputBuffer, void* outputBuffer, int* len, MPI_Datatype* datatype)
{
vecs *input = (vecs*)inputBuffer;
double* output = (double*)outputBuffer;
for (int i = 0; i < (*input).L2G_.size(); i++) {
output[(*input).L2G_[i]] += (*input).val_[(*input).G2L_[(*input).L2G_[i]]];
}
}

int main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
int size, rank;
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int root_rank = 0;
MPI_Op operation;
MPI_Op_create(&my_sum_function, 1, &operation);
MPI_Datatype mytype;
vecs p;
MPI_Datatype types[3] = { MPI_DOUBLE, MPI_INT, MPI_INT };
int lengths[3] = { p.val_.size(),p.L2G_.size(),p.G2L_.size() };
MPI_Aint displacements[3] = { (MPI_Aint)&p.val_, (MPI_Aint)&p.L2G_, (MPI_Aint)&p.G2L_ };
for (int i = 1; i < 3; i++) displacements[i] -= displacements[0];
displacements[0] = 0;
MPI_Type_create_struct(3, lengths, displacements, types, &mytype);
MPI_Type_commit(&mytype);
vecs buffer;
if (rank == 0)
{
buffer.val_ = { 3,2,5 };
buffer.L2G_= { 0,1,2 };
buffer.G2L_= { 0,1,2,-1 };
}
else
{
buffer.val_ = { 4,3,5 };
buffer.L2G_ = { 0,2,3 };
buffer.G2L_ = { 0,-1,1,2 };
}
double reduction_results[4] = { 0, 0,0,0};
MPI_Reduce(&buffer, reduction_results, 4, mytype, operation, root_rank, MPI_COMM_WORLD);

if (rank == root_rank)
{
printf("The sum of first elements of data is %g.n", reduction_results[0]);
printf("The sum of second elements of data is %g.n", reduction_results[1]);
printf("The sum of third elements of data is %g.n", reduction_results[2]);
printf("The sum of fourth elements of data is %g.n", reduction_results[3]);
}
MPI_Type_free(&mytype);
MPI_Op_free(&operation);
MPI_Finalize();
return EXIT_SUCCESS;
}

我会在一个简单的案例中解释我在做什么。我有2个具有4个节点的字符串元素,并且我为所有处理器中的每个元素构造刚度矩阵。在这种情况下,全局刚度矩阵是分布的。连接如下所示。元素0:0,1,2------>转到处理器零元素1:0,2,3------>转到处理器1您可以看到节点0和2在处理器之间共享。在这种情况下,我的局部刚度矩阵将是3乘3,而不是4乘4。我不共享整个向量,而是创建一个包含当前处理器中所有节点的向量。例如,处理器0中的刚度矩阵将乘以大小为3的向量。该向量包含节点0,1,2的局部结果。因此,我定义了Local2global{0,1,2}。这个向量表示全局索引中的哪个节点出现在当前处理器中。此外,我定义了另一个由-1初始化的大小为4的辅助向量global2local,用于局部索引,在处理器0的情况下,它是0,1,2,-1。对于第二个处理器,刚度矩阵将乘以大小为3的向量,该向量包含节点0,2和3的局部结果。Local2global是0,2,3。global2local是0,-1,1,2。现在,每个处理器最终得到一个大小为3的结果向量。比方说处理器0:{3=节点0上的值,2=节点1上的值、5=节点2上的值}。处理器1:{4=节点0上的值,3=节点2上的值、5=节点3上的值}。现在,我需要在处理器0中将结果汇总为全局结果向量。那些在处理器之间不共享的节点将直接到达它们在全局结果向量中的位置,但对于那些共享的节点,我需要将它们相加并除以它们在处理器之间重复的数量。处理器0已经具有重复向量。因此在结尾处为global_result[i]/MPI_reps[i]。在这种情况下,全局向量将是{3.5,2,4,5}。

如果我可以用这样的方式编写我的用户定义操作

For (int i=0;i<local2global.size();i++){
global_result [i]+=local_result [global2local[local2global[i]]];
}

我可以收集我的结果。现在我在定义用户定义的操作时遇到了问题。因为要完成上面的代码,我需要local_result、global2local和local2global将用户定义的函数传递到输入缓冲区中。用户定义的函数类似于(void*inputBuffer,void*outputBuffer,int*len,MPI_Datatype*数据类型(。这里有一些问题给我。首先,我有一个问题,在一维数组或向量中制作这些向量。因为它们通常有不同的类型。第二,我不能使用int MPI_Type_create_struct(int block_count,const int block_lengths[],const MPI_Aint displacements[],MPI_Datatype block_types[],MPI_Datatype*new_Datatype(;只要块大小的大小不是恒定的。我希望我现在能更清楚地解释我的问题。

使用本地/全局/本地转换给出的行只能在共享内存中以这种方式工作。在分布式内存中,必须设置索引转换数据结构,然后使用聚集操作来获取值。这并不有趣,但这是分布式内存中有限元的不幸事实。顺便说一句,有一些软件包可以帮你做到这一点。

最新更新