【问题标题】:How to use MPI derived data type for 3D array?如何将 MPI 派生数据类型用于 3D 数组?
【发布时间】:2012-04-01 22:53:53
【问题描述】:

我想编写一个在 3D 矩阵上工作的并行代码,其中每个进程都有自己的子矩阵,但是为了完成他们的工作,他们需要一些关于其相邻进程的子矩阵(只是边界平面)的信息。我通过点对点通信发送这些信息,但我知道对于大型矩阵这不是一个好主意,所以我决定使用派生数据类型进行通信。我对mpi_type_vector 有疑问:例如,我有一个NX*NY*NZ 矩阵,我想将带有常量NY 的平面发送到另一个进程,我为此编写了这些行:

MPI_Datatype sub;

MPI_Type_vector(NX, NZ, NY*NZ, MPI_DOUBLE, &sub);

MPI_Type_commit(&sub);

但它不起作用(无法发送我想要的飞机)。怎么了? 我的测试代码在这里:

#include <mpi.h>
#include <iostream>

using namespace std;

int main(int argc,char ** argv)
{

    int const IE=100,JE=25,KE=100;
    int size,rank;
    MPI_Status status;

    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);
    MPI_Datatype sub;
    MPI_Type_vector(KE,IE,IE+(JE-1)*IE,MPI_DOUBLE,&sub);
    MPI_Type_commit(&sub);

    if (rank==0){

        double*** a=new double**[IE];

        for(int i=0;i<IE;i++){
            a[i]=new double *[JE];
            for(int j=0;j<JE;j++){
                a[i][j]=new double [KE];
            }
        }

        for(int i=0;i<IE;i++){
            for(int j=0;j<JE;j++){
                for(int k=0;k<KE;k++){
                    a[i][j][k]=2;
                }}}

        for(int i=0;i<IE;i++){
            for(int j=0;j<JE;j++){
                a[i][j][0]=2;
            }}

        MPI_Send(&a[0][0][0],1,sub,1,52,MPI_COMM_WORLD);

    }

    if (rank==1){

        double*** b=new double**[IE];

        for(int i=0;i<IE;i++){
            b[i]=new double *[JE];
            for(int j=0;j<JE;j++){
                b[i][j]=new double [KE];
            }
        }

        for(int i=0;i<IE;i++){
            for(int j=0;j<JE;j++){
                for(int k=0;k<KE;k++){
                    b[i][j][k]=0;
                }}}

        MPI_Recv(&b[0][0][0][0],1,sub,0,52,MPI_COMM_WORLD,&status);

        for(int i=0;i<IE;i++){
            for(int j=0;j<JE;j++){
                for(int k=0;k<KE;k++){
                    if(b[i][j][k]>0){
                        cout<<"b["<<i<<"]["<<j<<"]["<<k<<"]="<<b[i][j][k]<<endl;
                    }}}}

    }

    MPI_Finalize();

}

