MPI Haversine 用于 C 中的距离计算

MPI Haversine for distance calculation in C

我是 MPI 的新手,所以我尝试在 C 中使用 Haversine distance 计算方法,到目前为止它似乎有效,但我注意到结果不正确,可能是我使用的 MPI 方法有问题,这是我的代码:

#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define ROW 10                 /* number of rows in matrix */
#define COLUMN 2               /* number of columns in matrix */
#define R 6371                 /* averange radius of Earth */
#define MASTER 0               /* taskid of first task */
#define FROM_MASTER 1          /* setting a message type */
#define FROM_WORKER 2          /* setting a message type */

int main(int argc, char *argv[])
{
    int numtasks,                       /* number of tasks in partition */
        taskid,                         /* a task identifier */
        numworkers,                     /* number of worker tasks */
        source,                         /* task id of message source */
        dest,                           /* task id of message destination */
        mtype,                          /* message type */
        rows,                           /* rows of matrix A sent to each worker */
        averow, extra, offset,          /* used to determine rows sent to each worker */
        i, j, rc;                       /* misc */
    double  target[1][COLUMN],          /* longitude and latitude of target */
        dlat, dlon,                     /* longitude and latitude of destination */
        a, c, d,                        /* variable for calculation */
        destination[ROW][COLUMN],       /* matrix dest for listed destination */
        result[ROW];                    /* result in matrix */
    const char *name[ROW];                      /* name of destination */
    MPI_Status status;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
    MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
    if (numtasks < 2) {
        printf("Memerlukan minimal dua MPI tasks. Membatalkan...\n");
        MPI_Abort(MPI_COMM_WORLD, rc);
        exit(1);
    }
    numworkers = numtasks - 1;


    /**************************** master task ************************************/
    if (taskid == MASTER)
    {
        printf("MPI dengan %d tasks.\n", numtasks);
        printf("Memulai...\n");

        target[0][0] = -6.9167;
        target[0][1] = 107.6000;

        destination[0][0] = -6.1745;
        destination[0][1] = 106.8227;
        name[0] = "Jakarta";
        destination[1][0] = -6.9167;
        destination[1][1] = 107.6000;
        name[1] = "Bandung";
        destination[2][0] = -7.8014;
        destination[2][1] = 110.3644;
        name[2] = "Jogja";
        destination[3][0] = -7.2653;
        destination[3][1] = 112.7425;
        name[3] = "Surabaya";
        destination[4][0] = -5.5500;
        destination[4][1] = 95.3167;
        name[4] = "Aceh";
        destination[5][0] = 3.5833;
        destination[5][1] = 98.6667;
        name[5] = "Medan";
        destination[6][0] = -5.1333;
        destination[6][1] = 119.4167;
        name[6] = "Makassar";
        destination[7][0] = -0.9500;
        destination[7][1] = 100.3531;
        name[7] = "Padang";
        destination[8][0] = -8.6500;
        destination[8][1] = 115.2167;
        name[8] = "Denpasar";
        destination[9][0] = -0.8667;
        destination[9][1] = 134.0833;
        name[9] = "Irian Jaya";

        /* Send matrix data to the worker tasks */
        averow = ROW / numworkers;
        extra = ROW%numworkers;
        offset = 0;
        mtype = FROM_MASTER;
        for (dest = 1; dest <= numworkers; dest++)
        {
            rows = (dest <= extra) ? averow + 1 : averow;
            MPI_Send(&offset, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD);
            MPI_Send(&rows, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD);
            MPI_Send(&target[0][0], 1, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);
            MPI_Send(&target[0][1], 1, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);
            MPI_Send(&destination[offset][0], rows, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);
            MPI_Send(&destination[offset][1], rows, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);
            offset = offset + rows;
        }

        /* Receive results from worker tasks */
        mtype = FROM_WORKER;
        for (i = 1; i <= numworkers; i++)
        {
            source = i;
            MPI_Recv(&offset, 1, MPI_INT, source, mtype, MPI_COMM_WORLD, &status);
            MPI_Recv(&rows, 1, MPI_INT, source, mtype, MPI_COMM_WORLD, &status);
            MPI_Recv(&result[offset], rows, MPI_DOUBLE, source, mtype, MPI_COMM_WORLD, &status);
        }

        /* Print results */
        printf("******************************************************\n");
        printf("Hasil:\n");
        for (i = 0; i<ROW; i++)
        {
            printf("Jarak ke %s: ", name[i]);
            printf("%f", result[i]);
            printf(" km\n");
        }
        printf("\n******************************************************\n");
        printf("Selesai.\n");
    }


    /**************************** worker task ************************************/
    if (taskid > MASTER)
    {
        mtype = FROM_MASTER;
        MPI_Recv(&offset, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&rows, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&target[0][0], 1, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&target[0][1], 1, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&destination[offset][0], rows, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&destination[offset][1], rows, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status);
        for (j = offset; j<offset + rows; j++)
        {

            dlon = destination[j][1] - target[0][1];
            /* printf("dlon ke %i : %f \n", j, dlon); */
            dlat = destination[j][0] - target[0][0];
            /* printf("dlat ke %i : %f \n", j, dlat); */
            a = pow((sin(dlat / 2)), 2) + (cos(target[0][0]) * cos(destination[j][0]) * pow((sin(dlon / 2)), 2));
            /* printf("a ke %i : %f \n", j, a); */
            c = 2 * atan2(sqrt(a), sqrt(1 - a));
            /* printf("c ke %i : %f \n", j, c); */
            d = R * c;
            /* printf("d ke %i : %f \n", j, d); */
            result[j] = d;
        }
        mtype = FROM_WORKER;
        MPI_Send(&offset, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD);
        MPI_Send(&rows, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD);
        MPI_Send(&result[offset], rows, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD);
    }
    MPI_Finalize();
}

这段代码应该显示到每个地方的距离,因为它是 MPI,它应该有完全相同的结果,但结果实际上发生了变化。 另外,发送给worker的一些数据等于0,导致计算错误。

如有错误,请指出。 提前致谢:)

问题来自:

MPI_Send(&destination[offset][0], rows, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);
MPI_Send(&destination[offset][1], rows, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);

if rows==4MPI_Send() 的第一次调用将发送 destination[offset][0],destination[offset][1],destination[offset+1][0],destination[offset+1][1] 因为这些元素对应于将要发送的一维数组。第二个 MPI_Send 调用发送 destination[offset][1],destination[offset+1][0],destination[offset+1][1],destination[offset+2][0]。这意味着永远不会发送 destination[offset+3][1] !

看来你要表演:

MPI_Send(&destination[offset][0], 2*rows, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);

此操作将同时执行两行: 第二个操作待注释。 接收操作也应该改变:

MPI_Recv(&destination[offset][0],2*rows, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status);

看看MPI_Scatterv() function : it does exactly what you want to do. Look at MPI_Bcast() and MPI_Gatherv()