【问题讨论】:

    标签: c++ mpi


    【解决方案1】:

    对于 3d 矩阵,通常您必须使用向量的向量(因为涉及两个跨步)- 这是可能的,但更简单的是使用 MPI_Type_create_subarray(),它可以让您切出平板你想要的多维数组。

    更新:上述代码中的一个问题是您分配的 3d 数组不是连续的;它是 IE*JE 分配的 1d 数组的集合,它们可能彼此靠近也可能不靠近。因此,没有可靠的方法可以从中提取数据平面。

    你需要做这样的事情:

    double ***alloc3d(int l, int m, int n) {
        double *data = new double [l*m*n];
        double ***array = new double **[l];
        for (int i=0; i<l; i++) {
            array[i] = new double *[m];
            for (int j=0; j<m; j++) {
                array[i][j] = &(data[(i*m+j)*n]);
            }
        }
        return array;
    }
    

    然后数据在一个大立方体中,正如您所期望的那样,有一组指针指向它。这 - C 没有真正的多维数组这一事实 - 一直出现在 C + MPI 中。

    【讨论】:

    • ...我需要更多信息。你尝试了什么,你是怎么遇到问题的?
    • 我测试了一下:int a_size[3]={100,25,100};int subside[3]={100,1,100};int start[3]={0,0,0};整数顺序=1; MPI_Type_create_subarray(3,aside,subside,start,order,MPI_DOUBLE,&sub);(我有一个 100*25*100 矩阵,我只想将具有常数 NY 的平面从一个进程发送到另一个进程)上面的代码发送数组的其他组件,不是我想要的飞机
    • 如何调用发送和接收?并且 order 应该是 MPI_ORDER_C,而不是 1,尽管对于某些特定的实现,两者可能相同。
    • 我觉得不错。这应该将底部 y 平面从等级 1 发送到等级 0。不是吗?哦,最后一件事 - 3d 数组是如何声明/分配的?是连续的吗?
    • 是的,你不能那样做;数据需要是一个连续的内存块,而不是一大堆随机分配的块。我会在答案中写正确的分配代码。
    【解决方案2】:

    感谢乔纳森·杜尔西。在这里,我想发布创建 3d 矩阵并使用派生数据类型进行通信的完整代码(只有具有常数 y 的平面才会从一个进程发送到另一个进程)。我使用了上面发布的 Jonathan Dursi 的函数。

    #include <mpi.h>
    #include <iostream>
    #include <math.h>
    #include <fstream>
    #include <vector>
    using namespace std;
    #define IE 100
    #define JE 50
    #define KE 100
    
    #define JE_loc 52
    double ***alloc3d(int l, int m, int n) {
    double *data = new double [l*m*n];
    double ***array = new double **[l];
    for (int i=0; i<l; i++) {
        array[i] = new double *[m];
        for (int j=0; j<m; j++) {
            array[i][j] = &(data[(i*m+j)*n]);
        }
    }
    return array;
    }
    
    
    
    
    int main(int argc ,char ** argv)
    {
    //////////////////////declartion/////////////////////////////
    int const NFREQS=100,ia=7,ja=7,ka=7;
    double const pi=3.14159;
    int i,j,size,rank,k;
    //MPI_Status status[10];
    MPI_Status status;
    MPI_Request request[10];
    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Datatype sub;
    MPI_Type_vector(KE,IE,IE+(JE-1)*IE,MPI_DOUBLE,&sub);
    MPI_Type_commit(&sub);
    
    
    double ***a=alloc3d(IE,JE,KE);
    for (i=0; i<IE; i++) {
        for (j=0; j<JE; j++) {
            for (k=0; k<KE; k++) {
                a[i][j][k]=0.0;
            }
        }
    }
    if (rank==0) {
        for (i=0; i<IE; i++) {
            for (j=0; j<JE; j++) {
                for (k=0; k<KE; k++) {
                    a[i][j][k]=2;
                }
            }
        }
        MPI_Send(&a[0][0][0],1,sub,1,52,MPI_COMM_WORLD);
    
    }
    if (rank==1) {
        MPI_Recv(&a[0][49][0],1,sub,0,52,MPI_COMM_WORLD,&status);
        for (i=0; i<IE; i++) {
            for (j=0; j<JE; j++) {
                for (k=0; k<KE; k++) {
                    if (a[i][j][k]>0) {
                        cout<<"a["<<i<<"]["<<j<<"]["<<k<<"]="<<a[i][j][k]<<endl;
                    }
                }
            }
        }
    
    }
    MPI_Finalize();
    }
    

    【讨论】:

      【解决方案3】:

      很遗憾地告诉您,您审核过的代码仍然无法正常工作。 输出看起来正确的原因是 IE 和 KE 相等。如果您对它们进行区分,您会看到,这些值是以交替的 Y 索引编写的。

      如果您查看 Jonathan Durst 的代码示例的内存分配,如下所示:

      [x0y0z0] [x0y0z1] [x0y1z0] [x0y1z1] [x1y0z0] [x1y0z1] [x1y1z0] [x1y1z1]   //or
      {x0:(y0:[z0,z1]) ; (y1:[z0,z1])} ; {x1:(y0:[z0,z1]) ; (y1:[z0,z1])} //nx=ny=nz=2 
              <bl.len>  
       X             count                X  
           |<-          stride               ->| 
      

      你会看到你有 nx 个块,块长度为 nz 值,它们之间的步幅为 ny*nz。

      如果您将数据类型更改为以下代码,您的代码将正常工作:

      MPI_Type_vector(IE,KE,KE*JE,MPI_DOUBLE,&sub);
      

      【讨论】:

        猜你喜欢
        • 2012-02-11
        • 2012-02-03
        • 2018-02-26
        • 2014-08-08
        • 2014-12-03
        • 2017-05-27
        • 2018-10-11
        • 2012-11-27
        相关资源
        最近更新 更多